Crack the heart
Convince your crush to go out with you. Note: the flag is what you need to say to convince him/her to go out with you.
Recon
$ file crackme
crackme: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped
$ ./crackme
Why should I go out with you?
becuz im leet haxx0r
that was pretty cringe
Okay, this binary is not falling for my advances.
Cursory observation when attempting to reverse this binary: very annoying flow control. During a CTF we're obviously pressed for time, so we looked for a way to cut some corners.
Near the entrypoint we encounter:
.data:00000000004021E5 mov eax, 65h
.data:00000000004021EA syscall ; LINUX - sys_ptrace
.data:00000000004021EC mov rbx, 0FFFFFFFFFFFFFFFFh
.data:00000000004021F3 cmp rax, rbx
.data:00000000004021F6 jnz short GOOD
.data:00000000004021F8 jmp short BAIL
.data:00000000004021FA GOOD:
.data:00000000004021FA pop rcx
Sweet, anti-debugging tricks from the early 2000's. 90 90
at 4021f8
(0x21f8
in the ELF file) it is.
Somewhere in the disassembly we find:
.data:000000000040220C mov qword ptr [rcx], offset loc_40214D
.data:0000000000402213 mov qword ptr [rcx+18h], offset BAIL
.data:000000000040221B test rbp, rbp
.data:000000000040221E jz short loc_402232
.data:0000000000402220 mov qword ptr [rcx+8], offset str_cringe <-- the "bad boy" string
.data:0000000000402228 mov qword ptr [rcx+10h], 17h
So apparently rbp
is used as some kind of good/bad flag. What a creative use of the frame pointer.
Cruising through the disassembly some more, we find:
.data:0000000000402137 mov al, [r10+r11]
.data:000000000040213B sub al, bl
.data:000000000040213D jz short loc_402144
.data:000000000040213F mov ebp, 1
So this rbp
flag is set based on a subtraction result here. Time for some GDB scripting:
set pagination off
br *0x40213b
commands
silent
if $al == $bl
printf "[GOOD] "
printf "SUB %02x - %02x = %02x\n", $al&0xff, $bl&0xff, ($al - $bl)&0xff
else
printf "[BAD ] "
printf "SUB %02x - %02x = %02x\n", $al&0xff, $bl&0xff, ($al - $bl)&0xff
quit
end
c
end
r
Lets take this technology for a spin, making a rough assumption here the flag starts with utflag{..
like the other challenges:
$ gdb -q -x x.gdb ./crackme.patched | egrep "GOOD|BAD"
utflag{lol_nope...
[GOOD] SUB 04 - 04 = 00
[GOOD] SUB 91 - 91 = 00
[GOOD] SUB 05 - 05 = 00
[GOOD] SUB 02 - 02 = 00
[GOOD] SUB 06 - 06 = 00
[GOOD] SUB cb - cb = 00
[GOOD] SUB 64 - 64 = 00
[BAD ] SUB 61 - 7a = e7
Sweet, we literally get a hit per character.. and thus should be able to recover the flag using a bit of bruteforce without paying any attention to the details(tm).
crack.php:
<?php
// cset is a file with the bf charset, 1 char per line
$cset = file("cset", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$pwd = $argv[1];
while(strlen($pwd) < 82) {
$found = false;
foreach($cset as $c) {
$p = $pwd . $c;
$o = `./try.sh '$p'`;
if (strstr($o, "GOOD")) {
$found = true;
$pwd .= $c;
break;
}
}
if (!$found) {
echo "CHAR NOT FOUND\n";
die();
}
echo "PWD: '" . $pwd . "'\n";
}
?>
try.sh:
#!/bin/sh
echo "$1" |
gdb -q -x x.gdb ./crackme.patched |
egrep "GOOD|BAD" | head -n ${#1} | tail -n1
$ php crack.php 'utflag{'
PWD: 'utflag{w'
PWD: 'utflag{wh'
PWD: 'utflag{wha'
PWD: 'utflag{what'
PWD: 'utflag{what_'
..
Well, this isn't a pretty/optimal solution, but it does work. Grab a cup of coffee and you will eventually learn the flag is:
utflag{what_1f....i_mapp3d_mY_m3m0ry_n3xt_to_y0urs....ahahaha, jkjk....unless ;)?}