转载:NB中的常见指令

2021-7-20

  返回  

DVWA通关--Brute Force(暴力破解)

2021/7/20 22:10:41 浏览:

目录

LOW

通关思路

代码分析

MEDIUM

通关思路

代码分析

HIGH

通关思路

代码分析

IMPOSSIBLE

代码分析


按照我的理解,暴力破解的成功概率,一方面取决于被攻击系统是否有防暴力破解机制,防暴力破解机制是否高效,另一方面取决于攻击者的字典以及计算机性能。

本文主要目的是分析防暴力破解机制是否有效,以及如何绕过某些防暴力破解机制,因此,出于节省时间的目的,会使用包含正确答案的比较小的用户名密码字典,仅作示范。

LOW

通关思路

1、首先观察页面,发现只要输入的用户名或者密码有一个错误,就回显“Username and/or password incorrect.”,并且尝试了6次用admin用户登录,6次都输错密码,也没有提示用户被锁定不准继续尝试登录。感觉这关并没有防暴力破解机制。

 2、尝试登录的过程中,用burpsuite抓包,抓到下面这个报文,send to intruder

3、intruder中,把username和password的值设置为爆破点,attack type选cluster bomb(这种type下用户名和密码payload会进行组合,payload总数=用户名payload数量✖密码payload数量)

第1个payload选simple list,点load按钮,把user.txt的内容加载进来(user.txt的内容是每行一个用户名)

第2个payload选simple list,点load按钮,把password.txt的内容加载进来(password.txt的内容是每行一个密码)

 4、点start attack开始暴力破解。得到的结果以length进行排序,如下图所示,length和其他不同的两组payload就是用户名和密码(用户smithy密码password,用户admin密码password)

代码分析

这关代码没什么可分析的,和猜想的一样完全没有防暴力破解机制(当然,也不防sql注入)

MEDIUM

通关思路

1、首先还是观察页面。medium和low大致是一样的,只要输入的用户名或者密码有一个错误,就回显“Username and/or password incorrect.”,并且尝试了6次用admin用户登录,6次都输错密码,也没有提示用户被锁定不准继续尝试登录。

唯一不同的是,medium关卡输错用户名密码之后,会延迟一段时间再返回登录失败的结果。也许服务器端做了登录失败情况下的sleep操作,企图通过延时降低暴力破解的效率。

2、这关的通关方法和LOW关一模一样,就是慢点,这里就不再赘述了。

另外,需要注意一下,线程过多可能导致服务器来不及响应,如果结果中有状态码500的报文,最好降低线程数量重新跑

代码分析

本关代码在防暴力破解方面比起LOW关所做的改进和猜想的一样,当用户名或密码输入错误的时候,先sleep(2)(等待2s),再返回登录失败的结果

HIGH

通关思路

1、观察页面,发现基本和MEDIUM没差,试了6次,感觉确实没多大差别,也没有锁死用户,唯一的差别是感觉有时候回显登录失败提示比较快,有时候比较慢,估计这关比起MEDIUM关的修改是登录失败时等待某个区间的随机时间。。

2、正当我以为这关竟然如此简单之时,我瞅了眼burpsuite,是我幼稚了,这关有token。。。

 3、把上图报文send to repeater,重放,返回302,说明token是一次性的;删除token也不行,结果一样。拿到网站去md5解密也解不出来。

 4、没关系,还有一招:burpsuite插件CSRF Token Tracker 

这个插件的作用是根据规则从reponse报文中找到token并使其他模块发送报文时自动更新新的token。

Extender中找到这个插件并install,然后就可以用了。

 用法很简单,勾选上Sync request based on the following rules,然后增加一条rule并勾选上就行。

 上图rule中的Name是response报文中token的名称,以本关卡为例,是在页面单击右键点击查看网页源代码,在网页源代码里找到的

 设置后在repeater中试试,发现可以正常返回提示登录失败的页面了

剩下的设置爆破参数的步骤就和前两关一样了,这里就不再赘述了。

但是有一点要特别注意,由于需要根据上一个response报文来获取下一个request报文携带的token,因此线程只能选1

代码分析

本关代码比起MEDIUM关卡甚至不一定能降低暴力破解的效率(谁知道随机sleep的时间是0s多还是3s多呢),只是防CSRF(使用anti-csrf token)的同时,误打误撞增加了一丢丢暴力破解的操作复杂度。

IMPOSSIBLE

代码分析

标准答案的代码比起前面的关卡有点长,但是不难,主要思路是某用户3次(不需要连续)登录失败后锁定15分钟,解锁后才能继续尝试登录。这种思路兼顾用户体验和安全性,较之前的关卡大大提高了暴力破解的时间成本。目前很多网站和软件基本也是采取这样的思路,只是允许的尝试次数和锁定时间不同。

下面具体分析一下本关代码。

19~21行设置了防暴力破解机制相关的3个参数:

$total_failed_login 表示允许尝试登录的次数,如果用户成功登录前,登录失败的次数达到或者超过这个值,就会锁定用户一段时间不让尝试登录。

$lockout_time 表示用户被锁定的时间。

$account_locked 是一个布尔值,表示用户是否被锁定。

24~27行进行了一个查询数据库的操作,从数据库中读取当前尝试登录的用户的登录失败次数(failed_login)和最后一次尝试登录的时间(last_login)

30~50行进行了一个判断,如果用户存在并且登录失败的次数达到或者超过了$total_failed_login,并且当前时间比上次尝试登录的时间晚不到15分钟,则$account_locked设置为true

53~57行进行了一个数据库查询操作,看用户输入的用户名和密码是否正确。

60~91行根据数据库中是否有用户输入的用户名和密码,以及用户是否还被锁定,来决定网页返回的结果。如果数据库中有用户输入的用户名和密码,并且用户不处于锁定状态,则网页回显用户登录成功后的信息,并在数据库中将用户的failed_login设置为0。其他情况下,等待一个随机时间,然后在数据库中将用户的failed_login设置为当前值加1,并返回登录失败的页面。

94~96行表示不管什么情况下,只要用户尝试登录,就在数据库中更新用户最后一次尝试登录的时间。

<?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();

?>

联系我们

如果您对我们的服务有兴趣,请及时和我们联系!

服务热线:18288888888
座机:18288888888
传真:
邮箱:888888@qq.com
地址:郑州市文化路红专路93号