目錄
一、水平越權
二、賬戶功能探測
1、登錄賬號lucy
2、登錄賬號lili
3、登錄賬號kobe
三、源碼分析
四、滲透實戰
1、登錄lucy賬號
2、越權訪問lili賬戶資料
3、越權訪問kobe賬戶資料
本系列為《pikachu靶場通關筆記》滲透實戰,本文通過對越權關卡源碼的代碼審計找到產生缺陷的真實原因,講解越權關卡的原理并進行滲透實踐。如下圖所示,pikcahu靶場在越權關卡介紹的過程中講解越權的產生原因:如果使用A用戶的權限去操作B用戶的數據,A的權限小于B的權限,如果能夠成功操作,則稱之為越權操作。 越權形成的原因是后臺使用了不合理的權限校驗規則導致的,本文專門講解越權之水平越權部分的滲透實戰。
越權分為兩個關卡,分別是水平越權和垂直越權,兩者區別如下所示。?
對比項目 | 水平越權 | 垂直越權 |
---|---|---|
定義 | 相同權限等級用戶間,非法訪問或操作其他用戶資源、數據,如同為普通用戶,一方訪問另一方信息。 | 不同權限等級用戶間,低權限用戶非法訪問高權限用戶資源數據,或高權限用戶訪問不應訪問的更高層級資源,如普通用戶獲取管理員權限。 |
一、水平越權
水平越權是指同一權限級別的用戶之間,通過非法手段訪問或操作其他用戶的資源或數據,而這些資源或數據本應是相互隔離、僅能由各自的所有者進行訪問和操作的。例如,在一個在線銀行系統中,兩個普通用戶 A 和 B,用戶 A 通過某種方式獲取了用戶 B 的賬戶信息,并能夠對其進行操作,這就發生了水平越權訪問。
類別 | 詳情 |
---|---|
定義 | 同一權限級別的用戶,能非法訪問、操作其他用戶的資源或數據,這些資源本應僅由各自所有者訪問操作。 |
產生原因 | 1.?參數可預測:應用用可預測參數(如連續數字 ID)標識用戶資源,攻擊者可猜測、枚舉修改參數訪問他人資源; 2.?訪問控制不足:僅依賴登錄狀態或簡單權限驗證,未嚴格檢查資源所有者,致攻擊者可越權操作 |
危害 | 1.?隱私泄露:攻擊者獲取他人敏感信息,侵犯用戶隱私; 2.?數據篡改:修改他人數據,致數據不一致,影響業務運行; 3.?身份冒用:冒用他人身份操作,給被冒用者帶來麻煩損失。 |
防范措施 | 1.?強化訪問控制:關鍵操作嚴格驗證,不僅驗登錄和權限,還查資源所有者與用戶是否一致; 2.?參數驗證過濾:嚴格驗證、過濾用戶輸入參數,用白名單、類型檢查、長度限制等確保參數安全; 3.?使用不可預測標識:用隨機 UUID 等不可預測標識符標識資源,增加攻擊者猜測難度; 4.?日志監控:記錄用戶操作日志,監控分析,及時發現異常訪問并處理。 |
二、賬戶功能探測
1、登錄賬號lucy
進入pikachu靶場越權之水平越權關卡,登錄普通賬號lucy(lucy/123456),密碼根據頁面右上角的提示“lucy/123456,lili/123456,kobe/123456”獲取,這個關卡的三個賬號都是普通用戶,沒有管理員,具體如下所示。
http://127.0.0.1/pikachu/vul/overpermission/op1/op1_login.php#
使用lucy賬號登錄后,進入了個人中心頁面,有一個“點擊查看個人信息”的頁面。
http://127.0.0.1/pikachu/vul/overpermission/op1/op1_mem.php
點擊查看個人信息,進入到如下頁面,可以查看lucy個人信息,此時完整URL地址如下所示。?
http://127.0.0.1/pikachu/vul/overpermission/op1/op1_mem.php?username=lucy&submit=%E7%82%B9%E5%87%BB%E6%9F%A5%E7%9C%8B%E4%B8%AA%E4%BA%BA%E4%BF%A1%E6%81%AF#
此時注意到頁面右上角的提示信息“這里可以查別人的信息嗎?”,然而在lucy登錄后的頁面中,我們沒有其他鏈接地址可以查到其他人的信息。
2、登錄賬號lili
接下來我們驗證下其他的賬號是否有查看他人信息的方法,此時退出lucy賬號,回到水平越權的登錄頁面,登錄賬號lili(lili/123456),和lucy用戶一樣,當我們點擊查看個人信息后,現實的只有lili賬號的信息,完整的URL地址與頁面效果如下所示。
http://127.0.0.1/pikachu/vul/overpermission/op1/op1_mem.php?username=lili&submit=%E7%82%B9%E5%87%BB%E6%9F%A5%E7%9C%8B%E4%B8%AA%E4%BA%BA%E4%BF%A1%E6%81%AF
這里注意,本步驟2.2相對于2.1步驟lucy的查看信息僅username不同,由lucy變為lili。?
3、登錄賬號kobe
接下來我們驗證下其他的賬號是否有查看他人信息的方法,此時退出lili賬號,回到水平越權的登錄頁面,登錄賬號kobe(kobe/123456),和lucy和lili用戶一樣,當我們點擊查看個人信息后,現實的只有lili賬號的信息,完整的URL地址與頁面效果如下所示。?
http://127.0.0.1/pikachu/vul/overpermission/op1/op1_mem.php?username=kobe&submit=%E7%82%B9%E5%87%BB%E6%9F%A5%E7%9C%8B%E4%B8%AA%E4%BA%BA%E4%BF%A1%E6%81%AF
這里注意,本步驟2.3相對于2.1、2.2步驟lucy和lili的查看信息僅username不同,用戶名變為lili。?
三、源碼分析
接下來分析普通用戶查看資料的頁面源碼op1_mem.php文件,其URL如下所示。
http://127.0.0.1/pikachu/vul/overpermission/op1/op1_mem.php
打開op1_mem.php文件,這段代碼的主要功能是實現一個用戶信息查詢和退出登錄的功能,對其源碼進行詳細注釋,具體如下所示。
<?php
// 調用 connect 函數,此函數可能用于建立與數據庫的連接,將返回的連接對象賦值給變量 $link
$link = connect();// 調用 check_op_login 函數,傳入數據庫連接對象 $link,用于檢查用戶是否已登錄
// 如果用戶未登錄,即 check_op_login 函數返回 false
if (!check_op_login($link)) {// 使用 header 函數將用戶重定向到登錄頁面 op1_login.phpheader("location:op1_login.php");
}// 初始化一個空字符串變量 $html,用于存儲后續要輸出的 HTML 內容
$html = '';// 檢查是否通過 GET 方式提交了名為 submit 的參數,并且名為 username 的參數不為空
if (isset($_GET['submit']) && $_GET['username'] != null) {// 調用 escape 函數,傳入數據庫連接對象 $link 和 $_GET['username']// 該函數可能用于對用戶輸入的用戶名進行轉義處理,防止 SQL 注入攻擊$username = escape($link, $_GET['username']);// 構建一個 SQL 查詢語句,用于從 member 表中查詢用戶名等于 $username 的所有記錄$query = "select * from member where username='$username'";// 調用 execute 函數,傳入數據庫連接對象 $link 和 SQL 查詢語句 $query// 該函數可能用于執行 SQL 查詢,并返回查詢結果$result = execute($link, $query);// 調用 mysqli_num_rows 函數,傳入查詢結果 $result,用于獲取查詢結果中的記錄數量// 如果記錄數量為 1,說明找到了對應的用戶記錄if (mysqli_num_rows($result) == 1) {// 調用 mysqli_fetch_assoc 函數,傳入查詢結果 $result,將查詢結果的第一行記錄以關聯數組的形式返回$data = mysqli_fetch_assoc($result);// 從關聯數組 $data 中提取用戶名、性別、電話號碼、地址和郵箱信息,并分別賦值給對應的變量$uname = $data['username'];$sex = $data['sex'];$phonenum = $data['phonenum'];$add = $data['address'];$email = $data['email'];// 使用 heredoc 語法將用戶信息拼接成 HTML 代碼,并追加到變量 $html 中$html .= <<<A
<div id="per_info"><h1 class="per_title">hello,{$uname},你的具體信息如下:</h1><p class="per_name">姓名:{$uname}</p><p class="per_sex">性別:{$sex}</p><p class="per_phone">手機:{$phonenum}</p> <p class="per_add">住址:{$add}</p> <p class="per_email">郵箱:{$email}</p>
</div>
A;}
}// 檢查是否通過 GET 方式提交了名為 logout 的參數,并且其值等于 1
if (isset($_GET['logout']) && $_GET['logout'] == 1) {// 調用 session_unset 函數,用于釋放當前會話中所有已注冊的變量session_unset();// 調用 session_destroy 函數,用于銷毀當前會話session_destroy();// 調用 setcookie 函數,將會話的 cookie 過期時間設置為當前時間減去 3600 秒,即讓該 cookie 立即過期setcookie(session_name(), '', time() - 3600, '/');// 使用 header 函數將用戶重定向到登錄頁面 op1_login.phpheader("location:op1_login.php");
}
?>
?代碼的主要功能流程如下所示。
- 建立與數據庫的連接。
- 檢查用戶是否已登錄,如果未登錄則重定向到登錄頁面。
- 當用戶通過 GET 請求提交 submit 參數和 username 參數時,從數據庫中查詢該用戶名對應的用戶信息。若找到匹配記錄,則將用戶信息以 HTML 格式展示出來。
- 當用戶通過 GET 請求提交 logout 參數且其值為 1 時,銷毀當前會話,清除會話 cookie,并將用戶重定向到登錄頁面。
然而本關卡的代碼存在水平越權安全風險,主要原因在于權限校驗機制存在問題。代碼僅對用戶的登錄狀態進行了檢查,而在查詢用戶信息時,沒有將查詢操作與當前登錄用戶進行綁定,而是直接使用了用戶通過 GET 請求傳入的 username 參數來查詢數據庫。這就意味著,只要用戶處于登錄狀態,就可以通過修改 URL 中的 username 參數,查詢到任意其他用戶的信息,從而導致同一權限級別的用戶之間出現水平越權訪問的情況。例如,用戶 A 登錄后,將 URL 中的 username 參數修改為用戶 B 的用戶名,就可以獲取到用戶 B 的個人信息。
四、滲透實戰
1、登錄lucy賬號
登錄lucy賬戶并查看個人信息,進入如下頁面,完整URL如下所示。
http://127.0.0.1/pikachu/vul/overpermission/op1/op1_mem.php?username=lucy&submit=%E7%82%B9%E5%87%BB%E6%9F%A5%E7%9C%8B%E4%B8%AA%E4%BA%BA%E4%BF%A1%E6%81%AF#
2、越權訪問lili賬戶資料
將第1步驟中URL地址中的username中的lucy替換為lili,如下所示。
http://127.0.0.1/pikachu/vul/overpermission/op1/op1_mem.php?username=lili&submit=%E7%82%B9%E5%87%BB%E6%9F%A5%E7%9C%8B%E4%B8%AA%E4%BA%BA%E4%BF%A1%E6%81%AF
訪問URL后進入到了lili賬號的個人信息查看頁面,具體如下所示。
3、越權訪問kobe賬戶資料
將第1步驟中URL地址中的username中的lucy替換為kobe,水平越權滲透成功,如下所示。
http://127.0.0.1/pikachu/vul/overpermission/op1/op1_mem.php?username=kobe&submit=%E7%82%B9%E5%87%BB%E6%9F%A5%E7%9C%8B%E4%B8%AA%E4%BA%BA%E4%BF%A1%E6%81%AF
訪問URL后進入到了kobe賬號的個人信息查看頁面,水平越權滲透成功,具體如下所示。