Slightly changing up the format of this post as I’ll be doing two crackmes, both of difficulty 1, one being JustSee
here and the other called WhiteRabbit
here:
I will begin with JustSee
:
0x0000000000400686 <+0>: push %rbp
0x0000000000400687 <+1>: mov %rsp,%rbp
0x000000000040068a <+4>: sub $0x40,%rsp
0x000000000040068e <+8>: mov %fs:0x28,%rax
0x0000000000400697 <+17>: mov %rax,-0x8(%rbp)
0x000000000040069b <+21>: xor %eax,%eax
0x000000000040069d <+23>: mov $0x4007d4,%edi
0x00000000004006a2 <+28>: callq 0x400520 <puts@plt>
0x00000000004006a7 <+33>: mov $0x4007dd,%edi
0x00000000004006ac <+38>: callq 0x400520 <puts@plt>
0x00000000004006b1 <+43>: mov $0x4007ef,%edi
0x00000000004006b6 <+48>: mov $0x0,%eax
0x00000000004006bb <+53>: callq 0x400540 <printf@plt>
0x00000000004006c0 <+58>: lea -0x40(%rbp),%rax
0x00000000004006c4 <+62>: mov %rax,%rsi
0x00000000004006c7 <+65>: mov $0x4007fc,%edi
0x00000000004006cc <+70>: mov $0x0,%eax
0x00000000004006d1 <+75>: callq 0x400570 <__isoc99_scanf@plt>
0x00000000004006d6 <+80>: movabs $0x7334457b67616c46,%rax
0x00000000004006e0 <+90>: mov %rax,-0x20(%rbp)
0x00000000004006e4 <+94>: movabs $0x7d6c6c3468635f79,%rax
0x00000000004006ee <+104>: mov %rax,-0x18(%rbp)
0x00000000004006f2 <+108>: movl $0x0,-0x10(%rbp)
0x00000000004006f9 <+115>: lea -0x20(%rbp),%rdx
0x00000000004006fd <+119>: lea -0x40(%rbp),%rax
0x0000000000400701 <+123>: mov %rdx,%rsi
0x0000000000400704 <+126>: mov %rax,%rdi
0x0000000000400707 <+129>: callq 0x400560 <strcmp@plt>
0x000000000040070c <+134>: test %eax,%eax
0x000000000040070e <+136>: jne 0x40071c <main+150>
0x0000000000400710 <+138>: mov $0x4007ff,%edi
0x0000000000400715 <+143>: callq 0x400520 <puts@plt>
0x000000000040071a <+148>: jmp 0x400726 <main+160>
0x000000000040071c <+150>: mov $0x400805,%edi
0x0000000000400721 <+155>: callq 0x400520 <puts@plt>
0x0000000000400726 <+160>: mov $0x0,%eax
0x000000000040072b <+165>: mov -0x8(%rbp),%rcx
0x000000000040072f <+169>: xor %fs:0x28,%rcx
0x0000000000400738 <+178>: je 0x40073f <main+185>
0x000000000040073a <+180>: callq 0x400530 <__stack_chk_fail@plt>
0x000000000040073f <+185>: leaveq
0x0000000000400740 <+186>: retq
An interesting an unrelated thing which would be interesting to learn regards the lines, +8:+21
and +165:+180
, which are the stack canary checking procedures to ensure no stack overflows occur by using a stack cookie I presume and XORing it after the main procedure is finished. Although this is quite simple, mov %fs:0x28,%rax
moves the canary value into %rax
, and saves it at the lowest possible offset of the stack at -0x8(%rbp)
, then at +165
we reload the old value into %rcx
and xor
it against the actual canary value in %fs:0x28
, if the values are not the same then __stack_chk_fail
is called which alerts to the program that stack corruption has occurred, and hence performs necessary measures, otherwise it returns normally if they are the same.
Anyway, back onto the main part of the program, it is notable that this program uses absolute direct addressing opposed to traditional RIP-relative addressing:
0x000000000040069d <+23>: mov $0x4007d4,%edi
0x00000000004006a2 <+28>: callq 0x400520 <puts@plt>
0x00000000004006a7 <+33>: mov $0x4007dd,%edi
0x00000000004006ac <+38>: callq 0x400520 <puts@plt>
0x00000000004006b1 <+43>: mov $0x4007ef,%edi
0x00000000004006b6 <+48>: mov $0x0,%eax
0x00000000004006bb <+53>: callq 0x400540 <printf@plt>
0x00000000004006c0 <+58>: lea -0x40(%rbp),%rax
0x00000000004006c4 <+62>: mov %rax,%rsi
0x00000000004006c7 <+65>: mov $0x4007fc,%edi
0x00000000004006cc <+70>: mov $0x0,%eax
0x00000000004006d1 <+75>: callq 0x400570 <__isoc99_scanf@plt>
Equivalent to:
int
main (int argc, char **argv)
{
char input[16];
puts ("Hello ! ");
puts ("Give Me Your Flag");
printf ("Check Flag: ");
scanf ("%s", &input);
/* ... */
}
Continuing:
0x00000000004006d6 <+80>: movabs $0x7334457b67616c46,%rax
0x00000000004006e0 <+90>: mov %rax,-0x20(%rbp)
0x00000000004006e4 <+94>: movabs $0x7d6c6c3468635f79,%rax
0x00000000004006ee <+104>: mov %rax,-0x18(%rbp)
0x00000000004006f2 <+108>: movl $0x0,-0x10(%rbp)
0x00000000004006f9 <+115>: lea -0x20(%rbp),%rdx
0x00000000004006fd <+119>: lea -0x40(%rbp),%rax
0x0000000000400701 <+123>: mov %rdx,%rsi
0x0000000000400704 <+126>: mov %rax,%rdi
0x0000000000400707 <+129>: callq 0x400560 <strcmp@plt>
0x000000000040070c <+134>: test %eax,%eax
0x000000000040070e <+136>: jne 0x40071c <main+150>
0x0000000000400710 <+138>: mov $0x4007ff,%edi
0x0000000000400715 <+143>: callq 0x400520 <puts@plt>
0x000000000040071a <+148>: jmp 0x400726 <main+160>
0x000000000040071c <+150>: mov $0x400805,%edi
0x0000000000400721 <+155>: callq 0x400520 <puts@plt>
I save time by doing b *0x0000000000400707; x/s $rsi
gives 0x7ffffffee120: "Flag{E4sy_ch4ll}"
, although it is valuable understanding the movabs
instruction and how the string even got there, so allow me to iterate line-by-line. +80
moves 0x7334457b67616c46
into -0x20(%rbp)
adjacent to 0x7d6c6c3468635f79
in -0x18(%rbp)
, afterwards we load the first big constant into %rdx
and the input buffer into %rax
, doing a strcmp (0x7d6c6c3468635f79, input)
, which would require noticing that due to the adjacency of the strings, and the fact that the input buffer is buffers, the buffer is actually: 0x7334457b67616c46
plus 0x7d6c6c3468635f79
which is just:
>>> "\x73\x34\x45\x7b\x67\x61\x6c\x46"[::-1] + "\x7d\x6c\x6c\x34\x68\x63\x5f\x79"[::-1]
'Flag{E4sy_ch4ll}'
Anyway, just to verify:
>./just\ see Flag{E4sy_ch4ll}
Hello !
Give Me Your Flag
Check Flag: Flag{E4sy_ch4ll}
G00d
Now onto the WhiteRabbit
challenge, here is the disassembly:
0x00000000000011d5 <+0>: push %rbp
0x00000000000011d6 <+1>: mov %rsp,%rbp
0x00000000000011d9 <+4>: lea 0xe58(%rip),%rdi # 0x2038
0x00000000000011e0 <+11>: callq 0x1030 <puts@plt>
0x00000000000011e5 <+16>: lea 0xe6c(%rip),%rdi # 0x2058
0x00000000000011ec <+23>: mov $0x0,%eax
0x00000000000011f1 <+28>: callq 0x1040 <printf@plt>
0x00000000000011f6 <+33>: lea 0xe63(%rip),%rdi # 0x2060
0x00000000000011fd <+40>: callq 0x1030 <puts@plt>
0x0000000000001202 <+45>: mov $0x0,%eax
0x0000000000001207 <+50>: pop %rbp
0x0000000000001208 <+51>: retq
The strings are irrelevant, as there is no input, the point of this is to figure out the hidden function which is quite easy as it’s named secret
:
0x0000000000001145 <+0>: push %rbp
0x0000000000001146 <+1>: mov %rsp,%rbp
0x0000000000001149 <+4>: sub $0x10,%rsp
0x000000000000114d <+8>: movl $0x5,-0x4(%rbp)
0x0000000000001154 <+15>: movl $0x3,-0x8(%rbp)
0x000000000000115b <+22>: movl $0x4,-0xc(%rbp)
0x0000000000001162 <+29>: movb $0x73,-0xd(%rbp)
0x0000000000001166 <+33>: movb $0x64,-0xe(%rbp)
0x000000000000116a <+37>: movb $0x63,-0xf(%rbp)
0x000000000000116e <+41>: movsbl -0xd(%rbp),%r9d
0x0000000000001173 <+46>: mov -0x4(%rbp),%eax
0x0000000000001176 <+49>: sub -0xc(%rbp),%eax
0x0000000000001179 <+52>: mov %eax,%r8d
0x000000000000117c <+55>: movsbl -0xe(%rbp),%edi
0x0000000000001180 <+59>: mov -0x4(%rbp),%eax
0x0000000000001183 <+62>: sub -0xc(%rbp),%eax
0x0000000000001186 <+65>: mov %eax,%esi
0x0000000000001188 <+67>: movsbl -0xe(%rbp),%r10d
0x000000000000118d <+72>: movsbl -0xf(%rbp),%ecx
0x0000000000001191 <+76>: movsbl -0xd(%rbp),%edx
0x0000000000001195 <+80>: mov -0x8(%rbp),%eax
0x0000000000001198 <+83>: pushq $0x0
0x000000000000119a <+85>: pushq $0x0
0x000000000000119c <+87>: push %r9
0x000000000000119e <+89>: pushq $0x0
0x00000000000011a0 <+91>: push %r8
0x00000000000011a2 <+93>: mov -0xc(%rbp),%r8d
0x00000000000011a6 <+97>: push %r8
0x00000000000011a8 <+99>: mov -0x8(%rbp),%r8d
0x00000000000011ac <+103>: push %r8
0x00000000000011ae <+105>: pushq $0x0
0x00000000000011b0 <+107>: push %rdi
0x00000000000011b1 <+108>: push %rsi
0x00000000000011b2 <+109>: mov %r10d,%r9d
0x00000000000011b5 <+112>: mov $0x0,%r8d
0x00000000000011bb <+118>: mov %eax,%esi
0x00000000000011bd <+120>: lea 0xe44(%rip),%rdi # 0x2008
0x00000000000011c4 <+127>: mov $0x0,%eax
0x00000000000011c9 <+132>: callq 0x1040 <printf@plt>
0x00000000000011ce <+137>: add $0x50,%rsp
0x00000000000011d2 <+141>: nop
0x00000000000011d3 <+142>: leaveq
0x00000000000011d4 <+143>: retq
Also no need to look at the strings, as we can b *0x00000000000011d4
and set $rip = 0x0000000000001145; c
:
(gdb) set $rip = 0x0000000008001145
(gdb) b *0x00000000080011d4
Breakpoint 5 at 0x80011d4
(gdb) c
Continuing.
flag{3sc0nd1d0_3h_M41s_G0st0S0}
Breakpoint 5, 0x00000000080011d4 in secret ()
Easy.
Thanks for reading.