Sunday, December 21, 2014

FireEye - FlareOn Challenge 6 Argument 2

So if you read my previous post..you'd know I was stuck on Argument 2 last time. I finally managed to crack it with a little help. The answer had been staring at me all the time and somehow I'd overcomplicated things. Oh well. I learnt a lot.

So..the last time in the previous post, I was stuck at the function 401164. I went through it multiple times, sat and marked blocks out in IDA, used Hexrays on it to get C code (I don't do this until it's an absolute last resort) but all I could see was loads of operations on a big chunk of encrypted text.

Yeah. So I found this chunk of text at 729900..and this is exactly what it looked like.

---------------------------
SIn46AAAAABIixwkSIPDCusKSDHSSDHAsDwPBcAI8oA4G3QC/+NIg8ABgDBAgDDygDCzgDgwdAL/40iDwAGAMHGAOB90Av/jSIPAAYAAo8AIvIA4sHQC/+NIg8ABgCh5gDjodAL/40iDwAHACIKAKCiAOPZ0Av/jSIPAAYAosMAITYAALIA4H3QC/+NIg8ABgABUwACZgDC4wAgqgAA/gDivdAL/40iDwAHACLqAOF10Av/jSIPAAYAw7cAIbIAAMIA4KXQC/+NIg8ABgCi/gDi1dAL/40iDwAHAALyAAIzAAHuAKDGAAGOAOKV0Av/jSIPAAcAAIMAAFoAwrsAAmIA483QC/+NIg8ABwAhugADSgDimdAL/40iDwAGAADSAOGJ0Av/jSIPAAYAAzYAoEIAAYoAwsoA4MnQC/+NIg8ABgDC3gDBzwAgHgDjrdAL/40iDwAGAADSAKGHACDaAAFuAKEyAOAt0Av/jSIPAAYAAWoA4mnQC/+NIg8ABwAiigDiZdAL/40iDwAGAMH6AKOeAOCt0Av/jSIPAAYAouIAwhoAATsAISsAAV4A4r3QC/+NIg8ABwAiGgDDowACVgDBKgDCtgDjDdAL/40iDwAHACEWAMMyAAByAOAN0Av/jSIPAAYAoSoA443QC/+NIg8ABgDClwAiQgDjKdAL/40iDwAHACN7AADaAMHiAKNiAOD50Av/jSIPAAYAAtYAorcAIicAAosAAEYA42HQC/+NIg8ABgABAgCghwAjAgDiCdAL/40iDwAHAAOOAOHt0Av/jSIPAAYAoeMAI9oA413QC/+NIg8ABSDHASDH/SDH2SDHSTTHAagJfagFeagZaailYDwVJicBIMfZNMdJBUsYEJAJmx0QkApoCx0QkBAkeS1ZIieZqEFpBUF9qKlgPBUgx9moDXkj/zmohWA8FdfZIMf9XV15aSL8vL2Jpbi9zaEjB7whXVF9qO1gPBZDr/pA=
------------------------------

The function iterated for the length of this string and performed some operation on it ... using a byte array at 4F4000. But I couldn't understand what it was doing....with all that math. Specially because the very next function, was just an exit function.

Now I'd marked it as an exit function a long time back...and forgotten about it...and not analyzed its code carefully at all. After all, it's exit() ffs... what's there to look into? I was wrong :(

I pinged a person on reddit for a pointer. He/she said I was close...and should think about encoding and the = sign. Sure, I think. Base64. Obviously. But why is that relevant here? Yeah the encrypted text had an = at the end...but so what? It's too big for an Email address. So what's the damn point of decoding it? That's what I'd thought...a long time back.

Anyway I copied the text and threw it into an online Base64 decoder...





and my eyes popped out when I saw what I did.









Look at the screenshot...the right pane..towards the bottom. You'll see some ASCII text called /bin/sh. It's trying to call a shell.... it's shell code. And I'd been staring at it for at least 2-3 days. #-o. Serves me right for assuming things. Sigh.

