Capture the Flag

TryHackMe Challenge: Operation Slither

Operation Slither LogoThis is a free Easy-Rated challenge on TryHackMe that you can find here. Our instructions are just “Follow the leads and find who’s behind this operation.” That leads me to believe that we’re doing a little bit of Blue Team-type of work or at least some recon and OSINT intel digging about a fictitious hacker group. As you follow along, you will very likely see people who are ruining our fun by just posting flags in places you’ll go. Ignore those even if you see them and follow along the steps anyway. We’re building specific kinds of skills here and by short-cutting the flags, you’re only cheating yourself from learning. Enough moralizing, back to the challenge.

We get this instruction, “We got access to a hacker forum and found the info of our company on sale! All the info we have is in this post. Find any information related to the leader of the Sneaky Viper group.” and we find this message:

Full user database TryTelecomMe on sale!!!

As part of Operation Slither, we've been hiding for weeks in their network and have now started to exfiltrate information. 
This is just the beginning. We'll be releasing more data soon. Stay tuned!

@v3n0mbyt3_

---

Task 1: The Leader

That just leads us to our first question: Aside from Twitter / X, what other platform is used by v3n0mbyt3_? Answer in lowercase.

This should be as easy as doing a search for that username, which seems pretty unique.

Results of a Google search for the username v3n0mbyt3_

That gives us the answer, threads.

Next question is What is the value of the flag?

That’s not super helpful in and of itself, but if we use some context clues, I’m guessing that on Threads there is a post giving away the flag. If we go to the profile, we don’t see anything in the posts, so let’s check replies. There, we see what looks like a Base64 encoded string, VEhNe3NsMXRoM3J5X3R3MzN0el80bmRfbDM0a3lfcjNwbDEzcyF9. If I take that to Cyberchef and decode it, we get the answer… THM{sl1th3ry_tw33tz_4nd_l34ky_r3pl13s!}

Task 2: The Sidekick

Opening Task 2, we see this, “A second message has been made public! Our account in their forum was deleted, so we couldn’t get the operator’s handle this time. Follow the crumbs from the first task and hunt any information related to the second operator of the group.”

60GB of data owned by TryTelecomMe is now up for bidding!

Number of users: 64500000 Accepting all types of crypto
For takers, send your bid on Threads via this handle:

HIDDEN CONTENT 
----------------------------------------------------------------------------------------------------- 
You must register or log in to view this content

The first question is What is the username of the second operator talking to v3n0mbyt3 from the previous platform?

So, right where we were before in the replies on Threads, you can see conversations and our next answer, _myst1cv1x3n_

And our next question, What is the value of the flag?

So – again – not super helpful, but this seems like something we’ll find over in _myst1cv1x3n_’s profile. Turns out, that’s wrong. The only thing in the replies is that flag we got and used in task 1. Let’s search for _myst1cv1x3n_’s username and see if there are more sites out there linked to them. Didn’t find anything overt, but Threads accounts do have Instagram accounts connected to them. If we click the Instagram icon in the Threads profile, we’re taken to _myst1cv1x3n_’s Instagram. Some people have taken to commenting answers in the posts and that’s cheating. Let’s try to do this for real. If I look at each post, especially this one, we see they have a Soundcloud. If you work back to their profile and look at each song, we find a hint in the song called Prototype 2. The user left a Base64 encoded message in the description, VEhNe3MwY20xbnRfMDBwczNjX2Yxbmczcl9tMXNjbDFja30=. Decoding that gives us our answer THM{s0cm1nt_00ps3c_f1ng3r_m1scl1ck}

Task 3: The Last Operator

This task says “A new post is up. Hunt the third operator using past discoveries and find any details related to the infrastructure used for the attack.” Our message is

FOR SALE

Advanced automation scripts for phishing and initial access!

Inclusions:
- Terraform scripts for a resilient phishing infrastructure 
- Updated Google Phishlet (evilginx v3.0)
- GoPhish automation scripts
- Google MFA bypass script
- Google account enumerator
- Automated Google brute-forcing script
- Cobalt Strike aggressor scripts
- SentinelOne, CrowdStrike, Cortex XDR bypass payloads

PRICE: $1500
Accepting all types of crypto
Contact me on REDACTED@protonmail.com 

---

Our first question is What is the handle of the third operator?

For this one, I assume we’re looking for someone else who might be interacting with one or the other or both of these two. I clicked through comments and didn’t find anything good. I then decided to look at followers and found this.

The third operator

This gives us the answer, sh4d0wF4NG

What other platform does the third operator use? Answer in lowercase.

Okay, let’s search that user.

Results of a Google search for the username sh4d0wF4NG

Our answer then is github.

What is the value of the flag?

I’m guessing we need to go digging in the GitHub of this person to find it. There are 3 repos, two are forks and one is their own. I decided to focus on the non-forked one first. However, it wouldn’t be crazy to expect that there was some change to one of the forked ones with our answer in it. I looked at all of the files first and didn’t see anything big. This repo only has 9 commits, so I looked at all of the diffs. This is a VERY FAVORITE trick in these kinds of CTFs. I ended up finding what I wanted in commit 90224ec. It was also in a diff that didn’t want to load. You had to click to load it since it was so large. There is a section that says

  "outputs": {
    "shadow-password": {
      "value": "VEhNe3NoNHJwX2Y0bmd6X2wzNGszZF9ibDAwZHlfcHd9"
      "type": "string"
    }
  },

