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方法時,預處理語句會把你所指定的參數值結合襲來。
這里很重要的就是參數