Didier Stevens

Sunday 8 October 2017

Quickpost: Mimikatz DCSync Detection

Filed under: Hacking,Networking,Quickpost — Didier Stevens @ 22:40

Benjamin Delpy/@gentilkiwi’s Brucon workshop on Mimikatz inspired me to resume my work on detecting DCSync usage inside networks.

Here are 2 Suricata rules to detect Active Directory replication traffic between a domain controller and a domain member like a workstation (e.g. not a domain controller):


alert tcp !$DC_SERVERS any -> $DC_SERVERS any (msg:"Mimikatz DRSUAPI"; flow:established,to_server; content:"|05 00 0b|"; depth:3; content:"|35 42 51 e3 06 4b d1 11 ab 04 00 c0 4f c2 dc d2|"; depth:100; flowbits:set,drsuapi; flowbits:noalert; reference:url,blog.didierstevens.com; classtype:policy-violation; sid:1000001; rev:1;)
alert tcp !$DC_SERVERS any -> $DC_SERVERS any (msg:"Mimikatz DRSUAPI DsGetNCChanges Request"; flow:established,to_server; flowbits:isset,drsuapi; content:"|05 00 00|"; depth:3; content:"|00 03|"; offset:22 depth:2; reference:url,blog.didierstevens.com; classtype:policy-violation; sid:1000002; rev:1;)

Variable DC_SERVERS should be set to the IP addresses of the domain controllers.

The first rule will set a flowbit (drsuapi) when DCE/RPC traffic is detected to bind to the directory replication interface (DRSUAPI).

The second rule will detect a DCE/RPC DsGetNCChanges request if the flowbit drsuapi is set.

 

These rules were tested in a test environment with normal traffic between a workstation and a domain controller, and with Mimikatz DCSync traffic. They were not tested in a production network.


Quickpost info


Tuesday 19 September 2017

Quickpost: Creating A Simple Flow Graph With GNU Radio Companion

Filed under: Hardware,Quickpost — Didier Stevens @ 0:00

If you installed GNU Radio and want to know how to create the Flow Graph I used to test my SDR, follow along:

Start GNU Radio Companion, and create a new WX GUI file:

You will see 2 blocks, Options and Variable:

Notice that the ID is “top_block” (that’s the default), and that the Generate Options is “WX GUI” (QT GUI is the default).

Variable is a block that defines a variable for the sample rate: samp_rate. By default, it’s 32k (32000), but that’s too small.

For my RTL-SDR, I will use 2 MHz (2000000 Hz). Double click the Variable block, change the value and click OK:

Now we will add a block that represents our SDR as a source of data. Go to the right menu and select “RTL-SDR Source” (you can click the search button on the toolbar to search for this block).

Drag this block into the flow graph:

Notice that the title of this block is in red: that’s to indicate that there is an error with this block (it’s not connected). We will fix that soon.

Next select the “WX GUI Waterfall Sink” block:

Drag this block into the flow graph:

Hover with your mouse over the blue port of block “RTL-SDR Source”, the word “out” will appear:

Click on the blue port:

Now hover with your mouse over the blue port of block “WX GUI Waterfall Sink”, the word “in” will appear:

Click on the blue port:

An arrow connects the 2 ports, and the titles turn black (no errors).

The default frequency of block “RTL-SDR Source” is 100 MHz. I will tune this to a local FM radio station at 100.6 MHz. Double click the “RTL-SDR Source” block, and edit the Ch0 Frequency: 100.6e6 is 100600000 or 100.6 MHz (e6 is the exponent notation for 1000000, 6 zeroes).

We can now save the flow graph. A flow graph has to be saved before it can be executed, if it is not saved, GNU Radio Companion will display a save dialog box when you execute the flow graph.

The extension for flow graph files is .grc:

A .grc file is an XML file:

Now we can execute the flow graph by clicking on the Play button:

When everything works fine, you should see output like this:

The green bands represent the signals of broadcast stations, and in the terminal you can see that a top_block.py program was generated and executed, and that GNU Radio is able to connect to the SDR device and get data.

GNU Radio Companion creates the top_block.py program (the name comes from the ID in the Options block), and executes it with GNU Radio:

If GNU Radio is not able to get data from your SDR device, it will generate null values: the waterfall plot will be uniform blue, and the terminal will report errors:

You can stop the Python program from running by clicking the stop button:

