UnderTheWire | Trebek

In this walkthrough, I demonstrate the methods I used to solve all of the Trebek challenges, 0 through 15, on Under the Wire.
In: UnderTheWire, PowerShell, CTF, Cybersecurity, Code, Easy Challenge

SSH Client

If you're running Windows 11 — the latest version of Windows at the time of writing — then, you already have access to the Windows Terminal app. If for some reason you do not, I recommend installing it, as you really don't need Putty to complete these exercises.

Windows Terminal - Free download and install on Windows | Microsoft Store
The Windows Terminal is a modern, fast, efficient, powerful, and productive terminal application for users of command-line tools and shells like Command Prompt, PowerShell, and WSL. Its main features include multiple tabs, panes, Unicode and UTF-8 character support, a GPU accelerated text rendering engine, and custom themes, styles, and configurations. This is an open source project and we welcome community participation. To participate please visit https://github.com/microsoft/terminal

Also, in most recent versions of Windows, the ssh.exe client and related binaries should already be installed and ready for use. Below, I've provided some examples of the most basic SSH syntax for connecting to the challenges.

ssh username@127.0.0.1

SSH using IP address

ssh username@domain.tld

SSH using FQDN


Trebek 0 -> 1

ℹ️
The credential for connecting is trebek1:trebek1
ssh -o 'StrictHostKeyChecking=no' trebek1@trebek.underthewire.tech

Use the StrictHostKeyChecking=no option to skip the key verification prompt

Connected to the challenge box and ready to dig in

Trebek 1 -> 2

The password for trebek2 is the name of the script referenced in a deleted task as depicted in the event logs on the desktop.
Target file
💡
In a previous challenge working with .evtx files, I had piped the Get-WinEvent data to Where-Object, but I don't like that strategy, because it degrades performance. This is because, you first have to collect all of the data and then pipe it to Where-Object to then filter all of said data on a specific $_.Message property.

This is significantly slower than using -FiltlerXPath where the filtering is happening at run time before piping.

To make efficient use of the -FilterXPath parameter, the best course of action is to search for the event ID that is generated when deleting a scheduled task.

4699(S) A scheduled task was deleted. - Windows 10
Describes security event 4699(S) A scheduled task was deleted. This event is generated every time a scheduled task is deleted.
$evt = Get-WinEvent -Path .\security.evtx -FilterXPath "*[System[EventID=4699]]"
✅ Much faster! 713 milliseconds with the -FilterXPath parameter. Piping to Where-Object took so long (more than a minute) that I just cancelled it.
Store logs in a variable for more efficient processing of data
$evt.Message
Parsing the log output, we see the name of the script in the last event
$evt[-1].Message.Split("`n")

Select the last log event and its Message property. Then, split the blob of text into an array of strings with .Split("`n")

$evt[-1].Message.Split("`n")[-12]
Choose the string that's 12th from the bottom
[xml]$evt[-1].Message.Split("`n")[-12]
Cast as type [xml] so we can process it like an object
([xml]$evt[-1].Message.Split("`n")[-12]).Arguments.Split('\\')[-1].Split('\.')[0].ToLower()

Finally, extract the string from the Arguments property and use the .Split() method to slice it at the \ first, then at the . and choose the script name.

mess_cleaner

Password for trebek2

exit

Exit the challenge


Trebek 2 -> 3

The password for trebek3 is the name of the executable associated with the C-3PO service PLUS the name of the file on the user’s desktop.
ssh trebek2@trebek.underthewire.tech

No longer need the additional option, since the host key has already been added to the known hosts list

Target file on Desktop
💡
Using the Get-Service cmdlet does not return the binary path, so we need to query a lower level interface such as CIM or WMI to get those details.

Also, with PowerShell, if a cmdlet exposes a -Filter option, it's much better to use that than piping to Where-Object as you want the filtration to apply during cmdlet runtime, not after piping a ton of data to the next command.
Get-CimInstance Win32_Service -Filter 'Name like "C-3PO"' | Select-Object *
See the PathName property
(Get-CimInstance Win32_Service -Filter 'Name like "C-3PO"').PathName.Split("\\")[-1].Split("\.")[0].ToLower() + (ls -File).Name.ToLower()

Similar solution to above, where we use .Split() to extract the file name, then + concatenate with the file name on the Desktop.

droid823

Password for trebek3

exit

Exit the challenge


Trebek 3 -> 4

