2015 m. spalio 6 d., antradienis

Qualys Security Advisory - OpenSMTPD Audit Report 1prt

(Sorry for the "CVE-2015-ABCD" place-holders in the report, but
OpenSMTPD's developers were ready with the patches before MITRE was
ready with the CVE-IDs.)


Qualys Security Advisory

OpenSMTPD Audit Report


============================================================
============
Contents
========================================================================

Summary
Approach
Local Vulnerabilities
Remote Vulnerabilities
Inter-Process Vulnerabilities
Miscellaneous Bugs
Acknowledgments


========================================================================
Summary
========================================================================

For the past few months, one of our background projects has been to
audit OpenSMTPD, a free implementation of the server-side Simple Mail
Transfer Protocol (SMTP). OpenSMTPD replaces Sendmail as OpenBSD's
default Mail Transfer Agent (MTA) since OpenBSD 5.6, released on
November 1, 2014.

OpenSMTPD was designed to be secure, reliable, performant, and easy to
configure. Indeed, its codebase lives up to OpenBSD's reputation: it is
clean, modular, privilege-separated, and made our audit easy and really
enjoyable. However, the project is pretty much in its infancy (the first
stable version, 5.3, was released on March 17, 2013), which explains why
we discovered various vulnerabilities during our security assessment:

- an oversight in the portable version of fgetln() that allows attackers
  to read and write out-of-bounds memory;

- multiple denial-of-service vulnerabilities that allow local users to
  kill or hang OpenSMTPD;

- a stack-based buffer overflow that allows local users to crash
  OpenSMTPD, or execute arbitrary code as the non-chrooted _smtpd user;

- a hardlink attack (or race-conditioned symlink attack) that allows
  local users to unset the chflags() of arbitrary files;

- a hardlink attack that allows local users to read the first line of
  arbitrary files (for example, root's hash from /etc/master.passwd);

- a denial-of-service vulnerability that allows remote attackers to fill
  OpenSMTPD's queue or mailbox hard-disk partition;

- an out-of-bounds memory read that allows remote attackers to crash
  OpenSMTPD, or leak information and defeat the ASLR protection;

- a use-after-free vulnerability that allows remote attackers to crash
  OpenSMTPD, or execute arbitrary code as the non-chrooted _smtpd user;

- multiple inter-process vulnerabilities that allow attackers to
  escalate from one (already-compromised) OpenSMTPD process to another.


========================================================================
Approach
========================================================================

The OpenSMTPD version that we audited is available at:

https://www.opensmtpd.org/archives/opensmtpd-5.4.4p1.tar.gz

and is installed by default on OpenBSD's latest release (OpenBSD 5.7,
released on May 1, 2015). Unless otherwise noted, the vulnerabilities
that we discovered in OpenSMTPD 5.4.4p1 affect OpenSMTPD's latest
release as well (OpenSMTPD 5.7.1p1, released on June 30, 2015).

The "hybrid approach" that we adopted to review OpenSMTPD is described
in the bible of code auditing, "The Art of Software Security Assessment"
(by Mark Dowd, John McDonald, and Justin Schuh):

