Didier Stevens

Monday 27 June 2022

Quickpost: Cracking PDF Owner Passwords

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

I added code to John the Ripper to crack PDF owner passwords (JtR cracks PDF user passwords only).

Source code can be found here.

Compiled Windows (Cygwin) and Linux (Ubuntu) executables can be found here.

This change introduces a new format: $pdfo$.

There is no tool for the moment to create this format. Just use pdf2john.pl to create a $pdf$ hash, and then change it into a $pdfo$ hash. To crack the owner password, one needs to recover the user password first.

This is the illustrated process:

There will be a PR for this change.

Cracking PDF owner passwords is just an academic exercise (writing this code was also just an exercise), as tools like QPDF can decrypt PDFs encrypted with a PDF owner password only without requiring the cleartext PDF owner password as argument.


Quickpost info

Friday 27 May 2022

PoC: Cobalt Strike mitm Attack

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

I did this about 6 months ago, but this blog post didn’t get posted back then. I’m posting it now.

I made a small Proof-of-Concept: cs-mitm.py is a mitmproxy script that intercepts Cobalt Strike traffic, decrypts it and injects its own commands.

In this video, a malicious beacon is terminated by sending it a sleep command followed by an exit command. I just included the sleep command to show that it’s possible to do this for more than one command.

I selected this malicious beacon for this PoC because it uses one of the leaked private keys, enabling the script to decrypt the metadata and obtain the necessary AES and HMAC keys.

The PoC does not support malleable C2 data transforms, but the code to do this can be taken from my other cs-* tools.

Saturday 11 December 2021

MiTM Cobalt Strike Network Traffic

Filed under: Encryption,Hacking,Malware,My Software — Didier Stevens @ 10:14

I made a small PoC. cs-mitm. py is a mitmproxy script that intercepts Cobalt Strike traffic, decrypts it and injects its own commands. In this video, a malicious beacon is terminated by sending it an exit command. I selected a malicious beacon that uses one of the leaked private keys.

The script does not support data transforms, but that can be easily added, for example with code found in cs-parse-traffic.py.

Friday 12 November 2021

Update: cs-decrypt-metadata.py Version 0.0.2

Filed under: Encryption,My Software,Update — Didier Stevens @ 0:00

This new version of my tool to decrypt Cobalt Strike metadata, now supports transformations.

By default, encrypted metadata in Cobalt Strike traffic is encoded with BASE64 and then transmitted via the Cookie header in HTTP(S) requests.

This metadata is encrypted with a public RSA key, and can be decrypted if the private key is known.

Here is an example of a malicious beacon with a specific metadata encoding.

Analyzing the beacon with my tool 1768.py yields the following information:

First: a public key (field 0x0007) is used, for which we know the private key: thus we will be able to decrypt the metadata.

Second: the encrypted metadata has a specific encoding (field 0x000c). This beacon was configured with a profile that specifies that the encrypted metadata must be encoded with BASE64 URL-safe (this is a variant of BASE64, that uses characters – and _ in stead of + and /). Then it is prefixed with string __cfduid= and transmitted via the Cookie header.

An error will result when this data is processed by tool cs-decrypt-metadata.py without providing the transformation instructions:

The following transformation instructions must be provided to properly decode and decrypt the metadata: 7:Metadata,13,2:__cfduid=,6:Cookie

This is done with option -t:

cs-decrypt-metadata_V0_0_2.zip (https)
MD5: 368EA059E91716DD071975B13A3F108D
SHA256: B906191D376F81E687392EC30EA57483BFC791E3D478E863FA0DB7B468662310

Wednesday 3 November 2021

New Tool: cs-extract-key.py

Filed under: Announcement,Encryption,My Software — Didier Stevens @ 0:00

cs-extract-key.py is a tool designed to extract cryptographic keys from Cobalt Strike beacon process memory dumps.

This tool was already available in my beta repository.

This tool can extract cryptographic keys from process memory dumps of a version 3.x beacon directly:

And from version 4.x together with encrypted data extracted from network capture:

More details can be found in the man page, and in and upcoming blog post.

cs-extract-key_V0_0_1.zip (https)
MD5: 4102A5A5BFD4D432DA4A721D43F568F5
SHA256: BBEDF6CBFFF51669187694F463C32A49F53420BEDF8B76508D06850643DE334F

Friday 22 October 2021

New Tool: cs-decrypt-metadata.py

Filed under: Announcement,Encryption,My Software,Reverse Engineering — Didier Stevens @ 0:00

cs-decrypt-metadata.py is a new tool, developed to decrypt the metadata of a Cobalt Strike beacon.

