SQL注入简介
SQL注入是比较常见的网络攻击方式之一,它不是利用操作系统的BUG来实现攻击,而是针对程序员编写时的疏忽,通过SQL语句,实现无账号登录,甚至执行篡改数据库等操作。
Low
输入1,用burp进行抓包;
将报文头复制,存储到txt文件中,命名为sql.txt;
打开sqlmap,用它去扫描文件,查看返回信息判断该网站是否存在SQL注入漏洞;
打开sqlmap,输入命令 python sqlmap.py -r "文件存储地址和文件名" --level=5 --risk=3 --dbs
-r:加载http请求,这里在文件中加载;
-level:探测级别1-5,越高越好;
-risk:探测风险1-3 越高越详细;
-dbs:爆库;
由图可以看出,该网站参数id处存在sql注入漏洞,数据库类型为MySQL,有8个数据库。
Medium
源码:
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$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( '<pre>' . mysqli_error($GLOBALS["___mysqli_ston"]) . '</pre>' );
// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Display values
$first = $row["first_name"];
$last = $row["last_name"];
// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
}
// This is used later on in the index.php page
// Setting it here so we can close the database connection in here like in the rest of the source scripts
$query = "SELECT COUNT(*) FROM users;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
$number_of_rows = mysqli_fetch_row( $result )[0];
mysqli_close($GLOBALS["___mysqli_ston"]);
?>
由代码$id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id)
发现,利用mysql_real_escape_string函数对特殊符号\x00,\n,\r,’,”,\x1a进行转义,同时前端页面设置了下拉选择表单,希望以此来控制用户的输入。
还是用sqlmap进行扫描的方法,首先选个ID值,用burp抓包,存在 .txt文件中;
在sqlmap中执行python sqlmap.py "文件地址和文件名称.txt "-t4 --dbs"
;
由图可以看出,该网站参数id存在sql注入漏洞,数据库类型为MySQL,有8个数据库。
High
源码:
<?php
if( isset( $_COOKIE[ 'id' ] ) ) {
// Get input
$id = $_COOKIE[ 'id' ];
// Check database
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // Removed 'or die' to suppress mysql errors
// Get results
$num = @mysqli_num_rows( $result ); // The '@' character suppresses errors
if( $num > 0 ) {
// Feedback for end user
echo '<pre>User ID exists in the database.</pre>';
}
else {
// Might sleep a random amount
if( rand( 0, 5 ) == 3 ) {
sleep( rand( 2, 4 ) );
}
// 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>';
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
由上可知,注入点还是id,没有做限制,与Medium级别的代码相比,High级别的只是在SQL查询语句中添加了LIMIT 1,用它控制只输出一个结果。而且,High级别的查询提交页面与查询结果显示页面不是同一个,也没有执行302跳转,这样做的目的是为了防止一般的sqlmap注入(sqlmap也是可以绕过的,可以注释掉LIMIT 1),因为sqlmap在注入过程中,无法在查询提交页面上获取查询的结果,没有了反馈,也就没办法进一步注入。这里用到的方法和Low级别相同。