Thursday, October 18, 2007

Binary Bomb

Since my Binary Bomb class is over, I thought I'd post some of my findings. It's basically a spoiler for other people who Google "Binary Bomb". If a few professors (my school or others) request that I take it down, I can do that. You are supposed to be learning this on your own, after all...

I mentioned earlier that you could simply use "strings" to find the magic phrase in the bomb. The better way is to look at the assembly itself:

Phase_1: About the 4th instruction down, there is the following disassembled code:
8048bd2: 68 54 98 04 08 push $0x8049854
This is the simplest to determine (even without “strings bomb > theStrings.txt”) the value, since all you need to do to see what this is, is to:
x /s 0x8049854

Phase_2: First, we learn that the function read_six_numbers() is called before any other tests are done, so we step into this function. We notice that this function, before testing anything itself, tries to pull in 6 values from the specified input. This, in reverse order, contains the 6 strings the user entered. Once all are pushed individually into the stack, we notice the following two lines:
8048f9f: 68 bf 9b 04 08 push $0x8049bbf
8048fa7: e8 88 f9 ff ff call 8048934
When the first address (0x8049bbf) is dereferenced, we see that it is a string of text:
"%d %d %d %d %d %d"
This shows that sscanf() is being asked to pull the 6 numbers in, and save the results into %eax.
Once we return to phase_2, the first result of sscanf() is placed on the top of the stack:
8048c08: 8b 44 9d d4 mov 0xffffffd4(%ebp,%ebx,4),%eax
This could be more easily understood to be:
a = userInput[0];
The next line shows how we wish to test against the future values:
8048c0c: 83 c0 05 add $0x5,%eaxBasically a += 5. We don’t get too much out of this until we see the next line is comparing this number with our next number:
8048c0f: 39 44 9d d8 cmp %eax,0xffffffd8(%ebp,%ebx,4)
Again, this can be read as:
if (userInput[x] == userInput[x-1] - 5);
So it simply checks that
userInput[1] == userInput[0] + 5
userInput[2] == userInput[1] + 5
, etc.

Phase_3: We see immediately that this function pushes three values onto the stack, followed by a function push:
8048c38: 68 be 98 04 08 push $0x80498be
Dereferencing this shows us that the numbers must be in the format of "%d %c %d". Another sscanf() gives us:
a = sscanf(userString, "%d %c %d", userInput1);
Our inputs will be an integer, followed with a single character, followed by another integer. This phase is more dynamic than the previous ones, as it contains a switch()…case pair, and the second and third values we enter will depend on the first integer specified. In some peoples’ bombs, this switch() statement actually is not a simple 0..7 number structure (some can be -2..4, or 100..108). If this were the case, there would be an additional statement such as “subl $0x4,%eax” or similar.
This should give us our first guesses as to the different case’s. Regardless of which one is selected, the next thing seen is along the lines of:
8048c66: b3 7a mov $0x7a,%bl
The bl is the lower byte of the %eax register, and the value $0x7a actually denotes an ASCII value (in this case, the letter ‘z’). The user’s 3rd input is checked next, before the letter is actually validated, so onto the next line:
8048c68: 81 7d f8 f2 00 00 00 cmpl $0xf2,0xfffffff8(%ebp)The user’s 3rd input needs to be 0xf2 (decimal 242), and if so, we are jumped out of the switch() statement. It is here that the user’s input and the ASCII letter is compared, and if equal, the phase is complete.

Phase_4: Before any checks are made in this function, the user’s input is pushed to the stack (which is normal) and another sscanf() is issued. What is unusual is that the string value used to parse out the value, is that there are TWO values specified in the address 0x80498c4:
8048d52: 68 c4 98 04 08 push $0x80498c4
as we can see when we dereference it:
"%d %s"
This calls for an integer and a string of char’s, but only uses the integer. The string is actually used for the secret_phase().
The integer value is passed into func4, which seems to do nothing but test the current value and return when (value – 1) <= 1. This turns out to be doing a Fibonacci sequence, and the result is returned to phase_4. That result is checked against a fixed value, and if it passes, the phase is complete:
8048d7d: 3d f1 6f 00 00 cmp $0x6ff1,%eax
// When userInput == “22”, %eax == 28657


