Huntress CTF: Week 1 – Malware: Hot Off The Press, HumanTwo, PHP Stager & Zerion

Hot Off The Press

To start with let’s see what kind of file this is.

UHARC is a compression/archiving system for PC platforms, which appears to be neglected since around 2005. It achieves better compression than most other archivers, at the expense of being much slower.” 

http://fileformats.archiveteam.org/wiki/UHARC

I scoured the internet looking for a copy of UHARC to download. I’m not going to link any here as many if not all may contain malware. Since this is a Windows only tool, (or Wine under Linux), we’ll open this one in a sandboxed Windows system.

When the file extracts we are presented with hot_off_the_press.ps1.

OMG that’s a lot of obfuscation! Let’s see if we can clean this up and make it more readable. First let’s remove all the ”+”

That’s a little bit better. There’s another obfuscation method going on where specific numbers are used to represent different letters. Originally, I tried to determine the substitution by completing terms I knew. Early ahead I saw (”Sc{2}i’pt{1}loc{0}Logging”) which to me reads like ScriptBlockLogging. So all 2’s are i’s, 1’s are B’s, and 0’s are k. I do a find/replace through the script with replacements on {0},{1}, and {2}. Now it looks like a block of Base64 in the middle block. I copy it over to CyberChef and … NADA. Something’s not right.

