LilacCTF 2026 - Gate-Way
文件属性
| 属性 | 值 |
|---|---|
| Arch | hexagon-le |
| RELRO | Partial |
| Canary | off |
| NX | on |
| PIE | off |
| strip | yes |
解题思路
不知道从哪里翻出来的小众架构,Ghidra、IDA和GDB都没支持...好不容易从GitHub上翻到个IDA插件,
因为我是Linux,所以还要下载IDA SDK然后编译一下,放到IDA的procs目录下。
好不容易能用IDA打开了,发现没有反编译支持,而且还剥了符号...
硬着头逆也不是办法,先运行一下看看,找到个输入大量字符串的地方,看到别人做出来这么快, 估计有栈溢出。输入很多文本后确实会崩,但是没有调试器太难搞了,幸好LLDB支持hexagon架构, 可以查看崩溃时的信息。

把报错的pc拿去做cyclic lookup,找到偏移为98。加上前面10个字符,栈空间+fp共占用108字节。 多次调试,发现sp也没有变过,所以先尝试直接在栈上尝试执行shellcode。好不容易写好了, 发现并不能执行,看了一眼page信息,有nx,不能直接执行...
那就需要走rop了。查阅了一些资料,了解了一些hexagon的汇编指令,其中调用syscall是trap0(1),
前五个参数放在r0-r5,系统调用号放在r6中。具体的系统调用号可以从qemu仓库中找到。
我们的目标是调用 execve("/bin/sh", NULL, NULL),并且qemu-user在调用execve的时候,
其实是会逃脱模拟的,因此只要我们能exec shell,就可以执行任意命令,不需要qemu了。
由于程序是静态编译的,我们直接找有没有好用的gadget。使用 llvm-objdump -d gateway | grep -B 4 trap0
可以找到有关trap0的gadget,其中有一个比较好用的(其实是出题人加的)。
1 | 214f4: 00 c0 70 70 7070c000 { r0 = r16 } |
可以看到只要控制r16-r19就可以任意控制了。接下来就是找能控制这些寄存器的gadget。
不过首先我们需要知道hexagon架构是如何做函数返回的。具体指令是dealloc_return,
其含义是把fp+8加载到sp中,从fp处加载fp和lr,最后跳转到lr的地方,和x86上类似。
我们搜索其相关的gadget,能找到一个合适的:
1 | 217e4: 05 1e 0c 3e 3e0c1e05 { r17:16 = memd(r29+#0x8); r19:18 = memd(r29+#0x0) } |
由于是栈溢出,我们可以继续往后控制内容,以上指令的含义是把sp+0的双字,
分别加载到r18和r19中;把sp+8的双字,加载到r16和r17中,正好之前的gadget对上了。
为了避免远端的环境和本地的环境可能存在不同,在bss上找到了与我们输入内容相同的缓冲区,
直接做一次栈迁移(因为要设置一次fp),保证成功率。而且地址已知的情况下,
也方便我们布局"/bin/sh"字符串。最后思路就是1.1.1.1:1|绕检查;放置/bin/sh字符串;
控制fp做栈迁移同时控制寄存器;跳转到gadget执行execve。
EXPLOIT
1 | from pwn import * |

参考
- 标题: LilacCTF 2026 - Gate-Way
- 作者: RocketDev
- 创建于 : 2026-01-27 23:08:00
- 更新于 : 2026-01-29 00:47:00
- 链接: https://rocketma.dev/2026/01/27/gateway/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。