2017 Flare-on write up

Had great fun attempting the Fire-Eye Flare on Challenge this year, was my first attempt and I have to say it has sparked a renewed interest in reverse engineering. I didn’t complete the challenge got to the 4th and hit a wall with my overall ASM inexperience so I have been working on some foundation building study so next year I expect to surpass and maybe even beat the challenge. If I took a convoluted route to my win let me know I’m always looking to improve and while I mussed my way through these challenges I know I wasn’t efficient.

Challenge 1 – login.html
First challenge we are given an html file and told the flags for each level will be in form of an email address @flare-on.com. Cool, let’s take a look at the source.

1
2
3
4
5
6
7
8
9
document.getElementById("prompt").onclick = function () {
	var flag = document.getElementById("flag").value;
	var rotFlag = flag.replace(/[a-zA-Z]/g, function(c){return String.fromCharCode((c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26);});
	if ("PyvragFvqrYbtvafNerRnfl@syner-ba.pbz" == rotFlag) {
		alert("Correct flag!");
	} else {
		alert("Incorrect flag, rot again");
	}
}

From here we can see that script accepts user input flag, passes it into a function that ‘encodes’ it and then it does a compare against an encoded string. So being javascript lets have it tell us what the password is.

1
2
3
	} else {
		alert(rotFlag);
	}

Then we simply copy the encoded string PyvragFvqrYbtvafNerRnfl@syner-ba.pb and check the flag and voila

Challenge 2 – IgniteMe.exe
Being that the first was so easy to complete it gave me a false sense of confidence that challenge 2 promptly smashed. It has been 10+ years since I’ve seriously tried to RE any executables so this was a great chance to brush up. This challenge gives us an executable IgniteMe.exe.

First thing I did was pop it into BinText to see if we can simply see the password in the strings.

Flare On Ch2 img1

No plaintext password, we see some garbage info and strings for prompt and success/fail.

Next step I loaded it up in debugger and followed through what happens. Program takes out input, loops through it backwards then comes down to the following code where we see our input being XOR in reverse by itself.

ex: input ASDF D^F, S^D, A^S > output

1
2
3
4
5
6
7
8
9
10
11
12
00401086 | 7C 27                    | jl igniteme.4010AF                      |
00401088 | 8B 55 F8                 | mov edx,dword ptr ss:[ebp-8]            |
0040108B | 0F BE 82 78 30 40 00     | movsx eax,byte ptr ds:[edx+403078]      | 
00401092 | 0F B6 4D FF              | movzx ecx,byte ptr ss:[ebp-1]           |
00401096 | 33 C1                    | xor eax,ecx                             | 
00401098 | 8B 55 F8                 | mov edx,dword ptr ss:[ebp-8]            |
0040109B | 88 82 80 31 40 00        | mov byte ptr ds:[edx+403180],al         |
004010A1 | 8B 45 F8                 | mov eax,dword ptr ss:[ebp-8]            |
004010A4 | 8A 88 78 30 40 00        | mov cl,byte ptr ds:[eax+403078]         |
004010AA | 88 4D FF                 | mov byte ptr ss:[ebp-1],cl              |
004010AD | EB CA                    | jmp igniteme.401079                     |
004010AF | C7 45 F8 00 00 00 00     | mov dword ptr ss:[ebp-8],0              |

This was a big hint to me so the password must be the gibberish that is listed xor in reverse and so I went off to try and solve the puzzle. Loaded up file in hex editor and pulled out that garbage text that’s showing in the text block just before our input prompt

1
2
0D2649452A1778442B6C5D5E45122F172B446F6E56095F454773260A0D1317484201404D0C0269
.&IE*.xD+l]^E./.+DonV._EGs&....HB.@M..i

A few lines of python

