首先说明一下PHP中empty()函数的特性,在empty($var)中,当var存在,并且是一个非空非零的值时,返回FALSE否则返回TRUE。而其中若变量为0则会被认为是空的,返回TRUE。
在问题代码else if里,当$dopost==safequestion时,通过用户ID查询出用户的安全问题和答案,当问题和答案不为空且等于数据库中查出来的问题和答案时就进入sn()函数。
而在$row['safequestion']==$safequestion && $row['safeanswer']==$safeanswer中,因为使用了不够严谨的==进行了比较,导致if语句的条件为真,就会进入分支sn函数。
但如果用户没有设置问题和答案,系统默认的问题是0而答案是空。
理一下逻辑:
当输入密保答案为空时,即传入答案$safeanswer=''时:
$row['safeanswer']==$safeanswer 成立
但是传入问题$safequestion="0"时,由于empty()函数,会进入if(empty($safequestion)) $safequestion='',导致$safequestion等于空。此时$row[safequestion]==$safequestion不成立。
因此要让$row[safequestion]==$safequestion
必须绕过if判断,这就是PHP弱类型问题,使用"0.0"、"0."、"0e1"就可以绕过判断,例如输入密保问题为0.0,那么:
if(empty(0.0))为FALSE,可以绕过if(empty($safequestion)) $safequestion=''的判断
if('0.0'=='0')为TRUE,可以使$row[safequestion]==$safequestion成立
成功进入sn()函数,跟进sn()函数
2、sn()函数,源码文件在 /member/inc/inc_pwd_function.php:
首先在数据库中根据id到pwd_tmp表中查询,判断之前是否进行过忘记密码操作。
如果没有$row则为空,进入之一个if条件,到发送新邮件的newmail()函数中。
newmail()函数
进入newmail()函数中,会根据邮件地址发送邮件并插入一个记录到pwd_tmp表中。
如果之前进行过忘记密码的操作,但时间超过了10分钟,则会更新pwd_tmp表中数据。
跟进newmail函数:
如果是之一次进行忘记密码操作,则newmail()函数会进入insert操作,将8位的随机字符串$randval加密后插入到pwd_tmp表中,然后当$send=N时(默认传入N),将随机字符串$randval拼接到url中返回,返回的url为:
http://www.123.com/member/resetpassword.php?dopost=getpassword&id=$mid&key=$randval
其中$mid为可控参数member_id,且返回的URL中含有重置密码的验证码key,那么就可以直接重置对应id的用户密码了。
再回到重置密码文件/member/resetpassword.php ,在重置密码时,判断用户id是否存在且进行过密码重置操作,若没有则退出。
如果超时,则删除pwd_tmp表中数据;如果未超时,则跳转到修改密码界面resetpassword2.htm
输入要修改的密码并提交后,数据包中提交setp变量值为2
判断传入key的md5值是否等于数据库中的值,若相等则修改对应用户密码。
漏洞验证
直接发送如下请求即可获取重置密码的链接:
http://127.0.0.1/dedecms/uploads/member/resetpassword.php?dopost=safequestion&safequestion=0.0&id=2
注意事项
若安全问题重置密码出现问题,即一直跳转对不起...则为id没有传进去,修改inc_pwd_function.php文件中如下位置:
任意文件上传漏洞
漏洞分析
1、文件上传检测逻辑
先在/include/uploadsafe.ini.php中使用黑名单机制进行检测
除非是管理员后台dedeadmin才可上传黑名单文件。
之后在/include/dialog/select_images_post.php中进行过滤和白名单检测。
2、上传绕过
在/include/dialog/select_images_post.php中,36行将文件名中正则匹配到的异常符号替换为空白,并在之后38行检测文件名中是否存在白名单中文件格式,这两种做法均未取文件后缀名来进行判断,所以存在被绕过的漏洞。
查找$cfg_imgtype白名单,在upload/data/config.cache.inc.php第16行发现了上传格式的限制
上传成功后会重命名文件,截取最后一个.后面的字符为后缀,如:1.jpg.php 则会重命名为时间+随机字符.php
因此可以用1.jpg.p*hp等方式绕过:
其中p*hp绕过uploadsafe.inc.php的黑名单检测,而后因其中包含特殊字符*,在select_images_post.php中被正则匹配替换为空,则变成1.jpg.php,再匹配白名单config.cache.inc.php中的$cfg_imgtype,发现文件名中包含jpg从而绕过白名单检测,最后重命名文件将1.jpg.php重命名为时间+随机字符.php实现上传绕过。
漏洞验证
注册账号进入会员中心
在内容中心找到文章发表
找到上传点
上传图片马并抓包
修改filename的2.png为2.png.p*hp后放包
代码执行漏洞
漏洞分析
由于DedeCMS的全局变量注册特性,content和filename变量可控
可以直接将content的值写入到文件中,因为正则,所以文件必须以.lib.php结尾
因为存在csrf_check()函数,所以请求中必须有token
漏洞利用
首先获取token,访问 127.0.0.1/dedecms/uploads/dede/tpl.php?action=upload,在页面源代码中获取到token值
添加到url的token值中
http://127.0.0.1/dedecms/dede/tpl.php?filename=1.lib.php&action=savetagfile&content=%3C?php%20phpinfo();?%3E&token=7b676a4b62bcba23832632e4fb7534b8
访问 127.0.0.1/dedecms/include/taglib/1.lib.php