emlogpro文件上传漏洞代码审计(CVE-2023-44974)(CVE-2023-44973)

17828147368   ·   发表于 2024-02-15 14:40:21   ·   代码审计

【产品介绍】

emlog 是 “Every Memory Log” 的简称,意即:点滴记忆。它是一款基于PHP语言和MySQL数据库的开源、免费、功能强大的个人或多人联合撰写的博客系统(blog)。基于PHP和MySQL的功能强大的博客及CMS建站系统。致力于提供快速、稳定,且在使用上又极其简单、舒适的博客服务。安装和使用都非常方便

环境配置环境配置

影响版本:emlog emlog pro 2.2.0

emlog pro /admin/plugin.php任意文件上传漏洞 CVE-2023-44974

Emlog官网下载存在漏洞版本的源码:
https://github.com/emlog/emlog/releases

使用PhpStudy进行搭建,配置数据库信息

开始代码审计,根据上面emlog pro提示 路径/admin/plugin.php存在任意文件上传漏洞,远程攻击者可利用该漏洞提交特殊的请求,可上传恶意文件,以应用程序上下文执行任意代码。
先访问路径,看看页面是什么样的,这个是原生开发的可以这样,如果是mvc的就不行

挖掘文件上传这种漏洞就直接找功能点,这个页面的功能点只有一个安装插件


先正常的安装个插件走一下流程


使用burp抓包


知道了这个数据包是成功上传文件的

打开源码通过搜索全局upload_zip

根据上面的提示路径找到了这个文件

  1. if ($action == 'upload_zip') {
  2. LoginAuth::checkToken();
  3. $zipfile = isset($_FILES['pluzip']) ? $_FILES['pluzip'] : '';
  4. if ($zipfile['error'] == 4) {
  5. emDirect("./plugin.php?error_d=1");
  6. }
  7. if ($zipfile['error'] == 1) {
  8. emDirect("./plugin.php?error_g=1");
  9. }
  10. if (!$zipfile || $zipfile['error'] >= 1 || empty($zipfile['tmp_name'])) {
  11. emMsg('插件上传失败, 错误码:' . $zipfile['error']);
  12. }
  13. if (getFileSuffix($zipfile['name']) != 'zip') {
  14. emDirect("./plugin.php?error_f=1");
  15. }
  16. $ret = emUnZip($zipfile['tmp_name'], '../content/plugins/', 'plugin');
  17. switch ($ret) {
  18. case 0:
  19. emDirect("./plugin.php?activate_install=1");
  20. break;
  21. case -1:
  22. emDirect("./plugin.php?error_e=1");
  23. break;
  24. case 1:
  25. case 2:
  26. emDirect("./plugin.php?error_b=1");
  27. break;
  28. case 3:
  29. emDirect("./plugin.php?error_c=1");
  30. break;
  31. }
  32. }

这段是可以绕过的,没什么问题获取文件后缀名zip

继续跟踪一下emUnZip,解压文件看看解压过程中有没有什么过滤

  1. function emUnZip($zipfile, $path, $type = 'tpl') {
  2. if (!class_exists('ZipArchive', FALSE)) {
  3. return 3;//zip模块问题
  4. }
  5. $zip = new ZipArchive();
  6. if (<span class="label label-primary">@$zip-</span>&gt;open($zipfile) !== TRUE) {
  7. return 2;//文件权限问题
  8. }
  9. $r = explode('/', $zip-&gt;getNameIndex(0), 2);
  10. $dir = isset($r[0]) ? $r[0] . '/' : '';
  11. switch ($type) {
  12. case 'tpl':
  13. $re = $zip-&gt;getFromName($dir . 'header.php');
  14. if (false === $re) {
  15. return -2;
  16. }
  17. break;
  18. case 'plugin':
  19. $plugin_name = substr($dir, 0, -1);
  20. $re = $zip-&gt;getFromName($dir . $plugin_name . '.php');
  21. if (false === $re) {
  22. return -1;
  23. }
  24. break;
  25. case 'backup':
  26. $sql_name = substr($dir, 0, -1);
  27. if (getFileSuffix($sql_name) != 'sql') {
  28. return -3;
  29. }
  30. break;
  31. case 'update':
  32. break;
  33. }
  34. if (true === <span class="label label-primary">@$zip-</span>&gt;extractTo($path)) {
  35. $zip-&gt;close();
  36. return 0;
  37. }
  38. return 1; //文件权限问题
  39. }

通过跟踪并没有什么过滤,emUnZip函数,可以发现他需要获取一个路径$dir,但是咱们的压缩包里面就是一个文件,安装正常的插件压缩包里面都有一个文件夹


去网上找了一个正常插件,上传,可以成功上传


然后在本地修改插件,创建一个php文件


写入内容

然后进行压缩上传,分析上面代码,知道了上传解压没有对文件内的内容进行过滤,成功上传


查看本地文件夹是否存在phpinfo.php


网页访问路径

emlog pro /content/templates/任意文件上传漏洞 CVE-2023-44973


打开网站,还是先找功能点,根据上面的cnvd提示也知道是模板那个位置有问题

和上面第一则一样先上传个正常的文件上去,抓一下包


