AHHH The field is full of mines! Screw it! I am going in!
Authors: @moaath, @Liikt
Category: Reversing
Solver: lukasrad02
Flag: ENO{H0p3fully_Y0ur_M1ND_D1D_G3t_scr3w3D}
Scenario
The challenge only consists of a single PowerShell script:
( 'wcyd'|%{${#/~} =+ $()}{ ${@}=${#/~}} { ${/.} = ++${#/~}}{ ${*~}=(${#/~} =${#/~} +${/.})} {${$./} =(${#/~}= ${#/~} + ${/.} )}{${)@}=( ${#/~}=${#/~}+${/.} )} { ${'} =(${#/~} =${#/~}+ ${/.}) } { ${;} = ( ${#/~}=${#/~} + ${/.}) } {${ *-}= ( ${#/~}=${#/~}+${/.})} {${``[+} = ( ${#/~} =${#/~} +${/.} ) } { ${#~=}= ( ${#/~}= ${#/~}+ ${/.} )} { ${``@} ="[" +"$(@{ } ) "[${ *-} ] + "$(@{})"[ "${/.}" +"${#~=}" ]+ "$(@{ })"["${*~}"+"${@}"]+"$? "[${/.} ]+"]" }{${#/~} = "".("$( @{} )"[ "${/.}${)@}" ]+"$(@{ }) "["${/.}${;}"] + "$( @{ } ) "[ ${@}]+ "$(@{} ) "[ ${)@}]+ "$?"[${/.}] + "$( @{ } ) "[${$./} ])}{${#/~} ="$( @{} ) "[ "${/.}${)@}"] + "$( @{ } )"[${)@}] +"${#/~}"[ "${*~}${ *-}"]} ); & ${#/~} ("${#/~} ( ${``@}${/.}${@} +${``@}${/.}${/.}${'}+${``@}${/.}${@}${/.}+ ${``@}${/.}${/.}${;} +${``@}${)@}${'} + ${``@}${/.}${/.}${*~} + ${``@}${/.}${/.}${'} + ${``@}${/.}${@}${@} + ${``@}${/.}${@}${/.} + ${``@}${#~=}${``[+} +${``@}${/.}${/.}${ *-} +${``@}${/.}${@}${$./}+ ${``@}${$./}${*~} + ${``@}${)@}${'} + ${``@}${/.}${/.}${;} + ${``@}${/.}${/.}${)@} + ${``@}${#~=}${ *-} + ${``@}${#~=}${#~=} +${``@}${/.}${@}${/.} + ${``@}${$./}${*~} +${``@}${)@}${``[+}+ ${``@}${/.}${@} )"); . ${#/~} ("${#/~} ( ${``@}${$./}${;} +${``@}${;}${``[+} + ${``@}${/.}${@}${/.} + ${``@}${#~=}${``[+}+ ${``@}${/.}${/.}${ *-} + ${``@}${/.}${@}${$./} + ${``@}${``[+}${@} + ${``@}${/.}${/.}${)@} + ${``@}${/.}${@}${/.} + ${``@}${/.}${@}${*~} +${``@}${/.}${@}${/.} + ${``@}${/.}${/.}${)@}+ ${``@}${/.}${@}${/.}+ ${``@}${/.}${/.}${@}+ ${``@}${#~=}${#~=}+${``@}${/.}${@}${/.}+${``@}${$./}${*~} + ${``@}${;}${/.} +${``@}${$./}${*~} +${``@}${$./}${)@} + ${``@}${``[+}${$./}+ ${``@}${/.}${@}${'} +${``@}${/.}${@}${``[+} + ${``@}${/.}${@}${/.} + ${``@}${/.}${/.}${@} + ${``@}${/.}${/.}${;} + ${``@}${/.}${@}${``[+} +${``@}${/.}${*~}${/.} +${``@}${;}${ *-}+ ${``@}${/.}${/.}${/.}+ ${``@}${/.}${/.}${@} + ${``@}${/.}${/.}${;}+ ${``@}${/.}${@}${'} +${``@}${/.}${/.}${@} + ${``@}${/.}${/.}${ *-}+ ${``@}${/.}${@}${/.}+ ${``@}${$./}${)@} + ${``@}${'}${#~=}+ ${``@}${$./}${;}+${``@}${/.}${*~}${@} + ${``@}${$./}${*~} +${``@}${;}${/.} + ${``@}${$./}${*~} + ${``@}${$./}${;}+ ${``@}${/.}${/.}${;}+ ${``@}${/.}${/.}${)@} + ${``@}${/.}${/.}${ *-} + ${``@}${/.}${@}${/.} + ${``@}${'}${#~=} + ${``@}${/.}${@}${'} + ${``@}${/.}${@}${*~}+${``@}${$./}${*~} + ${``@}${)@}${@} + ${``@}${$./}${;} + ${``@}${/.}${*~}${@} + ${``@}${)@}${/.} +${``@}${$./}${*~} + ${``@}${/.}${*~}${$./}+ ${``@}${$./}${*~}+${``@}${$./}${*~}+ ${``@}${$./}${*~} + ${``@}${$./}${*~} + ${``@}${$./}${;} + ${``@}${/.}${@}${*~} +${``@}${/.}${@}${``[+}+${``@}${#~=}${ *-}+${``@}${/.}${@}${$./} + ${``@}${$./}${*~} +${``@}${;}${/.} +${``@}${$./}${*~} +${``@}${$./}${)@} + ${``@}${;}${#~=}+ ${``@}${ *-}${``[+} + ${``@}${ *-}${#~=} + ${``@}${/.}${*~}${$./}+ ${``@}${ *-}${*~} +${``@}${)@}${``[+} +${``@}${/.}${/.}${*~} +${``@}${'}${/.} + ${``@}${/.}${@}${*~}+${``@}${/.}${/.}${ *-}+ ${``@}${/.}${@}${``[+} + ${``@}${/.}${@}${``[+}+${``@}${/.}${*~}${/.} +${``@}${#~=}${'} + ${``@}${``[+}${#~=}+${``@}${)@}${``[+} + ${``@}${/.}${/.}${ *-} + ${``@}${/.}${/.}${)@}+ ${``@}${#~=}${'} + ${``@}${ *-}${ *-} + ${``@}${)@}${#~=}+${``@}${ *-}${``[+} +${``@}${;}${``[+} + ${``@}${#~=}${'}+ ${``@}${;}${``[+} + ${``@}${)@}${#~=} + ${``@}${;}${``[+}+${``@}${#~=}${'} + ${``@}${ *-}${/.}+${``@}${'}${/.}+ ${``@}${/.}${/.}${;}+ ${``@}${#~=}${'}+ ${``@}${/.}${/.}${'} + ${``@}${#~=}${#~=}+ ${``@}${/.}${/.}${)@}+${``@}${'}${/.}+ ${``@}${/.}${/.}${#~=} + ${``@}${'}${/.} +${``@}${;}${``[+} + ${``@}${/.}${*~}${'} +${``@}${$./}${)@} + ${``@}${'}${#~=}+ ${``@}${$./}${*~} + ${``@}${$./}${*~} +${``@}${$./}${*~} + ${``@}${$./}${*~} +${``@}${``[+}${ *-} + ${``@}${/.}${/.}${)@} + ${``@}${/.}${@}${'} + ${``@}${/.}${/.}${;} + ${``@}${/.}${@}${/.} + ${``@}${)@}${'} + ${``@}${ *-}${*~}+${``@}${/.}${/.}${/.} +${``@}${/.}${/.}${'} + ${``@}${/.}${/.}${;}+ ${``@}${$./}${*~} +${``@}${$./}${)@} + ${``@}${/.}${@}${@} +${``@}${/.}${/.}${/.} +${``@}${$./}${*~} +${``@}${/.}${/.}${@} + ${``@}${/.}${/.}${/.}+${``@}${/.}${/.}${;} +${``@}${$./}${*~} + ${``@}${/.}${@}${/.}+${``@}${/.}${*~}${@} + ${``@}${/.}${@}${/.} +${``@}${#~=}${#~=}+ ${``@}${/.}${/.}${ *-} +${``@}${/.}${/.}${;} + ${``@}${/.}${@}${/.}+ ${``@}${$./}${*~} + ${``@}${/.}${/.}${ *-}+${``@}${/.}${/.}${@} + ${``@}${/.}${@}${ *-} + ${``@}${/.}${/.}${@}+${``@}${/.}${/.}${/.}+${``@}${/.}${/.}${#~=}+ ${``@}${/.}${/.}${@} +${``@}${$./}${*~} + ${``@}${``[+}${@} + ${``@}${/.}${/.}${/.}+ ${``@}${/.}${/.}${#~=} +${``@}${/.}${@}${/.} +${``@}${/.}${/.}${)@} + ${``@}${``[+}${$./} +${``@}${/.}${@}${)@}+ ${``@}${/.}${@}${/.} + ${``@}${/.}${@}${``[+} + ${``@}${/.}${@}${``[+} + ${``@}${$./}${*~} + ${``@}${#~=}${#~=} + ${``@}${/.}${/.}${/.}+ ${``@}${/.}${@}${@} +${``@}${/.}${@}${/.}+ ${``@}${$./}${)@}+ ${``@}${'}${#~=} + ${``@}${$./}${*~}+${``@}${$./}${*~}+${``@}${$./}${*~} + ${``@}${$./}${*~}+ ${``@}${$./}${;} + ${``@}${/.}${@}${*~} + ${``@}${/.}${@}${``[+} +${``@}${#~=}${ *-} + ${``@}${/.}${@}${$./}+ ${``@}${$./}${*~} +${``@}${;}${/.} + ${``@}${$./}${*~} + ${``@}${$./}${)@} + ${``@}${ *-}${``[+}+ ${``@}${/.}${/.}${/.} + ${``@}${/.}${/.}${*~} + ${``@}${/.}${@}${/.} + ${``@}${$./}${)@}+ ${``@}${'}${#~=} +${``@}${/.}${*~}${'})")
Our goal seems to be to understand what this script does.
Analyzing the Script
As we don’t know anything about the script, let’s start by checking whether there is some observable behavior. To prevent any harm to our system, we can use the official PowerShell docker container. We can simply spawn a container with sudo docker run --rm -it mcr.microsoft.com/powershell
and use it as a playground.
When pasting the script into the command line and executing it, there is not much to see:
PS /> ( 'wcyd'|%{${#/~} ...
do not execute unknown PowerShell code
Especially, there are no prompts or whatsoever. So we must take another approach to analyze the script.
When taking a closer look at the script, we can see that it consists of three commands, separated by semicolons1:
( 'wcyd'|%{${#/~} [...] );
& ${#/~} ("${#/~} [...] );
. ${#/~} ("${#/~} [...] )
The first command does some stuff we don’t yet understand, but the other ones are interesting: The &
and .
operators can be used to call the script or command passed as the first argument2. In both cases, this argument is a weird expression, ${#/~}
. We first thought that this could be some syntax to modify variable values, like variable substitution in bash. But it turned out to be much more simple:
To create or display a variable name that includes spaces or special characters, enclose the variable name with the curly braces (
{}
) characters. The curly braces direct PowerShell to interpret the variable name’s characters as literals.
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_variables?view=powershell-7.4#variable-names-that-include-special-characters
So ${#/~}
is just a variable with an ugly name! To find its value, we can simply type ${#/~}
into our PowerShell (keep in mind to re-run the script before, if you’ve closed your old shell!):
PS /> ${#/~}
iex
iex
is the eval function of PowerShell. It takes PowerShell code as string and evaluates it.
To find out what code is evaluated by the script, we can evaluate the code in parentheses behind ${#/~}
and receive
iex ( [CHar]10 +[CHar]115+[CHar]101+ [CHar]116 +[CHar]45 + [CHar]112 + [CHar]115 + [CHar]100 + [CHar]101 + [CHar]98 +[CHar]117 +[CHar]103+ [CHar]32 + [CHar]45 + [CHar]116 + [CHar]114 + [CHar]97 + [CHar]99 +[CHar]101 + [CHar]32 +[CHar]48+ [CHar]10 )
for the first and
iex ( [CHar]36 +[CHar]68 + [CHar]101 + [CHar]98+ [CHar]117 + [CHar]103 + [CHar]80 + [CHar]114 + [CHar]101 + [CHar]102 +[CHar]101 + [CHar]114+ [CHar]101+ [CHar]110+ [CHar]99+[CHar]101+[CHar]32 + [CHar]61 +[CHar]32 +[CHar]34 + [CHar]83+ [CHar]105 +[CHar]108 + [CHar]101 + [CHar]110 + [CHar]116 + [CHar]108 +[CHar]121 +[CHar]67+ [CHar]111+ [CHar]110 + [CHar]116+ [CHar]105 +[CHar]110 + [CHar]117+ [CHar]101+ [CHar]34 + [CHar]59+ [CHar]36+[CHar]120 + [CHar]32 +[CHar]61 + [CHar]32 + [CHar]36+ [CHar]116+ [CHar]114 + [CHar]117 + [CHar]101 + [CHar]59 + [CHar]105 + [CHar]102+[CHar]32 + [CHar]40 + [CHar]36 + [CHar]120 + [CHar]41 +[CHar]32 + [CHar]123+ [CHar]32+[CHar]32+ [CHar]32 + [CHar]32 + [CHar]36 + [CHar]102 +[CHar]108+[CHar]97+[CHar]103 + [CHar]32 +[CHar]61 +[CHar]32 +[CHar]34 + [CHar]69+ [CHar]78 + [CHar]79 + [CHar]123+ [CHar]72 +[CHar]48 +[CHar]112 +[CHar]51 + [CHar]102+[CHar]117+ [CHar]108 + [CHar]108+[CHar]121 +[CHar]95 + [CHar]89+[CHar]48 + [CHar]117 + [CHar]114+ [CHar]95 + [CHar]77 + [CHar]49+[CHar]78 +[CHar]68 + [CHar]95+ [CHar]68 + [CHar]49 + [CHar]68+[CHar]95 + [CHar]71+[CHar]51+ [CHar]116+ [CHar]95+ [CHar]115 + [CHar]99+ [CHar]114+[CHar]51+ [CHar]119 + [CHar]51 +[CHar]68 + [CHar]125 +[CHar]34 + [CHar]59+ [CHar]32 + [CHar]32 +[CHar]32 + [CHar]32 +[CHar]87 + [CHar]114 + [CHar]105 + [CHar]116 + [CHar]101 + [CHar]45 + [CHar]72+[CHar]111 +[CHar]115 + [CHar]116+ [CHar]32 +[CHar]34 + [CHar]100 +[CHar]111 +[CHar]32 +[CHar]110 + [CHar]111+[CHar]116 +[CHar]32 + [CHar]101+[CHar]120 + [CHar]101 +[CHar]99+ [CHar]117 +[CHar]116 + [CHar]101+ [CHar]32 + [CHar]117+[CHar]110 + [CHar]107 + [CHar]110+[CHar]111+[CHar]119+ [CHar]110 +[CHar]32 + [CHar]80 + [CHar]111+ [CHar]119 +[CHar]101 +[CHar]114 + [CHar]83 +[CHar]104+ [CHar]101 + [CHar]108 + [CHar]108 + [CHar]32 + [CHar]99 + [CHar]111+ [CHar]100 +[CHar]101+ [CHar]34+ [CHar]59 + [CHar]32+[CHar]32+[CHar]32 + [CHar]32+ [CHar]36 + [CHar]102 + [CHar]108 +[CHar]97 + [CHar]103+ [CHar]32 +[CHar]61 + [CHar]32 + [CHar]34 + [CHar]78+ [CHar]111 + [CHar]112 + [CHar]101 + [CHar]34+ [CHar]59 +[CHar]125)
for the second invocation of iex
.
Both scripts create a string from char ASCII codes and then evaluate that string as PowerShell code. If we remove the leading iex
and paste the remaining code into our PowerShell again, the string will be printed instead of evaluated.
These are the resulting strings:
set-psdebug -trace 0
$DebugPreference = "SilentlyContinue";$x = $true;if ($x) { $flag = "ENO{H0p3fully_Y0ur_M1ND_D1D_G3t_scr3w3D}"; Write-Host "do not execute unknown PowerShell code"; $flag = "Nope";}
The flag can be found in the second string.
-
Be careful when just searching for semicolons in the script. There are a lot some semicolons inside variable names, string literals, … ↩︎
-
https://stackoverflow.com/questions/54661916/what-is-the-difference-between-dot-and-ampersand-in-powershell ↩︎