If there are errors in your flow graph, you will not be able to click the play button. Click the error button to get more info:

 

 


Quickpost info


Monday 18 September 2017

Quickpost: GNU Radio On Windows

Filed under: Hardware,Quickpost — Didier Stevens @ 20:43

I’ve been using GNU Radio & GNU Radio Companion with the GNU Radio Live SDR Environment, but now I’ve switched to GNU Radio on Windows (I’ve seen posts that it’s stable now).

The installation was easy, I downloaded the GNURadio 3.7.11.1 x64 binaries and proceeded with a default install:

Next, install drivers for my HackRF One and RTL-SDR with Zadig.

Zadig can auto-update:

When I plug in my HackRF One, no driver is installed automatically (Windows 10), I use Zadig to install a WinUSB driver:

The same for my RTL-SDR, although the name of the device is “Bulk-In, Interface (Interface 0)”. A driver was automatically installed after connecting it (RTL2832UUSB), but I need WinUSB here too:

If you don’t see your device listed, make sure that all devices are listed:

Now I can use GNU Radio on my Windows machine. I start GNU Radio Companion, and get a one time warning about xterm missing, that I can ignore:

A quick flow graph connecting my RTL-SDR (tuned to a local FM station) to a waterfall plot shows my SDR is working (the terminal output confirms that too):

If GNU Radio is not receiving I/Q data from your SDR, the waterfall plot will be pure blue, and you will see a message attesting to that in the terminal.

 


Quickpost info


Sunday 17 September 2017

Quickpost: Update: Infinite Control For Bash Bunny

Filed under: Bash Bunny,Hardware,My Software,Quickpost,Update — Didier Stevens @ 16:39

This is an update to my Bash Bunny payload Infinite Control: it sends a CONTROL keypress every 10 seconds. I changed the LED colors, and if you uncomment line 27 the BREAK key will be used (function key 15, as some people suggested).

You can find it on HAK5’s GitHub Bash Bunny repository too.

#!/bin/bash
# Title:         Infinite Control
# Author:        Didier Stevens (https://DidierStevens.com)
# Version:       0.0.2 2017/09/02
# History:       0.0.1 2017/04/08 start
#                0.0.2 2017/09/02 changed LED colors, added BREAK
#
# Hit the CONTROL key every 10 seconds in an infinite loop,
# while blinking the CYAN LED with every keypress.
#
# Can be used to prevent a machine from sleeping or auto-locking.
#
# Some users have suggested to hit F15 (BREAK) in stead of CTRL.
# This can be done by uncommenting line #INFINITE_KEY=BREAK.
#
# WARNING: Do not type on the machine's keyboard while this script
#          is running, or your keystrokes might become commands,
#          for example CTRL-Q: Quit
#
# Cyan ..............Hitting CONTROL key
# Yellow Blinking ...Sleeping
# Red Blinking.......Wow! We broke out of the infinite while loop!

ATTACKMODE HID

INFINITE_KEY=CTRL
#INFINITE_KEY=BREAK

# infinite while loop
while true
do
	LED SPECIAL
	QUACK $INFINITE_KEY
	sleep 1
	LED ATTACK
	sleep 9
done

# this code will never be reached
LED FAIL

 


Quickpost info


Saturday 9 September 2017

Quickpost: Keyboard Setting For pfSense

Filed under: Quickpost — Didier Stevens @ 0:00

Here’s how I configured a belgian keyboard on pfSense: I added the command “kbdcontrol -l be.iso.kbd” to my profile (.profile):

Mappings for keyboards can be found in folder /usr/share/syscons/keymaps:

 

 


Quickpost info


Friday 8 September 2017

Quickpost: DllDemo

Filed under: Quickpost — Didier Stevens @ 0:00

This is a quick demo on loading DLLs with standard Windows tools.

I wrote a DLL for this demo:

#include <windows.h>

extern "C" __declspec(dllexport) void ExportedFunction(void)
{
	OutputDebugString("ExportedFunction");
	MessageBox(NULL, "Hello from ExportedFunction, DemoDll!", "DemoDll", MB_OK);;
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
	switch (fdwReason)
	{
	case DLL_PROCESS_ATTACH:
		OutputDebugString("DLL_PROCESS_ATTACH");
		MessageBox(NULL, "Hello from DllMain, DemoDll!", "DemoDll", MB_OK);;
		break;

	case DLL_THREAD_ATTACH:
		OutputDebugString("DLL_THREAD_ATTACH");
		break;

	case DLL_THREAD_DETACH:
		OutputDebugString("DLL_THREAD_DETACH");
		break;

	case DLL_PROCESS_DETACH:
		OutputDebugString("DLL_PROCESS_DETACH");
		break;
	}

	return TRUE;
}

