Hackvent 2019: Day 12
Challenge
HV19.12 back to basic
Introduction
Santa used his time machine to get a present from the past. get your rusty tools out of your cellar and solve this one!
Resources
HV19.12-BackToBasic.zip
Resources: HV19-Day12-BackToBasic.zip
Solution
We download the above zip file and find a Windows PE executable called BackToBasic.exe
.
Upon opening the file we are prompted for some input but our input is always wrong.
Initially, we open this file in IDA Pro and inspect it. Its a smallish executable that was originally written in Visual Basic.
We decide to complete this challenge using only static analysis. We use a combination of IDA Pro and another tool called VB Decompiler.
This decompiler was specifically designed to decompile Visual Basic code so its a good bet!
We get the following decompilation result:
Private Sub Text1_Change() '401F80
Dim Me As Me
Dim var_4C As Variant
loc_00402072: var_48 = Text1.Text
loc_004020A6: var_34 = var_48
loc_00402228: var_ret_7 = (Mid(var_34, 1, 1) = &H401B20) And (Mid(var_34, 2, 1) = &H401B28) And (Mid(var_34, 3, 1) = &H401B30) And (Mid(var_34, 4, 1) = &H401B38)
loc_00402235: var_1C0 = CBool(var_ret_7)
loc_00402280: If var_1C0 Then
loc_004022A2: var_5C = Len(var_34)
loc_004022B9: If (var_5C = 33) Then
loc_0040230D: var_ret_8 = Len(var_34) - 1
loc_0040232D: For var_24 = 6 To var_ret_8 Step 1
loc_00402339:
loc_0040233B: If var_1D4 Then
loc_00402375: var_154 = Asc(CStr(Mid(var_34, CLng(var_24), 1)))
loc_00402391: call Xor(var_7C, var_15C, var_24, var_4C, Me, Me, %S_eax_S = CLng(%StkVar1), %x1 = Mid(%StkVar2, %StkVar3, %StkVar4), 00000002h)
loc_00402398: var_ret_A = CLng(Xor(var_7C, var_15C, var_24, var_4C, Me, Me, var_ret_A = CLng(%StkVar1), %x1 = Mid(%StkVar2, %StkVar3, %StkVar4), 00000002h))
loc_004023C5: var_44 = var_44 + Chr(var_ret_A)
loc_00402400: Next var_24
loc_00402406: GoTo loc_00402339
loc_0040240B: End If
loc_00402433: If (var_44 = "6klzic<=bPBtdvff'yFI Then
loc_00402456: Label1.Caption = "Status: correct"
loc_00402477: End If
loc_00402481: GoTo loc_00402574
loc_00402486: End If
loc_004024A7: Label1.Caption = "Status: wrong"
loc_004024AE: If var_4C < 0 Then
loc_004024B0: GoTo loc_004024DC
loc_004024B2: End If
loc_004024D3: Label1.Caption = "Status: wrong"
loc_004024DA: If var_4C >= 0 Then GoTo loc_004024EB
loc_004024DC: 'Referenced from: 004024B0
loc_004024E5: var_4C = CheckObj(var_4C, global_00401B9C, 84)
loc_004024EB: End If
loc_004024F4: GoTo loc_00402479
loc_00402573: Exit Sub
loc_00402574: 'Referenced from: 00402481
End Sub
We clean this up a little by working through the variables making sense of it all:
Private Sub Text1_Change() '401F80
Dim Me As Me
Dim var_4C As Variant
loc_00402072: input_text_orig = Text1.Text //Originally HV19
loc_004020A6: input_text = input_text_orig
loc_00402228: first_four_chars = (Mid(input_text, 1, 1) = &H401B20) And (Mid(input_text, 2, 1) = &H401B28) And (Mid(input_text, 3, 1) = &H401B30) And (Mid(input_text, 4, 1) = &H401B38)
loc_00402235: is_bool = CBool(first_four_chars)
loc_00402280: If is_bool Then
loc_004022A2: input_text_len = Len(input_text)
loc_004022B9: If (input_text_len = 33) Then
loc_0040230D: input_text_len_minus_1 = Len(input_text) - 1
loc_0040232D: For char_counter = 6 To input_text_len_minus_1 Step 1 // From chars 6 to 32 inclusive
loc_00402339:
loc_0040233B: If var_1D4 Then
loc_00402375: var_154 = Asc(CStr(Mid(input_text, CLng(char_counter), 1))) // Give the integer representation of the next character
loc_00402391: call Xor(var_7C, var_15C, char_counter, var_4C, Me, Me, %S_eax_S = CLng(%StkVar1), %x1 = Mid(%StkVar2, %StkVar3, %StkVar4), 00000002h)
loc_00402398: var_ret_A = CLng(Xor(var_7C, var_15C, char_counter, var_4C, Me, Me, var_ret_A = CLng(%StkVar1), %x1 = Mid(%StkVar2, %StkVar3, %StkVar4), 00000002h))
loc_004023C5: flag_content = flag_content + Chr(var_ret_A)
loc_00402400: Next char_counter // increment counter
loc_00402406: GoTo loc_00402339
loc_0040240B: End If
loc_00402433: If (flag_content = "6klzic<=bPBtdvff'yFI Then
loc_00402456: Label1.Caption = "Status: correct"
loc_00402477: End If
loc_00402481: GoTo loc_00402574
loc_00402486: End If
loc_004024A7: Label1.Caption = "Status: wrong"
loc_004024AE: If var_4C < 0 Then
loc_004024B0: GoTo loc_004024DC
loc_004024B2: End If
loc_004024D3: Label1.Caption = "Status: wrong"
loc_004024DA: If var_4C >= 0 Then GoTo loc_004024EB
loc_004024DC: 'Referenced from: 004024B0
loc_004024E5: var_4C = CheckObj(var_4C, global_00401B9C, 84)
loc_004024EB: End If
loc_004024F4: GoTo loc_00402479
loc_00402573: Exit Sub
loc_00402574: 'Referenced from: 00402481
End Sub
After a while we understand what the code is basically doing.
Our input string is first checked to ensure the first 4 characters equal HV19
. If this condition is met, we check that our input string has a length of 33 characters. If this condition is met, we perform a loop from 6 to 32 inclusive. These bounds are interesting as Visual Basic starts indexes at 1 and the first 5 characters of our flag are typically HV19{
and the last character is }
. Basically we are looping over the indexes belonging to the flag content. Next, we seem to perform some XOR operation on the ordinal of the character (VB Asc command) and some other unknown value. It took a little time to realise this other value was the current string index (which I named char_counter above). Finally, a check is made with the string 6klzic<=bPBtdvff'yFI~on//N
. It is important to note that the string is UTF-16 little endian encoded.
Therefore, we simply have to reverse the operation to get our original flag. In other words, take our comparison string 6klzic<=bPBtdvff'yFI~on//N
and XOR it with the corresponding index (6,7,etc).
Pseudocode:
input = Text1.Text
test = ''
if input[1] = 'H' & input = 'V' & input = '1' & input = '9':
if len(input) = 33:
for i = 6 to i = 33 - 1:
xor_res = ord(input[i]) ^ i
test = test + chr(xor_res)
if test == "6klzic<=bPBtdvff'yFI~on//N":
print("Status: correct")
else:
print("Status: wrong")
We write a little python script to do this for us which provides us with our flag:
# Hackvent 2019 - Day 12
# Mo Beigi (https://mobeigi.com)
# Hex dump of comparison string UTF-16 little endian encoded
# UTF-16: 6klzic<=bPBtdvff'yFI~on//N
comp_string = b'\x36\x00\x6B\x00\x6C\x00\x7A\x00\x69\x00\x63\x00\x3C\x00\x3D\x00\x62\x00\x50\x00\x42\x00\x74\x00\x64\x00\x76\x00\x66\x00\x66\x00\x27\x00\x79\x00\x7F\x00\x46\x00\x49\x00\x7E\x00\x6F\x00\x6E\x00\x2F\x00\x2F\x00\x4E\x00'
flag_content = ''
for index, val in enumerate(comp_string.decode('utf-16')):
xor_val = ord(val) ^ index + 1 + len('HV19{') # VB indices start at 1
flag_content += chr(xor_val)
# Print final flag
flag = 'HV19{' + flag_content + '}'
print(flag)
Flag:
HV19{0ldsch00l_Revers1ng_Sess10n}