Tuesday, December 29, 2020

Nullify AMSI Scanner with PowerShell

 AMSI as per Microsoft is: "The Windows Antimalware Scan Interface (AMSI) is a versatile interface standard that allows your applications and services to integrate with any antimalware product that's present on a machine. AMSI provides enhanced malware protection for your end-users and their data, applications, and workloads."

AMSI is being used by multiple antimalware products and is known to cause headache to the malicious actors. Hence malicious actors and red teamers started finding ways around disabling AMSI.

Below is one such PowerShell snippet that's making rounds in the wild made use by the actors to nullify AMSI scanner.

The PowerShell code initially gets hold of the "AmsiScannerBuffer" API and changes the memory protection. Post that it replaces the initial '7' bytes of the function with these bytes - "66B80100C21800". When checking the function now the prologue looks much different.

The overwritten bytes made changes in AmsiScanBuffer so that it always returns '1' (AMSI_RESULT_NOT_DETECTED) denoting that the script that is being scanned is not detected, thus nullifying the effect of AMSI.


  • https://www.welivesecurity.com/2019/05/29/turla-powershell-usage/
  • https://docs.microsoft.com/en-us/windows/win32/api/amsi/nf-amsi-amsiscanbuffer

Thursday, September 17, 2020

Brute-Force Flareon2015 Challenge#2 with Qiling

In the previous post we used Qiling to decode strings in Aisuru malware. Qiling's snapshot mode is a cool feature that can be used to take snapshots of the process at critical stages. Qiling can save information about the memory, CPU state, registers state etc. In this post we'll use the snapshot feature of Qiling to brute-force the Flareon 2015 challenge#2.

Running the binary we can see that its is looking for an input.

Looking at the Graph Overview in Cutter we can see that the binary is not very complex, has very few branches.

The binary while run take a input from the user and the input is run against a function at offset 0x00401084. At first the function checks if the user input is at least of length 0x25.

If the length compares correctly the program flow then gets into checking the input. It uses the input against the encoded blob to verify if the input tallies properly. We need not get into the details of this function except for few little bits to get our Qiling script to compute the flag for us.

We would be brute-forcing our way to finding the right input. This means that we need to mutate character by character in the input to find if the program is progressing forward. Checking the function that's responsible for checking our input we can identify that very address that can be used to check if our mutated input character is the right character.

The function does some computation on our input and gets to the decision making phase at address 0x004010ce. If the character in the input tallies we get into the positive branch and continue performing computation on the next character in the input or we get to the bad output where the failure message is displayed.

So this would only mean that if the program gets to address 0x004010d0 we have the right character input in our hands.

 We would be needing the following to get going with the Qiling script,

1. The start and end address of the function that's responsible for checking our input
    • ql.run(begin=0x0040104C, end=0x004010DE)
2. Hook address to check whether the character in our input is right
    •  ql.hook_address(check_input_chr, 0x004010D0)

3. A way to mutate the character in our input

4. A way to save the correct character in the input, save the registers, memory, CPU state

After knowing what's required we can start writing our Qiling script. The complete Qiling script looks like below,

When the script is run we should be seeing the flag revealing itself character by character yielding the flag - a_Little_b1t_harder_plez@flare-on.com.

Friday, July 31, 2020

Decrypt Aisuru Bot Encoded Strings with Qiling Framework

Qiling is an advanced binary emulation framework, with the following features:

  • Cross platform: Windows, MacOS, Linux, BSD, UEFI
  • Cross architecture: X86, X86_64, Arm, Arm64, MIPS
  • Multiple file formats: PE, MachO, ELF
  • Emulate & sandbox machine code in a isolated environment
  • Supports cross architecture and platform debugging capabilities
  • Provide high level API to setup & configure the sandbox
  • Fine-grain instrumentation: allow hooks at various levels (instruction/basic-block/memory-access/exception/syscall/IO/etc)
  • Allow dynamic hotpatch on-the-fly running code, including the loaded library
  • True framework in Python, making it easy to build customized security analysis tools on top

Qiling is backed by Unicorn engine.

Using Qiling is very easy and since it can emulate & sandbox machine code we can take advantage of it to run malicious code/malware without affecting the host.

Statically looking at the strings of "aisuru" bot we can see that it employs some encoding scheme.

These strings are then fed to a function sequentially to get the decrypted string.