A message box is displayed when DllMain (the entrypoint for DLLs) is called when the DLL is loaded into a process, and another message box is displayed when function ExportedFunction is executed.

Function ExportedFunction is prefixed by __declspec(dllexport) to export the function, and with extern “C” to prevent C++ name mangling.

One method to load this DLL into a process, is to use the rundll32 command (since I’m doing this demo on Windows 10, I’m using the 64-bit version of my DLL):

No message box is displayed: the DLL was not loaded. The reason is that rundll32 requires you to specify an exported function that it needs to call.

With dumpbin, we can get an overview of the exported functions of a DLL:

We can specify the name of the exported function we want to call like this:

We can see the message box from the entrypoint, and then the message box from the exported function we called:

This means that the DLL was loaded into the rundll32 process, and that the called function was executed.

Exported functions have an ordinal too (a number to identify exported functions), and that number can be used too to specify the function, like this:

If we use rundll32 with a function that is not exported by the DLL, then the DLL is loaded:

rundll32 will display an error because it could not find the exported function:

But as we could see, the DLL got loaded.

Despite the name would make you think (rundll32), the version of rundll32 I used is a 64-bit executable, and that’s why I used a 64-bit DLL.

32-bit DLLs have to be loaded into 32-bit processses, and 64-bit DLLs into 64-bit processes.

However, rundll32 will start a “proxy” process if you mix bitness, so that DLLs will always be loaded.

Let’s look at the 4 possible combinations:

64-bit rundll32 with 32-bit DLL:

Taking a look with process explorer, we see that 64-bit rundll32 started 32-bit rundll32 to load the 32-bit DLL:

64-bit rundll32 with 64-bit DLL:

In this case, there is no need for a “proxy” process:

32-bit rundll32 with 32-bit DLL:

In this case too, there is no need for a “proxy” process:

And finally, 32-bit rundll32 with 64-bit DLL:

Here we see that 32-bit rundll32 started 64-bit rundll32 to load the 64-bit DLL:

The following is another method: rundll32 shell32.dll,Control_RunDLL C:\Demo\DemoDLL-64-bit.dll

You have to provide an absolute path.

Finally, another method to load a DLL is with regsvr32. I’ve started to use regsvr32 long ago, when I developed ActiveX object: you used it to deploy ActiveX objects on machines.

By default, regsvr32 will load the DLL and call exported function DllRegisterServer:

Since function DllRegisterServer is not exported by the demo DLL, we get an error:

But the DLL was loaded. If we export a function named DllRegisterServer in our DLL, it would get executed.

regsvr32 can be used to call other exported functions too (DllUnRegisterServer and DllInstall), as can be seen from the help dialog when you run regsvr32 without arguments:

DemoDll_V0_0_0_1.zip (https)
MD5: 51ED8255B71097269BFF9B5ADBFDC392
SHA256: 599BA297705B15580A297C3F47429225C38EA9FAA4A8DF27BCE49C918964AD30


Quickpost info


Tuesday 29 August 2017

Quickpost: PowerShell Options Order

Filed under: Quickpost — Didier Stevens @ 0:00

This is a reminder for myself: “powershell.exe -File test.ps1 -ExecutionPolicy Bypass” doesn’t work.

“File C:\Demo\hello.ps1 cannot be loaded because running scripts is disabled on this system.”

It’s because of this:

-ExecutionPolicy Bypass is not parsed as an option, but as arguments to option -File.

The correct option order is this:

powershell.exe -ExecutionPolicy Bypass -File hello.ps1

 


Quickpost info


Saturday 26 August 2017

Quickpost: Metasploit PowerShell BASE64 Commands

Filed under: Hacking,Quickpost — Didier Stevens @ 21:29

I wanted to generate some BASE64 encoded PowerShell commands (i.e. with option -EncodedCommand) for analysis with my tool base64dump.py, thus I turned to Metasploit to generate these commands.

Here is the list of encoders:

It looks like cmd/powershell_base64 is what I’m looking for.

