Didier Stevens

Friday 28 October 2022

The Making Of: qa-squeaky-toys.docm

Filed under: Hacking — Didier Stevens @ 0:00

qa-squeaky-toys.docm is a challenge I made for CSCBE 2022.

It’s a Word document with VBA code. But the VBA code has been “cleaned” by an anti-virus.

I was inspired by a real maldoc cleaned by a real anti-virus: “Maldoc Cleaned by Anti-Virus“.

Here is how I made this challenge.

I created a .docm file with the following vba code:

I extracted the vbaProject.bin file from the OOXML file (.docm).

First, I removed all the compiled VBA code from stream 3. -s 3c selects the compiled code stored in VBA stream 3.

I open a copy of vbaProject.bin with a binary editor, and search for the bytes of the compiled code. And I set them all to 0x00.

Then at position 0x40 inside that stream, I write this ASCII test: “Cleaned by your favorite anti-virus!”.

Next I will shorten the compressed VBA source code. This is the compressed VBA source code (selected with 3v):

Value F4B0 is a little-endian integer: 0xB0F4. B are some flags, F4 is the length of the chunk of compressed VBA code. F4 hexadecimal is 244 decimal. I shorten this by 206 bytes. Thus I replace F4 with 26 (with a binary editor).

The result is that now, only the first line is readable, followed by some gibberish:

And to get rid of the gibberisch, I also shorten the length of the stream. It is 1380 bytes long:

That’s 64 05 00 00 (representation for a 32-bit little-endian unsigned integer).

I subtract 204, thus 1380 – 204 = 1176. Or 98 04 00 00. I use again the binary editor to make this change.

Result:

How did I find the values to subtract? Educated guessing and trial and error. Why 2 different subtractions? Because that was also the case in the original sample that inspired me.

Thursday 16 June 2022

Discovering A Forensic Artifact

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

While developing my oledump plugin plugin_olestreams.py, I noticed that the item moniker’s name field (lpszItem) values I observed while analyzing Follina RTF maldocs, had a value looking like _1715622067:

The number after the underscore (_), is derived from the timestamp when the item moniker was created. That timestamp is expressed as an epoch value in local time, to which a constant number is added: 61505155.

I figured this out by doing some tests. 61505155 is an approximation: I might be wrong by a couple of seconds.

Item name _1715622067 is the value you find in Follina maldocs created from this particular RTF template made by chvancooten. 1715622067 minus 61505155 is 1654116912. Converting epoch value 1654116912 to date & time value gives: Wednesday, June 1, 2022 8:55:12 PM. That’s when that RTF document was created.

RTF documents made from this template, can be detected by looking for string 0c0000005f3137313536323230363700 inside the document (you have to look for this hexadecimal string, not case sensitive, because OLE files embedded in RTF are represented in hexadecimal).

Notice that the newest template in that github repository is taken from a cve-2017-0199 RTF template document, and that it no longer contains a item moniker.

But it does contain another timestamp:

This hexadecimal string can also be used for detection purposes: 906660a637b5d201

I used the following YARA rules for a retrohunt (34 matches):

rule follina_rtf_template_1 {
    strings:
        $a = "0c0000005f3137313536323230363700" nocase
    condition:
        $a
}

rule follina_rtf_template_2 {
    strings:
        $a = "906660a637b5d201" nocase
    condition:
        $a
}

Notice that I do not include a test for RTF documents in my rules: these rules also detect Python program follina.py.

And if you are a bit familiar with the RTF syntax, you know that it’s trivial to modify such RTF documents to avoid detection by the above YARA rules.

Later I will spend some time to find the actual code that implements the generation of the item value _XXXXXXXXXX. Maybe you can find it, or you already know where it is located.

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.

Sunday 26 September 2021

Patching A Java .class File

Filed under: 010 Editor,Forensics,Hacking,Malware — Didier Stevens @ 0:00

010 Editor is one of few commercial applications that I use daily. It’s a powerful binary editor with scripting and templates.

I recently had to patch a Java .class file: extend a string inside that class. Before going the route of decompiling / editing / recompiling, I tried with 010 Editor.

Here is the file opened inside the editor:

When opening the file, 010 Editor recognized the .class extension and installed and ran the template for .class files. That’s what I wanted to know: is there a template for .class files? Yes, there is!

Here is how you can apply a template manually, in case the file extension is not the original extension:

And this is how the template results look like:

Under the hex/ascii dump, the template results are displayed: a set of nested fields that match the internal structure of .class file. For example, the first field I selected here, u4 magic, is the magic header of a .class file: CAFEBABE.

The string I want to extend is this one:

I need to extend string “1.2 (20210922)”. Into something like “1.2 (20210922a)”.

Doing so will make the string longer, thus I need to add a byte to the file (trivial), but I also need to make sure that the binary structure of .java files remain valid: for example, if there is something in that structure like a field length, I need to change the field length too.

