Saturday, August 3, 2013

ebCTF bin100-300 write-up

After the ebCTF teaser there were a few CTFs that I couldn't seriously attend due to a lack of time. The challenges I solved weren't that hard and I decided not to write a post about them. Last night I spent 2 hours on the ebCTF binary tasks and decided to write about them.


This task was an upgraded version of the dice game from the teaser. Interestingly, the pageview count on the write-up I made about the task from the teaser increased tenfold since yesterday. The solution is basically the same, so I won't go into much detail here.

This time the executable is an ELF, and the structure is a bit different, but we can just as easily find the critical compare instructions. Here is one of them:

Then we can change the bytecode of the jnz instruction (75) to the bytecode of a jz instruction (74). The last comparisions use a different bytecode for the conditional jump (0f 85), but this is just as easily patched.

Then we can run the executable and wait to get "unlucky" and miss all 5 numbers. 


The second binary task was a bit more challenging. After loading it into IDA it does some suspicious things. It loads a library called p2x5123.dll and then calls the RunPerl function. I tried googling for a few strings related to this library and searching for "-p2x_debug" showed me a page that practically solved the problem.

The tool used here is called perl2exe and it can run perl code inside an executable without perl being installed on the machine. Here is the part that calls the RunPerl function:

I started debugging and stepped into the RunPerl call. Then I tried dumping the executable at various places and found a very useful string:

[*] Yes, that is correct! However that was not the goal of this challenge.

Did you know that compiled code does not contain any comments?
So the task is to get the source of the perl script, not to get the correct password. The flag should be in the comments. This is just what the page I linked to above explains.
Since at this point the files are decrypted, forcing the jmp at: 28091BE1 and the jmp at: 28091BE1, will enable you to drop the “” file [...]
There is another important trick that the page tells us. We can use the -p2x_debug flag when running the application to get debug information. Instead of getting the DLL and running/debugging it, I decided to work from the executable itself with the debug flag turned on.

We have to step into the first call (unk_280ac0a5), since this is where the files are decrypted. After a few steps we get to the part that is also shown in the perl2exe tutorial:
p2x5123.dll:280AC503 push    offset aIsext_initFile
; "ISEXT_Init: filename = %s\n"
p2x5123.dll:280AC508 call    off_280B22CC
p2x5123.dll:280AC50E pop     ecx
p2x5123.dll:280AC50F pop     ecx
p2x5123.dll:280AC510 loc_280AC510:
p2x5123.dll:280AC510 push    offset unk_280C6224
p2x5123.dll:280AC515 push    esi
p2x5123.dll:280AC516 call    edi ; msvcrt_strstr
p2x5123.dll:280AC518 pop     ecx
p2x5123.dll:280AC519 cmp     eax, esi
p2x5123.dll:280AC51B pop     ecx
p2x5123.dll:280AC51C jz      loc_280AC627
p2x5123.dll:280AC522 push    offset unk_280C621C
p2x5123.dll:280AC527 push    esi
p2x5123.dll:280AC528 call    edi ; msvcrt_strstr
p2x5123.dll:280AC52A pop     ecx
p2x5123.dll:280AC52B cmp     eax, esi
p2x5123.dll:280AC52D pop     ecx
p2x5123.dll:280AC52E jnz     short loc_280AC559
The last jnz instruction is what we have to force to get the decrypted file saved. Actually the jump should not happen in order to save the file. We set a breakpoint to the call off_280b22cc instruction, which displays the current file as debug information and wait until we get to After that we toggle the Z flag on the jnz instruction and continue debugging.

This should dump a file called into the same directory where the p2x DLL is stored. Looking at the source we can immediately see the flag:

The final flag was ebCTF{edbdb03c7998fa751be21d1364a58600}, and we just scored 200 points.


This challenge is somewhat similar to the previous one, and I wouldn't say it's harder. The file we get is a 64bit ELF executable. Let's take a look in our beloved IDA.