定位到代码位置

  1. if ($action === 'upload_zip') {
  2. LoginAuth::checkToken(); // 检查登录状态和令牌,确保安全性
  3. $zipfile = isset($_FILES['tplzip']) ? $_FILES['tplzip'] : ''; // 获取上传的ZIP文件
  4. if ($zipfile['error'] == 4) {
  5. emDirect("./template.php?error_d=1"); // 如果上传文件为空,重定向到错误页面
  6. }
  7. if ($zipfile['error'] == 1) {
  8. emDirect("./template.php?error_f=1"); // 如果上传文件超过了php.ini中的限制大小,重定向到错误页面
  9. }
  10. if (!$zipfile || $zipfile['error'] &gt; 0 || empty($zipfile['tmp_name'])) {
  11. emMsg('模板上传失败, 错误码:' . $zipfile['error']); // 如果上传文件出错,显示错误信息并返回
  12. }
  13. if (getFileSuffix($zipfile['name']) != 'zip') {
  14. emDirect("./template.php?error_a=1"); // 如果上传文件不是ZIP文件,重定向到错误页面
  15. }
  16. $ret = emUnZip($zipfile['tmp_name'], '../content/templates/', 'tpl'); // 调用解压缩函数解压上传的ZIP文件
  17. switch ($ret) {
  18. case 0:
  19. emDirect("./template.php?activate_install=1"); // 解压缩成功,重定向到激活安装页面
  20. break;
  21. case -2:
  22. emDirect("./template.php?error_e=1"); // 找不到header.php文件,重定向到错误页面
  23. break;
  24. case 1:
  25. case 2:
  26. emDirect("./template.php?error_b=1"); // 文件权限问题或解压缩失败,重定向到错误页面
  27. break;
  28. case 3:
  29. emDirect("./template.php?error_c=1"); // 缺少ZIP模块,重定向到错误页面
  30. break;
  31. }
  32. }


当action为upload_zip时,执行if后面的语句,LoginAuth::checkToken();是用来检测登录状态的。$zipfile用来接收tplzip上传上来的数据,然后对上传的数据进行各种错误判断,判断成功后,执行下面的emUnZip函数进行解压,并把解压后的文件放到/content/templates/目录下,我们在追踪一下emUnZip函数看看是否有过滤等情况
通过查看代码文件上传时会执行if后面的语句,$zipfile变量来接收上传的数据,对数据进行判断,符合要求执行解压函数emUnZip进行解压,所以我们继续跟踪emUnZip看看有没有过滤

  1. function emUnZip($zipfile, $path, $type = 'tpl') {
  2. if (!class_exists('ZipArchive', FALSE)) {
  3. return 3; // 如果服务器上没有安装Zip模块,返回错误码3,表示zip模块问题
  4. }
  5. $zip = new ZipArchive(); // 创建一个ZipArchive对象
  6. if (<span class="label label-primary">@$zip-</span>&gt;open($zipfile) !== TRUE) {
  7. return 2; // 如果无法打开指定的压缩文件,返回错误码2,表示文件权限问题
  8. }
  9. $r = explode('/', $zip-&gt;getNameIndex(0), 2); // 获取压缩文件中的第一个文件的路径
  10. $dir = isset($r[0]) ? $r[0] . '/' : ''; // 获取文件的目录路径
  11. switch ($type) {
  12. case 'tpl':
  13. $re = $zip-&gt;getFromName($dir . 'header.php'); // 从压缩文件中获取名为header.php的文件内容
  14. if (false === $re) {
  15. return -2; // 如果无法获取到header.php文件内容,返回错误码-2
  16. }
  17. break;
  18. case 'plugin':
  19. $plugin_name = substr($dir, 0, -1); // 获取插件的名称
  20. $re = $zip-&gt;getFromName($dir . $plugin_name . '.php'); // 从压缩文件中获取与插件名称对应的php文件内容
  21. if (false === $re) {
  22. return -1; // 如果无法获取到插件对应的php文件内容,返回错误码-1
  23. }
  24. break;
  25. case 'backup':
  26. $sql_name = substr($dir, 0, -1); // 获取备份文件的名称
  27. if (getFileSuffix($sql_name) != 'sql') { // 判断备份文件的后缀名是否为sql
  28. return -3; // 如果备份文件的后缀名不为sql,返回错误码-3
  29. }
  30. break;
  31. case 'update':
  32. break;
  33. }
  34. if (true === <span class="label label-primary">@$zip-</span>&gt;extractTo($path)) { // 将压缩文件内容解压到指定路径
  35. $zip-&gt;close();
  36. return 0; // 解压缩成功,返回0
  37. }
  38. return 1; // 解压缩失败,返回错误码1,表示文件权限问题
  39. }

可以看出没有过滤,然后对上传的文件添加恶意文件


还是和上面一样,在正常的模板里面添加一个php文件,文件内容不为空,压缩上传

上传成功访问


这两个文件上传都是一样调用同一个文件

用户名金币积分时间理由
Track-魔方 400.00 0 2024-02-17 20:08:45 深度 100 普适 200 可读 100

打赏我,让我更有动力~

2 条回复   |  直到 10个月前 | 875 次浏览

Track-魔方
发表于 10个月前

实际上有个错误:压缩包里面还需要一个文件夹才算正常插件,安装成功,这里,并不是因为压缩包里面需要有一个文件夹才能正常安装插件,在右键打压缩包的时候,windows是会自动创建一个和文件同名的zip压缩包,并且这个zip压缩包中的自带一个文件夹的【不需要额外创建】

这里需要满足的条件是:
由于这行代码,有个限制,需要你压缩包文件中有一个与文件夹同名的php文件,比如文件夹名是abc,那么你文件夹下面就需要有一个abc.php,并且abc.php中需要有内容,才能正常安装,否则返回 -1

评论列表

  • 加载数据中...

编写评论内容

Track-魔方
发表于 10个月前

代审流程上来说还是需要再细一些会好点

评论列表

  • 加载数据中...

编写评论内容
登录后才可发表内容
返回顶部 投诉反馈

© 2016 - 2024 掌控者 All Rights Reserved.