The function "sub_80482A0" helps in decoding the encoded strings. Instead of reversing or debugging the function we can use Qiling to get the decoded string.

For this particular case to get the decoded string we could need the following inputs to Qiling,

  1. The binary
  2. Address of the encoded string
  3. Start and End addresses of the function that decodes the string
  4. Address of the decoded string after the function has successfully run
(1). 552b07d4f8f611841eeb9a608c3d6e8526563b96df0b6676267dc274c1195853

(2). The addresses of the encoded strings starts from "0x080525A0" and goes on. Each of the encoded string needs to be put into EAX register and the decoding function has to be called.

(3). The decoding function starts at address "0x080482A0" and ends at "0x08048370".

(4). After some poking around the registers I was able to conclude that the register EDX holds the address of the decoded string.

We now have all the relevant inputs that Qiling requires. With just few lines of python script we can dump all the decoded strings. Below code does that job for us,

The decrypted string list where commands, C2, paths etc are visible now.

  1. https://n1ght-w0lf.github.io/tutorials/qiling-for-malware-analysis-part-2/

Sunday, July 26, 2020

Break On x86 Syscalls from Pintool

"Pin is a tool for the instrumentation of programs. It supports the Android*, Linux*, OS X* and Windows* operating systems and executables for the IA-32, Intel(R) 64 and Intel(R) Many Integrated Core architectures. Pin allows a tool to insert arbitrary code (written in C or C++) in arbitrary places in the executable. The code is added dynamically while the executable is running. This also makes it possible to attach Pin to an already running process" (https://software.intel.com/sites/landingpage/pintool/docs/81205/Pin/html/)

Pin has an API - "Pin_ApplicationBreakPoint" that can be used to stop execution in an application debugger as though a breakpoint was hit. This API can be made use to call an application debugger wherever & whenever we wish for it. The most common use case would obviously be to call the debugger at a specific place of interest. For the sake of this blog let us use this API to call the debugger at a specific syscall.

Well there's more easier way to break on a specific syscall under GDB using the "catch syscall <syscall name/number>" etc etc, but this blog is to understand the Pin's API, so let us stick to this easy task :)

The steps would be as follow,
  1. During instrumentation find whether a instruction that is to be executed is a syscall
  2. If it is a syscall instruction insert a call to get the syscall number and set a global flag
  3. Insert another call in the same instruction to see if we need to send a SIGTRAP to GDB if the syscall is of our interest
The below recorded demo video illustrates how Pin is able to instruct GDB to break on a specific syscall number - 120 which belongs to the clone syscall.

The ideal use case for the above API would be during break into the application during complex conditions and during that you might require a full blown debugger to proceed further.

Thursday, June 25, 2020

Frida DBI - DeObfuscate PowerShell Script

Frida is a Dynamic Binary Instrumentation (DBI) toolkit that can be used to hook into live processes, analyze various parts of the program and print out debug information including but not limited to getting loaded modules, executed functions, arguments passed to the function etc.

In this blog we'll use "frida-trace", part of Frida toolset to de-obfuscate obfuscated powershell script. When PowerShell loads it get injected with a dll "amsi.dll" that is the core of the "Anti Malware Scan Interface".

"amsi.dll" includes a function called "AmsiScanBuffer" that's called to analyze the powershell scripts executed. Every powershell script that gets executed is initially run through the "AmsiScanBuffer" function that determines whether the script that's to be executed is benign or malicious. If it is malicious the script is terminated and an error is raised. The arguments passed to the "AmsiScanBuffer" from MSDN,

As you can see the 2nd argument that's passed to the function "buffer" contains the buffer that is passed for scanning. "frida-trace"can be used to hook into this function and print out the contents of the "buffer" argument.

"frida-trace" can be run with minimal arguments initially to create a skeleton handler file.

Once you execute the above command you should have a ".js" file created automatically in your python path - "C:\Python36\Scripts\__handlers__\amsi.dll\AmsiScanBuffer.js". You can edit this file to print the necessary argument, in our case argument 1. Argument 1 is a wide string that can be printed on to the console using "log(Memory.readUtf16String(args[1]));"

Saving the file will automatically load the script into memory.

Now lets runs an obfuscated powershell script and see if we get de-obfuscated version of it. I took a malicious script from cylance's blog. Running the malicious powershell script in powershell window prints out the de-obfuscated version (which is essentially the 2nd stage of the script) that downloads and runs the final payload. The obfuscated version and de-obfuscated version of the script side by side in the below snapshot.