That shadow-password value is a Base64 encoded value that decodes to our flag: THM{sh4rp_f4ngz_l34k3d_bl00dy_pw}

And there we go! All done.

Capture the Flag

Hack the Box Walkthrough: Flag Command

AI-generated header image for this post of a green flag flying with terminal commands on it.Today, we’re going to tackle a Hack the Box Challenge on the offensive side called Flag Command. The scenario that we’re given is

Embark on the "Dimensional Escape Quest" where you wake up in a mysterious forest maze that's not quite of this world. Navigate singing squirrels, mischievous nymphs, and grumpy wizards in a whimsical labyrinth that may lead to otherworldly surprises. Will you conquer the enchanted maze or find yourself lost in a different dimension of magical challenges? The journey unfolds in this mystical escape!

If you click to start the challenge, you’ll be given an IP:Port to connect to. In my case, it is 154.57.164.75:32410, yours will almost certainly be different. Going to that page, I see this:
Our initial game screen

I follow along and type start and it gives me options like this:

>> start
YOU WAKE UP IN A FOREST.

You have 4 options!
HEAD NORTH
HEAD SOUTH
HEAD EAST
HEAD WEST

I tried to play along still, but even when I typed an available option, it is apparently case sensitive. So they are doing some sort of input validation. Given that this is a text engagement, I was wondering if we’d get some command injection or something. The first step to that would be to get past the validation.

>> head north
You do realise its not a park where you can just play around and move around pick from options how are hard it is for you????

>> HEAD NORTH
Venturing forth with the grace of a three-legged cat, you head North. Turns out, your sense of direction is as bad as your cooking - somehow, it actually works out this time. You stumble into a clearing, finding a small, cozy-looking tavern with "The Sloshed Squirrel" swinging on the signpost. Congratulations, you've avoided immediate death by boredom and possibly by beasties. For now...

I checked and it does send the commands to the server. My next command was sent to http://154.57.164.75:32410/api/monitor as this request and then response

// Request
{command: "TURN BACK"}

// Response
{ "message": "You decide to turn back, but you realize you've lost your way. Night falls, and the forest becomes a dark, eerie place. You hear mysterious sounds closing in. Game over!" }

I tried a few simple commands and couldn’t get anything going

>> id
'id' command not found. For a list of commands, type 'help'

>> help
start Start the game
clear Clear the game screen
audio Toggle audio on/off
restart Restart the game
info Show info about the game

>> info
You abruptly find yourself lucid in the middle of a bizarre, alien forest.
How the hell did you end up here?
Eerie, indistinguishable sounds ripple through the gnarled trees, setting the hairs on your neck on edge.
Glancing around, you spot a gangly, grinning figure lurking in the shadows, muttering 'Xclow3n' like some sort of deranged mantra, clearly waiting for you to pass out or something. Creepy much?
Heads up! This forest isn't your grandmother's backyard.
It's packed with enough freaks and frights to make a horror movie blush. Time to find your way out.
The stakes? Oh, nothing big. Just your friends, plunged into an abyss of darkness and despair.
Punch in 'start' to kick things off in this twisted adventure!

>> start
YOU WAKE UP IN A FOREST.

You have 4 options!
HEAD NORTH
HEAD SOUTH
HEAD EAST
HEAD WEST

>> id
You do realise its not a park where you can just play around and move around pick from options how are hard it is for you????

>> ;id
You do realise its not a park where you can just play around and move around pick from options how are hard it is for you????

>> id; #
You do realise its not a park where you can just play around and move around pick from options how are hard it is for you????

Okay, let’s take a look at the source code of the web app. I went into Developer Tools -> Sources and saw that there are 3 main javascript files at work here.

 <script src="/static/terminal/js/commands.js" type="module"></script>
 <script src="/static/terminal/js/main.js" type="module"></script>
 <script src="/static/terminal/js/game.js" type="module"></script>

Commands.js seems interesting. What’s in there?

export const START = 'YOU WAKE UP IN A FOREST.';

export const INITIAL_OPTIONS = [
    '<span class="command">You have 4 options!</span>',
    'HEAD NORTH',
    'HEAD SOUTH',
    'HEAD EAST',
    'HEAD WEST'
];

export const GAME_LOST =  'You <span class="command error">died</span> and couldn\'t escape the forest. Press <span class="command error">restart</span> to try again.';

export const GAME_WON = 'You <span class="command success">escaped</span> the forest and <span class="command success">won</span> the game! Congratulations! Press <span class="command success">restart</span> to play again.';