The password for trebek4 is the IP that the user Yoda last logged in from as depicted in the event logs on the desktop PLUS the name of the text file on the user’s desktop.
ssh trebek3@trebek.underthewire.tech
Target event log and target file on the user Desktop
💡
Similar challenge to Trebek 1, we need to parse an event log for a user login over the network. So, search for the correct event ID and use the -FilterXPath parameter to drill down.
Windows Security Log Event ID 4624 - An account was successfully logged on
$evt = Get-WinEvent -Path .\security.evtx -FilterXPath "*[System[(EventID=4624)]] and *[EventData[Data[@Name='TargetUserName'] and (Data='Yoda')]]"
After some research, I found the target event ID, and eventually found a working XPath filter to target only events with username Yoda

The events appear to be sorted by TimeCreated with the most recent event at the top of the list.

$evt[0].Message.Split("`n")
Similar solution to before, target the most recent event at index 0, then split the blob of text into an array of strings
$evt[0].Message.Split("`n")[25].Split(':')[-1]
We've got some extra space that we want to get rid of
$evt[0].Message.Split("`n")[25].Split(':')[-1].Trim()
Now, we just need to concatenate with the target file name
$evt[0].Message.Split("`n")[25].Split(':')[-1].Trim() + (ls -Exclude '*.evtx').Name.ToLower()

One-liner to output the password for trebek4

10.30.1.18address

Password for trebek4

exit

Trebek 4 -> 5

The password for trebek5 is the last execution date of Microsoft Access PLUS the name of the text file on the user’s desktop.
ssh trebek4@trebek.underthewire.tech
Target file on Desktop
💡
I hunted around in the registry and online looking at ShimCache, MUICache, Recent Items, Uninstall, Win32_Product, Win32_InstalledProduct, $env:ProgramFiles, $env:ProgramFiles(x86). But nothing turned up with a timestamp.

I asked ChatGPT for some ideas of other places to look for timestamps relating to binaries that are no longer installed and it suggested C:\Windows\Prefetch.
Get-ChildItem "C:\Windows\Prefetch" -Filter '*access*'
(Get-ChildItem "C:\Windows\Prefetch" -Filter '*access*').LastAccessTime.ToString('MM/dd/yyyy') + (ls -File).Name.ToLower()

One-liner to output password for trebek5

01/05/2017_red

Password for trebek5

exit

Trebek 5 -> 6

The password for trebek6 is the name of the executable that is starting at 3/23/2017 8:08:53 PM via the Software Protection service as depicted in the event log on the desktop.
ssh trebek5@trebek.underthewire.tech
Target event log
Google Search

Google search I used to find some event IDs

Event ID 8208, 8200, or 900 - Windows Server
Discusses that you see event ID 8200, 8208, or 900 in Windows Server. Provides a resolution.

Doing some research, these appear to be the event IDs that pertain to the Software Protection Service

Redirecting

Seems like the event IDs we want to target are going to be:

  • 900
  • 16384
  • 16394
$evt = Get-WinEvent -Path .\application.evtx -FilterXPath "*[System[(EventID=900)]] or *[System[(EventID=16384)]] or *[System[(EventID=16394)]]"
$evt.Where({$_.TimeCreated -eq (Get-Date '3/23/2017 8:08:53 PM')})
Filter on the timestamp given in the challenge
The program name is the last line in the message
$evt.Where({$_.TimeCreated -eq (Get-Date '3/23/2017 8:08:53 PM')}).Message.Split("`n")[-1].Split('=')[1].Split('\.')[0]

Final solution to do some string manipulation and output the program name without the file extension

wlms

Password for trebek6

exit

Trebek 6 -> 7

