前言

根据红日安全写的文章,学习PHP代码审计的第四节内容,题目均来自PHP SECURITY CALENDAR 2017,讲完题目会用一个实例来加深巩固,这是之前写的,有兴趣可以去看看:

PHP代码审计01之in_array()函数缺陷

PHP代码审计02之filter_var()函数缺陷

PHP代码审计03之实例化任意对象漏洞

漏洞分析

现在咱们看第一题,代码如下:

<?php
class Login {
public function __construct($user, $pass) {
$this->loginViaXml($user, $pass);
} public function loginViaXml($user, $pass) {
if (
(!strpos($user, '<') || !strpos($user, '>')) &&
(!strpos($pass, '<') || !strpos($pass, '>'))
) {
$format = '<?xml version="1.0"?>' .
'<user v="%s"/><pass v="%s"/>';
$xml = sprintf($format, $user, $pass);
$xmlElement = new SimpleXMLElement($xml);
// Perform the actual login.
$this->login($xmlElement);
}
}
} new Login($_POST['username'], $_POST['password']);
?>

题目分析

我们来看上面的代码,看第1214行,这里通过格式话字符串的方式,使用XML结构来存储用户的登陆信息,这样很容易造成注入,再看上面的代码,最后一行实例化了这个类,17行调用了login来进行登陆操作。下面到重点了,看代码810行,这里用到了strpos()函数来进行过滤<>符号,这个函数的用法如下:





如下:

<?php
var_dump(strpos("abcd","a"));
var_dump(strpos("abcd","y"));
?>



我们发现,找到子字符串的话就会返回对应的下标,没找到会返回false。而在PHP中,0和false的取反都是true,这点需要我们注意,这道题目就是开发者在使用这个函数时,只考虑了返回false的情况,而没有考虑当首字符匹配时返回0的情况。导致了过滤被绕过从而实施XML攻击。

现在知道了如何绕过,那么构造payload:user=<"><injected-tag%20property="&pass=<injected-tag>

为了更好的理解,来看一下构造这个payload时,strpos()函数的返回结果如下:

$user='<"><injected-tag property="';
$pass='<injected-tag>';
var_dump(strpos($user,'<'));
var_dump(!strpos($user,'<'));
var_dump(strpos($user,'>'));
var_dump(!strpos($user,'>'));



是不是理解了一些呢,现在看上面的代码,思考一下如果我们使用这个payload会返回什么呢。

var_dump((!strpos($user, '<') || !strpos($user, '>')) &&
(!strpos($pass, '<') || !strpos($pass, '>')));



返回了true,其实就是var_dump((true || false) &&(true || false))

成功绕过,可以进行XML注入。

通过上面的学习讲解是不是对strpos()函数了解更深一些了呢?下面咱们看一个实例,这个实例也是设计者没有考虑周全,导致任意用户密码重置。

实例分析

这次的实例是DeDecms V5.7SP2正式版,源码可以从网上下载搭建,这个很容易找到,就不详细说了,上面说了,这个漏洞是任意用户密码重置,下面我们来分析代码,漏洞的触发点在 member/resetpassword.php 文件中,是因为对接收的参数safeanswer没有进行严格的类型判断导致被绕过。下面看代码:



现在来对上面的代码做一个分析,当$dopost==safequestion时,通过$mid对应的id值来查询当前用户的safequestion,safeanswer,userid,email等值,现在来看第84行,这里的意思是当我们传入的安全问题和安全答案等于之前设置的值时,就传入sn()函数,重点来了,注意看,这里用的是双等于来验证,而没有用三等于,所以,这里是可以被绕过的。当用户没有设置安全问题时,那么默认情况安全问题值为0,安全答案值为null,这里指的是数据库中的值,而我们如果传入空值时,那么就是空字符串,84行语句也就变成了if('0' == '' && null == ''),也就是if(false&&true),所以我们只需要让前半部分转为true就可以了,通过测试如下图,都可以和0比较等于true。