export const INFO = [
    "You abruptly find yourself lucid in the middle of a bizarre, alien forest.",
    "How the hell did you end up here?",
    "Eerie, indistinguishable sounds ripple through the gnarled trees, setting the hairs on your neck on edge.",
    "Glancing around, you spot a gangly, grinning figure lurking in the shadows, muttering 'Xclow3n' like some sort of deranged mantra, clearly waiting for you to pass out or something. Creepy much?",
    "Heads up! This forest isn't your grandmother's backyard.",
    "It's packed with enough freaks and frights to make a horror movie blush. Time to find your way out.",
    "The stakes? Oh, nothing big. Just your friends, plunged into an abyss of darkness and despair.",
    "Punch in 'start' to kick things off in this twisted adventure!"
];

export const CONTROLS = [
    "Use the <span class='command'>arrow</span> keys to traverse commands in the command history.",
    "Use the <span class='command'>enter</span> key to submit a command.",
];

export const HELP = [
    '<span class="command help">start</span> Start the game',
    '<span class="command help">clear</span> Clear the game screen',
    '<span class="command help">audio</span> Toggle audio on/off',
    '<span class="command help">restart</span> Restart the game',
    '<span class="command help">info</span> Show info about the game',
];

Okay, nothing exciting in there. The game.js is extremely boring and nothing is in there. That leaves us with main.js. There is a lot in main.js, but here is a relevant part where it checks the command and sends it to the API and also where it gets your options.

// HTTP REQUESTS
// ---------------------------------------
async function CheckMessage() {
    fetchingResponse = true;
    currentCommand = commandHistory[commandHistory.length - 1];

    if (availableOptions[currentStep].includes(currentCommand) || availableOptions['secret'].includes(currentCommand)) {
        await fetch('/api/monitor', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({ 'command': currentCommand })
        })
            .then((res) => res.json())
            .then(async (data) => {
                console.log(data)
                await displayLineInTerminal({ text: data.message });

                if(data.message.includes('Game over')) {
                    playerLost();
                    fetchingResponse = false;
                    return;
                }

                if(data.message.includes('HTB{')) {
                    playerWon();
                    fetchingResponse = false;

                    return;
                }

                if (currentCommand == 'HEAD NORTH') {
                    currentStep = '2';
                }
                else if (currentCommand == 'FOLLOW A MYSTERIOUS PATH') {
                    currentStep = '3'
                }
                else if (currentCommand == 'SET UP CAMP') {
                    currentStep = '4'
                }

                let lineBreak = document.createElement("br");


                beforeDiv.parentNode.insertBefore(lineBreak, beforeDiv);
                displayLineInTerminal({ text: '<span class="command">You have 4 options!</span>' })
                displayLinesInTerminal({ lines: availableOptions[currentStep] })
                fetchingResponse = false;
            });


    }
    else {
        displayLineInTerminal({ text: "You do realise its not a park where you can just play around and move around pick from options how are hard it is for you????" });
        fetchingResponse = false;
    }
}

// LATER IN THE FILE
const fetchOptions = () => {
    fetch('/api/options')
        .then((data) => data.json())
        .then((res) => {
            availableOptions = res.allPossibleCommands;

        })
        .catch(() => {
            availableOptions = undefined;
        })
}

That /api/monitor gets POSTed to. Attempting a GET returns a MethodNotAllowed error. We will have to keep an eye on how it is interacted with. Let’s call the other API that we found: /api/options. That gives us this:

{
  "allPossibleCommands": {
    "1": [
      "HEAD NORTH",
      "HEAD WEST",
      "HEAD EAST",
      "HEAD SOUTH"
    ],
    "2": [
      "GO DEEPER INTO THE FOREST",
      "FOLLOW A MYSTERIOUS PATH",
      "CLIMB A TREE",
      "TURN BACK"
    ],
    "3": [
      "EXPLORE A CAVE",
      "CROSS A RICKETY BRIDGE",
      "FOLLOW A GLOWING BUTTERFLY",
      "SET UP CAMP"
    ],
    "4": [
      "ENTER A MAGICAL PORTAL",
      "SWIM ACROSS A MYSTERIOUS LAKE",
      "FOLLOW A SINGING SQUIRREL",
      "BUILD A RAFT AND SAIL DOWNSTREAM"
    ],
    "secret": [
      "Blip-blop, in a pickle with a hiccup! Shmiggity-shmack"
    ]
  }
}

Okay, what is the “secret” one? Can I use that? It turns out that I can’t use it at the beginning of the game. I still have to enter “start”. However, once the game is in play (which makes sense given all the other commands in this list are “in game” commands), I can use that secret to win the game.

>> Blip-blop, in a pickle with a hiccup! Shmiggity-shmack
'blip-blop, in a pickle with a hiccup! shmiggity-shmack' command not found. For a list of commands, type 'help'

>> start
YOU WAKE UP IN A FOREST.

You have 4 options!
HEAD NORTH
HEAD SOUTH
HEAD EAST
HEAD WEST

>> Blip-blop, in a pickle with a hiccup! Shmiggity-shmack
HTB{D3v3l0p3r_t00l5_4r3_b35t__t0015_wh4t_d0_y0u_Th1nk??}

You escaped the forest and won the game! Congratulations! Press restart to play again.

