Under The Wire | Century
Many of you may have read my series on a Linux command line wargame site called OverTheWire. If you’d like to check it out be sure to read all about it here.
That said, what if there was a similar wargame platform for Windows, Powershell, and other cool sysadmin-like stuff? Well the UTW team has done just that with UnderTheWire. UnderTheWire is a cool website that hosts several PowerShell-based wargames meant as “PowerShell Training for the People.”
In this new series, I’ll be featuring my walkthrough of the first set of challenges or “wargames” called Century. If you would like to jump to a specific level then each level with be accompanied with the username and password. I will be appending consecutive levels as I have time to post.
That said, I want to give a huge thank you to the creators of these games and for the effort that goes into designing and hosting them, and of course making them available for free!
Century 0 -> 1
https://underthewire.tech/century
The goal of this level is to log into the game.
At the time of this writing, the Slack link was dead so I had to lean on this Reddit thread.
Username: century1
Password: century1
Century 1 -> 2
https://underthewire.tech/century-1
The password for Century2 is the build version of the instance of PowerShell installed on this system.
NOTE:
- The format is as follows: **.*.*****.****
- Include all periods
- Be sure to look for build version and NOT PowerShell version
PS C:\users\century1\desktop> $PSVersionTable
Name Value
---- -----
PSVersion 5.1.14393.4467
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.14393.4467
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
Username: century2
Password: 10.0.14393.4467
Century 2 -> 3
https://underthewire.tech/century-2
“The password for Century3 is the name of the built-in cmdlet that performs the wget like function within PowerShell PLUS the name of the file on the desktop.”
To find the command similar to wget
within PowerShell use the Get-Alias
cmdlet.
PS C:\users\century2\desktop> get-alias wget
CommandType Name Version Source
----------- ---- ------- ------
Alias wget -> Invoke-WebRequest
We can also get the name of the file on the desktop.
PS C:\users\century2\desktop> ls
Directory: C:\users\century2\desktop
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 8/30/2018 3:29 AM 693 443
Username: century3
Password: invoke-webrequest443
Century 3 -> 4
https://underthewire.tech/century-3
“The password for Century4 is the number of files on the desktop.”
- You can use ‘Get-Childtem’ to list the directory contents or ‘ls’ which is an alias.
- By enclosing a command with
()
you create an order of precedence, so everything inside of()
executes first and after that, your other commands are evaluated. - We use
Measure-Object
to get the number of files on the desktop .
Property dereference operator to drill down to the specific.Count
method of the object
PS C:\users\century3\desktop> (Get-ChildItem | Measure-Object).Count
123
Username: century4
Password: 123
Century 4 -> 5
https://underthewire.tech/century-4
“The password for Century5 is the name of the file within a directory on the desktop that has spaces in its name.”
Two ways you could do this level.
Method 1:
You could use tree
with the /F
option to display the names of the files in each folder. This also grabs hidden files. For the challenge, this reveals only 1 of the directories containing a file thus that file is our password.
PS C:\users\century4\desktop> tree /F
Folder PATH listing for volume Windows
Volume serial number is 000000A7 641F:3922
C:.
│ file.txt
│ files.txt
│
├───Can You Open Me
│ 61580
│
├───One Directory
├───Open Me
└───Open Me
PS C:\users\century4\desktop>
Method 2:
Using Get-Childitem -Recurse
recursively returns each file and folder from a specified path. Again, for the challenge, this reveals only 1 of the directories containing a file thus that file is our password.
PS C:\users\century4\desktop> Get-ChildItem -Recurse
Directory: C:\users\century4\desktop
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 7/3/2021 1:15 AM Can You Open Me
d----- 3/2/2021 6:57 PM One Directory
d----- 7/3/2021 1:17 AM Open Me
d----- 3/14/2021 9:11 PM Open Me
-a---- 7/9/2021 6:07 PM 272 file.txt
-a---- 8/24/2021 12:17 AM 1486 files.txt
Directory: C:\users\century4\desktop\Can You Open Me
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 8/30/2018 3:29 AM 24 61580
PS C:\users\century4\desktop>
Username: century5
Password: 61580
Century 5 -> 6
https://underthewire.tech/century-5
“The password for Century6 is the short name of the domain in which this system resides in PLUS the name of the file on the desktop.”
First, we need to find the domain.
Method 1:
Using the $env:USERDOMAIN
environment variable.
PS C:\users\century5\desktop> echo $env:USERDNSDOMAIN
UNDERTHEWIRE.TECH
Method 2:
Using Get-ADDomain
cmdlet.
PS C:\users\century5\desktop> Get-ADDomain y
AllowedDNSSuffixes : {}
ChildDomains : {}
ComputersContainer : CN=Computers,DC=underthewire,DC=tech
DeletedObjectsContainer : CN=Deleted Objects,DC=underthewire,DC=tech
DistinguishedName : DC=underthewire,DC=tech
DNSRoot : underthewire.tech
DomainControllersContainer : OU=Domain Controllers,DC=underthewire,DC=tech
DomainMode : Windows2016Domain
DomainSID : S-1-5-21-758131494-606461608-3556270690
ForeignSecurityPrincipalsContainer : CN=ForeignSecurityPrincipals,DC=underthewire,DC=tech
Forest : underthewire.tech
InfrastructureMaster : utw.underthewire.tech
LastLogonReplicationInterval :
LinkedGroupPolicyObjects : {cn={ECB4A7C0-B4E1-41B1-9E89-161CFA679999},cn=policies,cn=system,DC=underthewire,DC=tech,
CN={31B2F340-016D-11D2-945F-00C04FB984F9},CN=Policies,CN=System,DC=underthewire,DC=tech}
LostAndFoundContainer : CN=LostAndFound,DC=underthewire,DC=tech
ManagedBy :
Name : underthewire
NetBIOSName : underthewire
ObjectClass : domainDNS
ObjectGUID : bdccf3ad-b495-4d86-a94c-60f0d832e6f0
ParentDomain :
PDCEmulator : utw.underthewire.tech
PublicKeyRequiredPasswordRolling : True
QuotasContainer : CN=NTDS Quotas,DC=underthewire,DC=tech
ReadOnlyReplicaDirectoryServers : {}
ReplicaDirectoryServers : {utw.underthewire.tech}
RIDMaster : utw.underthewire.tech
SubordinateReferences : {DC=ForestDnsZones,DC=underthewire,DC=tech, DC=DomainDnsZones,DC=underthewire,DC=tech,
CN=Configuration,DC=underthewire,DC=tech}
SystemsContainer : CN=System,DC=underthewire,DC=tech
UsersContainer : CN=Users,DC=underthewire,DC=tech
Or more specifically…
PS C:\users\century5\desktop> (Get-ADDomain).Name
underthewire
Lastly, we need the name of the file on the desktop.
PS C:\users\century5\desktop> ls
Directory: C:\users\century5\desktop
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 8/30/2018 3:29 AM 54 3347
Username: century6
Password: underthewire3347
Century 6 -> 7
https://underthewire.tech/century-6
“The password for Century7 is the number of folders on the desktop.”
Similar to level 3 we can use the Measure-Object
cmdlet to count the number of folders for us.
PS C:\users\century6\desktop> Get-ChildItem | Measure-Object
Count : 197
Average :
Sum :
Maximum :
Minimum :
Property :
More specifically…
PS C:\users\century6\desktop> (Get-ChildItem | Measure-Object).Count
197
Username: century7
Password: 197
Century 7 -> 8
https://underthewire.tech/century-7
“The password for Century8 is in a readme file somewhere within the contacts, desktop, documents, downloads, favorites, music, or videos folder in the user’s profile.”
First, let’s find the Readme file.
-Recurse
Recursively search through every folder
-File
Return only files, not directories.
-Include
We only want to include this specific search. Also, we can utilize a *
aka wildcard to assist with the case sensitivity or how the file might be named. Essentially we’re just searching for any file with the string “readme” in its name.
PS C:\users\century7\desktop> cd ..
PS C:\users\century7> Get-ChildItem -Recurse -File -Include *readme*
Directory: C:\users\century7\Downloads
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 8/30/2018 3:29 AM 7 Readme.txt
PS C:\users\century7>
Now we can get the contents of that file.
PS C:\users\century7> cat .\Downloads\Readme.txt
7points
Or we can do it all as a one-liner.
PS C:\users\century7> Get-ChildItem -Recurse -Include *readme* -File | cat
7points
Username: century8
Password: 7points
Century 8 -> 9
https://underthewire.tech/century-8
The password for Century9 is the number of unique entries within the file on the desktop.
We’ll be doing a lot of |
aka piping. Essentially this is just taking the output of one command and parsing it to another command to be manipulated or interacted with in some way.
-
Get-Content
This cmdlet is essentially the equivalent ofcat
. So we’re outputting the contents ofunique.txt
. -
Sort-Object
Now we can sort the entries within the text file. -
Get-Unique
Returns only the “unique” entries. -
.count
Returns the number of entries.
PS C:\users\century8\desktop> (Get-Content .\unique.txt | Sort-Object | Get-Unique).count
696
Username: century9
Password: 696
Century 9 -> 10
https://underthewire.tech/century-9
“The password for Century10 is the 161st word within the file on the desktop.”
In this level, we have more output manipulation. First, let’s output the contents of the file.
PS C:\users\century9\desktop> Get-Content .\Word_File.txt
larceny epibole ampliate trecentos psychotoxic sybarism shatterwit cartilaginification crenulation splenification freespac untragicalness
renovater smirch historism tymbal nonobjectivist protestive octobass crownal retrorenal activation ascocarp clawing unaccordingly strontia
nite refutatory reline unsubmersible unstuffy asynergia asha rejunction spiritrompe preestimates papabot postcoital forbearantly epistoliz
e corkwood rasers logicized rearrange rectigraph signposts prothrombin headkerchief upholden oversocialize semiperimeter hackbuteer tickli
sh brachiated atheneum naegait engrasp palaeoconcha deminudity tragions curteous stratal swandown succinylcholine swooners caskanet irresp
ectability flocculant palatefulness thalamocoele maleate tittivate eustachium etudes loppering fidos flayers murrion uninduced numbedness
nincompoopish compressors cassoulet protura fagopyrismus sesquibasic paxwaxes grievous remonstrator fulvid rotatoria ultraconservatives po
stcards hairdresser wagnerianism mistreats nefarious winberry usherance conductility yearner uranostaphylorrhaphy rehabilitator agrapha ju
nglegym emanant coy gaelicist parallelogram wealdsman objurgator tapeline amay psalterer eleostearate mainprise overdyeing dowly coronado
localed weasellike scattergram tocological disproportionation archicerebrum glazement zugtierlaster sleepwort yabber tenontodynia laevulos
e walkaway readept literally weinmannia englut caulopteris schellingian thiamid suberizes bistorta quinetum woolulose jaculiferous trestle
work unoriginativeness kua uncontemptibleness unconcernedly taryard escapologist traumata chlorochrous exocolitis dysgnosia steadfastness
keratoleukoma inordinate sacahuiste trippler intoxicatively pierid nonapplicabness patinas rabific scandaliser waggel reauthenticate sufei
sm lairds cookee bragget ledgering perceptual chomper obscurities merino ganguela unproposed epulis loppard ignoblesse carrotage heartbrok
enly unfusibness degenerate lacunae cirrocumulus knightlike overwhelmingness oxyrrhyncha capitalizations dimethylamine uninucleate syndicship graspable tropophil telchines abaiser overclement pursive
If we try to get a count what happens?
PS C:\users\century9\desktop> (Get-Content .\Word_File.txt).count
1
Remember .count
only returns the number of lines in a file. In this case, we have several strings on one line. So we need a way of splitting these strings onto separate lines.
We can do this by specifying a delimiter. A delimiter is usually a specified character to separate different pieces of data. In this case, a space is our delimiter.
Get-Content .\Word_File.txt -Delimiter ' '
...
cirrocumulus
knightlike
overwhelmingness
oxyrrhyncha
capitalizations
dimethylamine
uninucleate
syndicship
graspable
tropophil
telchines
abaiser
overclement
pursive
Our delimeter is working as it output the words on separate lines. Let’s try to get a count now.
PS C:\users\century9\desktop> (Get-Content .\Word_File.txt -Delimiter ' ').count
200
Aha! Now we can see the file has a total of 200 words. Let’s specify an index to grab the 161st word in the file.
PS C:\users\century9\desktop> Get-Content .\Word_File.txt -Delimiter ' ' | Select-Object -Index 160
pierid
Why did we put 160 instead of 161? One key thing to note is that computers don’t count starting from 1. They count starting from 0. So we counting from 0 we conclude that the word at index 160 is actually the 161st word.
Username: century10
Password: pierid
Century 10 -> 11
https://underthewire.tech/century-10
“The password for Century11 is the 10th and 8th word of the Windows Update service description combined PLUS the name of the file on the desktop.”
Several ways you could do this level but I chose to do this purely programmatically.
PS C:\Users\century10\Documents> Get-Service -DisplayName *update*
Status Name DisplayName
------ ---- -----------
Stopped wuauserv Windows Update
PS C:\Users\century10\Documents> Get-Service -Name "Windows Update" | Select-Object *
Name : wuauserv
RequiredServices : {rpcss}
CanPauseAndContinue : False
CanShutdown : False
CanStop : False
DisplayName : Windows Update
DependentServices : {}
MachineName : .
ServiceName : wuauserv
ServicesDependedOn : {rpcss}
ServiceHandle :
Status : Stopped
ServiceType : Win32ShareProcess
StartType : Manual
Site :
Container :
PS C:\Users\century10\Documents> Get-WMIObject -Class Win32_Service -Filter "Name='wuauserv'" | Select-Object *
PSComputerName : CENTURY
Name : wuauserv
Status : OK
ExitCode : 0
DesktopInteract : False
ErrorControl : Normal
PathName : C:\Windows\system32\svchost.exe -k netsvcs
ServiceType : Share Process
StartMode : Manual
[..]
Description : Enables the detection, download, and installation of updates for Windows and other programs. If this service is
disabled, users of this computer will not be able to use Windows Update or its automatic updating feature, and programs
will not be able to use the Windows Update Agent (WUA) API.
DisplayName : Windows Update
[..]
Expand the “Description” property.
PS C:\users\century10\desktop> Get-WmiObject -Class Win32_Service -Filter "Name='wuauserv'" | Select-Object -ExpandProperty Description
Enables the detection, download, and installation of updates for Windows and other programs. If this service is disabled, users of this computer will not be able to use Windows Update or its automatic updating feature, and programs will not be able to use the Windows Update Agent (WUA) API.
Lint the data to the format we need.
PS C:\users\century10\desktop> $desc = (Get-WmiObject -Class Win32_Service -Filter "Name='wuauserv'" | Select-Object -ExpandProperty Description).ToLower().Split()
A bit of string splicing/indexing to grab the words as well as the name of the file on the desktop we need.
PS C:\users\century10\desktop> $word10 = $desc | Select-Object -Index 9
PS C:\users\century10\desktop> $word8 = $desc | Select-Object -Index 7
PS C:\users\century10\desktop> $desktopfilename = Get-ChildItem -Path C:\Users\century10\Desktop -Name
Finally, putting it all together now thus returning the password for Century11.
PS C:\users\century10\desktop> $pass = $word10 + $word8 + $desktopfilename
PS C:\users\century10\desktop> $pass
windowsupdates110
Username: century11
Password: windowsupdates110
Century 11 -> 12
https://underthewire.tech/century-11
“The password for Century12 is the name of the hidden file within the contacts, desktop, documents, downloads, favorites, music, or videos folder in the user’s profile.”
Fairly simple level. We just specify an array of folders we want to search with the -Hidden
parameter. I added a few other parameters to exclude any false positives such as the desktop.ini
file.
PS C:\users\century11\desktop> cd ..
PS C:\users\century11> Get-Childitem -Path Contacts,Desktop,Documents,Downloads,Favorites,Music,Videos -File -Hidden -Recurse -Exclude desktop.ini -ErrorAction SilentlyContinue
Directory: C:\users\century11\Downloads
Mode LastWriteTime Length Name
---- ------------- ------ ----
--rh-- 8/30/2018 3:34 AM 30 secret_sauce
PS C:\users\century11>
Username: century12
Password: secret_sauce
Century 12 -> 13
https://underthewire.tech/century-12
“The password for Century13 is the description of the computer designated as a Domain Controller within this domain PLUS the name of the file on the desktop.”
Get the file name on the Desktop.
PS C:\users\century12\desktop> (Get-ChildItem -Path . -Name)
_things
Get the hostname of the Domain Controller using `Get-ADDomainController.
PS C:\users\century12\desktop> Get-ADDomainController
ComputerObjectDN : CN=UTW,OU=Domain Controllers,DC=underthewire,DC=tech
DefaultPartition : DC=underthewire,DC=tech
Domain : underthewire.tech
Enabled : True
Forest : underthewire.tech
HostName : utw.underthewire.tech
InvocationId : 09ee1897-2210-4ac9-989d-e19b4241e9c6
IPv4Address : 192.99.167.156
IPv6Address :
IsGlobalCatalog : True
IsReadOnly : False
LdapPort : 389
Name : UTW
NTDSSettingsObjectDN : CN=NTDS
Settings,CN=UTW,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=underthewire,DC=tech
OperatingSystem : Windows Server 2016 Standard
OperatingSystemHotfix :
OperatingSystemServicePack :
OperatingSystemVersion : 10.0 (14393)
OperationMasterRoles : {SchemaMaster, DomainNamingMaster, PDCEmulator, RIDMaster...}
Partitions : {DC=ForestDnsZones,DC=underthewire,DC=tech, DC=DomainDnsZones,DC=underthewire,DC=tech,
CN=Schema,CN=Configuration,DC=underthewire,DC=tech, CN=Configuration,DC=underthewire,DC=tech...}
ServerObjectDN : CN=UTW,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=underthewire,DC=tech
ServerObjectGuid : df17c8a3-dd76-438b-8ddf-b7ad3e624618
Site : Default-First-Site-Name
SslPort : 636
or…
PS C:\users\century12\desktop> hostname
utw
Based up the DC’s name we can examine the Description property using Get-ADComputer
PS C:\users\century12\desktop> Get-ADComputer UTW -Property Description
Description : i_authenticate
DistinguishedName : CN=UTW,OU=Domain Controllers,DC=underthewire,DC=tech
DNSHostName : utw.underthewire.tech
Enabled : True
Name : UTW
ObjectClass : computer
ObjectGUID : 5ca56844-bb73-4234-ac85-eed2d0d01a2e
SamAccountName : UTW$
SID : S-1-5-21-758131494-606461608-3556270690-1000
UserPrincipalName :
Select the description of the UTW computer object.
PS C:\users\century12\desktop> (get-adcomputer UTW -Properties * | Select-Object -ExpandProperty Description)
i_authenticate
Putting it all together.
PS C:\users\century12\desktop> (get-adcomputer UTW -Properties * | Select-Object -ExpandProperty Description) + (Get-ChildItem -Path . -Name)
i_authenticate_things
PS C:\users\century12\desktop>
Username: century13
Password: i_authenticate_things
Century 13 -> 14
https://underthewire.tech/century-13
“The password for Century14 is the number of words within the file on the desktop.”
More file parsing. Two methods we can use here.
Method 1
PS C:\users\century13\desktop> Get-Content .\countmywords | Measure-Object -Word
Lines Words Characters Property
----- ----- ---------- --------
755
Method 2
PS C:\users\century13\desktop> (Get-Content .\countmywords).Split(' ').Count
755
Username: century14
Password: 755
Century 14 -> 15
https://underthewire.tech/century-14
“The password for Century15 is the number of times the word “polo” appears within the file on the desktop.”
Final challenge! In this one, we’re doing a little bit of pattern matching.
PS C:\users\century14\desktop> (Get-Content .\countpolos -Delimiter ' ' | Select-String -Pattern '\bpolo\b').count
153
I originally had an issue with the command matching every occurrence of the string ‘polo’ thus returning words like antropologic or carpology which I didn’t need. Using the \b
anchor specifies that the match must occur between the boundary.
\b
matches a word boundary. See the documentation.
Username: century15
Password: 153
I hope you enjoyed this challenge! I feel like it definitely strengthened my PowerShell skills and I’m looking forward to doing more of them in the future!