当前位置:首页|资讯

【pwn18 2024SCTF GoComplier】

作者:K3yB0ard发布时间:2024-10-05

2024SCTF的一道pwn

题目描述

程序自实现了类go语言的编译器,为ugo语言还是啥不太懂,不过附件中给出了这种语言的书写示例:

example1
example2

可以看到,这种语言像是go也像是c,还有printf函数,猜测可能有栈溢出或者格式化字符串漏洞。看一下程序的docker,有server.py如下:

可以知道程序是让我们输入这种ugo语言的源码,然后编译出一个可执行程序去执行。编译脚本如下:

首先调用ugo程序将ugo源码解析为.ll的llvm可编译程序,然后再将其编译为二进制程序。

ugo的编译有一些安全检查,例如字符串溢出、格式化字符串等,但检查并不严格。这两种漏洞依然可以利用

1、格式化字符串漏洞,在printf("%p%p%p%p")的第一个参数中fmt数量过多时会报错,但是在比较少的时候(例如一个)这种情况可以正常泄露信息等,可以配合$符号实现printf的利用。

2、栈溢出,这里的栈溢出比较奇怪,可能涉及到编译器底层的知识,经过笔者“手动fuzz构造栈溢出”,发现了程序栈溢出的触发方式。需要绕过ugo程序的一些安全检查。

例如下面的ugo代码会爆出安全检查错误:

而下面这种可以触发栈溢出:

stack overflow

在这种情况下我们可以看一下编译出来的可执行程序

IDA analyse

可以看到这种情况下编译器生成的代码中,我们的变量a其实变成了一个int64的变量,而不是一个字符串,经过多次改变payload长度进行手动fuzz,笔者发现只要ugo代码满足上面的情况,pad函数返回的字符串的长度会作为后面a赋值所能接受的最大字符串长度,但是栈溢出的长度并不是固定的,但是一定是0x8对齐的。

由于二进制文件的编译脚本中gcc没有开pie保护,而在ugo代码payload长度固定时出来的二进制程序内部各个gadget偏移是相同的,因此笔者选择直接通过栈溢出构造rop,借助syscall来getshell。为解决栈溢出偏移不固定的问题,笔者在payload前填充ret滑栈的gadget,增加exp的稳定性:

最终攻击脚本如下:

通过syscall执行execve("/bin/sh")来getshell

ugo代码:

这样编译出来的hello程序一旦运行就会在main结束后弹出shell

执行结果:

hello

成功getshell。

【注意】上述python代码用于生成bytes的payload用于构造ugo代码,所有的gadget偏移为笔者自行本机调试,在比赛中需要本地自启一个docker来cp docker中的二进制程序找gadget偏移,因为远程环境和自己本地可能存在gcc版本差异导致最终二进制程序中的gadget偏移不同。

这题最关键的是发现ugo程序跟C语言的相似性,手动fuzz出ugo编译程序的一些安全检查,如何绕过这些安全检查构造出pwn手熟知的一些漏洞。

笔者编写本文章时参考了星盟安全团队的博客

https://blog.xmcve.com/2024/10/01/SCTF-2024-Writeup

By  Del0n1x

Keyboard


Copyright © 2024 aigcdaily.cn  北京智识时代科技有限公司  版权所有  京ICP备2023006237号-1