The password for trebek7 is the total number of DLLs within the “C:\program files\adobe\” folder and it’s subfolders PLUS the name of the file on the desktop.
ssh trebek6@trebek.underthewire.tech
Target file on the Desktop
(Get-ChildItem -Recurse -Filter '*.dll' 'C:\program files\adobe\').Count.ToString() + (ls -File).Name.ToLower()

One-liner to output the password for trebek7

40_reader

Password for trebek7

exit

Trebek 7 -> 8

The password for trebek8 is the name of the program set to run prior to login if sticky keys are activated PLUS the name of the file on the desktop.
ssh trebek7@trebek.underthewire.tech
Target file on Desktop
Get-Item 'HKCU:\Control Panel\Accessibility\StickyKeys'
Doing some research, we can tell if sticky keys is enabled for the user by inspecting this registry key. A flag of 510 indicates it is enabled.
💡
The sethc.exe binary is activated when press the SHIFT key multiple times. This is an old bypass I used when recovering systems where the password is unknown (and not encrypted with BitLocker as you'd need the key for that as well).

Boot into a recovery disk, backup sethc.exe to sethc.exe.bak and copy cmd.exe to sethc.exe. Then, when the computer boots, tap the SHIFT key a bunch of times and the command prompt launches.
Get-Item 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\sethc.exe' | Get-ItemProperty
(Get-Item 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\sethc.exe' | Get-ItemProperty).Debugger.Split("\.")[0] + (ls -File).Name.ToString()

One-liner to output password for trebek8

han_solo99

Password for trebek8

exit

Trebek 8 -> 9

The password for trebek9 the first 8 bytes of the file located on the desktop. Combine the answer together with NO spaces.
ssh trebek8@trebek.underthewire.tech
Target file on Desktop
-join[System.IO.File]::ReadAllBytes((ls .\Clone_Trooper_data.pdf).FullName)[0..7]

Use .NET reflection to read the file bytes and select the first 8 bytes, starting at index 0, then -join to merge into a string.

779014403000

Password for trebek9

exit

Trebek 9 -> 10

The password for trebek10 is the name of the potentially rogue share on the system PLUS the name of the file on the desktop.
ssh trebek9@trebek.underthewire.tech
Target file on user Desktop
Get-SmbShare
Obviously, the odd one out is shoretroopers$ and there most definitely is something to see here
(Get-SmbShare -Name 'shoretroopers$').Name.ToLower() + (ls -File).Name.ToLower()

One-liner to output password for trebek10

shoretroopers$_hiding

Password for trebek10

exit

Trebek 10 -> 11

The password for trebek11 is the last name of the user who enabled Obi-Wan Kenobi’s account as depicted in the event logs on the desktop PLUS the name of the file on the desktop.
ssh trebek10@trebek.underthewire.tech
Target file on user Desktop and event log
4722(S) A user account was enabled. - Windows 10
Describes security event 4722(S) A user account was enabled. This event is generated when a user or computer object is enabled.

Doing some research, event 4722 is the ID to filter on for user account enablement

$evt = Get-WinEvent -Path .\security.evtx -FilterXPath "*[System[EventID=4722]]"
Working in a similar fashion to previous challenges, we'll use the -FilterXPath parameter for speedy lookups and drill down further on messages.
$evt.Where({$_.Message -like '*obi*'})
$evt.Where({$_.Message -like '*obi*'}).Message.Split("`n")[4]
We've got the target text. Now, we need to do some string manipulation on it.
$evt.Where({$_.Message -like '*obi*'}).Message.Split("`n")[4].Split(":")[1].Trim().Split("\.")[1]
Last name of the user. Now, we just need to combine with the file name on the desktop
$evt.Where({$_.Message -like '*obi*'}).Message.Split("`n")[4].Split(":")[1].Trim().Split("\.")[1].ToLower() + (ls -Exclude '*.evtx').Name.ToLower()

One-liner to output the password for trebek11

ackbar2121

Password for trebek11

exit

Trebek 11 -> 12

The password for trebek12 is the username of the user who was created on 11 May 17 at 26 minutes after the hour, as depicted in the event logs on the desktop PLUS the name of the file on the desktop.
ssh trebek11@trebek.underthewire.tech
The target file on the user Desktop and the target event log
4720(S) A user account was created. - Windows 10
Describes security event 4720(S) A user account was created. This event is generated a user object is created.

Doing some research, event ID 4720 is the one to target

$evt = Get-WinEvent -Path .\security.evtx -FilterXPath "*[System[EventID=4720]]"
Taking a similar approach to previous challenges
The .TimeCreated property is an object of type DateTime. Therefore, we can use this to our advantage to query specific properties.
Demonstrating how we can probe different aspects of the DateTime object
$evt.Where({$_.TimeCreated.Day -eq 11 -and $_.TimeCreated.Minute -eq 26})
Per the challenge, we target an event happening at the 26th minute of the 11th day
💡
This is unique enough that we don't need to target Month -eq 5
$evt.Where({$_.TimeCreated.Day -eq 11 -and $_.TimeCreated.Minute -eq 26}).Message
The username of the user that was created
$evt.Where({$_.TimeCreated.Day -eq 11 -and $_.TimeCreated.Minute -eq 26}).Message.Split("`n")[10].Split(":")[1].Trim()
Looks good, now we need to concatenate with the file on the Desktop
$evt.Where({$_.TimeCreated.Day -eq 11 -and $_.TimeCreated.Minute -eq 26}).Message.Split("`n")[10].Split(":")[1].Trim().ToLower() + (ls -Exclude '*.evtx').Name.ToLower()

One-liner to output the password for trebek12

general.hux100

Password for trebek12

exit

Trebek 12 -> 13

The password for trebek13 is the username of the user who created the user Lor San Tekka as depicted in the event logs on the desktop PLUS the name of the file on the desktop.
ssh trebek12@trebek.underthewire.tech
Target file on user Desktop and event logs
$evt = Get-WinEvent -Path .\security.evtx -FilterXPath "*[System[EventID=4720]]"
Same event ID as trebek11, just inspecting who created the user, not who was created
$evt.Where({$_.Message -like '*Lor*'})
Found the target event log
$evt.Where({$_.Message -like '*Lor*'}).Message
This is the user who created the account
$evt.Where({$_.Message -like '*Lor*'}).Message.Split("`n")[4]
Looks good, just need to concatenated with the file name
$evt.Where({$_.Message -like '*Lor*'}).Message.Split("`n")[4].Split(":")[1].Trim().ToLower() + (ls -Exclude '*.evtx').Name.ToLower()

One-liner to output the password for trebek13

poe.dameron53

Password for trebek13

exit

Trebek 13 -> 14

The password for trebek14 is the last name of the user who has an encoded PowerShell command in their City property PLUS the name of the file on the desktop.
ssh trebek13@trebek.underthewire.tech
Target file on Desktop
Get-ADUser -Filter * -Properties City
Select all users in AD and include the City property
(Get-ADUser -Filter * -Properties City).Where({$_.City})
The .Where({$_.City}) filter selects only users where the City attribute contains any data at all. There is only one user with a City attribute containing data.
(Get-ADUser -Filter * -Properties City).Where({$_.City}).Surname.ToLower() + (ls -File).Name.ToLower()

Select the Surname of the user, make it lowercase, and concatenate with the file name

prindel3003

Password for trebek14

exit

Trebek 14 -> 15

The password for trebek15 is the output from decoding the PowerShell code found in the account properties of the user account from the previous level PLUS the name of the file on the desktop.
ssh trebek14@trebek.underthewire.tech
Target file on the Desktop
The City property contains base64-encoded data

The process to convert a base64 string back to UTF-8 data is effectively:

  1. Convert the base64 string back to raw bytes
  2. Encode the raw bytes as UTF-8 characters
ℹ️
In the spirit of the way I've been doing these challenges, I want to have the end result as a one-liner, so follow along as I step through the way to do this.
(Get-ADUser -Filter * -Properties City).Where({$_.City}).City.ForEach({[Convert]::FromBase64String($_)})
We've accomplished step 1 of the process described above
⚠️
However, we do not want those null bytes in the final output, so we'll use a .Where({}) filter to remove them.
(Get-ADUser -Filter * -Properties City).Where({$_.City}).City.ForEach({[Convert]::FromBase64String($_).Where({$_ -ne 0A})})
Null bytes removed.
(Get-ADUser -Filter * -Properties City).Where({$_.City}).City.ForEach({[System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($_).Where({$_ -ne 0}))}).ToLower() + (ls -File).Name.ToLower()

What we've done here is wrap the [Convert]::FromBase64String($_).Where({$_ -ne 0}) inside of [System.Text.Encoding]::UTF8.GetString()

Final password
$targetFile = Get-ChildItem -File -Path 'C:\users\trebek14\desktop'
$userWithCity = Get-ADUser -Filter * -Properties City | Where-Object {$_.City}
$base64String = $userWithCity.City
$base64ToBytes = [Convert]::FromBase64String($base64String) | Where-Object {$_ -ne 0}
$bytesToUTF8String = [System.Text.Encoding]::UTF8.GetString($base64ToBytes)
$bytesToUTF8String.ToLower() + $targetFile.Name.ToLower()
✅ Same solution, but much more readable
exit
Comments
More from 0xBEN
Table of Contents
Great! You’ve successfully signed up.
Welcome back! You've successfully signed in.
You've successfully subscribed to 0xBEN.
Your link has expired.
Success! Check your email for magic link to sign-in.
Success! Your billing info has been updated.
Your billing was not updated.