读《一处代码执行引发的思考》有感
正文
- win
执行如下命令后,会切换到dir1目录下
cd dir1/一个不存在的目录/../
- linux
执行如下命令后,会报错,提示不存在该目录或文件
cd dir1/一个不存在的目录/../
番外
读了FreeBuf的文章
然后就在想file_exists函数还有这种操作呢...
各种找资料无果,后来专门搞PHP代码审计的同事告诉了我,其实是操作系统的原因。好吧....
身为萌新,初入代码审计的我好惨....
中秋假期,闲来无事,复现一下吧:
可以看到,直接调用的Factory.class.php文件里面的Factory类,并没有像传统的那样直接包含Factory.calss.php文件
经过我搜寻资料后,GET到了新知识
魔法方法__autoload可以自动加载类
例如:
./myClass.php
class myClass {
public function __construct() {
echo "myClass init'ed successfuly!!!";
}
}
./index.php
function __autoload($classname) {
$filename = "./". $classname .".php";
include_once($filename);
}
$obj = new myClass();
在index.php中,在调用静态方法setAction时,发现没有找到myClass类,那么便会调用魔法函数__autoload,此时变量$classname=myClass,然后便会去包含./myClass.php文件
php类中的静态方法,可以直接调用而不必提前创建对象
因此原代码中,此时包含的文件便是/controller/Factory.class.php文件
可以看到要实现任意代码执行,需要先满足/绕过上面两个条件
- 第一处,可以看到,需要是admin用户的登陆状态
- 第二处,/controller/$_GET['a']/Action.class.php
直接看第二处,上文中已经说到过了,利用windows对路径处理的特性,我们可以实现这样的路径
/controller/任意字符/../Action.class.php
也就是说如果controller目录下存在Action.class.php文件,那么便可以绕过这个file_exists函数
所幸,还真有
前面的条件都已经满足了,再来看最后面的代码执行函数
就像SQL注入、XSS已经,我们要先闭合前面的字符,可以看到
self:$_obj = new $_GET['a']
ucfirst函数是首字母大写的功能
意思声明类中的私有变量$_obj为一个对象,对象名可以通过变量a来指定
当前类是Factory类,在URL中直接输入
?a=Factory();
来闭合前面的字符,然后利用//注释掉后面的Acton字符
在结合file_exists的条件,需要最后面是/../
最后的Payload便是
?a=Factory();phpinfo();//../
在file_exists中传入的是
/controller/Factory();phpinfo();//../Action.class.php'
此时的 Factory();phpinfo();/ 就像是任意字符一样,因此顺利绕过file_exists
[附] 源码地址