That’s it. Not “nothing”, but definitely “Very Easy” by Hack the Box standards, as advertised. Any questions, let me know!

Flag Command Solved

Capture the Flag

Hack the Box Walkthrough: PhantomRing

PhantomRing LogoThis post, we are going to tackle a Hack the Box Sherlock called PhantomRing. You can find it here. It is rated Very Easy, but Hack the Box skews a little harder than other sites, so there are still some good learning points here… even if you aren’t on Day 2 of your InfoSec journey. To get started, download the zip and extract the files using the provided password hacktheblue. Inside, you’ll find one file called simply agent.

Our given scenario is

Your organization's SOC team intercepted a suspicious binary during a routine threat hunting operation on a Linux server. The file was found in /var/tmp with an unusual name and was attempting to establish outbound connections. Initial analysis suggests this could be a post-exploitation agent. Your task is to perform static analysis on the binary to identify its capabilities, extract indicators of compromise, and understand the threat actor's infrastructure.

Task 1 Question: What is the SHA256 hash of the malicious binary?

This starts out easily enough. If you’re using Linux, you can just issue this command and get the result. (PS… yes this hash is in VirusTotal)

$ sha256sum agent                   
2d7b1b2178f76c26893b2a56cbf9b36700235259e76b893d53817d5b66b634a5  agent

Task 1 Answer: 2d7b1b2178f76c26893b2a56cbf9b36700235259e76b893d53817d5b66b634a5

Task 2 Question: What is the IP address hardcoded in the binary for C2 communication?
Let’s use strings right off the bat. That might help us with a few of these next couple of questions. In this case, I only see one IP Address returned.

$ strings agent              
/lib64/ld-linux-x86-64.so.2
_ITM_deregisterTMCloneTable
## SNIP ## 
get 
recv 
users
netstat
kick
privesc
sdestruct
killbpf
exit
[*] 404 Command not found [*]
io_uring_queue_init
192.168.56.1
socket
io_uring_wait_cqe: %s
connect() failed: trying to reconnect
## SNIP ##
.data
.bss
.comment            

Task 2 Answer: 192.168.56.1

Task 3 Question: What port does the agent connect to on the C2 server?
Okay, the strings thing was a naive way to approach this and I knew Hack the Box would drive this deeper. I don’t see anything overtly obvious in strings, so I decided to use Ghidra to decompile it. You know you can do it without difficulty because it isn’t a stripped binary. How do I know that? If you run the file command on the file, it tells you.

$ file agent            
agent: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=1f617f2ea259a7ec724d7bbc01627982dc2f0495, for GNU/Linux 3.2.0, not stripped

This isn’t a Ghidra tutorial (and trust me, you wouldn’t want me to give you one), but here are the steps I took. I created a new project, did File -> Import File to bring in the agent executable, and then after it loaded, right clicked it and did Open With -> CodeBrowser. Then, on the left hand side, there is a section called Symbol Tree. Scroll into functions, find the main and click to select it.

Ghidra's Symbol Tree

Then, go to the menu at the top of Ghidra and select Window -> Decompile:main (or hit CTRL-E).

That opens a code window to the right of the assembly code you had been looking at. It is written in C and doesn’t have any variables named in a friendly way. However, you can scan over the code or read through if you’re familiar with C. I was looking for something related to this network call, and found where it logged out what was being attempted.

printf("[+] Connected to %s:%d\n","192.168.56.1",0x115d);

That string format is telling you it is going to output this in the format of string:decimal and we know the string is going to be 192.168.56.1. But what’s the decimal? The decimal is being represented by the hex of 0x115d, which if you hover on it in CodeBrowser (or do the math), tells you that is 4445. And that’s our answer.

Task 3 Answer: 4445

Task 4 Question: How many seconds does the agent wait before attempting to reconnect after a failed connection?

Inside one of the nested while(true) loops, as it ends, the code does this:

sleep(0x78);

0x78 (again, do the math or hover on the value in Ghidra) is 120, which is our answer.

Task 4 Answer: 120

Task 5 Question: How many different commands does the agent support? (excluding invalid commands)

Over in the Symbol Tree, there is another function called process_cmd. Since we already have the Decompile window open, just click on process_cmd and the relevant code shows up. There is a long if-else statement in there that covers all the commands: recv, users, ss, netstat, ps, me, kick, privesc, sdestruct, killbpf, and exit.

Task 5 Answer: 11

Task 6 Question: What Linux kernel interface does this malware abuse to evade EDR syscall monitoring?
So, this one is what gives the room its name. If you look in the symbol tree, there are a ton of calls to io_uring_cq_advance, io_uring_cqe_seen, io_uring_prep_close… I think 14 in total. Googling it, you see that this interface was abused in RingReaper malware, so that should be our answer… and it is.

Task 6 Answer: io_uring

Task 7 Question: What file does the agent read to enumerate logged-in users?

Another function is called cmd_users, if we open it for decompile, we see the file being read

iVar2 = read_file_uring(param_1,"/var/run/utmp",local_4018,0x2000);

Task 7 Answer: /var/run/utmp

