想起来这是前几年在湖里打的印象比较深刻的题目,难度不大,但是非常有意思,最后做出来用的是一个非预期的做法。
题面
这里已经找不到当年的题面了,但是业务逻辑非常简单。这里尝试描述下。
主界面大概长这样。输入一段groovy代码并执行。
执行失败,这里打开一个不存在的文件。
成功执行。可惜没有给stdout。
一些危险的代码会被过滤掉,例如 execute
。估计不止字符串过滤。
过滤绕过
由于题目并没有给具体的过滤规则,因此只能直接尝试了。最后试出来,下面的代码可以获取flag中的信息,但是没有信息返回到前端。
1 | File file = new File("flag") |
事实上根据官方题解,可以通过 UTF-8
进行字符绕过。据说使用 Groovy
自带的API也行。
事实上如果是现在的我,可能直接尝试反弹shell了,然而当时没有vps。
正常解法
可以看官方解析,反正我是看不太懂。不会一点web和misc/(ㄒoㄒ)/~~
ByteCTF 2022 官方writeup - Feishu Docs (larkoffice.com)
画风长这样:
同时还有朋友用Groovy的API来扒文件的解
https://o.hujiekang.top/2022/09/25/ByteCTF-2022-WriteUp
野路子:阴间信道
没回显≠没泄露信息
–不等式解题就是快
由于当时没有vps,反弹shell和各种渗透方法也不太懂,因此需要找其他方法来在没有回显的情况下泄露信息。
虽然没给stdout,但是前端会在执行结束后会提示是否执行成功,事实上这个事件本身就传递了一比特的信息。因此如果我们能控制执行的成功和失败,将它和我们需要泄露的内容关联起来(事实上就是编码了),这样就相当于构造了一个信道。阴间信道这个词似乎有点虎狼之辞啊。。。
如何操控程序成功失败呢?其实挺简单的,用条件分支控制程序爆一个异常就行了。
因此可以枚举flag的每一位,判断是否是某字符,比较成功时让程序执行一下除以0。剩余的工作就是写web板子了,post发送代码,参数名为ctx。
贴上代码:
1 | code='''File file = new File("flag") |
小结
类似信道的思路在ctf中也常常出现。例如2022年TCTF的初赛ezvm这题。
题目给了一个虚拟机,每次都可以运行给定的指令,每次运行结束都会给打印提示信息,但是没有任意print所以事实上也是没给自由的stdout。
而题目给的指令中有一个print(“what???”)的指令,事实上这就至少给了一个单比特信道。这样在两次执行的结束提示之间,通过检查输出了多少what字符串就可以逐比特或者逐字节泄露。
企鹅佬似乎没有通过这种泄露方法,这里也贴一下。ezvm