If you look closer at the code, you’ll see that each one of the strings that had a {#} substitution in it ends with “-f” followed by other letters in quotations. The first character after -f is substituted for {0}, the next for {1}, etc. So I run the same substitution pattern on the script using the correct letters for this string this time.

Replace the {0} with L.

Replace the {1} with E.

Now we’ve got a nice clean block of Base64.

Bring that over to CyberChef for decoding and:

We’ve got a script within the script.

If you scroll down in the output, you’ll see that there’s something else encoded as well.

We’ll run that through CyberChef.

Interesting we have an encoded_flag. Let’s add URL decode to the recipe.


HumanTwo

There were 1,000 files in the zip container. Easy comparison options like file size, modification date etc. don’t help as they are the same for all the files. It’s something in the content that has to be different. How the ‘f’ am I going to find the outlier in 1,000 files?! Meld and diff are two options coming up in the Discord. I install Meld, which is really a gui for diff, and start getting a feel for it. You can compare files or directories. If doing files you could do a 3 way comparison between 3 files. But not 1000. As I was looking through the files with Meld it struck me that all of the file contents we also the same with the exception of one line.

Let’s run through all the files with the_silver_searcher and isolate on String.Equals

Scrolling down through the output we see that one is a definite outlier, or as we like to say around here, an Irregular.

Once more to CyberChef, this time from Hex.


PHP Stager

Heavily obfuscated PHP. This is going to be fun.

Let’s see if ChatGPT can give some insight into what’s going on here.

After several hours of back and forth from PHP to Python to PowerShell, online IDE’s, more ChatGPT, googling, and back again I was able to roughly reproduce the PHP in a Python and get it to execute.

Looks like we’re not done yet. In the middle of the output we can see another block of Base64. What happens if we toss that into CyberChef.

Great! Now we have a Perl script. How far down does this challenge go? It’s like those Matryoshka dolls from Russia. One inside another inside another. But wait… there’s something interesting in the Perl script.

There’s a reference to UU encoding and a string. We’ll copy the string and bring it over to another of my favorite decoding sites, dcode.fr.

Sure enough it handles the decoding and we have our flag.


Zerion

Yay (said no one), another crazy PHP file.

Looks to be using Base64 encoding, Rot13, and some other options to obfuscate the code. Back to school (ChatGPT) to see what’s going on.

Let’s copy the large encoded text block to CyberChef. We’ll apply Rot13, then Reverse the text by Character, and finally – decrypt using Base64.

And that’s our flag!


Use the tag #HuntressCTF on BakerStreetForensics.com to see all related posts and solutions for the 2023 Huntress CTF.

Huntress CTF: Week 1 – WarmUps

The team at Huntress pulled off an amazing CTF that ran through the month of October with new challenges released daily. In this series, I’ll be providing my solutions to the challenges. WARNING Will Robinson, spoilers ahead! Use the tag #HuntressCTF to see all related posts.

Technical Support

There wasn’t really a solve to this one, but I’m including here for consistency. If you head to the Discord server for the event and went to the support channel, the flag was provided.


String Cheese

Taking this literally – we’ll run STRINGS on cheese:

If we scroll down through the output…


Notepad

Right click on the notepad file, open with VS Code or text editor of choice.


CaesarMirror

When you examined the text file you got

I copied the text over to CyberChef and started running some recipes on it. I found an algorithm that would work on it, well, one half at a time.

I took the original file and edited it into 2 versions, caesar_left.text and caesar_right.txt. I converted each side of the file, screenshotted the output, and then aligned them next to each other to read the complete output.


Book By Its Cover

Use the FILE command to get the properties of book.rar.

Hmm. A png file. Let’s open that with an image viewer.


BaseFFFF+1

Examining the file contents yielded…

Back to CyberChef. There’s Base64 and Base85 but neither of those work. Looking closer at the title…. BaseFFFF+1… FFFF is the Hexadecimal for 65535. Add one and you have 65536. I googled Base65536, and while it’s not in CyberChef it does exist.


Read the Rules

Head over to the Rules page. While you’re there, be sure to read up on what tools are not allowed. CTFs are usually not the situation where you bring a tank to a knife fight. Once you’ve read everything, visible, three or four times if you’re me, right, click on the webpage and choose view source.


Query Code

Once again the FILE command gives us our first clue.

It’s a png image so open with an image viewer and you have a QR code. Scan that with a QR reader and…


Dialtone

The provided wav file is a recording of different telephone buttons being pushed. The first thing to do is identify what buttons/numbers are being pushed. Using the site DialABC I uploaded the wav file and then transcribed the DTMF Tone outputs.

13040004482820197714705083053746380382743933853520408575731743622366387462228661894777288573. That is on heck of a phone number!

A hint on Discord led me to the next step. It referenced that this was a BigInteger value. After several trips with Alice down various rabbit holes I found a PowerShell syntax to convert BigInt to strings.

Hmm. Looks closer to what an encoded flag might look like, but still not there yet. Back over to CyberChef and sprinkle a little Magic dust… and we see that the next and last decoding step is to From_Hex.


Layered Security

The file command indicates that it’s a GIMP image file. I recall that GIMP is an open-source application that’s comparable to Adobe Photoshop. I’d used it previously but not in a long time. I also can’t help but think of Pulp Fiction and “Bring out the Gimp.”

After a morbid chuckle and a quick installation, I launch GIMP and open the file. In the bottom right we see there are a number of faces that are part of this picture.

As we peel down the layers we find the flag in one of the images.


Comprezz

We’ve been pretty successful starting with the file command, so let’s start there.

As the challenge suggests, no I have not heard of this file type. A quick google for compress’d data 16 bits takes me to several posts on how to uncompress theses files. After a brief trial and error (it may have taken me 2 times), I cat’d the file and then piped it to uncompress.


That’s it for the challenges in the Warm Up category. There were also challenges in Forensics, Malware and Miscellaneous.

Use the tag #HuntressCTF to see all related posts. Now that October is over, I’ll be releasing as many of these as I can.

Huntress Capture the Flag – A CTF Marathon

Throughout October, as part of Cyber Security Awareness Month, the team over at Huntress put on a ~30 day Capture the Flag event with 58 unique challenges.

First and foremost, kudos to the organizers for pulling off an event of this size and duration. There were only minor technical difficulties noticed throughout the month, and on more than one occasion those were due to people not observing the rules and using brute force tools where they weren’t needed (or allowed.)

Overall, I found the event to be a great learning experience that challenged me, increased my confidence, and gave me an avenue to pursue skills I want to develop further.

The challenges covered a wide area of subjects with the majority being DFIR related. The categories included:

  • Warm Ups (14)
  • Forensics (10)
  • Malware (16)
  • M365 (4)
  • OSINT (3)
  • Steganography (1)
  • Miscellaneous (10)

Today the final challenge of the event, graced us with another lovely malware sample to analyze.

I was very pleased with myself at having solved nearly 80% of the challenges. There’s still another 20 or so hours to go, so we’ll see if that improves any further. The only categories I didn’t have 100% in were Miscellaneous and Malware. I think this is fair considering my skill levels. The Malware scenarios were appropriately challenging for someone newer to this area. This is an area that I’ve been developing my skills in more recently. I’m looking forward to seeing others’ write-ups on those challenges where I didn’t make it all the way through, and following along with my own data.

Tools used in the CTF

I added a number of new tools to my toolkit throughout the CTF, and got more experienced with some old friends as well. Depending on the challenge I switched between operating systems including MacOS, REMnux (Linux), and a customized Windows VM with a plethora of malware analysis utilities. By the end of the event the tools used included:

  • PowerShell
  • Strings
  • CyberChef
  • Gimp
  • Curl
  • Firepwd.py
  • rita
  • the_silver_searcher
  • nmap
  • dcode.fr
  • meld
  • Cutter
  • Ghidra
  • Python
  • ChatGPT
  • Google Chrome Developer Tools
  • iSteg
  • exiftool
  • Google Lens
  • Google Maps
  • detonaRE
  • Process Monitor (procmon)
  • Visual Studio Code
  • Site Sucker
  • 7zip
  • Magnet AXIOM
  • olevba
  • x64dbg
  • AADInternals
  • Microsoft Excel
  • Event Viewer
  • chainsaw
  • PowerDecode
  • PowerShell ISE
  • rclone
  • Volatility3
  • hashcat
  • impacket

Write-Ups

Over the next few days I’ll be releasing the write-ups on how I solved each of the completed challenges. The organizers requested that no solutions be posted until 24 hours after the conclusion of the CTF.

Based on the amount of content, I’ll be breaking the write-ups down by week number (1-4) and challenge category.

Wednesday:

Thursday:

Friday:

Saturday:

You can follow along through the week, or come back on the weekend to read them all.

Once again, I want to extend my thanks to the Huntress team for a great event. I hope you’ll follow along with my solutions, and please comment with other ways to solve if you have them. It’s all about the learning.


Use the tag #HuntressCTF on BakerStreetForensics.com to see all related posts and solutions for the 2023 Huntress CTF.

Creating YARA files with Python

When I’m researching a piece of malware, I’ll have a notepad open (usually VS Code), where I’m capturing strings that might be useful for a detection rule. When I have a good set of indicators, the next step is to turn them into a YARA rule.

It’s easy enough to create a YARA file by hand. My objective was to streamline the boring stuff like formatting and generating a string identifier ($s1 = “stringOne”) for each string. Normally PowerShell is my goto, but this week I’m branching out and wanted to work on my Python coding.

The code relies on you having a file called strings.txt. One string per line.

When you run the script it will prompt for (metadata):

  • rule name
  • author
  • description
  • hash

It then takes the contents of strings.txt and combines those with the metadata to produce a cleanly formatted YARA rule.

Caveats:

If the strings have special characters that need to be escaped, you may need to tweak the strings in the rule after it’s created.

The script will define the condition “any of them”. If you prefer to have all strings required, you can change line 22 from

yara_rule += '\t\tany of them\n}\n'

to

yara_rule += '\t\tall of them\n}\n'

CreateYARA.py

def get_user_input():
    rule_name = input("Enter the rule name: ")
    author = input("Enter the author: ")
    description = input("Enter the description: ")
    hash_value = input("Enter the hash value: ")
    return rule_name, author, description, hash_value

def create_yara_rule(rule_name, author, description, hash_value, strings_file):
    yara_rule = f'''rule {rule_name} {{
    meta:
    \tauthor = "{author}"
    \tdescription = "{description}"
    \thash = "{hash_value}"

    strings:
    '''
    with open(strings_file, 'r') as file:
        for id, line in enumerate(file, start=1):
            yara_rule += f'\t$s{id} = "{line.strip()}"\n\t'
    yara_rule += '\n'
    yara_rule += '\tcondition:\n'
    yara_rule += '\t\tany of them\n}\n'

    return yara_rule

def main():
    rule_name, author, description, hash_value = get_user_input()
    strings_file = 'strings.txt'  

    yara_rule = create_yara_rule(rule_name, author, description, hash_value, strings_file)
    print("Generated YARA rule:")
    print(yara_rule)
    
    yar_filename = f'{rule_name}.yar'
    with open(yar_filename, 'w') as yar_file:
        yar_file.write(yara_rule)

    print(f"YARA rule saved to {yar_filename}")

if __name__ == "__main__":
    main()
Sample strings.txt file used as input for the YARA rule
Running CreateYARA.py
YARA rule created from Python script, viewed in VS Code.