Anyway, if there's shell code, that means the program is going to jump to it at some point. And I think...wtf.... all that's left is that exit() call at 44bb2b. When the hell is it jumping? And where's that code?

So I then decide to separately throw the shellcode into a disassembler and analyze it. Since it didn't have the ELF header and I was in no mood to recreate one (if I could :D) I threw the code into an awesome online disassembler at http://www2.onlinedisassembler.com/.













...and the code there looked very very familiar. I'd seen it somewhere. Where? Then it hit me...it was IN the exit function.

The exit function had code that compared something with '1b' at the offset cfc4... and exit if it didn't match. And what was it comparing it with? The 2nd argument. And if you didn't enter that correctly..which I wasn't...it'd fail.

So at this point...it was just about reversing the algorithm inside. Here I have a confession to make. While searching for hints and verifying the 1st argument, I'd accidentally seen part of the 2nd argument on one of the solutions, so I knew it started with lin. That sucked. But anyway... just to verify I entered 'l' and..yes..it passed the jump. So the I just needed to solve that entire algorithm...which was just different basic math at every step. Rotate right an left, xor, add, and sub..with binary and hex. I started doing it manually...but was just horribly bored as the pace was very slow guessing it.

So I decided I'd write code for it and solve it. It's basically mind numbing work predicting character by character...and the algorithm is different each time. An utter waste of time really... and this made no sense to me from FireEye's perspective. Oh well I guess that's how real malware is :shrug

Here's the code I wrote - it's just a very quickly written piece of code. Not great at all. But it works:

https://gist.github.com/arvinddoraiswamy/846de119b09dcbb8ea92

I wrote code till the "@" character...and then just guessed the rest. Here too...out of sheer tedium...I guessed 1 character...manually added it to my flag..and then proceeded to solve the algorithm again for the same character. And wondered wtf was wrong now...and why gdb kept throwing me out.

Only googling the exact answer showed me the error of my ways :|. Obviously, that's not how it works in real life...but really I was done...and there was nothing left to solve in the challenge, so I think it was ok.

The final flag was:- l1nhax.hurt.u5.a1l@flare-on.com

Oh you bet. This was a painful painful challenge. What an utter load of junk there was inside. 7 or 8 functions out of some 2700+ that were useful. Sheesh :)

p.s..The bad thing was that someone had written the flag of challenge 7 underneath challenge 6... :( but luckily I have already forgotten it :D. I won't solve challenge 7 for a few days till I am sure I don't remember anything.

Friday, December 19, 2014

Fireeye - FlareOn Challenge 6 Argument 1

Challenge 6 was a 64 bit statically linked ELF binary. Now I haven't yet finished solving it (hey it's hard ;)) but have got through half of it. I needed a tiny hint though this time to set me on the right track. Anyway though...its complex enough that I can write about Part 1. Later maybe I'll add Part 2 once I solve it someday. If not and I look at spoilers, I'll try and blog about the learnings :). Ok lets start.

Once I ran file and identified it was statically linked, I sighed inwardly. That's coz static binaries have the Linux libraries that they are linked to as part of the binary. This ensures that these binaries will run on any system - unlike when there is dynamic linking in place, and dependency on specific libraries. From a reverse engineering standpoint this is bad, because the disassembly in IDA is cluttered with library code and its super hard to identify what code is user written.

Ran the file in a VM. Always make sure you run the file in a VM. All it did was come back with "no". That's it. So the next thing is to find out where the "no" was referenced. So after a bit of stepping in and stepping out, the call at 45dea0 looked suspicious - it pointed to another function at 45dce0. This eventually makes a call to sub_452079. A quick tip incase you start to debug 452079 but forget where it was called from is to either:

-- Hit ESC to go back and Ctrl+Enter to come forward again
-- Or right click on sub_452079 in the IDA View and click List cross references to

