4 minute read

In Level13 we are given the following code:

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

    #define FAKEUID 1000

    int main(int argc, char **argv, char **envp)
    {
      int c;
      char token[256];

      if(getuid() != FAKEUID) {
          printf("Security failure detected. UID %d started us, we expect %d\n", getuid(), FAKEUID);
          printf("The system administrators will be notified of this violation\n");
          exit(EXIT_FAILURE);
      }

      // snip, sorry :)

      printf("your token is %s\n", token);

    }

In order to receive the token we need to FAKE our UID to bypass the if statement.

Now, we could solve this a few different ways. The two that pop into mind are: 1.) Write a fake getuid() program to trick the call. 2.) Use a debugger.

I personally decided to use a debugger to refresh some of my knowledge, but don’t let my decision dictate yours.

Small caveat: This blog post is not an extensive walk-through on how to use a debugger. There are tons of better resources to learn up on gdb.

Let’s load the program into gdb, which my friend Derrick refers to as “The real man’s debugger,” and set a breakpoint at main:

    level13@nebula:/home/flag13$ gdb flag13
    GNU gdb (Ubuntu/Linaro 7.3-0ubuntu2) 7.3-2011.08
    Copyright (C) 2011 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "i686-linux-gnu".
    For bug reporting instructions, please see:
    <http://bugs.launchpad.net/gdb-linaro/>...
    Reading symbols from /home/flag13/flag13...(no debugging symbols found)...done.
    (gdb) break main
    Breakpoint 1 at 0x80484c9

Looks good, let’s run it:

    (gdb) r
    Starting program: /home/flag13/flag13

    Breakpoint 1, 0x080484c9 in main ()
    (gdb) x/20i main
       0x80484c4 <main>:	  push   %ebp
       0x80484c5 <main+1>:	mov    %esp,%ebp
       0x80484c7 <main+3>:	push   %edi
       0x80484c8 <main+4>:	push   %ebx
    => 0x80484c9 <main+5>:	and    $0xfffffff0,%esp
       0x80484cc <main+8>:	sub    $0x130,%esp
       0x80484d2 <main+14>:	mov    0xc(%ebp),%eax
       0x80484d5 <main+17>:	mov    %eax,0x1c(%esp)
       0x80484d9 <main+21>:	mov    0x10(%ebp),%eax
       0x80484dc <main+24>:	mov    %eax,0x18(%esp)
       0x80484e0 <main+28>:	mov    %gs:0x14,%eax
       0x80484e6 <main+34>:	mov    %eax,0x12c(%esp)
       0x80484ed <main+41>:	xor    %eax,%eax
       0x80484ef <main+43>:	call   0x80483c0 <getuid@plt>
       0x80484f4 <main+48>:	cmp    $0x3e8,%eax
       0x80484f9 <main+53>:	je     0x8048531 <main+109>
       0x80484fb <main+55>:	call   0x80483c0 <getuid@plt>
       0x8048500 <main+60>:	mov    $0x80486d0,%edx
       0x8048505 <main+65>:	movl   $0x3e8,0x8(%esp)
       0x804850d <main+73>:	mov    %eax,0x4(%esp)

We hit our first breakpoint and I run x/20i main to view the first 20 lines of the main() function.

I set another break using break *main + 48 and continued stepping through:

    (gdb) break *main + 48
    Breakpoint 2 at 0x80484f4
    (gdb) cont
    Continuing.

FYI: The new breakpoint is set at 0x80484f4, which is right after the first getuid@plt call. As you can see in main(), the program compares $0x3e8 (1000 in Hex) and %eax.

    Breakpoint 2, 0x080484f4 in main ()
    (gdb) print $eax
    $1 = 1014
    (gdb) set $eax = 1000
    (gdb) print $eax
    $2 = 1000

Next, we check $eax, which is currently set at 1014. Looking back at the source code, this UID will cause us to fall into the if block and generate the error message, so we modify $eax to our fake id of 1000.

As we continue, the if statement evaluates to false and we are presented with the token.

       (gdb) cont
       Continuing.
       your token is b705702b-76a8-42b0-8844-3adabbe5ac58
       [Inferior 1 (process 3567) exited with code 063]

Let’s try logging into the flag13 account with the token:

    $ ssh flag13@192.168.98.138

          _   __     __          __
         / | / /__  / /_  __  __/ /___ _
        /  |/ / _ \/ __ \/ / / / / __ `/
       / /|  /  __/ /_/ / /_/ / / /_/ /
      /_/ |_/\___/_.___/\__,_/_/\__,_/

        exploit-exercises.com/nebula


    For level descriptions, please see the above URL.

    To log in, use the username of "levelXX" and password "levelXX", where
    XX is the level number.

    Currently there are 20 levels (00 - 19).


    flag13@192.168.98.138's password:
    Welcome to Ubuntu 11.10 (GNU/Linux 3.0.0-12-generic i686)

     * Documentation:  https://help.ubuntu.com/
    New release '12.04 LTS' available.
    Run 'do-release-upgrade' to upgrade to it.


    The programs included with the Ubuntu system are free software;
    the exact distribution terms for each program are described in the
    individual files in /usr/share/doc/*/copyright.

    Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
    applicable law.

    flag13@nebula:~$ id
    uid=986(flag13) gid=986(flag13) groups=986(flag13)
    flag13@nebula:~$ getflag
    You have successfully executed getflag on a target account

It worked. This was one of my favorite levels so far!

Mike

comments powered by Disqus