Task 8 Question: What directory does the agent scan when searching for SUID binaries for privilege escalation?

There is another function called cmd_privesc. Inside there, you can see this, giving us our answer.

local_4330 = opendir("/usr/bin");

Task 8 Answer: /usr/bin

Task 9 Question: What string does the agent search for in /proc/[pid]/maps to identify security tools using eBPF?

In the function, cmd_killbpf, if we scan down we can find this path. While working in there, it reads the file for the process (using read_file_uring), then searches for the string anon_inode:bpf-map

snprintf(local_6118,0x100,"/proc/%s/maps",local_6150->d_name);
*(undefined8 *)(puVar6 + -0x11a8) = 0x103cb2;
iVar2 = read_file_uring(param_1,local_6118,local_4018,0x4000);
} while (iVar2 < 1);
  *(undefined8 *)(puVar6 + -0x11a8) = 0x103cde;
  pcVar4 = strstr(local_4018,"anon_inode:bpf-map");

Task 9 Answer: anon_inode:bpf-map

Task 10 Question: What is the full path of the first tracing file the agent attempts to disable?

Same function. The first one in the array is the answer.

  local_6138[0] = "/sys/kernel/debug/tracing/tracing_on";
  local_6138[1] = "/sys/kernel/debug/tracing/set_event";
  local_6138[2] = "/sys/kernel/debug/tracing/current_tracer";

Task 10 Answer: /sys/kernel/debug/tracing/tracing_on

Task 11 Question: What procfs path does the agent read to find its own executable location before self-destruction?

In cmd_selfdestruct, it is right here:

local_2a8 = readlink("/proc/self/exe",local_218,0x1ff);

Task 11 Answer: /proc/self/exe

Task 12 Question: What command string is compared by the agent to trigger deletion of its own binary?

Back in Task 5, I listed all the commands and where to see them. It is the obvious one where the if/else leads to cmd_selfdestruct.

Task 12 Answer: sdestruct

And here we go.

PhantomRing Pwned

Any questions, let me know.

Capture the Flag

Hack the Box Walkthrough: RomCom

HTB RomCom LogoThis time, we’re going to tackle a Sherlock from Hack the Box called RomCom. To get started, download the zip, extract it with the password hacktheblue, and let’s get ready to work. Our scenario is

Susan works at the Research Lab in Forela International Hospital. A Microsoft Defender alert was received from her computer, and she also mentioned that while extracting a document from the received file, she received tons of errors, but the document opened just fine. According to the latest threat intel feeds, WinRAR is being exploited in the wild to gain initial access into networks, and WinRAR is one of the Software programs the staff uses. You are a threat intelligence analyst with some background in DFIR. You have been provided a lightweight triage image to kick off the investigation while the SOC team sweeps the environment to find other attack indicators.

Inside the zip is a disk image named 2025-09-02T083211_pathology_department_incidentalert.vhdx. If we treat this like a real investigation, we need to always make sure that the file is read only. When I mount it in Windows, I can click through and see “stuff”.

Mounting the Image as a Read Only Drive on my Machine

Let’s see what we have to do.

Task 1 Question: What is the CVE assigned to the WinRAR vulnerability exploited by the RomCom threat group in 2025?

So this one is just a Google problem. I searched romcom winrar vulnerability and the second link pointed me here, which gave the answer.

Task 1 Answer: CVE-2025-8088

Task 2 Question: What is the nature of this vulnerability?

Read the link and it is right there at the start.

Task 2 Answer: path traversal

Task 3 Question: What is the name of the archive file under Susan’s documents folder that exploits the vulnerability upon opening the archive file?

Here, I just want to dig in and look at the files. The Drive Label is “KAPE (2025-09-02T08:32:11)” and inside the C folder is an $MFT file. We know we’re dealing with KAPE artifacts now, so we need help from hero of the community, Eric Zimmerman. I was just going to use his suggestion and grab all tools so that I’m totally up to date. However, the download links are broken at the moment. I’m using a version from Chocolatey “choco install ericzimmermantools“, but it isn’t 100% up-to-date. However, I think this will get us enough of the tools to do this easy HTB room.

One of the tools that I got was called MFT Explorer. This is a graphical version of his famed MFTECmd tool. I used that to load up the image and here’s what I see.

The Disk Image in MFT Explorer

I used the tool to navigate to c:\users\susan\Documents and this is what I see, telling us the answer.

Susan's Documents Folder

Task 3 Answer: Pathology-Department-Research-Records.rar

Task 4 Question: When was the archive file created on the disk?

Look at the SI_Created On column.

Task 4 Answer: 2025-09-02 08:13:50

Task 5 Question: When was the archive file opened?

You can see this in SI_Record Changed or in the Overview tab when the file is selected under Record Modified On.

Flags: Archive, Max Version: 0x0, Flags 2: None, Class Id: 0x0, Owner Id: 0x0, Security Id: 0x9DD, Quota Charged: 0x0 
Update Sequence #: 0x364A528