Anyway, on first sight 452079 looks like a gold mine with a ton of juicy strings. Every single one of them is utter garbage. So I just kept scrolling in IDA till I saw the last (or so I thought) strings go by. And set a breakpoint after that. Sometimes it'd not hit my breakpoint because it's position was wrong. But slowly, after a few attempts, I managed to find out where the "No" was getting called from - 4535bb. And then the very next call at 4535c5 was causing the program to exit.

So one thing was then clear, I had to skip that jump for sure, so I used a little bit of gdbinit magic :) for now to patch the program in memory and see where it leads me. The .gdbinit file is something that gdb runs commands from before starting to run the program.

------
br *0x4535b4
commands
set $ps=$ps&0x4
continue
end
-------

This basically breaks execution at 4535b4 and unsets the zero flag so execution can jump over the exit code, and then continues execution.

Well, that worked for a while but then I crashed after some time with a very fishy looking "Program has a segfault" error. Digging further revealed that all this was happening at 41F21C. So usually when something like that happens, the code that is making that happen is usually in the call just above that. So.. digging into the call at 41F211..revealed that there was a line at 474319 which made a syscall and had an argument of 0x65 [syscall(0x65)]. This means that there is some kind of system call being made...and it's very interesting many times ;). But we need to find out what 0x65 stands for. So let's search for a syscall table online. We find a nice one at:

https://filippo.io/linux-syscall-table/

What's 65? semop. Eh? Linux IPC? Wtf. What does that even mean? Ah its Hex. And the table is decimal :). 65 in hex is 101 in decimal and that...is ptrace. Ah that makes sense. ptrace() is a call on Linux that detects if code is running inside a debugger, like us. gdb remember? So we need to run outside gdb. But then how do we find out what's going on? We can't. So we do some more gdbinit magic. Heh.

----------------
br *0x41f21c
commands
set $ps=$ps|0x40
continue
end
-----------------

Okay, that sets the zero flag, because this time ..that's what we want and jump to 41F232...not to the silly SEGV message.

Great...then we continue debugging...and the program just hangs. Like just hangs. Nothing I do makes a difference. In the past, when I've debugged and a program has hung, it's been because it's potentially waiting for some network connection and listening. Checking with netstat and lsof revealed nothing this time, so the next logical candidate was a long long sleep() call.

So .. hitting a Ctrl+C inside gdb gave me the address of where the "hanging" was happening.

--------------
Breakpoint 2, 0x000000000041f21c in ?? ()
^C
Program received signal SIGINT, Interrupt.
0x0000000000473d50 in ?? ()
--------------

Hmm... 473d50. What's there? Ha. Another syscall...this time its 0x23.  Or 35 in decimal. Lets go back to our syscall table again. Ah there we go. nanosleep(). Man page - "nanosleep() suspends the execution of the calling thread until either at least the time specified in *req has elapsed"

ok..that's the first argument to nanosleep() then which is some huge number. Now where is the first argument stored. It's called from 473C67...and the arguments are stored in the lines just above that. That's rdi and rsi then. That's how things happen in Linux...the arguments are stored in registers and not explicitly pushed on to the stack like in Windows. So... if we can edit rdi to a smaller value than what's currently there....which is

(gdb) x/d $rdi
0x7fffffffd530:    3597
(gdb)

...that's 3597 seconds. 1 hour. I'm not sure we want to wait for an hour before resuming debugging. So I did some more gdbinit magic and edited rdi at runtime to 0x10.

--------------------------
br *0x473c67
commands
set $rdi=0x10
continue
end
--------------------------

... which should have caused sleeping for 10 seconds. But it didn't and almost returned instantly. :D. Not sure why. Didn't dig too deep though as my purpose was to get past the sleep() call.