An active beacon regularly checks in with its team server, transmitting medata (like the AES key, the username & machine name, …) that is encrypted with the team server’s private key.

This tool can decrypt this data, provided:

  1. you give it the file containing the private (and public) key, .cobaltstrike.beacon_keys (option -f)
  2. you give it the private key in hexadecimal format (option -p)
  3. the private key is one of the 6 keys in its repository (default behavior)

I will publish blog posts explaining how to use this tool.

Here is a quick example:

cs-decrypt-metadata_V0_0_1.zip (https)
MD5: 31F94659163A6E044A011B0D82623413
SHA256: 50ED1820DC63009B579D7D894D4DD3C5F181CFC000CA83B2134100EE92EEDD9F

Thursday 21 October 2021

“Public” Private Cobalt Strike Keys

Filed under: Encryption,Malware,My Software — Didier Stevens @ 18:05

I found 6 private keys used by malicious Cobalt Strike servers. There’s a significant number of malicious CS servers on the Internet that reuse these keys, thus allowing us to decrypt their C2 traffic. For the details, I recommend reading the following blog post I wrote “Cobalt Strike: Using Known Private Keys To Decrypt Traffic – Part 1“.

I integrated these keys in the database (1768.json) of my tool 1768.py (starting version 0.0.8).

Whenever you analyze a beacon with 1768.py that uses a public key with a known private key, the report will point this out:

And when you use option verbose, the private key will be included:

If you want to integrated these 6 keys in your own tools: be my guest. You can find these key pairs in 1768.json.

Monday 7 June 2021

How-to: Make Your Own Cert With OpenSSL on Windows (Reloaded)

Filed under: Encryption — Didier Stevens @ 0:00

As several things have changed since I published “Howto: Make Your Own Cert With OpenSSL on Windows” 5 years ago, I’m publishing an updated how-to.

This time, I’m using the OpenSSL Windows binaries provided by the Curl developers:

I’m using OpenSSL version 1.1.1i. I chose the 32-bit version, so that you can still follow along in case you have to do this on a 32-bit computer.

This OpenSSL version from the Curl developers is packaged inside a ZIP file: it requires no installation with administrative rights. Just unzip the downloaded file.

Then open a command-line (I’m using cmd.exe) and go to the unzipped folder:

I issue the command “openssl version”, to check that I can run OpenSSL.

Now you are ready to follow along.

And just like in my previous how-to(s), I’m creating 2 certificates (not just one self-signed certificate): one root certificate and one subordinate certificate.

First we generate a 4096-bit long RSA key for our root CA and store it in file ca.key:

openssl genrsa -out ca.key 4096

This generates a private key that is not password protected. It is stored inside file ca.key as printable text (PEM format):

If you want to password-protect this private key, add command option -aes256 to encrypt the private key with AES using a key derived from a password you will be prompted for.

Next, we create our self-signed root CA certificate ca.crt; you’ll need to provide an identity for your root CA:

openssl req -new -x509 -days 1826 -key ca.key -out ca.crt -config openssl.cnf

The -x509 command option is used for a self-signed certificate. 1826 days gives us a cert valid for 5 years.

On Windows, you can double-click the root certificate we just created (ca.crt), and inspect it:

Next step: create our subordinate CA that will be used for the actual signing. First, generate the key:

openssl genrsa -out ia.key 4096

Then, request a certificate for this subordinate CA:

openssl req -new -key ia.key -out ia.csr -config openssl.cnf

Make sure that the Common Name you enter here is different from the Common Name you entered previously for the root CA. If they are the same, you will get an error later on when creating the pkcs12 file.

Next step: process the request for the subordinate CA certificate and get it signed by the root CA.

Here the command requires an extra option, that I did not use in previous how-tos. We need a small text file (altname.cnf), with the following content:

subjectAltName=DNS:www.didierstevens.com

I use the same value as I used for the Common Name (CN): http://www.didierstevens.com.

This subjectAltName is necessary, since Google Chrome version 58 and later no longer use the CN when there is no subjectAltName.

After creating this altname.cnf file, we can issue this command to create the subordinate CA signed by the root CA:

openssl x509 -req -days 730 -in ia.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out ia.crt -extfile altname.cnf

The certificate (ia.crt) will be valid for 2 years (730 days) and I decided to choose my own serial number 01 for this cert (-set_serial 01). For the root CA, I let OpenSSL generate a random serial number.

You can also inspect this certificate (ia.crt) with Windows:

