您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
由一次需求边界值测试引发的【整数溢出攻击】思考
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
由一次需求边界值测试引发的【整数溢出攻击】思考
自猿其说Tech
2022-01-06
IP归属:未知
245240浏览
测试
### 1 整体思路 #### 1.1 背景描述 某需求测试过程中:新增报价申请界面,点击【暂存】或【提交】,显示系统错误,无法提交,截图如下: ![](//img1.jcloudcs.com/developer.jdcloud.com/db98b49d-e6ad-47a4-bd86-6e274cd0cbcb20220106112340.png) #### 1.2 日志定位 查看日志,发现报错是:4398046512275超过int(-2147483648-2147483647)的边界范围。 ![](//img1.jcloudcs.com/developer.jdcloud.com/55116cfd-2f12-443e-b1a2-427cbc8db54820220106112355.png) #### 1.3 查看数据库 可以看到在数据库对应的表中,product_id被定义为bigint类型,表中的数据长度定义的足够长,所以4398046512275可以存储到数据库中,是没有问题的。 ![](//img1.jcloudcs.com/developer.jdcloud.com/3158e3c8-2bf8-428b-a679-5ba5c8329fd620220106112413.png) ![](//img1.jcloudcs.com/developer.jdcloud.com/20ff1ebb-042f-494c-96f5-d7a62d0deb2520220106112431.png) #### 1.4 查看代码 可以看到后端代码是声明的int类型,所以4398046512275是在代码层处理的时候也是有问题的,会将4398046512275转为为一个错误的值,导致代码处理中产生错误。 ![](//img1.jcloudcs.com/developer.jdcloud.com/7f003800-9c3f-4ae4-86c0-75347f895d8720220106112454.png) #### 1.5 思路总结 报错显示的4398046512275为“产品ID”,即产品对应的是产品的编号,在数据库中可以存下,而在后台代码处理中是int,导致代码运行中其他要用到的“产品ID”是个异常值,所以报错。 #### 1.6 解决方案 修改代码中productId的类型为long,这样可以存下4398046512275这样的比较的大的数据。 ![](//img1.jcloudcs.com/developer.jdcloud.com/fca8c9ad-1702-4c37-aeb9-a3336801f50b20220106112539.png) ### 2 关于整数溢出深入代码层的思考 #### 2.1 举个栗子 ``` #include <stdio.h> //返回读取的内容长度 int Read(int fd, int start, int end) { int length = end - start + 1; //Read 函数中最大只支持一次读取1024个字节,所以增加了一个判断逻辑。 if (length > 1024) return -1; return length; } int main(void) { //调用函数Read int Length = Read(0, 0, 5); printf("长度为:%d\n",Length); return 0; } ``` 大家看下,以上代码有没有什么问题 #### 2.2 调用函数 ``` Length = Read(0, 0, 4294967295); ``` 这里的4294967295会传参给end,而4294967295大于1024,正常会返回-1,但是真实情况是这样的吗? 但是请注意Read这个函数的参数中,start和end都是int型变量,把4294967295传递给end的时候,会被当作有符号的整数解析,也就是 -1 !所以在执行以下代码时, ``` int length = end - start + 1; ``` length的结果会是0!计算结果就是-1 - 0 + 1 = 0!这里计算的结果逃过了代码中对于长度大于1024的检查。 ``` if (length > 1024) return -1; ``` #### 2.3 思考 整数溢出在日常其他方面是否真实存在影响? ### 3 关于整数溢出的影响 #### 3.1 真实栗子 漏洞编号:CVE-2015-1635 ![](//img1.jcloudcs.com/developer.jdcloud.com/dc8856c9-d2c4-4039-a0b0-fdd4950a7d0e20220106112831.png) 这是一个微软的互联网服务器IIS中的一个漏洞,更重要的是,这个漏洞位于IIS处理HTTP请求的HTTP.sys驱动程序中。 而驱动程序是运行在操作系统内核之中,一旦内核驱动执行出现异常,那后果,轻则蓝屏崩溃,重则直接被攻击者远程执行代码,控制服务器。 #### 3.2 HTTP协议中Range字段 HTTP 1.1版本的协议中,可以通过请求头中的Range字段,请求或上传指定资源的部分内容: ``` GET /bg-upper.png HTTP/1.1 User-Agent: curl/7.35.0 Host: 127.0.0.1:8180 Accept: */* Range: bytes=0-10 ``` 其中的Range字段格式如下: ``` Range: bytes=start-end ``` 微软的IIS为了提高性能,将HTTP协议的解析放在了内核驱动 HTTP.sys 中实现。 分析:而其中对range字段的处理,就是第2部分中的Read代码的那个逻辑错误,不同的是,我们上面的那个示例是一个32位整数的版本,而IIS这个真实的漏洞是64位整数产生的问题,但原理是一样的。 #### 3.3 整数溢出攻击 通过向存在漏洞的IIS服务器发送对应的HTTP请求,即可将目标服务器打蓝屏,实现DOS——拒绝服务攻击。 ![](//img1.jcloudcs.com/developer.jdcloud.com/169caa45-69c3-43b9-a89e-721b01dbefa220220106113138.png) 这种攻击方式就是——整数溢出攻击。 #### 3.4 思考 其他常见的整数溢出有哪些? ### 4 其他常见的整数溢出 #### 4.1 有符号数溢出 ##### 4.1.1 上溢出 ``` #include <stdio.h> #include <limits.h> int main(void) { int i; i = INT_MAX; //i = 2147483647 i++; printf("i = %d\n",i); //i = -2147483648 return 0; } ``` ##### 4.1.2 下溢出 ``` #include <stdio.h> #include <limits.h> int main(void) { int i; i = INT_MIN; //i = -2147483648 i--; printf("i = %d\n",i); //i = 2147483647 } ``` #### 4.2 无符号数回绕 ##### 4.2.1 上回绕 ``` #include <stdio.h> #include <limits.h> int main(void) { unsigned int i; i = UINT_MAX; //在32位电脑上:i = 4294967295 i++; printf("i = %u\n",i); //i = 0 } ``` ##### 4.2.2 下回绕 ``` #include <stdio.h> int main(void) { unsigned int i; i = 0; i--; printf("i = %u\n",i); //在32位电脑上:i = 4294967295 } ``` #### 4.3 截断 ##### 4.3.1 加法截断 ``` #include <stdio.h> int main(void) { long a, b, c; a = 0xffffffff; b = 0x00000001; c = a + b; // c = 0x0000001 00000000(long long) = 0x00000000(long) printf("c = 0x%x\n",c); //c = 0x00000000 } ``` ##### 4.3.2 乘法截断 ``` #include <stdio.h> int main(void) { long a, b, c; a = 0x00123456; b = 0x00654321; c = a * b; // c = 0x00000733 6bf94116(long long) = 0x6bf94116(long) printf("c = 0x%x\n",c); //c = 0x6bf94116 } ``` #### 4.4 宽度溢出(不够的用符号位填充) ``` #include<stdio.h> int main(){ int a; short b; char c; a = 0xabcddcba; b = a; c = a; printf("a = 0x%x(%d bits)\n", a, sizeof(a) * 8);//a = 0xabcddcba(32 bits) printf("b = 0x%x(%d bits)\n", b, sizeof(b) * 8);//b = 0xffffdcba(16 bits) printf("c = 0x%x(%d bits)\n", c, sizeof(c) * 8);//c = 0xffffffba(8 bits) printf("b + c = 0x%x(%d bits)\n", b+c, sizeof(b+c) * 8);//b + c = 0xffffdc74(32 bits) } ``` **思考:为什么输出的b和c的高位用ffff填充?** 解答:因为变量b和c定义的为有符号的类型,以b为例,当语句执行b = a;此时先看 低位 dcba(1101 1100 1011 1010)2个字节(16位)可以容纳b,而高位需要看b的符号位,dcba(1101 1100 1011 1010)为1,所以高位全部用1填充,即ffff(1111 1111 1111 1111),执行完语句b = a后 b = 0xffffdcba; 以c为例,当语句执行c = a;此时先看 低位 ba(1011 1010)1个字节(8位)可以容纳c,而高位需要看c的符号位, ba(1011 1010)为1,所以高位全部用1填充,即ffffff(1111 1111 1111 1111 1111 1111),执行完语句c = a后 c= 0xffffffba。 ### 5 心得及总结 1. 开发 or 测试 中,一定要注意变量的数据类型,特别是涉及到数据类型转换的地方要格外留神。比如符号数与无符号数的互转,32位整数和64位整数的转换等等。 1. 涉及联调,在处理上下游系统传参数处理时,要慎之又慎,一个小小的变量类型可能就会给服务器计算机造成毁灭性打击。 1. 测试活动中,要注意数据类型的边界值的测试(而非仅仅是PRD中定义的最大值)。 1. 数据类型的长度范围汇总: ![](//img1.jcloudcs.com/developer.jdcloud.com/517b91a2-fd76-49b0-9d95-f4cc42740c8620220106113544.png) ------------ ###### 自猿其说Tech-京东物流技术发展部 ###### 作者:王鹏(西安CS测试小分队)
原创文章,需联系作者,授权转载
上一篇:架构解析 | 从ABTest是啥开始说
下一篇:京东云视频云全面支持AVS2标准
相关文章
安全测试之探索windows游戏扫雷
Jmeter压测实战:Jmeter二次开发之JSF采样器实现
Laputa自动化测试框架介绍
自猿其说Tech
文章数
426
阅读量
2149964
作者其他文章
01
深入JDK中的Optional
本文将从Optional所解决的问题开始,逐层解剖,由浅入深,文中会出现Optioanl方法之间的对比,实践,误用情况分析,优缺点等。与大家一起,对这项Java8中的新特性,进行理解和深入。
01
Taro小程序跨端开发入门实战
为了让小程序开发更简单,更高效,我们采用 Taro 作为首选框架,我们将使用 Taro 的实践经验整理了出来,主要内容围绕着什么是 Taro,为什么用 Taro,以及 Taro 如何使用(正确使用的姿势),还有 Taro 背后的一些设计思想来进行展开,让大家能够对 Taro 有个完整的认识。
01
Flutter For Web实践
Flutter For Web 已经发布一年多时间,它的发布意味着我们可以真正地使用一套代码、一套资源部署整个大前端系统(包括:iOS、Android、Web)。渠道研发组经过一段时间的探索,使用Flutter For Web技术开发了移动端可视化编程平台—Flutter乐高,在这里希望和大家分享下使用Flutter For Web实践过程和踩坑实践
01
配运基础数据缓存瘦身实践
在基础数据的常规能力当中,数据的存取是最基础也是最重要的能力,为了整体提高数据的读取能力,缓存技术在基础数据的场景中得到了广泛的使用,下面会重点展示一下配运组近期针对数据缓存做的瘦身实践。
自猿其说Tech
文章数
426
阅读量
2149964
作者其他文章
01
深入JDK中的Optional
01
Taro小程序跨端开发入门实战
01
Flutter For Web实践
01
配运基础数据缓存瘦身实践
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号