1
2
3
4
5
6
7
8
9
10
initial = 0x69
key = 0x0D,0x26,0x49,0x45,0x2A,0x17,0x78,0x44,0x2B,0x6C,0x5D,0x5E,0x45,0x12,0x2F,0x17,0x2B,0x44,0x6F,0x6E,0x56,0x09,0x5F,0x45,0x47,0x73,0x26,0x0A,0x0D,0x13,0x17,0x48,0x42,0x01,0x40,0x4D,0x0C,0x02,0x69
solution = []
for x in reversed(key):
    output = x ^ initial
    initial = x
    solution.insert(0,output)
 
 
print '[{}]'.format(', '.join(hex(z) for z in solution))

And boom, garbage.. overlooked a few things. Went back into the debugger and realized that it is not simply XOR the last vs 2nd last all the way through the loop, not exactly… The first digit (last in string) is being xor by 0x04. That is then saved and is used to xor the previous all the way through. So a tiny tweak in the code from

initial = 0x69

to

initial = 0x04

and then set

initial = output

and rerun it.

1
R_y0u_H0t_3n0ugH_t0_1gn1t3@flare-on.com

Challenge 3 – Greek_to_me.exe
This program loads up and appears to be just a blank cmd window.. odd. Looking at the file in BinText we see two lines that really stick out.. 127.0.0.1 and WS2_32.dll. A Google search shows this to be a DLL for socket connections. So check netstat and see if we have any open connections.

We do see one listener showing address 127.0.0.1:2222 so let’s try to pass info to it and see what happens

1
2
3
4
5
6
7
8
9
10
import socket
 
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
TCP_IP = '127.0.0.1'
TCP_PORT = 2222
 
sock.connect((TCP_IP, TCP_PORT))
sock.send("test")
print sock.recv(1024)
sock.close

and we get the output:

Nope, that's not it.

so we know we are on the right path. Let’s load the file up into a debugger and see what happens. Tracing through the code we see the program loads out string into memory appends an X to it then proceeds to load the following 121 bytes into memory, XOR against the first character of our input string and then add 0x22 to it and save it back into memory.

1
2
3
4
33 E1 C4 99 11 06 81 16 F0 32 9F C4 91 17 06 81 14 F0 06 81 15 F1 C4 91 1A 06 81 1B E2 06 81 18
F2 06 81 19 F1 06 81 1E F0 C4 99 1F C4 91 1C 06 81 1D E6 06 81 62 EF 06 81 63 F2 06 81 60 E3 C4
99 61 06 81 66 BC 06 81 67 E6 06 81 64 E8 06 81 65 9D 06 81 6A F2 C4 99 6B 06 81 68 A9 06 81 69
EF 06 81 6E EE 06 81 6F AE 06 81 6C E3 06 81 6D EF 06 81 72 E9 06 81 73 7C 6A

After looping through the full string, we see it break the string into 8 14 byte segments where it does some other malarky then checks everything. Turns out all of that is not needed. After looping through the debug code more times than I care to admit and only ever seeing the program use the first character no matter what string I gave it… I abandoned that line of thinking and decided to find the correct first character and go from there. So I loaded up and wrote a little bruteforce python script.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import socket
import subprocess
 
TCP_IP = '127.0.0.1'
TCP_PORT = 2222
 
msg = 0x00
flag = False
 
while flag is False:
    sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    subprocess.Popen("C:\Users\Flare\Desktop\greek_to_me.exe", stdout=subprocess.PIPE)
    sock.connect((TCP_IP,TCP_PORT))
    sock.send(chr(msg))
    result = sock.recv(1024)
    sock.close()
    if result[0] is not 'N':
        flag = True
    print result + " " + chr(msg) + " " + hex(msg)
    msg = msg + 0x01

Ran this and let it go, few mins later and 161 loops later we get a win. “Congratulations! But wait, where’s my flag? ¢ 0xa2”. We now know that we need to feed it ¢ and see what happens. Turns out everything. Setting a break point just before line

0040105E

where the program does the check to see if we are successful or not is all we really need to do. Doing this then passes into the JE which will send us to congrats or to failure and with the correct character entered we are sent to the success loop which as we step into it shows us everything we need to know.

try the key and win!

1
et_brute_force@flare-on.com
Close