if("0"=="0.0"){echo "成功1"."\n";}
if("0"=="0e1"){echo "成功2"."\n";}
if("0"=="0e12"){echo "成功3"."\n";}
if("0"=="0e123"){echo "成功4"."\n";}
if("0"=="0."){echo "成功5"."\n";}

上面的几种payload均能使得 ​safequestion 为 true,成功进入sn()函数



我们跟进sn()函数,代码如下:



在sn()内部,会根据id到pwd_tmp表中判断是否存在对应的临时密码记录,根据结果确定分支,走向 newmail 函数。现在我们假设第一次来进行忘记密码操作,那么现在的$row的值应该为空,也就会进入if(!is_array($row))分支,然后在newmail()函数中执行INSERT操作,具体代码在这个文件的上面,如图:



这个代码的功能是发送邮件到相关邮箱,并插入一条记录到dede_pwd_tmp表中,漏洞触发点在这里,我们现在看92~95行。如果 ($send == 'N') 这个条件为真,那就跳转到修改页,通过 ShowMsg 打印出修改密码功能的链接。拼接的url为:

http://www.dmsj.com/DedeCMS-V5.7-UTF8-SP2/uploads/member/resetpassword.php?dopost=getpasswd&id=$mid&key=$randval

现在咱们跟进dopost=getpasswd去看看,在member/resetpassword.php文件中,代码如下:

这里用empty()函数来判断$id和$row是否为空,如果不为空的话,就继续向下走,进入if(empty($setp))中,先判断是否超时,如果没超时的话进入修改页面,我圈起来了,现在跟过去看一下具体代码如下:



发现数据包中 $setp=2,所以代码功能又回到了member/resetpassword.php文件中,如下:



分析上面代码,我们发现如果传入的$key和数据库中的$row['pwd']相同时,则完成密码的重置,也完成了攻击的分析过程。

漏洞验证

现在注册两个账号,分别是test123和test456,查看mid的值如下,test456的mid为3。test123的mid为2。



我现在登陆test456账户,访问咱们构造的payload。来修改test123的密码。

http://www.dmsj.com/DedeCMS-V5.7-UTF8-SP2/uploads/member/resetpassword.php?dopost=safequestion&safequestion=0e1&safeanswer=&id=2

我现在登陆的是test456账户,访问url抓包。



获取到了key值,然后来访问修改密码的url:

http://www.dmsj.com/DedeCMS-V5.7-UTF8-SP2/uploads/member/resetpassword.php?dopost=getpasswd&id=2&key=xy8UzeOI



我们发现到了修改密码的页面,直接可以修改密码。我们将密码修改为abcdef,然后登陆test123,发现登陆成功,密码成功被修改。

小结

通过这篇文章的学习与讲解,是不是对strpos()函数和PHP弱类型绕过有了一定的了解了呢?下一篇文章会对escapeshellarg与escapeshellcmd使用不当来进行学习与讲解,一起努力吧!