I’m not familiar with the internal structure of .class files, that why I’m using 010 Editor’s .class template, hoping that the template will make it clear to me what needs to be changed.

To find the template result field I need to modify, I position my cursor on the string I want to modify inside the ASCII dump, I right-click and select “Jump To Template Variable”:

Which selects the corresponding template variable:

So my cursor was on the 10th byte (bytes[9]) of the string, which is part of template variable cp_info constant_pool[27]. From that I gather that the string I want to modify is inside a pool of constants.

I can select that template variable:

And here I can see which bytes inside the .class file were selected. It’s not only the string, but also bytes that represent the tag and length. The length is 14, that’s indeed the length of the string I want to extend. Since I want to add 1 character, I change the length from 14 to 15: I can do that inside the template results by double-clicking the value 14, I don’t need to make that change inside the hexdump:

Next I need to add a character to the string. I can do that in the ASCII dump:

I have to make sure that the editor is in insert mode (INS), so that when I type characters, they are inserted at the cursor, in stead of overwriting existing bytes:

And then I can type my extra character:

So I have changed the constant string I wanted to change. Maybe there are more changes to make to the internal structure of this .class file, like other length fields … I don’t know. But what I do as an extra check is: save the modified file and run the template again. It runs without errors, and the result looks good.

So I guess there are no more changes to make, and I decide to tryout my modified .class file and see what happens: it works, so there are no other changes to make.

Monday 19 July 2021

Using SeBackupPrivilege With Python

Filed under: Hacking — Didier Stevens @ 0:00

Access to files on a Windows NTFS filesystem is governed by permissions and privileges.

For permissions, it is done with a security descriptor on a file which contains a Discretionary Access Control List (DACL): these are the permissions that decide if a user has access (and which type of access) to said file. Most files don’t have their own, proper permissions: they inherit them from their parent folders.

Even administrators can be denied access to a file through DACL configuration.

But there is another mechanism that governs access to securable objects like files: privileges. A privilege is a property that a user holds. Administrators have many privileges that normal users don’t have. Like SeBackupPrivilege and SeRestorePrivilege (these are privileges necessary for backup operators).

When a user holds a privilege, it allows that user to do things that other users without that privilege are not allowed to do. For example, the SeBackupPrivilege allows a user to read any file, even if the security descriptor denies access.

But just having the SeBackupPrivilege is not enough:

1) it needs to be enabled programmatically

2) when opening a file, the intention to use the privilege must be specified

Doing this in a programming language like C is easy (for example, I programmed this into my FileScanner tool), but for Python, it’s a bit more complicated.

Part 1, enabling the privilege can be done in Python with the following code (it relies on pywin32).

import win32security
import win32api

def EnablePrivilege(privilege):
    hToken = win32security.OpenProcessToken(win32api.GetCurrentProcess(), win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY)
    win32security.AdjustTokenPrivileges(hToken, 0, [(win32security.LookupPrivilegeValue(None, privilege), win32security.SE_PRIVILEGE_ENABLED)])
    win32api.CloseHandle(hToken)

EnablePrivilege(win32security.SE_BACKUP_NAME)

Part 2, opening the file, is typically done with WIN32 API function CreateFile and passing it the FILE_FLAG_BACKUP_SEMANTICS flag with argument dwFlagsAndAttributes.

In Python, we usually access files via function open, and not via WIN32 API function CreateFile. We can do that, but I found a simpler method.

Python’s open function has no argument where we can pass flag FILE_FLAG_BACKUP_SEMANTICS, so we cannot use open.

Python also has function os.open, it returns a file descriptor that can then be used with other file descriptor operations, like read. Like open, os.open has no argument to pass flag FILE_FLAG_BACKUP_SEMANTICS. However, someone figured out it can be done indirectly by using flag 0x2000 (os.O_DIRECTORY ?) :

fd = os.open('c:\\demo\\test.txt', 0x2000)
os.read(fd, 0x10) # read 10 bytes

Here under is a demo. File c:\demo\test.txt is only accessible (full control) by a given, normal user. And not by the administrator. This instance of Python is running under the account of an elevated administrator (so that it has the SeBackupPrivilege ready to be enabled).

When attempting to open file c:\demo\test.txt with open and os.open, permission is denied.

But after enabling SeBackupPrivilege, access via os.open is granted:

Monday 7 December 2020

Quickpost: finger.exe

Filed under: Hacking,Networking,Quickpost — Didier Stevens @ 0:00

Windows 10 comes with the finger command, an ancient computer network tool.

You can still use it to lookup weather information, for example 🙂

It establishes a TCP connection to the hostname/IP address after the @ character, using destination port 79. And then it sends the text before the @ characters in ASCII, terminated with carriage return & line feed.

After that, it reads the reply, displays it, and closes the TCP connection.

finger.exe is not proxy-aware.

Port 79 is not hardcoded as an integer in finger.exe: the port is identified by service name “finger” (UNICODE), which is defined in the services list (%SystemRoot%\system32\drivers\etc\services). GetAddrInfo uses this list.