I couldn’t get the results that I wanted with this encoder, so I took a look at the source code:

This encoder will actually encode commands you pass to cmd.exe, and not PowerShell scripts.

I wanted an encoder for PowerShell scripts, like this simple PowerShell script to display a message box:

Add-Type -AssemblyName PresentationFramework
[System.Windows.MessageBox]::Show('Hello from PowerShell!')

Or even simpler:

Write-Host "Hello from PowerShell!"

And at this point, I really got sidetracked…

I coded my own encoder (based on the powershell_base64 encoder):

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Encoder
  Rank = NormalRanking

  def initialize
    super(
      'Name'             => 'Powershell Base64 Script Encoder',
      'Description'      => %q{
        This encodes a PowerShell script as a base64 encoded script for PowerShell.
      },
      'Author'           => 'Didier Stevens',
      'Arch'             => ARCH_CMD,
      'Platform'         => 'win')

    register_options([
      OptBool.new('NOEXIT', [ false, 'Add -noexit option', false ]),
      OptBool.new('SYSWOW64', [ false, 'Call syswow64 powershell', false ])
    ])

  end

  #
  # Encodes the payload
  #
  def encode_block(state, buf)
    base64 = Rex::Text.encode_base64(Rex::Text.to_unicode(buf))
    cmd = ''
    if datastore['SYSWOW64']
      cmd += 'c:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe '
    else
      cmd += 'powershell.exe '
    end
    if datastore['NOEXIT']
      cmd += '-NoExit '
    end
    cmd += "-EncodedCommand #{base64}"
  end
end

To install my encoder, I created folder powershell inside folder C:\metasploit\apps\pro\vendor\bundle\ruby\2.3.0\gems\metasploit-framework-4.15.4\modules\encoders (that’s on Windows) and copied my encoder base64.rb into it.

That’s all that is needed to make it available:

And now I can just use it with msfvenom, for example:

 

–payload – indicates that the payload has to be taken from stdin.

What I have no explanation for, is why on Windows input redirection does not work while piping works:

Echo works too:

With this encoder, I can encode a PowerShell script generated with msfvenom, like this:

The first msfvenom command will generate a powershell script with 32-bit shellcode for a meterpreter shell. The second msfvenom command will encode this command into a BASE64 PowerShell command. Option NOEXIT adds -NoExit to the PowerShell command, and option SYSWOW64 uses 32-bit powershell.exe on 64-bit Windows.

As the generated code was too long for the command line, I had to use option –smallest with the first msfvenom command to reduce the size of the script.

Here is the generated command:

And here is the execution:

More info:

 


Quickpost info


Thursday 24 August 2017

Quickpost: Using ClamAV On Windows

Filed under: Malware,Quickpost — Didier Stevens @ 0:00

This is how I deploy and configure ClamAV on Windows:

I download the portable Windows x64 version in a ZIP file (clamav-0.99.2-x64.zip).

I extract the content of this ZIP file to folder c:\portable\, this will create a subfolder ClamAV-x64 containing ClamAV.

Then I copy the 2 samples for the config files:

copy c:\portable\ClamAV-x64\conf_examples\clamd.conf.sample c:\portable\ClamAV-x64\clamd.conf

copy c:\portable\ClamAV-x64\conf_examples\freshclam.conf.sample c:\portable\ClamAV-x64\freshclam.conf

I create a database folder (to contain the signature files):

mkdir c:\portable\ClamAV-x64\database

I edit file c:\portable\ClamAV-x64\freshclam.conf:

Line 8: #example

Line 13: DatabaseDirectory c:\portable\ClamAV-x64\database

Now I can run freshclam.exe to download the latest signatures:

Then I edit file c:\portable\ClamAV-x64\clamd.conf:

Line 8: #example

Line 74: DatabaseDirectory c:\portable\ClamAV-x64\database

And now I can run clamscan.exe to scan a sample:

 


Quickpost info


Sunday 30 July 2017

Quickpost: Trying Out JA3

Filed under: Networking,Quickpost — Didier Stevens @ 21:19

I tried out JA3 (a Python program to fingerprint TLS clients) with a 1GB pcap file from my server. It was fast (less than 1 minute), but I had to add some error handling to skip packets it would crash on.

I did not identify a lot of client HELLO packets with the JSON fingerprint database: around 5%.

 


Quickpost info


Next Page »

Blog at WordPress.com.