115 IOLI 0x06
Onto the seventh crackme.
$ rz-bin -z ./crackme0x06
[Strings]
nth paddr vaddr len size section type string
---------------------------------------------------------------------------
0 0x00000738 0x08048738 4 5 .rodata ascii LOLO
1 0x00000740 0x08048740 13 14 .rodata ascii Password OK!\n
2 0x0000074e 0x0804874e 20 21 .rodata ascii Password Incorrect!\n
3 0x00000763 0x08048763 24 25 .rodata ascii IOLI Crackme Level 0x06\n
4 0x0000077c 0x0804877c 10 11 .rodata ascii Password:
Doing our routine strings check we can see a new contender: LOLO
.
$ ./crackme0x06
IOLI Crackme Level 0x06
Password: LOLO
Password Incorrect!
No dice, so let’s take a closer look.
[0x08048400]> pdg @ main
// WARNING: [rz-ghidra] Detected overlap for variable var_11h
(undefined4 placeholder_0, undefined4 placeholder_1, char **envp)
undefined4 main{
int32_t var_88h;
int32_t var_7ch;
.imp.printf("IOLI Crackme Level 0x06\n");
sym.imp.printf("Password: ");
sym.imp.scanf(0x8048787, &var_7ch);
sym.check((int32_t)&var_7ch, (int32_t)envp);
symreturn 0;
}
[0x08048400]> ps @ 0x8048787
%s
[0x08048400]> afvl @ main
int32_t var_88h @ stack - 0x88
var int32_t var_7ch @ stack - 0x7c
var char **envp @ stack + 0xc arg
This looks the same as before, except the program’s environment variables envp
are passed to check
.
[0x08048400]> pdg @ sym.check
// WARNING: Variable defined which should be unmapped: var_28h
// WARNING: Variable defined which should be unmapped: var_24h
// WARNING: [rz-ghidra] Detected overlap for variable var_11h
void sym.check(int32_t arg_4h, int32_t arg_8h)
{
uint32_t uVar1;
int32_t var_28h;
int32_t var_24h;
;
undefined var_11hint32_t var_10h;
int32_t var_ch;
int32_t var_8h;
= 0;
var_ch = 0;
var_10h while( true ) {
= sym.imp.strlen(arg_4h);
uVar1 if (uVar1 <= (uint32_t)var_10h) break;
= *(undefined *)(var_10h + arg_4h);
var_11h .imp.sscanf(&var_11h, 0x804873d, &var_8h);
sym= var_ch + var_8h;
var_ch if (var_ch == 0x10) {
.parell(arg_4h, arg_8h);
sym}
= var_10h + 1;
var_10h }
.imp.printf("Password Incorrect!\n");
symreturn;
}
This looks mostly the same as well. If we follow envp
(now named arg_8h
) we can see it gets passed to parell
.
[0x08048400]> pdg @ sym.parell
// WARNING: Variable defined which should be unmapped: var_18h
// WARNING: Variable defined which should be unmapped: var_14h
void sym.parell(int32_t arg_4h, int32_t arg_8h)
{
int32_t iVar1;
int32_t var_18h;
int32_t var_14h;
int32_t var_ch;
int32_t var_8h;
.imp.sscanf(arg_4h, 0x804873d, &var_8h);
sym= sym.dummy(var_8h, arg_8h);
iVar1 if (iVar1 != 0) {
for (var_ch = 0; var_ch < 10; var_ch = var_ch + 1) {
if ((var_8h & 1U) == 0) {
.imp.printf("Password OK!\n");
sym.imp.exit(0);
sym}
}
}
return;
}
We can see that the parity check is still in place, except it’s now in a loop that executes 10 times, but only if dummy()
returns non-zero.
[0x08048400]> pdg @ sym.dummy
// WARNING: Variable defined which should be unmapped: var_18h
// WARNING: Variable defined which should be unmapped: var_14h
.dummy(undefined4 placeholder_0, int32_t arg_8h)
undefined4 sym{
int32_t iVar1;
int32_t var_18h;
int32_t var_14h;
int32_t var_ch;
int32_t var_8h;
= 0;
var_8h do {
if (*(int32_t *)(var_8h * 4 + arg_8h) == 0) {
return 0;
}
= var_8h * 4;
iVar1 = var_8h + 1;
var_8h = sym.imp.strncmp(*(undefined4 *)(iVar1 + arg_8h), "LOLO", 3);
iVar1 } while (iVar1 != 0);
return 1;
}
Living up to its name, dummy
does not use its first parameter at all, only the second one is used which is the envp
parameter from main
. Apparently some part of envp
has to equal “LOL” (only the first 3 characters are used, note the ‘3’ in strncmp
).
It will be easier to figure out how dummy
works if we run the code, so let’s use the debugger again!
$ rizin -d ./crackme0x06
[0xe8570cd0]> aa
[0xe8570cd0]> dcu sym.dummy
Continue until 0x080484b4
IOLI Crackme Level 0x06
Password: 88
hit breakpoint at: 0x80484b4
Now we should be at the start of dummy
, let’s see where we can place a breakpoint.
[0x08048502]> pdf; CALL XREF from sym.parell @ 0x8048547
.dummy(int32_t arg_8h);
┌ sym; var int32_t var_18h @ stack - 0x18
│ ; var int32_t var_14h @ stack - 0x14
│ ; var int32_t var_ch @ stack - 0xc
│ ; var int32_t var_8h @ stack - 0x8
│ ; arg int32_t arg_8h @ stack + 0x8
│ push ebp
│ 0x080484b4 mov ebp, esp
│ 0x080484b5 sub esp, 0x18
│ 0x080484b7 mov dword [var_8h], 0
│ 0x080484ba mov eax, dword [var_8h]
│ ┌─> 0x080484c1 lea edx, [eax*4]
│ ╎ 0x080484c4 mov eax, dword [arg_8h]
│ ╎ 0x080484cb cmp dword [edx + eax], 0
│ ╎ 0x080484ce je 0x804850e
│ ┌──< 0x080484d2 mov eax, dword [var_8h]
│ │╎ 0x080484d4 lea ecx, [eax*4]
│ │╎ 0x080484d7 mov edx, dword [arg_8h]
│ │╎ 0x080484de lea eax, [var_8h]
│ │╎ 0x080484e1 inc dword [eax]
│ │╎ 0x080484e4 mov dword [var_14h], 3
│ │╎ 0x080484e6 mov dword [var_18h], 0x8048738 ; str.LOLO
│ │╎ 0x080484ee ; [0x8048738:4]=0x4f4c4f4c ; "LOLO"
│ │╎ mov eax, dword [ecx + edx]
│ │╎ 0x080484f6 ;-- eip:
│ │╎ mov dword [esp], eax
│ │╎ 0x080484f9 call sym.imp.strncmp ; sym.imp.strncmp ; int strncmp(const char *s1, const char *s2, size_t n)
│ │╎ 0x080484fc test eax, eax
│ │╎ 0x08048501 jne 0x80484c1
│ │└─< 0x08048503 mov dword [var_ch], 1
│ │ 0x08048505 jmp 0x8048515
│ │┌─< 0x0804850c mov dword [var_ch], 0
│ └──> 0x0804850e ; CODE XREF from sym.dummy @ 0x804850c
│ │ mov eax, dword [var_ch]
│ └─> 0x08048515 leave
│ 0x08048518 ret └ 0x08048519
The instruction at 0x080484f9
looks like a good spot. This is just before strncmp
is called, so we can see what value is passed to it.
[0x08048502]> db @ 0x080484f9
[0x08048502]> dbc 'psi @r:eax' @ 0x080484f9
[0x08048502]> dcr
PWD=/home/rizin
HOME=/home/rizin
USER=rizin
PATH=/usr/local/sbin:/usr/local/bin:/usr/bin
SHELL=/usr/bin/sh
Running dcr
you should be greeted with all the environment variables passed to the program. From this we can safely conclude that dummy
is looking for an environment variable starting with “LOL”, so let’s try it.
Remember that there are 3 constraints to the password now:
- Digit sum reaches 16 at some point
- The number is even
- An environment variable starting with “LOL” is set
$ LOL= ./crackme0x06
IOLI Crackme Level 0x06
Password: 88
Password OK!
$ LOL= ./crackme0x06
IOLI Crackme Level 0x06
Password: 12346
Password OK!