Gracker level1 (GDB basics)

Try the challenge thoroughly before reading the write-up. Otherwise, it's your loss.

We access level1 by ssh [email protected] with the password we read when we solved level0. Do read the story of this level.

Recap of previous level

The recap of the level0 provides a detailed write-up which is different than my method in the previous post. Do check it out. In fact, it’s a hint for level1 ;) . We were right, the flag was indeed hardcoded.

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>

char secret_password[] = "s3cr3t_backd00r_passw0rd";

int main (int argc, char *argv[]) {
    gid_t gid;
    uid_t uid;
    char password_input[32];
    char *pos;

    gid = getegid();
    uid = geteuid();

    setresgid(gid, gid, gid);
    setresuid(uid, uid, uid);

    printf(" _____\n| _ _ |\n|| | || Hidden\n||_|_||   Backdoor\n| _ _ o  by \n|| | ||     ~Zero Cool\n||_|_||  \n|_____|\n\nEnter Secret Password:\n");

    read(STDIN_FILENO, password_input, 32);
    password_input[31]='\0';

    if ((pos=strchr(password_input, '\n')) != NULL) *pos = '\0';

    if(strcmp(password_input,secret_password)==0) {
        printf("Correct! Here is the level1 shell.\nRead the level1 password in /home/level1/.pass to login with `ssh [email protected]`\n");
        system("/bin/sh");
    } else{
        printf("wrong!");
    }

    return 0;
}

Level 1

We try the same technique that we used in level0, the strings command. But of course it doesn’t work. It seems Zero Cool has somehow managed to allow authentication without having to hardcode the password. Let’s get our hands a bit dirty by examining the disassmebly using gdb.

[email protected]:/matrix/level1$ gdb level1 -q
Reading symbols from level1...(no debugging symbols found)...done.
(gdb) disas main
Dump of assembler code for function main:
   0x000000000040083d <+0>:	push   %rbp
   0x000000000040083e <+1>:	mov    %rsp,%rbp
   0x0000000000400841 <+4>:	push   %rbx
   0x0000000000400842 <+5>:	sub    $0x48,%rsp
   0x0000000000400846 <+9>:	mov    %edi,-0x44(%rbp)
   0x0000000000400849 <+12>:	mov    %rsi,-0x50(%rbp)
   0x000000000040084d <+16>:	mov    $0x4009b0,%edi
   0x0000000000400852 <+21>:	callq  0x400620 <[email protected]>
   0x0000000000400857 <+26>:	lea    -0x40(%rbp),%rax
   0x000000000040085b <+30>:	mov    $0x20,%edx
   0x0000000000400860 <+35>:	mov    %rax,%rsi
   0x0000000000400863 <+38>:	mov    $0x0,%edi
   0x0000000000400868 <+43>:	callq  0x4006a0 <read@plt>
   0x000000000040086d <+48>:	movb   $0x0,-0x21(%rbp)
   0x0000000000400871 <+52>:	lea    -0x40(%rbp),%rax
   0x0000000000400875 <+56>:	mov    $0xa,%esi
   0x000000000040087a <+61>:	mov    %rax,%rdi
   0x000000000040087d <+64>:	callq  0x400670 <[email protected]>
   0x0000000000400882 <+69>:	mov    %rax,-0x20(%rbp)
   0x0000000000400886 <+73>:	cmpq   $0x0,-0x20(%rbp)
   0x000000000040088b <+78>:	je     0x400894 <main+87>
   0x000000000040088d <+80>:	mov    -0x20(%rbp),%rax
   0x0000000000400891 <+84>:	movb   $0x0,(%rax)
   0x0000000000400894 <+87>:	movl   $0x0,-0x14(%rbp)
   0x000000000040089b <+94>:	jmp    0x4008c1 <main+132>
   0x000000000040089d <+96>:	mov    -0x14(%rbp),%eax
   0x00000000004008a0 <+99>:	cltq   
   0x00000000004008a2 <+101>:	movzbl 0x600e40(%rax),%eax
   0x00000000004008a9 <+108>:	movzbl 0x2005ad(%rip),%edx        # 0x600e5d <XORkey>
   0x00000000004008b0 <+115>:	xor    %eax,%edx
   0x00000000004008b2 <+117>:	mov    -0x14(%rbp),%eax
   0x00000000004008b5 <+120>:	cltq   
   0x00000000004008b7 <+122>:	mov    %dl,0x600e40(%rax)
   0x00000000004008bd <+128>:	addl   $0x1,-0x14(%rbp)
   0x00000000004008c1 <+132>:	mov    -0x14(%rbp),%eax
   0x00000000004008c4 <+135>:	movslq %eax,%rbx
   0x00000000004008c7 <+138>:	mov    $0x600e40,%edi
   0x00000000004008cc <+143>:	callq  0x400640 <[email protected]>
   0x00000000004008d1 <+148>:	cmp    %rax,%rbx
   0x00000000004008d4 <+151>:	jb     0x40089d <main+96>
   0x00000000004008d6 <+153>:	lea    -0x40(%rbp),%rax
   0x00000000004008da <+157>:	mov    $0x600e40,%esi
   0x00000000004008df <+162>:	mov    %rax,%rdi
   0x00000000004008e2 <+165>:	callq  0x4006c0 <[email protected]>
   0x00000000004008e7 <+170>:	test   %eax,%eax
   0x00000000004008e9 <+172>:	jne    0x400901 <main+196>
   0x00000000004008eb <+174>:	mov    $0x4009e0,%edi
   0x00000000004008f0 <+179>:	callq  0x400620 <[email protected]>
   0x00000000004008f5 <+184>:	mov    $0x0,%eax
   0x00000000004008fa <+189>:	callq  0x4007e6 <spawn_shell>
   0x00000000004008ff <+194>:	jmp    0x400910 <main+211>
   0x0000000000400901 <+196>:	mov    $0x400a59,%edi
   0x0000000000400906 <+201>:	mov    $0x0,%eax
   0x000000000040090b <+206>:	callq  0x400680 <printf@plt>
   0x0000000000400910 <+211>:	mov    $0x0,%eax
   0x0000000000400915 <+216>:	add    $0x48,%rsp
   0x0000000000400919 <+220>:	pop    %rbx
   0x000000000040091a <+221>:	pop    %rbp
   0x000000000040091b <+222>:	retq   