If you replace “finger” with “http\x00\x00” (UNICODE) in finger.exe (via binary patching, a shim, …), the finger command will connect to port 80:

As noted by many, finger.exe can be (ab)used to exchange information and files. Here I had my own go at it with finger.exe & Excel:

 


Quickpost info


Saturday 10 October 2020

Quickpost: 4 Bytes To Crash Excel

Filed under: Hacking,Quickpost,Reverse Engineering — Didier Stevens @ 0:00

A couple of years ago, while experimenting with SYLK files, I created a .slk file that caused Excel to crash.

When you create a text file with content “ID;;”, save it with extension .slk, then open it with Excel, Excel will crash.

Microsoft Security Response Center looked at my DoS PoC last year: the issue will not be fixed. It is a “Safe Crash”, Excel detects the invalid input and calls MsoForceAppExitIf to terminate the Excel process.

If you have Excel crashing with .slk files, then look at the first line. If you see something like “ID;;…”, know that the absence of characters between the semi-colons causes the crash. Add a letter, or remove a semi-colon, and that should fix the issue.


Quickpost info


Monday 27 April 2020

NVISO Innovation Coin

Filed under: Announcement,Hacking — Didier Stevens @ 0:00

I received an Innovation Coin for the research I conduct at NVISO.

An important element in research, that doesn’t get much (public) attention, is failure.

When you perform research, know that many of the things you will try, will fail: they will not lead to the desired outcome. This is inherent to research.

Publishing failed research is useful, if only to avoid others taking the same, dead-end path. And maybe to inspire future researchers to find other paths.

 

I would like to show an example of some simple research I did recently, that didn’t produce the desired outcome.

 

While adding a new feature to my zipdump.py tool, I got the idea to bypass anti-virus detection of a payload by putting it inside the comment of a ZIP archive.

The last record in a ZIP file, is the end-of-central-directory (EOCD) record. In normal situations, this record marks the end of the ZIP file: there is no data beyond this record. One of the last fields in this record, is the comment-length field. If there is no comment (most ZIP files have no comment), the comment-length field is zero and it it the last field in the record. So it marks the end of the ZIP file.

If there is a comment, the comment-length contains the length (in bytes) of the comment, and the comment itself is the last field in the record (right after the comment-length field).

Here is a binary view of the EOCD record of a ZIP file without comment. The comment-length field (2 bytes, little-endian) is equal to zero:

And here is an EOCD record with a comment: 18 bytes long (0x12). The comment-length field (2 bytes, little-endian) is equal to 0x12, and the comment itself is right after this field:

I created a ZIP file with the mimikatz driver as comment. Since the comment-length field is 2 bytes long, a comment can not be longer than 65536 bytes (0xFFFF). Hence I couldn’t use mimikatz.exe (it’s larger than 64KB) and had to use mimikatz.sys (33KB).

The version of mimikatz.drv I used has 55/70 detections on VirusTotal at time of writing, and stored inside a ZIP file, it has 43/62 detections.

A ZIP file containing a simple text file has 0 detections.

And the same ZIP file with mimikatz.sys as a comment, has 13/60 detections.

Here is a binary view of that file:

From these results, I could conclude that this is indeed a valid method to bypass static detection by several anti-virus products, and that my research yielded a useful bypass method.

However, I also created a file where mimikatz.sys is just appended to that ZIP file containing a text file. Not as a comment, just appending one file to another. And here the detection rate on VT is just 4/61.

This is a simpler and better method, one that is already known and used by many actors on the Internet.

 

Remark that I used VirusTotal here for quick results, but that the anti-virus products on VirusTotal are limited in their detection capability, compared to the same AVs deployed on endpoints.

Wednesday 1 April 2020

April 1st 2020: FlashPix File With VBA Code

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

Last year, there was some misunderstanding regarding Office Documents with VBA code mistakenly identified as FlashPix picture files.

The FlashPix picture format is an old format, based on the Compound File Binary Format (what I like to call OLE files). It has no support for VBA code at all (it doesn’t support any embedded scripting).

However, since it is an ole file, it’s technically possible to add storages and streams containing VBA code. This code can never execute, because the FlashPix specifications does not support it, and hence there are no image viewers that would recognize and execute this code.

So I took a FlashPix image (3d996a887c4a1b5b5ce70528f6bb4508). Here you can see the streams it contains:

And then I took a malicious AutoCAD drawing, and copied the VBA streams and storages into the FlashPix file:

Giving me this file 5040ef90824371a0bd0acaa36263553b.When I submitted this file to VirusTotal a couple of months ago, the AV detection ratio was 29/59. Which is far better than the other “AV-alert pictures” that I created.

If you are in need of a benign file that will trigger anti-virus, I shared this FlashPix PoC on the new malware sharing service Malware Bazaar.

Next Page »

Blog at WordPress.com.