Created On:		2025-09-02 08:13:50.5190826
Content Modified On:	2025-09-02 14:54:54.0000000
Record Modified On:	2025-09-02 08:14:04.9807437
Last Accessed On:	2025-09-02 08:14:18.8730290

Task 5 Answer: 2025-09-02 08:14:04

Task 6 Question: What is the name of the decoy document extracted from the archive file, meant to appear legitimate and distract the user?

Using the 8:14:04 as a clue, we look in the Documents folder and see that a .pdf was created at 08:14:18 of the same day. That’s our file.

Task 6 Answer: Genotyping_Results_B57_Positive.pdf

Task 7 Question: What is the name and path of the actual backdoor executable dropped by the archive file?

We cheated a bit to get those last 2 answer. That’s not the best way to go about that. At this point, we need to not be lazy and do this correctly. We need to parse the journal and to do that, we’re going to use the MFTECmd.exe tool against the $J file and also give it the location of where to save the csv and what to call it.

PS > MFTECmd.exe -f 'd:\C\$Extend\$J' --csv "c:\code\" --csvf "Journal.csv"
MFTECmd version 2026.5.0

Author: Eric Zimmerman (saericzimmerman@gmail.com)
https://github.com/EricZimmerman/MFTECmd

Command line: -f d:\C\$Extend\$J --csv c:\code\ --csvf Journal.csv

File type: UsnJournal


Processed d:\C\$Extend\$J in 0.2817 seconds

Usn entries found in d:\C\$Extend\$J: 215,579
        CSV output will be saved to c:\code\Journal.csv

Okay, now we’re going to use another tool to open that csv called TimelineExplorer.exe that also gets installed when you get all of the Eric Zimmerman tools.

Timeline Explorer after Opening Journal.csv

I then added a filter for .exe files and then sorted by “Update Timestamp“. If we scroll down to the 2025-09-02 08:14:04 timeframe, we find our problem child.

The dropped backdoor file

So we can see the name, but not where it is dropped. We could look all around the MFT Explorer, but this is what I get for using GUI tools instead of going command line first. The best way to do this is to parse the $MFT file into a .csv also and use Timeline Explorer to get the path.

PS> MFTECmd.exe -f 'd:\C\$MFT' --csv "c:\code\" --csvf MFT.csv
MFTECmd version 2026.5.0

Author: Eric Zimmerman (saericzimmerman@gmail.com)
https://github.com/EricZimmerman/MFTECmd

Command line: -f d:\C\$MFT --csv c:\code\ --csvf MFT.csv

File type: Mft

Processed d:\C\$MFT in 1.7880 seconds

d:\C\$MFT: FILE records found: 139,533 (Free records: 0) File size: 136.5MB
        CSV output will be saved to c:\code\MFT.csv

Okay, when we open that up and search for the file name, it comes right up.

The dropped backdoor file path

Task 7 Answer: c:\users\susan\AppData\Local\ApbxHelper.exe

Task 8 Question: The exploit also drops a file to facilitate the persistence and execution of the backdoor. What is the path and name of this file?

Persistence and execution usually means that something needs to run on startup. So the first thing I’d check would be shortcuts in a startup path, next I’d check for services added. But when I just do a find for startup in Timeline Explorer in the MFT csv, I get 254 lines. The first one that appears after the incident (and any time for the next several minutes) is a file called Display Settings.lnk.

Task 8 Answer: c:\users\susan\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\Display Settings.lnk

Task 9 Question: What is the associated MITRE Technique ID discussed in the previous question?

I googled for mitre id for persistence via the startup folder and that let me to T1547:Boot or Logon Autostart Execution. I guessed the wrong sub-technique, thinking that it would be .001: Registry Run Keys / Startup Folder, but eventually figured that they wanted .009:Shortcut Modification.

Task 9 Answer: T1547.009

Task 10 Question: When was the decoy document opened by the end user, thinking it to be a legitimate document?

Within the MFT csv, search for the document name Genotyping_Results_B57_Positive.pdf, you can see when it was opened and you can confirm it in the Journal.csv.

Task 10 Answer: 2025-09-02 08:15:05

That’s it. Maybe not the most efficient run-through, but we got it done. Any questions or comments, please let me know.

Sherlock Complete

Capture the Flag

TryHackMe Walkthrough: Intermediate Nmap

TryHackMe Intermediate NmapWe’re going to break up our Hack the Box streak and switch over to doing a TryHackMe challenge this time called Intermediate Nmap. It is a premium room, which means that you have to be a subscriber to play along. If you aren’t a subscriber and you aren’t interested in becoming one, hopefully you can follow along and still learn or reinforce your learning with this walkthrough.

Here’s the description:
You’ve learned some great nmap skills! Now can you combine that with other skills with netcat and protocols, to log in to this machine and find the flag? This VM is listening on a high port, and if you connect to it it may give you some information you can use to connect to a lower port commonly used for remote access!

There is only one thing to answer for this room and it turns out that all they want is a flag. So let’s get after it. You can se the AttackBox or your own machine. I’m using my own Kali VM here, so I’ve downloaded my openvpn config file and I connect like this

sudo openvpn ~/Downloads/ThmPremium.ovpn