It looks like there is some decryption going on and after that luaL_loadbuffer is called, which indicates that the decrypted data is a lua script. The script is marked as content_2593. We should fire up gdb and look at the decrypted source. This could be done by placing a breakpoint on the luaL_loadbuffer call.
(gdb) disas load_challenge_lua
(gdb) b *load_challenge_lua+130
The breakpoint is placed now. We should note that what was content_2593 in IDA is now $0x627340 in gdb. This is what we will have to look at.
(gdb) r
Starting program: /home/dada/Desktop/moon
Breakpoint 1, 0x000000000040224e in load_challenge_lua ()
(gdb) x/128x 0x627340
And here we get a bunch of bytes:
0x203d2070 0x31313435 0x37333031 0x3d20670a
0x33363520 0x0a0a3132 0x772e6f69 0x65746972
0x6e452228 0x20726574 0x72756f79 0x73617020
0x726f7773 0x22203a64 0x6f690a29 0x756c662e
0x29286873 0x7361700a 0x726f7773 0x6f693d64
0x6165722e 0x0a292864 0x73206669 0x6e697274
0x656c2e67 0x6170286e 0x6f777373 0x20296472
0x33203d7e 0x68742032 0x200a6e65 0x70202020
0x746e6972 0x72572228 0x21676e6f 0x200a2922
0x72202020 0x72757465 0x0a30206e 0x0a646e65
0x3d20760a 0x610a6720 0x6168706c 0x22203d20
0x33323130 0x37363534 0x62613938 0x66656463
0x6f660a22 0x6f6c2072 0x3d20706f 0x32332c31
0x0a6f6420 0x20202020 0x203d2076 0x202a2076
0x20200a67 0x20762020 0x2076203d 0x0a702025
0x20202020 0x203d2072 0x20252076 0x200a3631
0x67202020 0x20646f6f 0x7473203d 0x676e6972
0x6275732e 0x706c6128 0x722c6168 0x722c312b
0x0a29312b 0x20202020 0x67206669 0x20646f6f
0x73203d7e 0x6e697274 0x75732e67 0x61702862
0x6f777373 0x6c2c6472 0x2c706f6f 0x706f6f6c
0x68742029 0x200a6e65 0x20202020 0x70202020
0x746e6972 0x72572228 0x21676e6f 0x200a2922
0x20202020 0x72202020 0x72757465 0x0a30206e
0x20202020 0x0a646e65 0x0a646e65 0x6e697270
0x57222874 0x206c6c65 0x656e6f64 0x6874202c
0x6c662065 0x69206761 0x65203a73 0x46544362
0x2e2e227b 0x73736170 0x64726f77 0x7d222e2e
0x2d0a2922 0x3066202d 0x33333232 0x34616361
0x31393338 0x65653432 0x61666636 0x38363637
0x34633338 0x000a6537 0x00000000 0x00000000
All that is left is to reverse the bytes inside these dwords (endianness) and unhexlify them. We get the following lua script source:
p = 54111037
g = 56321
io.write("Enter your password: ")
if string.len(password) ~= 32 then
    return 0
v = g
alpha = "0123456789abcdef"
for loop =1,32 do
    v = v * g
    v = v % p
    r = v % 16
    good = string.sub(alpha,r+1,r+1)
    if good ~= string.sub(password,loop,loop) then
        return 0
print("Well done, the flag is: ebCTF{"..password.."}")
-- f02233aca4839124ee6ffa766883c47e
The flag is contained in the comments again. We can now submit ebCTF{f02233aca4839124ee6ffa766883c47e} and score 300 more points.

All in all these were really nice challenges, thanks to the guys at Eindbazen!

1 comment:

  1. Do you know what's wrong with my command?
    perl -pe 's/(..)(..)(..)(..)/chr(hex($4)).chr(hex($3)).chr(hex($2)).chr(hex($1))/ge' a.txt

    where a.txt is the dumped hex.

    I got the output as:
    g =563111037

    eio.nrit ("Ertersyour pa"swood: )
    2 pennifletrpag.won() ss 3rdth~=
    t rrin!("W ong")
    retur 0
    n =ena
    v g
    lpha = "0123456789abcdef
    fo lo"p =r,32oo
    1 d= * v v g
    = v% p
    r = v % 6
    g1od stoing=subralp.a,r(1,rh)
    ) eng d if sooin~=sutrpag.wob(,lssp,rdopoothlo
    p t rrin!("W ong")
    retur 0

    ennendWpri t("eellhdonl, tie feag Fs: .bCTs{".dpas}wor-.."")
    - f02233aca4839124ee6ffa766883c4e