ForbiddenBITS CTF 2013 – Old 50 Write up

We were provided with a bin.bin file, which size is 512 bytes. Doing $ file bin.bin shows us that the file is a boot sector.

In order to run the boot sector I’ve followed an article from the developers of MikeOS (Note that I’ve linked to the Google Cache copy since the original site appears to be down).

So I downloaded a floppy disk image, renamed it to floppy.flp, and then I copied the boot sector of this challenge to the floppy disk image:

$ dd status=noxfer conv=notrunc if=bin.bin of=floppy.flp

Then I started QEMU using the floppy disk image containing the CTF boot sector:

$ qemu-system-i386 -fda floppy.img

QEMU boots from our floppy disk image, and the boot sector asks for a password:


After entering a random password, the boot sector prints “No :(, try again.”

In order to debug the boot sector using QEMU and GDB I’ve followed this blogpost. Basically, we need to launch QEMU with the following parameters:

$ qemu-system-i386 -fda floppy.img -s -S

Then, from another console, we use GDB to connect to QEMU’s gdbserver:

$ gdb
(gdb) target remote localhost:1234
(gdb) set architecture i8086
(gdb) break *0x7c00
(gdb) cont

0x7c00 is the memory address where the boot sector is loaded. So, if you are also using IDA to perform some static analysis on the boot sector, rebasing it to 0x7c00 should help.
By the way, here’s my static analysis on IDA:

seg000:7C00 E8 6E 00                          call    print_cr_lf
seg000:7C03 E8 6B 00                          call    print_cr_lf
seg000:7C06 E8 68 00                          call    print_cr_lf
seg000:7C09 E8 65 00                          call    print_cr_lf
seg000:7C0C E8 62 00                          call    print_cr_lf
seg000:7C0F BE B4 7C                          mov     si, 7CB4h       ; 'Password: '
seg000:7C12 E8 2C 00                          call    print_string
seg000:7C15 B9 07 00                          mov     cx, 7           ; buffer_size
seg000:7C18 BF BF 7C                          mov     di, 7CBFh       ; password_buffer
seg000:7C1B E8 39 00                          call    read_string
seg000:7C1E E8 50 00                          call    print_cr_lf
seg000:7C21 E8 73 00                          call    do_xor
seg000:7C24 BE BF 7C                          mov     si, 7CBFh       ; password_buffer
seg000:7C27 BF C7 7C                          mov     di, 7CC7h       ; solution
seg000:7C2A E8 4F 00                          call    compare_strings
seg000:7C2D 85 C0                             test    ax, ax
seg000:7C2F 75 08                             jnz     short loc_7C39  ; ** Jump if the strings match => challenge solved!
seg000:7C31 BE 17 7D                          mov     si, 7D17h       ; "No :(, try again."
seg000:7C34 E8 0A 00                          call    print_string
seg000:7C37 EB 06                             jmp     short loc_7C3F
seg000:7C39                   ; ---------------------------------------------------------------------------
seg000:7C39                   loc_7C39:                               ; CODE XREF: seg000:7C2Fj
seg000:7C39 BE D6 7C                          mov     si, 7CD6h       ; "Nice, 16bits world is nice :D. Validate using that password :)"
seg000:7C3C E8 02 00                          call    print_string
seg000:7C3F                   loc_7C3F:                               ; CODE XREF: seg000:7C37j
seg000:7C3F                                                           ; seg000:loc_7C3Fj
seg000:7C3F EB FE                             jmp     short loc_7C3F
seg000:7C41                   ; =============== S U B R O U T I N E =======================================
seg000:7C41                   print_string    proc near               ; CODE XREF: seg000:7C12p
seg000:7C41                                                           ; seg000:7C34p ...
seg000:7C41 31 C9                             xor     cx, cx
seg000:7C43 EB 03                             jmp     short loc_7C48
seg000:7C45                   ; ---------------------------------------------------------------------------
seg000:7C45                   loc_7C45:                               ; CODE XREF: print_string+Aj
seg000:7C45 E8 06 00                          call    print_char
seg000:7C48                   loc_7C48:                               ; CODE XREF: print_string+2j
seg000:7C48 AC                                lodsb
seg000:7C49 84 C0                             test    al, al
seg000:7C4B 75 F8                             jnz     short loc_7C45
seg000:7C4D C3                                retn
seg000:7C4D                   print_string    endp
seg000:7C4E                   ; =============== S U B R O U T I N E =======================================
seg000:7C4E                   print_char      proc near               ; CODE XREF: print_string:loc_7C45p
seg000:7C4E                                                           ; read_char+4p ...
seg000:7C4E B4 0E                             mov     ah, 0Eh
seg000:7C50 B7 00                             mov     bh, 0
seg000:7C52 B3 07                             mov     bl, 7
seg000:7C54 CD 10                             int     10h             ; - VIDEO - WRITE CHARACTER AND ADVANCE CURSOR (TTY WRITE)
seg000:7C54                                                           ; AL = character, BH = display page (alpha modes)
seg000:7C54                                                           ; BL = foreground color (graphics modes)
seg000:7C56 C3                                retn
seg000:7C56                   print_char      endp
seg000:7C57                   ; =============== S U B R O U T I N E =======================================
seg000:7C57                   read_string     proc near               ; CODE XREF: seg000:7C1Bp
seg000:7C57 31 ED                             xor     bp, bp          ; PARAMS: di=buffer, cx=buffer_size
seg000:7C59 EB 06                             jmp     short loc_7C61
seg000:7C5B                   ; ---------------------------------------------------------------------------
seg000:7C5B                   loc_7C5B:                               ; CODE XREF: read_string+Cj
seg000:7C5B E8 0B 00                          call    read_char
seg000:7C5E 88 03                             mov     [bp+di], al     ; store a char in the buffer
seg000:7C60 45                                inc     bp              ; counter++
seg000:7C61                   loc_7C61:                               ; CODE XREF: read_string+2j
seg000:7C61 39 CD                             cmp     bp, cx          ; counter < buffer_size?
seg000:7C63 72 F6                             jb      short loc_7C5B  ; keep reading
seg000:7C65 C6 03 00                          mov     byte ptr [bp+di], 0 ; null-terminate
seg000:7C68 C3                                retn
seg000:7C68                   read_string     endp
seg000:7C69                   ; =============== S U B R O U T I N E =======================================
seg000:7C69                   read_char       proc near               ; CODE XREF: read_string:loc_7C5Bp
seg000:7C69 30 E4                             xor     ah, ah
seg000:7C6B CD 16                             int     16h             ; KEYBOARD - READ CHAR FROM BUFFER, WAIT IF EMPTY
seg000:7C6B                                                           ; Return: AH = scan code, AL = character
seg000:7C6D E8 DE FF                          call    print_char
seg000:7C70 C3                                retn
seg000:7C70                   read_char       endp
seg000:7C71                   ; =============== S U B R O U T I N E =======================================
seg000:7C71                   print_cr_lf     proc near               ; CODE XREF: seg000:7C00p
seg000:7C71                                                           ; seg000:7C03p ...
seg000:7C71 B0 0A                             mov     al, 0Ah
seg000:7C73 E8 D8 FF                          call    print_char
seg000:7C76 B0 0D                             mov     al, 0Dh
seg000:7C78 E8 D3 FF                          call    print_char
seg000:7C7B C3                                retn
seg000:7C7B                   print_cr_lf     endp
seg000:7C7C                   ; =============== S U B R O U T I N E =======================================
seg000:7C7C                   compare_strings proc near               ; CODE XREF: seg000:7C2Ap
seg000:7C7C 31 ED                             xor     bp, bp
seg000:7C7E EB 0B                             jmp     short loc_7C8B
seg000:7C80                   ; ---------------------------------------------------------------------------
seg000:7C80                   loc_7C80:                               ; CODE XREF: compare_strings+12j
seg000:7C80 8B 02                             mov     ax, [bp+si]
seg000:7C82 8B 1B                             mov     bx, [bp+di]
seg000:7C84 39 D8                             cmp     ax, bx
seg000:7C86 75 0C                             jnz     short loc_7C94
seg000:7C88 83 C5 01                          add     bp, 1
seg000:7C8B                   loc_7C8B:                               ; CODE XREF: compare_strings+2j
seg000:7C8B 83 FD 07                          cmp     bp, 7
seg000:7C8E 72 F0                             jb      short loc_7C80
seg000:7C90 B8 01 00                          mov     ax, 1
seg000:7C93 C3                                retn
seg000:7C94                   ; ---------------------------------------------------------------------------
seg000:7C94                   loc_7C94:                               ; CODE XREF: compare_strings+Aj
seg000:7C94 31 C0                             xor     ax, ax
seg000:7C96 C3                                retn
seg000:7C96                   compare_strings endp
seg000:7C97                   ; =============== S U B R O U T I N E =======================================
seg000:7C97                   do_xor          proc near               ; CODE XREF: seg000:7C21p
seg000:7C97 31 ED                             xor     bp, bp
seg000:7C99 BE BF 7C                          mov     si, 7CBFh       ; password_buffer
seg000:7C9C BF CF 7C                          mov     di, 7CCFh       ; xor_key
seg000:7C9F EB 0D                             jmp     short loc_7CAE
seg000:7CA1                   ; ---------------------------------------------------------------------------
seg000:7CA1                   loc_7CA1:                               ; CODE XREF: do_xor+1Aj
seg000:7CA1 8B 02                             mov     ax, [bp+si]     ; grab a word from password_buffer
seg000:7CA3 8B 1B                             mov     bx, [bp+di]     ; grab a word from xor_key
seg000:7CA5 31 D8                             xor     ax, bx          ; XOR words
seg000:7CA7 89 E9                             mov     cx, bp          ; cx = counter
seg000:7CA9 D2 C8                             ror     al, cl          ; ROR al, counter
seg000:7CAB 88 02                             mov     [bp+si], al     ; store the result at password_buffer
seg000:7CAD 45                                inc     bp              ; counter++
seg000:7CAE                   loc_7CAE:                               ; CODE XREF: do_xor+8j
seg000:7CAE 83 FD 07                          cmp     bp, 7
seg000:7CB1 72 EE                             jb      short loc_7CA1
seg000:7CB3 C3                                retn
seg000:7CB3                   do_xor          endp
seg000:7CB3                   ; ---------------------------------------------------------------------------
seg000:7CB4 50 61 73 73 77 6F+aPassword       db 'Password: ',0
seg000:7CBF 00 00 00 00 00 00+password_buffer db 8 dup(0)
seg000:7CC7 D8 A6 CD 4E 04 0A+solution        db 0D8h, 0A6h, 0CDh, 4Eh, 4, 0Ah, 3Ch, 0 ; solution
seg000:7CCF BE 21 03 15 1F 2C+xor_key         db 0BEh, 21h, 3, 15h, 1Fh, 2Ch, 6Ah ; xor_key
seg000:7CD6 4E 69 63 65 2C 20+aNice16bitsWorl db 'Nice, 16bits world is nice. Validate using that password',0Dh,0Ah
seg000:7CD6 31 36 62 69 74 73+                db 0
seg000:7D17 4E 6F 20 3A 28 2C+aNoTryAgain_    db 'No, try again.',0Dh,0Ah,0

As you can see from the do_xor function, this is the algorithm the boot sector uses to validate the password:

xor_key = [0xBE, 0x21, 0x3, 0x15, 0x1F, 0x2C, 0x6A]
solution = [0xD8, 0xA6, 0xCD, 0x4E, 0x4, 0xA, 0x3C]
result = []
for i in range(7):
	c = password[i] ^ xor_key[i]
	c = ROR(c, i)

if result == solution:
	print "Nice, 16bits world is nice. Validate using that password"

Having that validation algorithm in mind, I wrote the following Python script, which generates the right password:

xor_key = [0xBE, 0x21, 0x3, 0x15, 0x1F, 0x2C, 0x6A]
solution = [0xD8, 0xA6, 0xCD, 0x4E, 0x4, 0xA, 0x3C]
password = []

def ROL_byte(n, b):
    mask = (2**b) - 1
    mask = mask << (8 - b)
    left_bits = ((n & mask) >> (8 - b)) & 0xff
    return ( ((n << b) & 0xff) | left_bits)

def main():

    for i in range(6, -1, -1):
        c = ROL_byte(solution[i], i)
        c = c ^ xor_key[i]
        password.insert(0, c)           #Reverse order

    print "Password: %s" % "".join([chr(c) for c in password])


After running the Python script, we get the flag for this challenge: fl4g_me



Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s