The complete de-obfuscated script below,

Tuesday, May 19, 2020

Tagging ARM Syscalls in IDA

While reversing ARM binaries you will come across multiple syscalls that in turn does specific things. These syscalls are identified by a number and each syscall has a unique number. For instance in ARM 32bit architecture the syscall for "FORK" function is '2'.

A typical syscall will first have a "MOV" or "LDR" function into the "R7" register followed by a "SVC" (supervisor call) or "SWI" (software interrupt in older cases) instruction.

In this case the "R7" register is loaded with value "0x121" and then a supervisor call is initiated. The value 0x121 in this case refers to the function "send".

Its suffice to say that it will be overwhelming to look back and forth referring the arm syscall table to find the respective functions names for the syscall number. The below IDA Python script can come in handy to automatically comment on the syscalls with the respective function names along with changing the function name where this syscall is invoked from.

Save and run the script in IDA and you should see the results.

Sunday, December 22, 2019

WinDbg pykd 101 - Dumping Meterpreter Payload

WinDbg is a kernel-mode and user-mode debugger that is included in Debugging Tools for Windows. WinDbg has a very powerful scripting language but using it can sometimes be very annoying. Alternatively there's an extension "pykd" that can used to run python scripts to automate various repetitive tasks while debugging.

In this blog post we'll see how to use pykd to automate dumping of Metrepreter DLL injected into legitimate process memory. For purpose of demonstration I injected Merterpreter DLL into a "notepad" process. We can take a look at the notepad process memory using "Process Hacker".

The highlighted memory sections are suspicious since it doesn't belong to any of the loaded modules and it has a memory protection value of "RWX". As you can see the other loaded modules have a memory protection value of "RX".

Looking at one of the memory sections reveals the Meterpreter DLL payload (there's another section that has the shellcode for reflectively loading the DLL). We can dump the notepad process and load the same into WinDbg.

The headers of the DLL in WinDbg at that memory location from notepad process.

Now we can automate the payload dumping part using pykd. To load pykd first copy the "pykd.dll" (according to the architecture) under the "winext" directory in WinDbg folder. I'm using a 64 bit version of WinDbg so my extension folder is under "\Program Files (x86)\Windows Kits\10\Debuggers\x64\winext".

Once done load the extension using "!load pykd" command. If everything worked well you should see no output :)

The python script will be used to dump the memory section that contains traces of Meterpreter related strings. The script does the following,

  1. Search for the pattern (using 's' command)
  2. Check the pattern's associated memory region  (using '!vprot' command)
  3. Gets the base address & region size of the memory section (output from vprot)
  4. Dump the memory section (using '.writemem' command)
You can get the python shell post loading of pykd extension using "!py" command.

To interact with WinDbg you can use the "pykd.dbgCommand". All WinDbg commands can be executed using this function and the output can be displayed or saved to a variable.

During analysis it was found that the Meterpreter payload has a unique pattern ('[REU') in the MZ header section. Lets use that term and search it throughout the process memory.

Using the above we can write our logic into a python file and run it inside WinDbg using pykd extension. To run the python file use the "!py " format. The complete script looks like below,

from pykd import *
import sys

def get_val(data, index):
 data = data.splitlines()
 for i in data:
  if index in i:
   val = i.split(':')[1].strip()
   return val
 return False

if len(sys.argv) < 3:
 print("Usage !py " + sys.argv[0] + "  ")

pattern = sys.argv[2]
directory = sys.argv[1]

res = pykd.dbgCommand("s -a 0 L?80000000 " + pattern)

if res == None:
 print("[*] Pattern not found!")

res = res.splitlines()

for i in res:
 addr = i.split("  ")[0]
 vprot_res = pykd.dbgCommand("!vprot %s" % addr)
 base_addr = get_val(vprot_res, "BaseAddress")
 region_size = get_val(vprot_res, "RegionSize")

 if base_addr and region_size:
  filename = directory + "\\" + base_addr + ".bin"
  cmd = ".writemem %s %s L?%s" % (filename, base_addr, region_size)
  print("[*] Wrote memory dump to: %s of size %s from base address: %s" % (filename, region_size, base_addr))

The script takes the output directory and search string as input and dump the associated memory section. There's lot of scope for further improving the script :)

Looking at the dumped file inside PE studio confirms it is a DLL.