arm_exploit_me学习
arm_exploit_me
wp:一文读懂ARM架构下的漏洞利用 - IOTsec-Zone
刷下来感觉有点pwn入门的味了~🥰
这里只刷了一遍32位。
arm架构基础知识
ARM32寄存器集
R0:存储临时变量 或者 函数返回值
R0~R3:四个寄存器存储函数调用时前4个参数 多余参数放到栈上
R7:系统调用号
R11:寄存器即可以用来记录回溯信息,也可以当做局部变量来使用 –> 相当于ebp FP
R13/SP:指向栈顶
R14/LP:存放函数返回地址
R15/PC(程序计数器) IP:与x86不同的点在于PC在ARM状态下存储当前指令+8的地址。
Level 1 – 整数溢出
atoi函数
atoi函数接受一个指向字符串的指针作为参数,并返回转换后的整数值。如果转换失败,则返回0。
atoi函数的参数是一个指向字符串的指针,该字符串表示一个整数。字符串可以带有正负号和小数点,但必须以数字开头,否则转换将失败。
32位
漏洞逻辑:输入的a1字符串在被atoi强转后被存储在int类型的v2中,我们需要过第一个对v2的check以及后面2字节v2的check。
也就是说我们需要控制v2的值(DWORD)非空,且v2(WORD)为空
这里有个取巧方法,第一次check了四字节,第二次check了2字节,那么设置低16位为0,其余非0即可绕过
输入65536
第一次比较 R3(0x10000)
第二次比较 R3(0)
拿到password
输入-65536(0xffff0000)同理
至于输入一个极大的负数时能够绕过check
可以看看atoi的返回值
可以看到atoi(-9999999999999999999)返回结果为0x80000000即int类型(32位)最小值-2,147,483,648
32.gdb
1 | # qemu-arm-static -L /usr/arm-linux-gnueabi/lib/ -g 1234 ./exploit hello 65536 |
Level 2 – 堆栈溢出
32位
没有对输入的a1和a2进行check,存在栈溢出
我们利用第三个strcpy进行利用,r11存储着函数的返回地址。前面填充长度为12字节。
再拿到level3Password的函数地址,直接打就ok了
32.gdb
1 | qemu-arm-static -L /usr/arm-linux-gnueabi/lib/ -g 1234 ./exploit help aaaa bbbb |
32exp.py
1 | from pwn import * |
Level 3 – 数组溢出
32位
不难看出没有限制a1的大小,导致a1可以输入一个大数或者负数,然后将改写v3数组对应的值即可。
这里我们看一下堆栈布局。
也就是意味着我们需要控制 v3[4]=v3[4*a1-128],计算得到a1=33
32.gdb
1 | qemu-arm-static -L /usr/arm-linux-gnueabi/lib/ -g 1234 ./exploit Velvet 33 73912 |
32exp.py
1 | from pwn import * |
Level 4 – strcpy末尾+\x00导致的off by null
32位
题目名叫off by one,感觉叫off by null更贴切一点,strcpy会在末尾加上\x00导致一字节溢出
复制前
strcpy复制后
32.gdb
1 | qemu-arm-static -L /usr/arm-linux-gnueabi/lib/ -g 1234 ./exploit mysecret $(cyclic 256) |
Level 5 – 堆栈溢出
32位
实现了一个简单的类似于canary的保护机制,我们需要溢出dest来控制v5=1
v5在v6的低四字节,只溢出到v5可以不用管v6,这个canary有些名存实亡了。
32.gdb
1 | qemu-arm-static -L /usr/arm-linux-gnueabi/lib/ -g 1234 ./exploit happyness |
Level 6 – 非栈上格式化字符串漏洞
32位
格式化字符串漏洞,往v2中写89即可
这里输入了%p-%p-%p-%p-%p-%p-%p-%p,可以看到前三位为空,很有可能时R1 R2 R3,然后开始打印栈上数据(SP开始)。那么就可以计算出栈上数据的偏移。
v2为v1地址,也就是下图sp+4。得到偏移值为5。从而构造payload=%89c%5$n
成功!
32exp.py
1 | from pwn import * |
Level 7 – 堆溢出
32位
没有对输入的a1进行限制,导致strcpy复制时将字符串复制进dest指向的堆块,dest的堆块溢出至v3堆块
调试一下,不难看出这是两个申请的堆块,输入的字符串将填充进0x3a098,也就是dest所在chunk的data域。
所以构造payload=b’a’*0x28+p32(26467)
Level 8 – 类型混淆
32位
dest溢出覆盖ptr使其指向v1指针指向的地址即可。payload=b’a’*0x48+p32(0x3a098)
32exp.py
1 | from pwn import * |
当然,因为是qemu起的,所以栈地址也不会变化,所以也能直接往栈上写入0x216a0,然后控制ptr指向写入0x216a0的栈地址。
1 | from pwn import * |
Level 9 – 无效化
32位
我们需要输入两个参数addr和flag,然后这两个参数将传入nullify函数中,我们需要v3=0,那么可以利用 *v4=0,而 v4=addr,addr可控,条件flag=1可控,因为是v4的数据设置为了0,那么我们填入v3的地址即可。
Level 10 – 命令注入
32位
使用;来连接命令,这里要注意;、&&需要加引号,否则命令行优先级大于程序输入变量,导致在命令行被解析成为正常命令,而没有出现在程序中,如下图:
Level 11 – 路径遍历
32位
匹配到了即可
Level 12 – ROP
32位
没有校验a1长度,且memcpy没有限制正确长度,导致dest存在溢出。
要么直接溢出返回到打印password的地方,用gadget来控制r0=22136然后返回到comp函数
pop r0
32exp.py
1 | from pwn import * |
Level 13 – UAF
32位
我们需要输入参数以及cmd
目标函数
不难看出我们的目标就是将mappingptr+64改为上面的level3password函数地址或者是在dele操作中 将mappingptr+68改为上面的level3password函数地址
new_mapping
add操作
每次能申请出0x208大小的chunk
destroymapping
delete操作
fillmapping
先申请0x200的chunk,再往chunk里写入0x100字节数据
逻辑:先使用add申请出一块0x200的chunk1,再将它释放掉,它会进入tcachebin中(我使用的libc应该>=2.27),这个过程中mappingptr没有变化。然后再进行fillmapping操作,将刚刚释放掉的堆块申请回来,往其中写入数据,即可利用case 3或者dele操作执行level3password
32.exp
1 | from pwn import * |
32.gdb
1 | qemu-arm-static -L /usr/arm-linux-gnueabi/lib/ -g 1234 ./exploit Magic 0 |
Level 14 – JOP
32位
我们len以及par都可控,那么第二个fread处存在溢出,可以直接使用溢出改程序控制流,使程序结束后直接跳到第38行。