That’s all there is to it! Of course, there are many options I didn’t use. Consult the OpenSSL documentation for more info. For example, I didn’t restrict my subordinate CA key usage to digital signatures. It can be used for anything, even making another subordinate CA. When you buy a code signing certificate, the CA company will limit its use to code signing. And I did not use passwords to protect my keys. In a production environment, you want to protect your keys with passwords.

To use this subordinate CA key for Authenticode signatures with Microsoft’s signtool, you’ll have to package the keys and certs in a PKCS12 file:

openssl pkcs12 -export -out ia.p12 -inkey ia.key -in ia.crt -chain -CAfile ca.crt

Then it can be used to sign a Windows PE file:

signtool sign /f ia.p12 /fd sha256 /td sha256 /tr http://timestamp.globalsign.com/?signature=sha2 Dialog42.exe

Some Observations

Configuration file

Some OpenSSL commands (like the req command we used) require the openssl.cnf configuration file. That is why on Windows, we use command option: -config openssl.cnf

If we do not use this command option on Windows, we get an error:

Can't open C:/Windows/System32/OpenSSL/ssl/openssl.cnf for reading, No such file or directory
22256:error:02001003:system library:fopen:No such process::0:fopen('C:/Windows/System32/OpenSSL/ssl/openssl.cnf','r')
22256:error:2006D080:BIO routines:BIO_new_file:no such file::0:

Even if we run openssl.exe in the same folder as openssl.cnf.

Another option is to set environment variable OPENSSL_CONF to point to the configuration file:

set OPENSSL_CONF= c:\Demo\openssl-1.1.1i_2-win32-mingw\openssl.cnf

Then we can issue commands without referencing the openssl.cnf explicitly:

Command option subj

When we use command req like we did, we are prompted for extra information. This extra information can be passed via the command line too, with command option -subj:

openssl req -new -x509 -days 1826 -key ca.key -out ca.crt -subj “/C=BE/ST=/L=Brussels/O=Didier Stevens/OU=/CN=didierstevens.com/emailAddress=ca@didierstevens.com” -config openssl.cnf

Do not use interactive mode

Interactive mode in OpenSSL, is when you launch opensll.exe, and then issue commands at the OpenSSL prompt, like this:

The error message:

problem creating object tsa_policy1=1.2.3.4.1
25156:error:08064066:object identifier routines:OBJ_create:oid exists::0:
error in req

is a known issue with OpenSSL.

Interactive mode doesn’t “clean up” correctly between commands: it is best not to use interactive mode.

Certificates with a validity period longer than one year

I know that Chrome is no longer accepting certificates with a validity period longer than one year, so I expected my 2-year certificate to be rejected by Chrome (using Chrome 87 on Windows). It was not.

It turns out that this requirement does not apply to certificates like the one I created:

Beginning with Chrome 85, TLS server certificates issued on or after 2020-09-01 00:00:00 UTC will be required to have a validity period of 398 days or less. This will only apply to TLS server certificates from CAs that are trusted in a default installation of Google Chrome, commonly known as “publicly trusted CAs”, and will not apply to locally-operated CAs that have been manually configured.

X.509 Version 1 and Version 3

In my previous blog posts on OpenSSL, the created root certificates (ca.crt) are X.509 Version 3 certificates, and the created subordinate certificates (ia.crt) are X.509 Version 1 certificates. That’s because I did not use any version 3 extensions for the subordinate certificates, and thus OpenSSL creates version 1 certificates.

This changes with the use of the Subject Alternative Name (SAN) extension (subjectAltName) in this how-to. subjectAltName is a version 3 extension, and thus the subordinate certificate (ia.crt) created in this how-to is a version 3 X.509 certificate. In this how-to, I had only one Common Name and therefore I used just one SAN: DNS:www.didierstevens.com.

It is possible to use several SANs, and not only DNS, but also IP for example:

subjectAltName=DNS:www.didierstevens.com,DNS:*.didierstevens.be,IP:127.0.0.1

There are also version 3 extensions that dictate what a certificate can be used for. When these extensions are not present, a certificate can be used for everything.

If you want to limit the use of a certificate to web servers, you can use the following values:

basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage=serverAuth
subjectAltName=DNS:www.didierstevens.com

This one can not be used for code signing:

SignTool Error: No certificates were found that met all the given criteria.

And you can use the following values to limit the use of a certificate to code signing:

basicConstraints = CA:FALSE
keyUsage = digitalSignature
extendedKeyUsage=codeSigning

Caveat: I just did some basic tests with these extensions. For example, the cert restricted to code signing can be used by signtool, and Chrome will refuse it when I use it with my simple web server. I didn’t do exhaustive testing to see if code signing is the only thing this cert can be used for.