In my case, the IP of the machine is 10.64.156.76, so the first thing I do is give it enough time and then make sure that a) it is up and b) that I can see it through my VPN connection (this isn’t always a guarantee and I’ve had to get a newer config file in the past and reconnect and try again). After seeing some responses from the ping, I hit CTRL-C to stop it and move on

$ ping 10.64.156.76
PING 10.64.156.76 (10.64.156.76) 56(84) bytes of data.
64 bytes from 10.64.156.76: icmp_seq=1 ttl=62 time=67.8 ms
64 bytes from 10.64.156.76: icmp_seq=2 ttl=62 time=89.0 ms
64 bytes from 10.64.156.76: icmp_seq=3 ttl=62 time=73.8 ms
64 bytes from 10.64.156.76: icmp_seq=4 ttl=62 time=50.8 ms
^C
--- 10.64.156.76 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 50.790/70.361/89.006/13.682 ms

The next step is to run an nmap scan. They told us that there is a high port available as a hint. So, I’m not going to play around and I’m going to start by checking all TCP ports (-p-). This can take longer, especially when you are on a VPN instead of the AttackBox, but I don’t mind. The -T4 helps speed it up and I don’t mind waiting. As it is, this came back in about 13 seconds for me. The –sCV tells nmap to run default scripts (C) and to try to determine versions (V) of the services running.

