Codegate CTF 2011 Issue 500 (bootsector)

Find a key.
[link to submit form]

binary

$ file challenge.bin 
challenge.bin: x86 boot sector, code offset 0xc0

Summary: bootsector with password check, bruteforcing 2 bytes hash.

Bootsector, cool! Let’s load it and see how it looks! I created a virtual machine in VirtualBox, booted from linuxmint10.iso and rewrote a bootsector:

sudo dd if=challenge.bin of=/dev/sda

Warning! this action overwrites existing bootloader! don’t do this on your PC!

Then reboot, and…

bootscreen

Oh, it asks for a password. Maximal length is 5. Ok… Let’s disassemble it. There’s no much code there. It’s easy to find keyboard scan loop:

seg000:0210 loc_210:
seg000:0210                 mov     si, 7FBAh
seg000:0213                 call    sub_331
seg000:0216                 mov     bx, 7E7Ah
seg000:0219                 xor     di, di
seg000:021B
seg000:021B loc_21B:
seg000:021B                 mov     ah, 10h
seg000:021D                 int     16h
; KEYBOARD - GET ENHANCED KEYSTROKE
; Return: AH = scan code, AL = character
seg000:021F                 cmp     ah, 1
seg000:0222                 jz      short loc_24F
seg000:0224                 cmp     ah, 0Eh
seg000:0227                 jz      short loc_25D
seg000:0229                 cmp     ah, 1Ch
seg000:022C                 jz      short loc_26B
seg000:022E                 cmp     ah, 0E0h        ; ENTER
seg000:0231                 jz      short loc_26B
seg000:0233                 cmp     al, 21h         ; '!'
seg000:0235                 jb      short loc_21B
seg000:0237                 cmp     al, 7Eh         ; '~'
seg000:0239                 ja      short loc_21B
seg000:023B                 cmp     di, 5
seg000:023E                 jnb     short loc_21B
seg000:0240                 mov     [bx+di], al
seg000:0242                 inc     di
seg000:0243                 push    bx
seg000:0244                 mov     ax, 0E2Ah       ; '*'
seg000:0247                 mov     bx, 7
seg000:024A                 int     10h
; - VIDEO - WRITE CHARACTER AND ADVANCE CURSOR (TTY WRITE)
; AL = character, BH = display page (alpha modes)
; BL = foreground color (graphics modes)
seg000:024C                 pop     bx
seg000:024D                 jmp     short loc_21B

Some important things:

  • Password buffer is bx = 7E7Ah
  • Current password length is stored in di
  • Character range: 0x21 - 0x7E

Ok, we want to get right password, so let’s see what is done when Enter is pressed ( loc_26B ):

seg000:026B loc_26B:
seg000:026B                 push    bx
seg000:026C                 mov     ax, 0E0Dh
seg000:026F                 mov     bx, 7
seg000:0272                 int     10h
; - VIDEO - WRITE CHARACTER AND ADVANCE CURSOR (TTY WRITE)
; AL = character, BH = display page (alpha modes)
; BL = foreground color (graphics modes)
seg000:0274                 mov     ax, 0E0Ah
seg000:0277                 mov     bx, 7
seg000:027A                 int     10h
; - VIDEO - WRITE CHARACTER AND ADVANCE CURSOR (TTY WRITE)
; AL = character, BH = display page (alpha modes)
; BL = foreground color (graphics modes)
seg000:027C                 pop     bx
seg000:027D                 mov     al, 20h ; ' '
seg000:027F loc_27F:
seg000:027F                 cmp     di, 10h
seg000:0282                 jnb     short loc_289
seg000:0284                 mov     [bx+di], al
seg000:0286                 inc     di
seg000:0287                 jmp     short loc_27F
seg000:0289 ; ---------------------------------------------------------------------------
seg000:0289 loc_289:
seg000:0289                 mov     cl, 10h
seg000:028B                 xor     dx, dx
seg000:028D                 mov     si, 7E7Ah
seg000:0290                 cld
seg000:0291
seg000:0291 loc_291:
seg000:0291                 lodsb
seg000:0292                 call    sub_368
seg000:0295                 dec     cl
seg000:0297                 jnz     short loc_291
seg000:0299                 cmp     dx, ds:7FFAh
seg000:029D                 jz      short loc_2B2

First part is easy – write “\r\n” and add spaces to password until it’s length is 0x10 (16).

Next, si points to buffer (7E7Ah), dx = 0, al contains a character from password. Then, sub_386 is called for cl = 16 times and dx is compared to ds:7FFAh which is at offset 5Fah:

seg000:05FA                 dw 2002h

Now, look at sub_386:

seg000:0368 sub_368         proc near
seg000:0368                 push    ax
seg000:0369                 push    cx
seg000:036A                 mov     ah, al
seg000:036C                 xor     al, al
seg000:036E                 xor     dx, ax
seg000:0370                 mov     cl, 8
seg000:0372
seg000:0372 loc_372:
seg000:0372                 shl     dx, 1
seg000:0374                 jnb     short loc_37A
seg000:0376                 xor     dx, 1975h
seg000:037A
seg000:037A loc_37A:
seg000:037A                 dec     cl
seg000:037C                 jnz     short loc_372
seg000:037E                 pop     cx
seg000:037F                 pop     ax
seg000:0380                 retn
seg000:0380 sub_368         endp

Looks like just some simple hash function. Don’t know how to easily reverse it, so let’s code a bruteforcer:

int hash(unsigned char *s) {
    unsigned int dx = 0;
    unsigned int i, n;
    for (i = 0; i < 16; i++) {
        unsigned int ax = s[i] << 8;
        dx ^= ax;
        
        for (n = 0; n < 8; n++) {
            dx <<= 1;
            if (dx & 0x10000)
                dx ^= 0x1975;
            dx &= 0xffff;
        }
    }
    return dx;
}

int main(int argc, char * argv[]) {
    unsigned char buf[17] = "\x21\x21\x21\x21\x21           ";
    while (1) {
        if (hash(buf) == 0x2002) {
            printf("%s\n", buf);
        }
        int pos = 0;
        int add = 1;
        while (add) {
            buf[pos]++;
            if (buf[pos] > 0x7e) {
                buf[pos] = 0x21;
                pos++;
            }
            else add = 0;
        }
        if (pos > 4) break;
    }    
}
$ gcc brute.c -O9 -o brute && ./brute 
+0%!!           
j#.!!           
Lq/!!           
0^7!!           
qM<!!           
1GB!!           
pTI!!           
*)P!!           
MhZ!!
...

Heh, “1GB!!” or “MhZ!!” looks cool ;)
You can take any, submit form accepts them all. I choose “oWnu\“, let’s try to enter it:

error loading os

Oh, it tries to load the system! I have no one on the VM, so it fails.
To solve the task, you needed to submit answer in special form and get the flag.

The flag: dltbdhqor

Leave a Reply

Your email address will not be published.