Find a key.
[link to submit form]
$ 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…
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:
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