LOW等级
我们先输入1
我们加上一个单引号,页面报错
我们看一下源代码:
<?php if( isset( $_REQUEST[ 'Submit' ] ) ) { // Get input $id = $_REQUEST[ 'id' ]; // Check database $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';"; $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>' ); // Get results while( $row = mysqli_fetch_assoc( $result ) ) { // Get 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>"; } mysqli_close($GLOBALS["___mysqli_ston"]); } ?>
我们看
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';"
$id = $_REQUEST[ 'id' ];
id也没有进行过滤。。。。我们可以尝试闭合单引号
比如我们输入id=1' or '1'='1
原句就变成:
$query = "SELECT first_name, last_name FROM users WHERE user_id = '1' or '1'='1';";
下面是如何来利用sql注入
文件读取
写入一句话木马
或者用sqlmap自动化注入:
sqlmap.py sqlmap -u "http://www.secexercise.tk/vulnerabilities/sqli/?id=1&Submit=Submit#" -p "id" --cookie "uuid=uid15204271354091678690121028269; PHPSESSID=rsv9ga280c8gpn6oheb5vhd8p3; security=low"
sqlmap成功注入
sqlmap获取webshell:
Medium等级
我们先尝试来抓包:
然后尝试修改id参数,Go向前观察页面变化
后面的利用跟LOW等级一样,这里不再赘述
High等级
我们尝试LOW等级的注入方法,发现一下就成功了
我们使用LOW等级的SQL map自动化攻击,发现失效,应为注入的点与返回的点不在同一个页面上
后面步骤不再展示
impossible等级
我们先来看一下代码:
<?php if( isset( $_GET[ 'Submit' ] ) ) { // Check Anti-CSRF token checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Get input $id = $_GET[ 'id' ]; // Was a number entered? if(is_numeric( $id )) { // Check the database $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(); // Make sure only 1 result is returned if( $data->rowCount() == 1 ) { // Get 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>"; } } } // Generate Anti-CSRF token generateSessionToken(); ?>
重点看以下代码:
if(is_numeric( $id )) { // Check the database $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();
这里对接受过的参数id进行判断,is_numeric()函数——》如果id是一个数字,则返回真
然后通过使用预编译语句(prepared statements)和参数化查询(parameterized queries)。这些sql语句从参数,分开的发送到数据库服务端,进行解析。这样黑客不可能插入恶意sql代码。
有两种方式去完成这个:
1.使用PDO对象(对于任何数据库驱动都好用)
$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name'); $stmt->execute(array('name' => $name)); foreach ($stmt as $row) { // do something with $row }
2. 使用MySqli
$stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?'); $stmt->bind_param('s', $name); $stmt->execute(); $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) { // do something with $row }
如果你链接的数据库不是mysql,你可以参考具体数据库所提供的其他选项,例如(pg_prepare() and pg_execute() for PostgreSQL)
Pdo是一个通用的选项。
1|0解释
到底发生了什么呢?你的SQL语句交给prepare 之后被数据库服务器解析和编译了。通过制定参数(不管是?还是命名占位符:name),你都可以告诉数据库引擎哪里你想过滤掉。然后当你执行execute方法时,预处理语句会把你所指定的参数值结合袭来。
这里很重要的就是参数