crackmes.one “EZ crackme” Writeup

This is a write up for “EZ crackme” by R3tr0BS: https://crackmes.one/crackme/5fcfb87933c5d424269a1afc

This challenge came with two files: Readme.txt and run.exe

Readme.txt contained the following:

so this is my first crackme, you need to use the password or..... do it your way,
good luck, 
R3tr0.

run.exe has a hash of 3bc592f4963add05a2d28bc469b5cd6ea00b973516ba1a1fccc10f1590f26152

% sha256sum run.exe
3bc592f4963add05a2d28bc469b5cd6ea00b973516ba1a1fccc10f1590f26152  run.exe

file shows that this is a 32 bit ELF with debug_info and debugging symbols:

% file run.exe 
run.exe: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, with debug_info, not stripped

I used dwarfdump to get debug_info. This shows that this sample was likely compiled with NASM 2.15.05 and had a filename of code.asm, which is interesting but doesn’t help much.

% dwarfdump run.exe 

.debug_info

COMPILE_UNIT<header overall offset = 0x00000000>:
< 0><0x0000000b>  DW_TAG_compile_unit
                    DW_AT_low_pc                0x08049000
                    DW_AT_high_pc               0x08049045
                    DW_AT_stmt_list             0x00000000
                    DW_AT_name                  code.asm
                    DW_AT_producer              NASM 2.15.05
                    DW_AT_language              DW_LANG_Mips_Assembler

...Snip!...

Next, I used objdump to disassemble run.exe. The output shows a small, straightforward program:

% objdump -d run.exe

run.exe:     file format elf32-i386


Disassembly of section .text:

08049000 <_start>:
 8049000:	5b                   	pop    %ebx
 8049001:	5b                   	pop    %ebx
 8049002:	5b                   	pop    %ebx
 8049003:	a1 00 a0 04 08       	mov    0x804a000,%eax
 8049008:	3b 03                	cmp    (%ebx),%eax
 804900a:	74 02                	je     804900e <_start.goodjob>
 804900c:	eb 18                	jmp    8049026 <_start.wrong>

0804900e <_start.goodjob>:
 804900e:	b8 04 00 00 00       	mov    $0x4,%eax
 8049013:	bb 01 00 00 00       	mov    $0x1,%ebx
 8049018:	b9 08 a0 04 08       	mov    $0x804a008,%ecx
 804901d:	ba 0e 00 00 00       	mov    $0xe,%edx
 8049022:	cd 80                	int    $0x80
 8049024:	eb 16                	jmp    804903c <_start.end>

08049026 <_start.wrong>:
 8049026:	b8 04 00 00 00       	mov    $0x4,%eax
 804902b:	bb 01 00 00 00       	mov    $0x1,%ebx
 8049030:	b9 16 a0 04 08       	mov    $0x804a016,%ecx
 8049035:	ba 07 00 00 00       	mov    $0x7,%edx
 804903a:	cd 80                	int    $0x80

0804903c <_start.end>:
 804903c:	b8 01 00 00 00       	mov    $0x1,%eax
 8049041:	31 db                	xor    %ebx,%ebx
 8049043:	cd 80                	int    $0x80

It is helpful to know the calling conventions for system calls on Linux/x86. Generally speaking, you place the number of the system call you wish to call into the EAX register, arguments in their corresponding registers, and issue an int 80 instruction to execute the call.

This is a handy reference that explains syscalls much better: http://shell-storm.org/shellcode/files/syscalls.html

With knowledge of how syscalls work and the chart above, this assembler translates into pseudo code:

if (arg == *0x804a000) {
    write(1, *0x804a008, 0xe);
} else {
    write(1, *0x804a016, 0x7);
}
exit(0);

On Linux, fd 1 is stdout

% grep STDOUT /usr/include/unistd.h
#define	STDOUT_FILENO	1	/* Standard output.  */

So this code basically writes a 14 byte (0xe) message to stdout if an argument equals whatever is in 0x804a000, otherwise it prints a 7 byte (0x7) message. After printing the appropriate message, the program exits with a value of 0.

Using gdb, it is easy to resolve what strings these are stored in the memory addresses 0x804a008, and 0x804a016:

% gdb -q run.exe 
Reading symbols from run.exe...
(gdb) x/s 0x804a008
0x804a008 <goodjobText>:	"You Got This!\nWrong!\n"<error: Cannot access memory at address 0x804a01d>
(gdb) x/s 0x804a016
0x804a016 <nope>:	"Wrong!\n"<error: Cannot access memory at address 0x804a01d>

After revising the pseudo code with these strings, it makes much more sense:

if (arg == *0x804a000) {
    write(1, "You Got This!\n", 14);
} else {
    write(1, "Wrong!\n", 7);
}
exit(0);

Now, let’s see what we need to set the argument to:

(gdb) x/s 0x804a000
0x804a000 <password>:	"P455w0rdYou Got This!\nWrong!\n"<error: Cannot access memory at address 0x804a01d>

Looks like “P455w0rd”. Let’s try it out:

(gdb) set args P455w0rd
(gdb) run
Starting program: /home/daniel/Downloads/run.exe P455w0rd
You Got This!
[Inferior 1 (process 56490) exited normally]
(gdb) set args wrongpass
(gdb) run
Starting program: /home/daniel/Downloads/run.exe wrongpass
Wrong!
[Inferior 1 (process 56503) exited normally]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s