Insomni’hack 2024 – Bash to the Future writeup

The Challenge

You have been contracted to help COPERNIC Inc spot the light on a potential compromise. It seems that one of their scientists has been spied through a 20 years old malware… And fortunately, Zeus was on your side since the 4 Gb snapshot was carried out at the best possible time to facilitate your analysis.

Let’s download this 595 Mb archive [protected with the usual “infected” password] and see how it looked like in 2004. 😜

The final flag is split in 2 sub-flags in that challenge. You must merge them, but keep a dash between them.

For example, let’s suppose you found the following 2 sub-flags:

Part 1: INS{XXX}

Part 2: INS{ZZZ}

Then, you must submit the following flag to score: INS{XXX-ZZZ}


Congratulations to the Russian team “More Smoked Leet Chicken” who was the unique team that solved that challenge.

Other teams were pretty close. Most teams easily noticed the decoy flag and successfully managed to find the first real flag. The second flag was a little bit trickier, despite at least one other team found it, but missed the easier one.

Thank you to everyone who came to congratulate me and appreciated the originality of this challenge, which was ultimately only a retrospective analysis of what we could already observe 20 years ago.

Historical context

“Ba(ck)Sh(ell)” [aka, “Bash” for close friends] was a challenging project started with Dodoche on DevCpp in 2004, during the good old Windows XP time when Firefox was also born… A project which was created for fun, but it finally remained very useful for years during my previous Pentester life:

  • It was a DLL-based RAT which was injected into Internet Explorer memory space.
  • Modular payloads were supported by loading additional modules, like the “libspy.dll” which provided keylogger, screenshots and password stealer features [initially to retrieve cached credentials for the ISA proxy which was very common by that time, and to dump the weakly passwords from IE, then to also get those from a new comer named Firefox].

I quickly added a cover channel through ADS… And the code basically remained untouched until 2013, where we switched the project to CodeBlocks with F0x and a few fancy features were added, like:

  • Adding support for Chrome [which was born at the end of 2008] to the password stealer feature.
  • Obfuscation of the strings in the binaries [XOR+Base64].
  • Internal processes hiding in the native task manager.
  • Various tricks to get FUD against common AV by that time.
  • Encryption of the traffic toward the C2 [AES].

Besides replacing the original background on the C2 panel [which was a probably a little bit too sexy for this write-up], nothing changed for that challenge. It is a very realistic scenario, with a 20 years old private RAT that did me many favors in the past. 😉


The bad way

There was a fake flag waiting to be picked up by lazy hunters who simply relied on a strings. It was easy to know it was a decoy, since there was no “PART 1” or “PART 2” nearby:

The proper way

The most efficient approach is to parse the snapshot with the wonderful Volatility framework [here we will use the version 3], coupled with the powerful CSVKIT [here for the very handy CSVSQL, which permits to parse an output CSV as if it was an SQL database].

The snapshot comes from a Windows 10 VM:

There are at least 3 easy starting points. The first one is to locate 32 bits executables… It is often a quick win to spot malware, especially if it was written 20 years ago: 😉

Here the WOW64 field reveals several 32-bits instances of iexplore.exe.

The “netstat” approach is also often interesting. Here, it reveals some established connections [as well as recently closed ones] from msedge.exe [PID 6508] and iexplore.exe [PID 8124]:

There is much more noise from msedge.exe and iexplore.exe if we look for remnant structures of network connections:

The 3rd approach consists into focusing on VADs to identify process memory ranges that potentially contain injected code:

3 distinct hunting approaches which all spot the light on iexplore.exe. So, let’s focus on the most recent instance [PID 8124] which still has an established connection:

No weird parameters were submitted to run it:

This process has no child, which is normal. On the contrary, we can notice that we are facing an orphan process, and this is very suspicious for a browser… It was run by the PID 1776, who there is no trace left from his parent:

This can also be observed by a simple pstree:

Parsing the EPROCESS doubly-linked list is always risky since it can easily be defeated to hide running processes. So, it is wise to also take the time to search EPROCESS pool allocations in memory. Unfortunately, not that much information here… Besides some recently terminated processes whose remnant structures can still be found in RAM:

Let’s look at the DLLs now. No arbitrary DLLs mapped at a first glance:

But similarly to the processes in the EPROCESS doubly-linked list, this “DllList” module remains blind to DLLs that got unlinked from the doubly-linked LDR list, so it is always better to cross-check its results with the “LdrModules”. The latter relies on the VAD to identify all allocated memory within processes and check if the files are mapped, thereby also detecting DLLs which are not present in the PEB.

This is the case here. We see many executables in the VAD that are not mapped into the PEB, like winhttp.dll, mswsock.dll, ws2_32.dll, bcrypt.dll, crypt32.dll, libspy.dll and logo.jpg. This definitely smells injection:

Obviously, if the processes were not loaded in a traditional manner through LoadLibrary() [like they for example would  with a Reflective DLL Injection], then they would also not have appeared here [since the VAD would have remained unchanged]. Similarly, some false negatives could also happen if a rootkit is used.

Interestingly, we can see many files that are loaded into iexplore.exe’s memory space but have the InLoad, InInit and InMem fields set to False, therefore indicating that those executables have been unlinked from the PEB. 2 of those files seem pretty interesting according to their path:

  • A DLL probably disguised as “logo.jpg” is stored in the “C:\Users\John WICK\AppData\Roaming\Microsoft\Windows\Recent\SystemDestinations\” directory.
  • An other smelling library, “libspy.dll”, is stored in “C:\$Recycle.Bin\SystemDestinations\”.

Volatility is right. It turns out that I heavily used to hide myself in the dark areas of Windows to benefit from what I called a native rootkit.

The initial trick in 2004 was to extract both the DLL and the injector from the loaders’ binary into the root of the recycled bin [a stealth location since nobody looked into that special directory, which also provided sustainability since files were not deleted when the recycled bin got emptied].

But a few years later, the recycled bin’s internals drastically evolved, and Bash was slightly modified to leverage this. Its loader then relied on 2 interesting objects within the “%userprofile%\AppData\Roaming\Microsoft\Windows\Recent\” directory [which apparently still works nowadays]… A subdirectory and a link that has the same name:

  • “%userprofile%\AppData\Roaming\Microsoft\Windows\Recent\SystemDestinations\” was a nice directory to hide some payloads, like a copy of the loader [which either held a decoy picture containing the main DLL of Bash in an ADS or was configured at compile time to download it from the C2 at runtime] and that decoy picture holding the main payload.
  • “%userprofile%\AppData\Roaming\Microsoft\Windows\Recent\SystemDestinations.lnk” is a link that points to the “C:\$Recycle.Bin\SystemDestinations\” directory, where some additional DLL payloads and temporary files were sitting. The link had [and apparently still has] the priority from the Windows explorer perspective. So, it is not possible to reach the previous directory within the graphical file explorer [even by adding a trailing backslash], which made it a very interesting place to hide the main payloads. It was only reachable through the CMD, which was rarely used by SysAdmins. 😉

But let’s go back to the future… :-]

In my environment, the first attempt to check what we can see in the weird directory where the libspy.dll library was uncovered raised an error:

The stdout that gets redirected to the outfile is encoded in ANSI, which generates an exception when it receives the Unicode characters uncovered by volatility. A quick fix is then to override the encoding of sys.stdout:


Now that the filescan command runs fine, let’s see what we can find in one of the two weird paths from where executable files were loaded in a stealthy manner:

Interesting, there is a log file next to the DLL whose name doesn’t look like it’s up to anything good. Let’s look at it:

Bingo! The first part of the flag was indeed recorded by a keylogger feature provided by the libspy module. Yeah, I know it sucks… It was in plain text. But come on, it was more than 20 years ago. 😉

We just need to consider the backspaces while reading the log. I made typos on purpose while I was typing the credentials, to prevent people from simply running a “strings” on the VMEM:

PART1 / INS{W3D0ntN33dR04d$}

Now, let’s see what other files we may have in the second directory where the weird executable “logo.jpg” was loaded:

The “logo.jpg” file is the decoy picture which was hosting the main DLL of Bash inside an ADS. Grabbing it would only permit very limited Basic Static Analysis opportunities since Bash’s DLL had custom protections to disturb analysis [like decrypting variables on the fly through basic XOR operations to avoid strings capture]:

But there is another interesting file to dig in that unusual directory, since there is indeed a “Windows Imaging Format” file [aka, WIM] next to that “executable picture”. This is a file-based disk image format that is supported by tools like 7z and which permits to preserve the Alternate Data Streams from the source files. The WIM files turned to be very handy, and they replaced the RAR format in my own initial TTPs when the infamous Windows Vista was released. So, let’s dump that WIM file and uncompress it on an NTFS volume:

The “Quotes.txt” file from that archive is a decoy:

But we can notice easily that the file has an ADS nowadays, since the “/R” option was added to the “DIR” commands in Windows Vista if I remember correctly. But in previous versions of Windows, it was a perfect place to hide my payloads and to covertly centralize data before exfiltration since no native utilities were available to even get a minimal visibility:

So, let’s extract this ADS and see what was hidden there:

Here we go. A screenshot was saved for stealth exfiltration, and it contains the second part of the flag:


So, the final flag to submit was: INS{W3D0ntN33dR04d$-DocuGotThe2.21GW}

Happy Hacking,

Frédéric BOURLA