1

When I execute the shellcode in the main function, it works fine. However, when I execute it by other function called by main, it will cause Segmentation fault. As far as I know, function call should influence the stack, and the shellcode should be in the heap. Is there something wrong in my code?

The shellcode is generated by matesploit, and I use qemu-arm to run the program.

The code is:

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

// msfvenom -p linux/armle/exec CMD=/bin/pwd -f c
unsigned char buf[] = 
"\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x78\x46\x0a\x30\x01\x90\x01"
"\xa9\x92\x1a\x0b\x27\x01\xdf\x2f\x62\x69\x6e\x2f\x70\x77\x64";

void runShellCode(){
    unsigned char *pShellCode = (unsigned char *)calloc(1, 4096);
    memcpy(pShellCode, buf, sizeof(buf));
    (*(void(*)()) pShellCode)();
}

int main(int argc, char *argv[])
{
    // uncomment these lines it will work perfectly fine
    // unsigned char *pShellCode = (unsigned char *)calloc(1, 4096);
    // memcpy(pShellCode, buf, sizeof(buf));
    // (*(void(*)()) pShellCode)();

    runShellCode();
    return 0;
}

The cmd to compile & run:

arm-linux-gnueabi-gcc test.c -o test_arm -static
qemu-arm test_arm

The disassembly code of the shellcode(which is uncorrect so I delete it)


Update the code with mmap() way. However, if the argment of the main() is void, it works fine. While the argument is int argc, char *argv[], it will cause SEGV.

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <sys/mman.h>

// msfvenom -p linux/armle/exec CMD=/bin/pwd -f c
unsigned char buf[] = 
"\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x78\x46\x0a\x30\x01\x90\x01"
"\xa9\x92\x1a\x0b\x27\x01\xdf\x2f\x62\x69\x6e\x2f\x70\x77\x64";

int main(int argc, char *argv[])
//int main(void)
{
    unsigned char *pShellCode = (unsigned char *)calloc(1, 4096);
    memcpy(pShellCode, buf, sizeof(buf));
    
    void (*sc) () = NULL;
    sc = mmap (0, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
    memcpy (sc, pShellCode, 4096);
    __builtin___clear_cache (sc, sc + sizeof(sc));
    sc();

    return 0;
}
Marsman
  • 66
  • 5
  • 1
    It would be helpful if you could give us a disassembly listing of your `buf[]` array, and an explanation of what it is trying to do. – TonyK Aug 05 '20 at 15:27
  • The shellcode is trying to run the cmd '/bin/pwd' as the comment says, and I update the disassembly list. – Marsman Aug 05 '20 at 15:58
  • 2
    That disassembly listing looks like gibberish to me. – TonyK Aug 05 '20 at 16:05

1 Answers1

0

the posted code results in:

untitled1.c:14:7: warning: ISO C forbids conversion of object pointer to function pointer type [-Wpedantic]

Linux/Unix specific:

You need a memory page with `write execute` permissions. 

See `mmap(2)` and `mprotect(2)`. 

Windows-specific:

`VirtualAlloc()` function to reserve memory 

`VirtualProtect()` function to mark as executable
applying, for instance, the `PAGE_EXECUTE_READ` flag.

you can cast the pointer to the allocated memory
to an appropriate function pointer type 
and just call the function. 

`VirtualFree()` function to clean up afterwards

regarding your EDIT section:

The revised code, when run through the compiler, results in:

gcc -ggdb3 -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled1.c" -o "untitled1.o" (in directory: /home/richard/Documents/forum)
untitled1.c: In function ‘main’:
untitled1.c:18:8: warning: ISO C forbids assignment between function pointer and ‘void *’ [-Wpedantic]
     sc = mmap (0, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
        ^
untitled1.c:19:13: warning: ISO C forbids passing argument 1 of ‘memcpy’ between function pointer and ‘void *’ [-Wpedantic]
     memcpy (sc, pShellCode, 4096);
             ^~
In file included from /usr/include/memory.h:29:0,
                 from untitled1.c:3:
/usr/include/string.h:42:14: note: expected ‘void * restrict’ but argument is of type ‘void (*)()’
 extern void *memcpy (void *__restrict __dest, const void *__restrict __src,
              ^~~~~~
untitled1.c:20:37: warning: pointer to a function used in arithmetic [-Wpointer-arith]
     __builtin___clear_cache (sc, sc + sizeof(sc));
                                     ^
untitled1.c:20:30: warning: ISO C forbids passing argument 1 of ‘__builtin___clear_cache’ between function pointer and ‘void *’ [-Wpedantic]
     __builtin___clear_cache (sc, sc + sizeof(sc));
                              ^~
untitled1.c:20:30: note: expected ‘void *’ but argument is of type ‘void (*)()’
untitled1.c:20:34: warning: ISO C forbids passing argument 2 of ‘__builtin___clear_cache’ between function pointer and ‘void *’ [-Wpedantic]
     __builtin___clear_cache (sc, sc + sizeof(sc));
                                  ^~
untitled1.c:20:34: note: expected ‘void *’ but argument is of type ‘void (*)()’
untitled1.c:11:14: warning: unused parameter ‘argc’ [-Wunused-parameter]
 int main(int argc, char *argv[])
              ^~~~
untitled1.c:11:26: warning: unused parameter ‘argv’ [-Wunused-parameter]
 int main(int argc, char *argv[])
                          ^~~~
Compilation finished successfully.

Even though the compiler outputs: Compilation finished successfully That does not mean the resulting code is correct. What is does mean is the compiler substituted some 'work around' for each of the 'warnings'. It does not mean the result is what you want.

Please read executable data for some idea on how to execute data.

user3629249
  • 16,402
  • 1
  • 16
  • 17
  • Do you have any idea why it would work when called from `main()`? I'd expect the permissions on memory allocated by `calloc` would be the same, regardless of where it is called from. – Nate Eldredge Aug 05 '20 at 18:14
  • I suspect that 'working in main()' is just a coincidental event. I gave the correct way in my answer. – user3629249 Aug 05 '20 at 19:51
  • Yeah, but if the heap is normally not executable, it should be impossible for it to work at all, coincidence or no. – Nate Eldredge Aug 05 '20 at 19:59
  • Thanks for the reply! I update the code with `mmap()`, but it still can not be executed. And even in the `main()` it would not work unless the argument is `void`. – Marsman Aug 06 '20 at 01:09
  • Could it be the problem of qemu? And may I ask whether the two problems could be reproduced in your environment? Thanks. – Marsman Aug 06 '20 at 01:12
  • so you have applied `mmap()` Now you need to apply `mprotect()` to that same memory. – user3629249 Aug 06 '20 at 16:44