web安全學習筆記(三) SQL注入

在上一節中,使用PHP搭建了簡單的登陸界面,爲了更加熟悉網站的配置,對網站的默認主頁進行了修改,並且將網站的程序移動到了/home/tong/Downloads/目錄下。
修改網站的默認主頁,可以通過修改/etc/apache2/mods-enabled/dir.conf文件:
在這裏插入圖片描述
講login.php移動到DirectoryIdex後面,則輸入localhost時,默認跳轉到登陸界面了:
在這裏插入圖片描述
移動網站路徑,先講所有的網站文件移動到/home/tong/Downloads 下,然後修改/etc/apache2/sites-available/php_website.conf,目錄爲移動後的目錄:
在這裏插入圖片描述
除此之外,還需要修改/etc/apache2/apache2.conf中的路徑:
在這裏插入圖片描述
(這個文件比較長,可以輸入/,再輸入關鍵字快速定位到需要修改的位置。

接下來就是進行sql注入的測試了:
程序的登陸邏輯如下:

<?php

$conn = new mysqli("localhost","phpadmin", "ppzz4869","PHP");
if ($conn->connect_error){
    die("connection fail" . $conn->connect_error);
}
$name = trim($_POST['username']);
$psw = trim($_POST['password']);
$sql="select * from user where name='$name' and psw='$psw'";
$res = $conn->query($sql);
if ($res->num_rows > 0){
    setcookie('username',$name,time()+3600);
    header("Location:index.php");
} else{
    echo "login fail,<a href=\"login.php\">Please re-login</a>";
}

在程序中,對接收的關鍵字username 和 password做了trim()處理,即過濾掉字符串中的所有空格。那麼如果不加trim(), 會發生什麼情況呢?
假如我們這裏去掉了對username的trim()處理,用戶名輸入’or 1=1-- (注意–後有一個空格),密碼爲空,不輸入。
在這裏插入圖片描述
點擊登陸,竟然發現登陸成功了:
在這裏插入圖片描述
打開phpstorm調試,在$sql 處設置斷點:
在這裏插入圖片描述
可以看到,這裏的sql語句根據輸入變成了:

select * from user where name=''or 1=1-- 'and psw='";

在MySQL中,註釋符有#,-- ,和/* */ 被註釋掉的代碼不會被執行
所以sql語句變爲了:

select * from user where name=''or 1=1;

1=1 始終爲true,那麼where後的表達式,也始終爲true,數據庫則會返回所有的行。所以,$res->num_rows > 0條件滿足,cookie被設置並且自動跳轉到登陸界面。
如果對username做了空格的過濾後,則發現登陸失敗。因爲MySQL中註釋–後必須跟有空格。
萬能密碼登陸的一個思路就是,閉合sql語句中的單引號,並且使where後的表達式恆爲一。那麼如果用戶名和密碼字段都不允許出現空格該如何登陸?
在MySQL中,註釋符號不僅有-- ,還有# 和 /**/,所以構造用戶名:
username=‘or’1’=‘1’#
在這裏插入圖片描述
顯示登陸成功。
上面的兩個例子,都使用到了MySQL的註釋符,然而在很多系統中,註釋符號往往被系統過濾掉了,那麼可以進行如下的構建:
username=adasd’=’
password=adasd’=’
登陸成功:
在這裏插入圖片描述
還是按照剛纔的思路,sql語句被構建成了:

select * from user where username='adasd'='' and password='adasd'=''

username=‘adasd’返回值爲空,判斷空=’’,成立,所以and的左右兩側都爲1,
查詢返回所有用戶的信息,num_row>0,登陸成功。

假設現在index界面有一個查詢功能,輸入用戶名,可以返回在數據庫的用戶名,如果不存在,則返回空。修改後的代碼如下:

<?php
$cookie = $_COOKIE['username'];
if (!isset($_COOKIE['username']))
{
    echo 'Illegal login!<a href="login.php">please login</a>';
    exit();
} else{
    echo "Welcome  " , $cookie;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <title> Hello World! </title>
    <meta charset="UTF-8">
</head>
<body>
<form name="input" action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
    user: <br /><label>
        <input type="text" name="username">
        <input type="submit" value="query">
    </label><br>

</form>

<?php
$conn = new mysqli("localhost","phpadmin","ppzz4869","PHP");
if ($conn->connect_error){
    echo "connection fail";
}
$name = $_POST['username'];
$sql = "select * from user where name = '$name'";
$res = $conn->query($sql);
if ($res->num_rows > 0){
    while ($row = $res->fetch_row()){
        echo $row[0] , "\t";
    }
} else {
    echo "no such user";
}
?>

</body>
</html>

查詢用戶tong,存在:
在這裏插入圖片描述
查詢用戶aaaaaaa:
在這裏插入圖片描述
這裏的查詢語句是:

select * from user where name = '$name'

可以知道,如果我們讓where後爲真,那麼查詢則會返回所有用戶的數據:
在這裏插入圖片描述
由此我們可以得知,數據庫的user表中,共有四行。
如何知道後端的sql語句查詢了多少個字段呢?
在數據庫查詢中,有時會用到order by命令,order by 命令對查詢結果進行排序。
假設我們註冊的用戶用戶名爲a,那麼:
在這裏插入圖片描述
結果正常返回,
在這裏插入圖片描述
依然正常返回,
在這裏插入圖片描述
當 order by 3 時,可以發現提示 no such user, 說明查詢出錯,select 語句一共查詢了兩個字段,當按第三列進行排序時,就會報錯了。
或是使用union查詢也可以達到相同的效果,例如:
在這裏插入圖片描述
不同的是,使用union查詢時,只有匹配到正確的行數,程序纔可以返回正常。
union查詢也可以查看查詢返回的信息屬於第幾個字段,比如在MySQL中,支持這樣的union查詢:

select * from user where name = '$name' union select 1,2;

我們可以構建類似的SQL注入:
在這裏插入圖片描述
可以發現,返回的結果是a 1,說明查詢返回的結果是第一個字段。
通過UNION查詢,利用MySQL自帶的系統函數,可以查詢到許多想要的信息。
例如,@@datadir 可以返回數據庫的路經,@@basedir可以返回MySQL的安裝路經,通過UNION查詢返回出來。
在這裏插入圖片描述
在這裏插入圖片描述
還有一些函數,例如user()返回當前數據庫的用戶名:
在這裏插入圖片描述
由於在搭建網站的過程中,對數據庫的賬戶的權限進行了限制,如果登陸數據庫的賬戶具有File 權限時,可以讀取服務器中的文件,甚至可以寫文件,生成一句話木馬。由於這個網站在搭建過程中,對用戶做了權限的限制,沒有FILE權限,不可以達到這些目的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章