PHP代码审计-hadsky
环境搭建:
代码审计:
路由分析
该系统使用 puyuetian 自研框架进行开发,所以我们先去分析下路由构成
如果想要完整的分析路由的访问走向,那么就要从最原始的出发点去仔细分析,我们从页面访问情况可
以看到,在功能点调用时总是从index.php开始走的,所以我们先去看看index.php文件内容:
index.php中上面是一些环境检测代码,这里包含一个框架加载文件puyuetian.php,我们跟进看看:
从该文件中可以知道,在初始时框架就会加载如缓存、访问控制、框架公用变量等文件,而前台的路由
主要由下面的 laod.php 文件进行控制,我们跟进该文件
在该文件中通过get传入c参数来控制路由,如果不传入该参数,则默认访问phpscript目录下
main.php,否则包含phpscript目录下相应文件实现相应功能。
而后台路由我们需要访问admin.php,在该文件中直接跳转了,这里的app其实代表app文件夹,
superadmin:index则表示superadmin文件夹下的index.php文件,这样路由就定位到该php文件,跟进
该文件
在该文件中,107-109行代码中需要传递另一个参数 s 来控制调用后台的某些功能点,以此类推,/app
目录下文件的调用方式就是通过这样来调用的。
1.任意文件写入
在全局搜索 file_put_contents( 时,发现这里写入的内容直接可通过POST传参控制,那么这里的重
点是要回溯 $path 是否可控
回溯文件,在文件最开始通过传入type参数来控制switch....case来执行我们的
file_get_contents() ,而这里的path也是通过我们GET传入的,只是这里的path参数有
realpath() 函数包裹和下面23-29行代码进行限制,以至于这个点不能直接创建新文件,而只能将任意
内容写到存在的php文件中。
所以这里这需要传入type=save,path是一个存在的文件则可以覆盖该文件将任意内容写入,这里判断
格式是否是如下格式,并不存在过滤。
如果不想覆盖原有php文件其实还可以通过先创建php文件再将文件内容写入到创建的文件中,代码如
下:
通过type=mkfile,并且传入 mkname 参数即可创建文件,这样我们就可以通过创建的文件进行文件内容
的写入。
漏洞复现:
我们构造路由进行测试,这里我们找一个install目录下的文件进行测试,代码中是会提示保存失败的,
当文件已经写入了。
2.任意文件删除
在定位上诉漏洞点时,不知道大家是否注意到 unlink() 函数,经过前面的分析这里的$path我们确定是
可控的,只要该文件存在即可进行删除。
漏洞复现:
3.任意文件删除+rce
通过上述我们知道有任意文件删除漏洞,那么我们就可以删除锁文件(xx.locked)达到重装的效果,而
在重装页面的代码中我们会发现我们的数据库信息会记录到config.php中,这也是大多数系统的通用操
作。看下面的install.php:
最上面接收参数,也就是我们安装时填入的一些数据库信息。
下面将我们填入的数据库信息写入config.php文件中,期间没有过滤,而且这里是先写入php文件在执
行数据库连接、创建等操作,所以这里无论如何是可以写入的。但这里也要保证数据库在执行连接、创
建等操作时不报错。如果数据库执行期间报错的话那么就会导致系统安装不成功,后续的config.php即
使写入文件也无法利用。为什么这么说,接着往下面分析
在config.php文件中,最上面的代码决定了我们不能随意访问该文件。而红框中的参数是我们可以“控
制"的参数。
经过尝试发现只有这里的 mysql_prefix 参数也就是数据库前缀这里是可以完全控制的,其他参数如果
拼接特殊字符会导致数据库语句执行报错,大家如果有比较特别的MySQL语句欢迎随时交流。
这里在mysql_prefix注入特殊字符可以顺利安装,文件内容也会被顺利写入。那么我们该如何执行
config.php,接着往下分析
上面config.php文件中我们可知,必须定义了puyuetian常量才可以访问该文件,那么很明显该文件不
能直接访问,而是通过特定路由去访问的。而我们知道index.php路由文件中包含了框架加载文件
puyuetian.php ,而在该文件中包含了config.php文件,那么也就是说只要我们成功安装系统,再访问
index.php的话就可以成功rce了。
漏洞复现:
首先在安装界面填入我们payload,这里系统会成功安装。
4.任意文件读取
此处漏洞发现也是通过搜索危险函数 file_get_contents( ,在此处发现这里传入参数为path而且又是
上述分析过的路由,所以我们知道这里的path是可控的,而且只需要通过传入type来控制执行到该处代
码即可
传入type=edit走到这个分支,这里白名单后缀已经可以满足我们读取大部分文件,path可控,这里只差
一步:回显。
当我们GET传入json参数时,就会进入ExitJson函数中,该函数的大致意思就是将我们读取到的内容通过
json形式进行回显,这里所有条件都满足,所以存在漏洞。
漏洞复现:
5.模板上传绕过getshell
这里的上传上传应用,根据以往的经验来看的话,这里的处理流程应该是通过上传.zip压缩包然后自动解
压缩来进行模板部署,而且这里可能会检测压缩包中内容是否合法,如果这里检测不完善或者该处压缩
包可以伪造的话,那么大概率我们可以通过上传压缩文件来绕过该处的后缀检测,从而上传我们想要上
传的文件
定位到如下代码处 app\superadmin\phpscript\app.php
通过控制 t=uploadapp 参数来控制代码执行此处的else if,其中就是上传zip文件的代码,可以看到这里
代码121行的后缀白名单,然后通过ZipArchive class(php自带类库,可以对文件进行压缩与解压缩处理)
下的open方法打开压缩文件;然你通过ZipArchive::extractTo()方法将.zip文件解压到根目录。在此过程
中,并没有对解压后的文件进行后缀的校验。且通过ZipArchive解压文件的骚操作还有很多,这里就使
用最简单的方式进行getshell。
下面是ZipArchive Class下的一些常用方法
<?php
/******** ziparchive 可选参数 *******/
/*
1.ZipArchive::addEmptyDir
添加一个新的文件目录
三、渗透测试
1.任意文件写入
我们构造路由进行测试,这里我们找一个install目录下的文件进行测试,代码中是会提示保存失败的,
当文件已经写入了。
访问install目录
2.ZipArchive::addFile
将文件添加到指定zip压缩包中。
3.ZipArchive::addFromString
添加的文件同时将内容添加进去
4.ZipArchive::close
关闭ziparchive
5.ZipArchive::extractTo
将压缩包解压
6.ZipArchive::open
打开一个zip压缩包
7.ZipArchive::getStatusString
返回压缩时的状态内容,包括错误信息,压缩信息等等
8.ZipArchive::deleteIndex
删除压缩包中的某一个文件,如:deleteIndex(0)删除第一个文件
9.ZipArchive::deleteName
删除压缩包中的某一个文件名称,同时也将文件删除。
......
*/
?>
漏洞复现:
这里我们将我们的php文件进行压缩
REF:
https://cri1stur.github.io/2023/02/02/hadsky%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/
- 点赞
- 收藏
- 关注作者
评论(0)