End of assembler dump.
(gdb)

The following lines seem to be the ones doing the check against the password, as seen by the call to strcmp. This would be a good place to examine .

   
   0x00000000004008d6 <+153>:	lea    -0x40(%rbp),%rax
   0x00000000004008da <+157>:	mov    $0x600e40,%esi
   0x00000000004008df <+162>:	mov    %rax,%rdi
   0x00000000004008e2 <+165>:	callq  0x4006c0 <[email protected]>
   0x00000000004008e7 <+170>:	test   %eax,%eax
   0x00000000004008e9 <+172>:	jne    0x400901 <main+196>
   0x00000000004008eb <+174>:	mov    $0x4009e0,%edi
   0x00000000004008f0 <+179>:	callq  0x400620 <[email protected]>
   0x00000000004008f5 <+184>:	mov    $0x0,%eax
   0x00000000004008fa <+189>:	callq  0x4007e6 <spawn_shell>

So we set a breakpoint at the address where the comparison is being made: 0x00000000004008e2 using set b *0x00000000004008e2 . Now we don’t need to understand the entire assembly. We can examine the values of registers and memory addresses before the call to strcmp() is made, because that’s where our password and the actual password will be stored as parameters.

(gdb) b *0x00000000004008e2
Breakpoint 1 at 0x4008e2
(gdb) r
Starting program: /matrix/level1/level1 
~Zero Cool Simple Backdoor v2~
Enter Password:
AAAA

Breakpoint 1, 0x00000000004008e2 in main ()
(gdb) x/s $rax
0x7fffffffead0:	"AAAA"
(gdb) x/s $esi
0x600e40 <secret_password>:	"n0b0dy_gu3sses_thi5_passw0rd"
(gdb) 

So, the password we had entered had been stored in the rax register, and actual one in the esi register.

We now have the password to the binary. On running the binary with this password, we get:

[email protected]:/matrix/level1$ ./level1
~Zero Cool Simple Backdoor v2~
Enter Password:
n0b0dy_gu3sses_thi5_passw0rd
Correct! Here is the level2 shell.
Read the level2 password in /home/level2/.pass to login with `ssh [email protected]`
$ whoami
level2
$ 

And Voila! We now have level2 shell through which we can read the password to level2. I am not revealing the password here so that the readers try the challenge on their own.