I did compare it with a commercial code signing certificate I acquired years ago, and there was a difference for the keyUsage: it was marked as critical.

basicConstraints = CA:FALSE
keyUsage = critical,digitalSignature
extendedKeyUsage=codeSigning

Installing the root certificate

When you use the subordinate certificate, you will see that it is still rejected by web browsers, and that the Authenticode signature is not valid.

That is because the subordinate’s root certificate is not trusted. If you install it as a trusted root certification authority, the subordinate certificate will be trusted.

Linux

You can use the same commands on a Linux machine where the OpenSSL package is installed.

Don’t use command option -config though: openssl will find its config file.

And I got an issue with the command option -subj and “empty strings”:

problems making Certificate Request
140254820331968:error:0D07A098:asn1 encoding routines:ASN1_mbstring_ncopy:string too short:../crypto/asn1/a_mbstr.c:100:minsize=1

I had to remove ST= and OU=.

Monday 26 April 2021

Quickpost: Decrypting Cobalt Strike Traffic

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

I have been looking at several samples of Cobalt Strike beacons used in malware attacks. Although work is still ongoing, I already want to share my findings.

Cobalt Strike beacons communicating over HTTP encrypt their data with AES (unless a trial version is used). I found code to decrypt/encrypt such data in the PyBeacon and Geacon Github repositories.

This code works if you know the AES key: which is not a problem in the use cases of the code above, as it is developed to simulate a beacon. Beacons generate their own AES key, and thus these beacon simulations also generate their own AES key.

But what if you’re analyzing real beacons used in malware attacks? How do you obtain the AES key?

I found a way to extract the keys (AES and HMAC) from process memory of a running beacon.

I use the following procdump command to prepare process memory dumps:

procdump -mp -w -s 1 -n 5 malware.exe

Then I start the beacon malware.exe in a malware analysis virtual machine while capturing traffic with Wireshark.

My new tool cs-extract-key.py looks in the dumped process memory for the unencrypted (RSA encryption) metadata that a beacon sends to the C2. This metadata contains the AES en HMAC keys.

Example:

This method does not always work: the metadata is overwritten after some time, so the process dump needs to be taken quickly after the beacon is started. And there are also cases were this metadata can not be found (I suspect this is version bound).

For those cases, my tool has another way of obtaining the keys. I extract the encrypted data of the first post of the beacon to the C2 (this is called a callback in the PyBeacon code):

And then I provide this to my tool, together with the process dump. My tool will then proceed with a dictionary attack: extract all possible AES and HMAC keys from the process dump, and try do authenticate and decrypt the callback. If this works, the keys have been found:

And once I have obtained the keys, I can pass them to my traffic decoding program that I have updated to include decryption (and that I have renamed to cs-parse-http-traffic.py):


Quickpost info


Saturday 27 March 2021

FileZilla Uses PuTTY’s Registry Fingerprint Cache

Filed under: Encryption,Forensics,Networking — Didier Stevens @ 10:01

Today I figured out that FileZilla uses PuTTY‘s registry key (HKCU\SOFTWARE\SimonTatham\PuTTY\SshHostKeys) to cache SSH fingerprints.

This morning, I connected to my server over SFTP with FileZilla, and got this prompt:

That’s unusual. I logged in over SSH, and my SSH client did not show a warning. I checked the fingerprint on my server, and it matched the one presented by FileZilla.

What’s going on here? I started to search through FileZilla configuration files (XML files) looking for the cached fingerprints, and found nothing. Then I went to the registry, but there’s no FileZilla entry under my HKCU Software key.

Then I’m taking a look with ProcMon to figure out where FileZilla caches its fingerprints. After some searching, I found the answer:

FileZilla uses PuTTY’s registry keys!

And indeed, when I start FileZilla again and allow it to cache the key, it appears in PuTTY’s registry keys.

One last check: I modified the registry entry and started FileZilla again:

And now FileZilla warns me that the key is different. That confirms that FileZilla reads and writes PuTTY’s registry fingerprint cache.

So that answered my question: “Why did FileZilla warn me this morning?” “Because the key was not cached”.

But then I was left with another question: “Why is the key no longer cached, because it was cached?”

Well, I started to remember that some days ago today, I had been experimenting with PuTTY’s registry keys. I most likely deleted that key (PuTTY is not my default SSH client). I verified the last-write timestamp for PuTTY’s registry key, and indeed, 4 days ago it was last written to.

Update:

Thanks to Nicolas for pointing out that fzsftp is based on PuTTY:

Next Page »

Blog at WordPress.com.