- We started with a "top-down approach" and reviewed the high-level
  information that we gathered on OpenSMTPD: READMEs, manual pages, web
  pages (https://www.opensmtpd.org/presentations/asiabsdcon2013-smtpd/
  and https://www.poolp.org/).

  This approach allowed us to quickly understand OpenSMTPD's design
  (seven privilege-separated, long-running, and event-driven processes
  that communicate through UNIX sockets and the imsg API) and identify
  its attack surface (local, remote, and inter-process entry points).

- We continued with a "bottom-up approach" and reviewed OpenSMTPD's
  implementation: the lowest-level code first (openbsd-compat/ and
  smtpd/mproc.c), followed by the higher-level code.

  This approach allowed us to quickly identify complex vulnerabilities:
  the remote out-of-bounds memory read and use-after-free are actually a
  combination of several low-level and high-level bugs.

------------------------------------------------------------------------
Privilege Separation
------------------------------------------------------------------------

--[ PROC_PARENT ]-------------------------------------------------------

User: root

Chroot: no

Peers: PROC_CONTROL, PROC_LKA, PROC_QUEUE, PROC_CA, PROC_PONY

PROC_PARENT, the "[priv]" process, spawns the six other long-running
processes at startup (by calling fork_peers() from main()), and the
transient Mail Delivery Agent (MDA) processes on demand (by calling
forkmda() from parent_imsg()).

If any of its long-running children dies, PROC_PARENT calls
parent_shutdown(), kill()s its remaining children, and exit()s, but does
not restart automatically: if we try to exploit a memory corruption, we
have to come up with a one-shot, not a brute-force.

--[ PROC_CONTROL ]------------------------------------------------------

User: _smtpd

Chroot: /var/empty

Peers: PROC_SCHEDULER, PROC_QUEUE, PROC_PARENT, PROC_LKA, PROC_PONY,
PROC_CA

PROC_CONTROL, the "control" process, handles messages from the control
socket "/var/run/smtpd.sock" (by calling control_dispatch_ext()), and
gathers statistics from its peers (by calling control_imsg()).

--[ PROC_PONY ]---------------------------------------------------------

User: _smtpd

Chroot: /var/empty

Peers: PROC_PARENT, PROC_QUEUE, PROC_LKA, PROC_CONTROL, PROC_CA

PROC_PONY, the "pony express" process
(https://en.wikipedia.org/wiki/Pony_Express), handles the server-side
SMTP sessions (by calling smtp_imsg()), the client-side MTA sessions (by
calling mta_imsg()), and the local MDA deliveries (by calling
mda_imsg()).

--[ PROC_LKA ]----------------------------------------------------------

User: _smtpd

Chroot: no (needs access to /etc/resolv.conf and /etc/ssl/cert.pem)

Peers: PROC_PARENT, PROC_QUEUE, PROC_CONTROL, PROC_PONY

PROC_LKA, the "lookup" process, performs all lookups on behalf of the
other processes: asynchronous DNS resolution (by calling dns_imsg() and
libasr), user information and credentials lookup, SSL certificate
verification, alias expansion (by calling lka_imsg()).

--[ PROC_QUEUE ]--------------------------------------------------------

User: _smtpq (or _smtpd if _smtpq does not exist)

Chroot: /var/spool/smtpd

Peers: PROC_PARENT, PROC_CONTROL, PROC_LKA, PROC_SCHEDULER, PROC_PONY

PROC_QUEUE, the "queue" process, manages the persistent storage of
messages and envelopes (by calling queue_imsg()). By default, the
smtpd/queue_fs.c backend is used.

--[ PROC_SCHEDULER ]----------------------------------------------------

User: _smtpd

Chroot: /var/empty

Peers: PROC_CONTROL, PROC_QUEUE

PROC_SCHEDULER, the "scheduler" process, knows about all existing
messages and envelopes (by calling scheduler_imsg()), and decides when
to relay or deliver them. By default, the smtpd/scheduler_ramqueue.c
backend is used.

--[ PROC_CA ]-----------------------------------------------------------

User: _smtpd

Chroot: /var/empty

Peers: PROC_CONTROL, PROC_PARENT, PROC_PONY

PROC_CA, the "klondike" process
(https://en.wikipedia.org/wiki/Klondike_Gold_Rush), performs
privilege-separated RSA encryption and decryption on behalf of PROC_PONY
(by calling ca_imsg()).

------------------------------------------------------------------------
Attack Surface
------------------------------------------------------------------------

--[ Local Vectors ]-----------------------------------------------------

----[ .forward

Local users may put a .forward file in their home directory in order to
control how their incoming email is processed and delivered.

When PROC_PONY receives a CMD_RCPT_TO from one of its SMTP clients, it
sends an IMSG_SMTP_EXPAND_RCPT to PROC_LKA. If the recipient is a local
user, the (unprivileged) PROC_LKA sends an IMSG_LKA_OPEN_FORWARD to the
(privileged) PROC_PARENT. If PROC_PARENT manages to open() the user's
.forward file, it sends its file descriptor back to PROC_LKA, which
parses and expands its contents.

----[ Control Socket

PROC_CONTROL calls getpeereid(), or getsockopt(SO_PEERCRED), in order to
determine the credentials of the clients that connect to its UNIX socket
"/var/run/smtpd.sock". It processes all the messages received from
connections initiated by root, but otherwise processes only the
IMSG_CTL_SMTP_SESSION and forwards it to PROC_PONY.

Clients normally connect to the control socket with the command-line
program "smtpctl", but we may also connect() to it directly, should we
ever want to exploit a vulnerability in the imsg API, for example.

----[ Offline Directory

The command-line program "smtpctl" can be used to send email (when
invoked as "sendmail"): it connects to the control socket, sends an
IMSG_CTL_SMTP_SESSION to PROC_CONTROL (which forwards it to PROC_PONY),
and enqueues the email through this local SMTP session (enqueue() in
smtpd/enqueue.c).

However, if OpenSMTPD is not running, the connection to the control
socket will fail, and "smtpctl" will simply store the email into the
"/var/spool/smtpd/offline" directory, which is mode 01777
(enqueue_offline() in smtpd/enqueue.c).

Later, when OpenSMTPD restarts, it will execvp() "smtpctl" for each
email stored in the offline directory, exactly as if its owner had just
submitted it for the first time (offline_enqueue() in smtpd/smtpd.c).

Komentarų nėra:

Rašyti komentarą