The code went on ..after this. But if you're still following along I'd advise you to straight away put a breakpoint on 44bb2b :D. Coz all the code .. well most of it :) after the nanosleep() and before 44bb2b is utter utter junk and you'll just waste hours stepping in and out.

There is a call here to 44b942. Scroll down here as well...until you see the last 2 calls inside this function. A little debugging reveals that the call at 44bb2b is an exit call and the program just exits here. Which usually, usually means that the call before that has some juicy stuff. This is the call at 401164. But while this function looks different and interesting....its very unclear where the flag is hidden here. Coz all that happens inside here is a lot of integer operations and some fancy math :(.

Now at this point I got stuck and decided to ask for help on reddit. 2 people who had already solved it very kindly poked me in the right direction ..while talking about arguments. Ah... the program has arguments? How many? What? Time for strace. Thanks guys :)

strace ./C6 1234 abcd ... shows me that SEGFAULT message. Means its 2 arguments. Nice. I'm still unclear though, about how to identify via static analysis...how many arguments a program takes.

Anyway... so then logically, what are those arguments? So running the function with no arguments...if you remember gave us "No"...but running it with 2 arguments gives us "bad". Trying to figure out where bad came from in the first place was another big pain.

Eventually though as it turns out...bad is called from 2 places 43710a and 4371DE. The first one checks if the 1st argument has 10 digits

cmp rax, 0xa

and if that's satisfied...it goes on to 437120 ...else it goes to "bad". The second "bad" message is at 4371DE.... and the comparison is at 4734b4. Now this was the first place I found that IDA was wrong. :-o. This caused more chaos. Eventually with gdb's help I found out that the comparison was happening at 4734b4.

.text:00000000004734AE mov     eax, [rdi-0Ah]
.text:00000000004734B1 mov     ecx, [rsi-0Ah]
.text:00000000004734B4 cmp     eax, ecx

Now one of these (I forget which) contains a string "bngcg`debd" and the other...I have to enter the right input so it computes to this string. A little bit of playing around with 10 digit numbers and I found the right number. (I think I got lucky here directly with numbers, I could have easily tried strings and struggled a while longer :D)

The first argument is 4815162342.

I haven't figured out what the 2nd argument is...and want to slog at this a while more before reading the many great solutions to this that are already online. But...this was complex enough for me to put it out :)

Hopefully I'll have part 2 soon. Until then ...adios :)

Sunday, December 7, 2014

OllyDbg - Running DLLs

So this isn't something new really. There's plenty of articles that talk about running DLLs. You usually either write a small EXE that uses LoadLibrary to load the DLL or use rundll32.exe with the arguments set to calling DllMain(). That'll work.

But that'll work only if all the functions are eventually called. I mean... if a DLL has 4 functions A, B, C and D. And the program flow is something like:

DLLMain(){
   a()
}

a() {
  b()
  c()
}

c(){
  d()
}

... it'll work and you'll end up being able to reverse the entire DLL.

But if you have a 5th function e() that isn't directly called... and is called only on some specific case... you won't directly ever end up there.

A quick tip on how to analyze this in Olly is to identify the function() to reverse using IDA or any other disassembler and go to that address. Now right click on that address and click "Set new origin here". This will allow you to run that function :)

Of course...this will work out of the box only if the function takes no arguments at all. If it does you will have to set up the registers EAX, EBX, ECX and anything else...with the correct arguments. This you can do..by finding out where it was called from... or by studying how the arguments are processed inside the function by running it and seeing why it crashes.

For example: A function may need 2 arguments and takes these from EBX and ECX. So you might fill in EBX="A" and ECX="d" and try and run the function. But you might find out later that there was code which was dividing EBX and ECX... (EBX/ECX). This means that they both had to be numbers... integers maybe. So you fill up EBX=4 and ECX=2 and see what happens. It might crash again but for some different reason...and you then go back .. and so on :)

Nothing new but a quick little thing that I learnt last week or so...while working on that Fireeye challenge.