PHP代码审计04之strpos函数使用不当的更多相关文章

  1. ***用php的strpos() 函数判断字符串中是否包含某字符串的方法

    判断某字符串中是否包含某字符串的方法 if(strpos('www.idc-gz.com','idc-gz') !== false){ echo '包含'; }else{ echo '不包含'; } ...

  2. PHP strpos() 函数

    定义和用法 strpos() 函数返回字符串在另一个字符串中第一次出现的位置. 如果没有找到该字符串,则返回 false. 语法 strpos(string,find,start) 参数 描述 str ...

  3. 字符串处理——strpos()函数

    strpos() 函数返回字符串在另一个字符串中第一次出现的位置. 大小写敏感 如果没有找到该字符串,则返回 false. strpos(string,find,start)  string 必需:规 ...

  4. PHP strlen()函数和strpos()函数

    strlen()  函数返回字符串的长度(字符数) 代码:   <?php echo strlen("Hello world!"); ?> 上面的代码将输出:12   ...

  5. php中strpos()函数

    1,strpos()函数 mixed strops(]) 返回needle在haystack中首次出现的数字位置,从0开始查找,区分大小写. 参数:haystack,在该字符串中进行查找. needl ...

  6. php strpos() 函数介绍与使用方法详解

    本文主要和大家介绍PHP中mb_strpos的使用技巧,通过使用语法以及实例给大家详细分析了用法,需要的朋友参考学习下.希望能帮助到大家.mb_strpos(PHP 4 >= 4.0.6, PH ...

  7. php strpos()函数 语法

    php strpos()函数 语法 作用:寻找字符串中某字符最先出现的位置.大理石平台怎么选择 语法:strpos(string,find,start) 参数: 参数 描述 string     必需 ...

  8. PHP代码审计02之filter_var()函数缺陷

    前言 根据红日安全写的文章,学习PHP代码审计审计的第二节内容,题目均来自PHP SECURITY CALENDAR 2017,讲完这个题目,会有一道CTF题目来进行巩固,外加一个实例来深入分析,想了 ...

  9. php基础04:字符串函数

    <?php //1.strlen(),strlen() 函数返回字符串的长度,以字符计. echo strlen("hello world"); echo "< ...

随机推荐

  1. Docker 容器化部署 Python 应用

    Docker 是一个开源项目,为开发人员和系统管理员提供了一个开放平台,可以将应用程序构建.打包为一个轻量级容器,并在任何地方运行.Docker 会在软件容器中自动部署应用程序. 在本篇中,我将介绍如 ...

  2. python3-day3

    一.函数基本语法及特性 重复用到的代码通过def封装起来,用到的时候直接调用函数名字:语法 1 def 函数名字(内容): 2 需要执行的动作 什么是函数: 函数一词来源于数学,但编程中的「函数」概念 ...

  3. jpa基础知识掌握-分页-sql

    https://blog.csdn.net/liuchuanhong1/article/details/52042477

  4. OpenCV图像处理学习笔记-Day4(完结)

    OpenCV图像处理学习笔记-Day4(完结) 第41课:使用OpenCV统计直方图 第42课:绘制OpenCV统计直方图 pass 第43课:使用掩膜的直方图 第44课:掩膜原理及演示 第45课:直 ...

  5. Java学习day02

    day02-课堂笔记 1.打开DOS命令窗口,执行java HelloWorld,执行原理? * java.exe命令会启动JVM * JVM启动之后会启动类加载器ClassLoader * Clas ...

  6. error C2491: 不允许 dllimport 函数 的定义

    转载:https://blog.csdn.net/gaofeidongdong/article/details/7781345 在工程属性中 预编译宏中加上 DLL_EXPORT为了减少使用dll时候 ...

  7. 电机AB相编码器测速

    控制任务 检测编码器的脉冲并测速 电路设计 图1 直流电机带减速器和编码器 图2  编码器接线定义 编码器接线定义如下 M1:电机电源接口,绿色的 GND:编码器电源负极输入口,橙色的 C1:编码器A ...

  8. 【题解】[CH弱省胡策R2]TATT

    本蒟蒻第一道\(K-D-Tree\)维护\(dp\) Question 题目大意:求一条路径,使得其四个维度单调不降. 先排序消掉一维再说. 对于每一个点,初始的时候绝对长度是1啊.于是,先赋值一个1 ...

  9. Docker 启动容器时,报错 WARNING:IPv4 forwarding is disabled. Networking will not work. 的解决办法

    Centos 7 Docker 启动了一个web服务 但是启动时 报 WARNING: IPv4 forwarding is disabled. Networking will not work. 解 ...

  10. HanLP的分词统计

    HanLP的分词效果鄙人研究了HanLP,他的分词效果确实还可以,而且速度也比较快,10的数据是9000毫秒 @SneakyThrows@Overridepublic LinkedHashMap< ...