Phase_5: After the user’s input is pushed onto the stack, its string length is checked. If the user has input exactly 6 ASCII characters, the specific letters are each given a different weight. The total weight of all 6 letters are computed to equal a single value:
8048dc8: 83 f9 20 cmp $0x20,%ecx
I found it easiest to write down all the letters and their values (a..z) by breaking on this line:
8048dc6: 7e f0 jle 8048db8
then simply watching the value of %ecx change, and writing down that value. My ASCII weights were:
a = 10 b = 6 c = 1 d = 12 e = 16 f = 9 g = 3 h = 4
i = 7 j = 14 k = 5 l = 11 m = 8 n = 15 o = 13 p = 2
q = 10 r = 2 s = 1 t = 12 u = 16 v = 9 w = 3 x = 4
y = 7 z = 14

Once the weights equal the specified value (in the above case, 0x20 or 32 decimal), the phase is complete. I found the simplest to be bbbbbp (5(6) + 1(2)), but any other values that added up would work.

Phase_6: Through trial-and-error, I found that this is actually quite simple to test. You want your output to equal this line of code:
8048e60: 74 05 je 8048e67
// Break here: Test %ebx, and that’s what your input should be
The fun6() function doesn’t really do too much; it is a linked list that tries to twist around a lot, but does very little otherwise. You can pretty much skip any testing in it if you simply test the output value above.

Secret_Phase: Once the previous phases are complete, a branch in phase_defused() opens up. It tests whether you have finished all 6 previous phases:
80495bc: 83 3d 6c a8 04 08 06 cmpl $0x6,0x804a86c
// Check whether we're on phase 0x6 (6)

then enters starts to pull strings and values from previous phases. One that it lingered on was the “%d %s” from phase_4. It pulls the second value (the string) and tests if anything was entered. The simplest way to get into the secret_phase() is to look at the check value for the returned %s. This turned out to be the string “austinpowers” in a few bombs I worked on (I actually tried about 3 bombs, just for fun, and also to have a more complete guide that I'm writing now):
80495e4: 68 cb 9d 04 08 push $0x8049dcb
// 0x8049dcb contains the value "austinpowers"

The strings_not_equal() function tests these values, and you are taken into the secret_phase() to determine the last value.
The secret_phase() was more tricky than the other phases because it had a lookup array as well as a recursive function (fun7()). The lookup array contained several different values, and depending on the user input (either at the end of the user’s solutions text, or prompted), some or several of the tables were used. This result was returned and modified by the parent fun7() functions, until the end result passed back to the secret_phase() was the value it was looking for:
8048ee7: 83 f8 03 cmp $0x3,%eax
// Test that the (final) return value of fun7() is 3


That’s it! That’s all the bombs, and how they were found. The final phase (fun7()) took quite a bit of plug-and-chug before I began to see a pattern to how it was calculating which lookup array to use and how different return values affected the parent fun7()’s results as well.

Please leave comments if you found this useful, and especially if your values or addresses were different. How did you solve it? Are you still stuck on parts of it? What parts of the world are you from? Why are 95% of the readers for this post using Windows and Chrome instead of some Linux variant (I wasn't aware that Binary Bomb ran on anything BUT Linux...)?

5 comments:

  1. Win/Chrome user here, the reason is that you can always use school computers for Linux.

    When not dealing with Dr. Evil I play TF2 which doesn't run native on Linux.

    ReplyDelete
  2. Hi, i need HELP!

    BombLab,Phase3:

    http://pastebin.com/TfbH1Jk8

    Thanks!!!!!

    ReplyDelete
    Replies
    1. Lena,

      I'd say to take a look at http://pastebin.com/AcBUt6Ns

      It's only rough comments, and some of my "jg" and "ja" may be backwards after doing a comparison, but it should be pretty straight-forward.

      Delete
  3. Can you take a look at my phase 6 and help me figure it out? I've determined it takes 6 non repeating integers between 1 and 6.

    http://pastebin.com/5iZeiDW2

    ReplyDelete
  4. phase 6 also says that no integer can be -1 from the integer before it (at least in my bomb)

    ReplyDelete