$ nmap -sCV -p- -T4 10.64.156.76 
Starting Nmap 7.99 ( https://nmap.org ) at 2026-06-25 12:13 -0400
Nmap scan report for 10.64.156.76
Host is up (0.031s latency).
Not shown: 65532 closed tcp ports (reset)
PORT      STATE SERVICE VERSION
22/tcp    open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 7d:dc:eb:90:e4:af:33:d9:9f:0b:21:9a:fc:d5:77:f2 (RSA)
|   256 83:a7:4a:61:ef:93:a3:57:1a:57:38:5c:48:2a:eb:16 (ECDSA)
|_  256 30:bf:ef:94:08:86:07:00:f7:fc:df:e8:ed:fe:07:af (ED25519)
2222/tcp  open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 0b:8d:7c:be:ac:e7:ae:f5:29:c5:61:eb:fa:c1:93:c2 (RSA)
|   256 3d:16:86:a3:ee:9d:3a:8b:d1:00:3a:70:d2:20:e5:d9 (ECDSA)
|_  256 c1:fa:11:55:97:53:bb:a5:0b:8a:61:c0:12:60:ad:52 (ED25519)
31337/tcp open  Elite?
| fingerprint-strings: 
|   DNSStatusRequestTCP, DNSVersionBindReqTCP, FourOhFourRequest, GenericLines, GetRequest, HTTPOptions, Help, Kerberos, LANDesk-RC, LDAPBindReq, LDAPSearchReq, LPDString, NULL, RPCCheck, RTSPRequest, SIPOptions, SMBProgNeg, SSLSessionReq, TLSSessionReq, TerminalServer, TerminalServerCookie, X11Probe: 
|     In case I forget - user:pass
|_    ubuntu:Dafdas!!/str0ng
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port31337-TCP:V=7.99%I=7%D=6/25%Time=6A3D53BA%P=x86_64-pc-linux-gnu%r(N
SF:ULL,35,"In\x20case\x20I\x20forget\x20-\x20user:pass\nubuntu:Dafdas!!/st
SF:r0ng\n\n")%r(GetRequest,35,"In\x20case\x20I\x20forget\x20-\x20user:pass
SF:\nubuntu:Dafdas!!/str0ng\n\n")%r(SIPOptions,35,"In\x20case\x20I\x20forg
SF:et\x20-\x20user:pass\nubuntu:Dafdas!!/str0ng\n\n")%r(GenericLines,35,"I
SF:n\x20case\x20I\x20forget\x20-\x20user:pass\nubuntu:Dafdas!!/str0ng\n\n"
SF:)%r(HTTPOptions,35,"In\x20case\x20I\x20forget\x20-\x20user:pass\nubuntu
SF::Dafdas!!/str0ng\n\n")%r(RTSPRequest,35,"In\x20case\x20I\x20forget\x20-
SF:\x20user:pass\nubuntu:Dafdas!!/str0ng\n\n")%r(RPCCheck,35,"In\x20case\x
SF:20I\x20forget\x20-\x20user:pass\nubuntu:Dafdas!!/str0ng\n\n")%r(DNSVers
SF:ionBindReqTCP,35,"In\x20case\x20I\x20forget\x20-\x20user:pass\nubuntu:D
SF:afdas!!/str0ng\n\n")%r(DNSStatusRequestTCP,35,"In\x20case\x20I\x20forge
SF:t\x20-\x20user:pass\nubuntu:Dafdas!!/str0ng\n\n")%r(Help,35,"In\x20case
SF:\x20I\x20forget\x20-\x20user:pass\nubuntu:Dafdas!!/str0ng\n\n")%r(SSLSe
SF:ssionReq,35,"In\x20case\x20I\x20forget\x20-\x20user:pass\nubuntu:Dafdas
SF:!!/str0ng\n\n")%r(TerminalServerCookie,35,"In\x20case\x20I\x20forget\x2
SF:0-\x20user:pass\nubuntu:Dafdas!!/str0ng\n\n")%r(TLSSessionReq,35,"In\x2
SF:0case\x20I\x20forget\x20-\x20user:pass\nubuntu:Dafdas!!/str0ng\n\n")%r(
SF:Kerberos,35,"In\x20case\x20I\x20forget\x20-\x20user:pass\nubuntu:Dafdas
SF:!!/str0ng\n\n")%r(SMBProgNeg,35,"In\x20case\x20I\x20forget\x20-\x20user
SF::pass\nubuntu:Dafdas!!/str0ng\n\n")%r(X11Probe,35,"In\x20case\x20I\x20f
SF:orget\x20-\x20user:pass\nubuntu:Dafdas!!/str0ng\n\n")%r(FourOhFourReque
SF:st,35,"In\x20case\x20I\x20forget\x20-\x20user:pass\nubuntu:Dafdas!!/str
SF:0ng\n\n")%r(LPDString,35,"In\x20case\x20I\x20forget\x20-\x20user:pass\n
SF:ubuntu:Dafdas!!/str0ng\n\n")%r(LDAPSearchReq,35,"In\x20case\x20I\x20for
SF:get\x20-\x20user:pass\nubuntu:Dafdas!!/str0ng\n\n")%r(LDAPBindReq,35,"I
SF:n\x20case\x20I\x20forget\x20-\x20user:pass\nubuntu:Dafdas!!/str0ng\n\n"
SF:)%r(LANDesk-RC,35,"In\x20case\x20I\x20forget\x20-\x20user:pass\nubuntu:
SF:Dafdas!!/str0ng\n\n")%r(TerminalServer,35,"In\x20case\x20I\x20forget\x2
SF:0-\x20user:pass\nubuntu:Dafdas!!/str0ng\n\n");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 12.83 seconds

So, interesting. I see 3 ports open: 22 (running SSH), 2222 (running SSH), and 31337 (service unrecognized despite returning data) that tells us, “In case I forget – user:pass ubuntu:Dafdas!!/str0ng”

I decided to netcat directly to port 31337 and I just got that message and then the connection was closed. So that is seemingly all there is to find from that port.

$ nc 10.64.156.76 31337         
In case I forget - user:pass
ubuntu:Dafdas!!/str0ng

Okay. Well, we have 2 ports open with SSH, let’s try them in order.

$ ssh ubuntu@10.64.156.76                 
The authenticity of host '10.64.156.76 (10.64.156.76)' can't be established.
ED25519 key fingerprint is: SHA256:8VuYGtc5lO2sXK+MVsdbgQV9nF+EVHf8wJcrMAEWg10
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.64.156.76' (ED25519) to the list of known hosts.
ubuntu@10.64.156.76's password: 
Welcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.13.0-1014-aws x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

This system has been minimized by removing packages and content that are
not required on a system that users do not log into.

To restore this content, you can run the 'unminimize' command.

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

$ 

That worked. When I try port 2222, I get rejected immediately for not providing a public key.

$ ssh ubuntu@10.64.156.76 -p 2222
The authenticity of host '[10.64.156.76]:2222 ([10.64.156.76]:2222)' can't be established.
ED25519 key fingerprint is: SHA256:31v1b7mqLgFtZOZP/4qvBzUw5AzWmecr4m6GLPgDRJs
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[10.64.156.76]:2222' (ED25519) to the list of known hosts.
ubuntu@10.64.156.76: Permission denied (publickey).

So, let’s keep working in that port 22 connection.

$ ls
$ pwd
/home/ubuntu
$ ls -la
total 28
drwxr-xr-x 1 ubuntu ubuntu 4096 Jun 25 16:18 .
drwxr-xr-x 1 root   root   4096 Mar  2  2022 ..
-rw-r--r-- 1 ubuntu ubuntu  220 Feb 25  2020 .bash_logout
-rw-r--r-- 1 ubuntu ubuntu 3771 Feb 25  2020 .bashrc
drwx------ 2 ubuntu ubuntu 4096 Jun 25 16:18 .cache
-rw-r--r-- 1 ubuntu ubuntu  807 Feb 25  2020 .profile
$ find / -name flag.txt 2>/dev/null                
/home/user/flag.txt
$ cat /home/user/flag.txt
flag{251f309497a18888dde5222761ea88e4}

So, I expected to find a flag in the directory. There wasn’t one. So I checked where I landed and it was /home/ubutu, as I figured. So, I checked for hidden contents and there was nothing really there. Lastly, I took a shot and just searched the entire computer for a file named flag.txt (piping errors to /dev/null). If that came up with nothing, my next step would have been to look for user.txt, which is another popular flag file name. But, that proved not to be necessary, and I found the file and was able to cat its contents to the screen and finish the challenge. Pretty light work, but a good exercise in some of the just-beyond-basic-but-not-a-whole-lot uses of nmap.

Any questions or comments, let me know.