0

I have two questions related to C programming and shellcoding (assembly) following below.

Question 1: Can anyone provide an answer on why putting two shellcodes in one program wouldn't work? I know it's related to the memory region but I need to know the exact reason. Program is compiled using gcc with the -zexecstack and -fno-stack-protector options.

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

main(int argc, char *argv[])
{

  unsigned char shellcode[] = "\x01\x02<SHELLCODE>";

  /* if the below line is uncommmented it will result in segault */ 
  /* unsigned char shellcode_[] = "\x01\x02<SHELLCODE>"; */

  int (*ret)() = (int(*)())shellcode;
  return 0;
}

So how would it be possible to divide multiple shellcodes into different memory regions and call them without them interrupting the execution flow between each other, and decide which one to call? (I mean just STORE two shellcodes, not RUN them simultaneously, if that's possible at all).

Question 2: if the shellcode has to be passed as a parameter to a function, what would be the proper way to do it?

Pseudocode:

unsigned char shellcode[]  = "\x01\x02...";

void call_shellcode(unsigned char shellcode[200]);
main()
{
   call_shellcode(shellcode);
}

void call_shellcode(unsigned char shellcode[200])
{
   ... print/call shellcode
}

UPDATE: As there seems to be some misunderstanding to the question, this is not the ACTUAL shellcode. I do know what shellcode is and how it is generated, and how it works. I have not provided an actual shellcode within the C stub to leave it in a readable state. The value "\x01\x01" is a pseudo code to point to the idea of the question and NOT any actual contents.

  • 1
    Please make your answer reproducible by including the full, exact shellcode that you're trying to run. – Joseph Sible-Reinstate Monica Jul 14 '22 at 23:53
  • 2
    Uncommenting won't give you a fault, because you are not calling any shellcode. You can have as many shellcodes as you want, especially artificial ones like these. If you get a fault use the debugger to see why. To pass a shellcode to a function just pass a pointer to it. – Margaret Bloom Jul 15 '22 at 08:05
  • @asmquestions you do know that it will result in segfaults and not in segfaults - depending on the shellcode? ;) and; also - "I have not provided an actual shellcode within the C stub to leave it in a readable state" - `I doubt it would become unreadable if you would include the original shellcode..` if you can't include it, **please kindly link to it**. so the code will stay as it is; and we can see the original shellcode, win win! :) – William Martens Jul 17 '22 at 18:41
  • @asmquestions; Also; it results in segfaults? can you dump it and include that? it would be **extremely helpful** :) – William Martens Jul 17 '22 at 18:43

2 Answers2

1

Your shellcode cannot possibly work for a very simple reason: it begins with \x01\x02:

unsigned char shellcode[] = "\x01\x02<SHELLCODE>";

I'm not sure why your think your shellcode has to begin with those two bytes: it really doesn't!

Those two bytes decode to add DWORD PTR [rdx],eax (or edx if running in 32-bit mode). Since you do not have any control over the value of RDX/EDX at the time your shellcode is called, it will very likely immediately cause a segmentation fault because RDX/EDX does not contain a valid (and writable) memory address.

Changing literally anything around the shellcode, in the function or outside, could cause the compiler to choose a different register allocation that will result in RDX/EDX having a good value at runtime that doesn't result in a crash, but that'd just be a lucky coincidence. Writing and using shellcode like this is inherently undefined behavior, or at least implementation defined (fixed an operating system and compiler) so extra care must be taken.

So how would it be possible to divide multiple shellcodes into different memory regions and call them without them interrupting the execution flow between each other, and decide which one to call?

Well, you're not really dividing anything in "different memory regions"... whether you use one array or two or ten, they are all declared on the stack and they will be close together on the stack.

If you want to jump from one to the other, that's going to be a complex task, because in general you do not know the location of a variable on the stack beforehand, so you will have to do some math calculating your current location and then the offset from one shellcode chunk to the other, ultimately performing a relative call/jump.

If shellcode has to be passed as a parameter to a function what would be the proper way to do this?

The proper way is to mmap a region of memory that is RWX, write the shellcode into it (memcpy, read from stdin, etc.) and then pass a pointer to that memory region to the function you want. You have no guarantee that a piece of global data will be put by the compiler in an executable memory region. In fact, no modern day compiler would do that, and furthermore, no modern day kernel would map such a region as executable even if the ELF is compiled with -z execstack.

In recent kernels -z execstack is only respected for the stack itself, so passing a shellcode as function argument through a variable will only work if the variable was defined on the stack.

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
  • please see update to the question - the answers from your quoted paragraph onwards is exactly what I needed to know, thanks. The code provided was a pseudo-code only and it was related to actual working shellcodes which were executing properly when compiled separately but not when stored in one program. – asmquestions Jul 15 '22 at 15:03
  • @asmquestions saw the update. Glad I could clarify some doubts for you. Unfortunately we cannot really tell you why your shellcode crashes if you do not show exactly what its content is. I can guess that the reasoning is similar to the one I explain above though: you are probably doing operations with invalid register values, or fail to calculate correct memory addresses when reading/writing memory or jumping/calling something. You might want to post another question for that, providing a [mre]. – Marco Bonelli Jul 15 '22 at 15:21
  • If you put `unsigned char shellcode[] = "..."` in a function (not global scope, @asmquestions), and pass it to another, then it'll still be on the stack and thus affected by `-z execstack` ([even with recent kernels](https://stackoverflow.com/questions/9960721/how-to-get-c-code-to-execute-hex-machine-code/55893781#55893781)). But yeah, if the callee can't assume that, it should allocate a RWX page and copy it, or `mprotect` the page containing the original. (Very few programs depend on a page *not* being writeable or executable for correctness, so that's fine for playing around). – Peter Cordes Jul 15 '22 at 15:55
  • @asmquestions: if you want to show "dummy" placeholder code, it's always a bad idea if it includes something that would actually produce the problem you're asking about. `"\xC3"` (ret) would make much more sense, if it's code that actually returns, and thus just a hand-written asm function, not truly "shellcode" at all. People writing answers can't assume you don't have that part literally, since we don't know exactly what you do/don't understand. Someone that fully knew what they were doing wouldn't have had to ask on SO in the first place, they'd just use GDB to find the crash. – Peter Cordes Jul 15 '22 at 15:57
  • @Marco Bonelli and Peter Cordes thank you for your answers, I just assumed it's better not to include the actual shellcodes and write pseudo code instead, didn't even think someone may go there and consider I have actual non-sense within the shellcode value – asmquestions Jul 15 '22 at 17:23
  • @asmquestions I do not know where you got that idea from.. changing code contents; then asking for help? how would one solve; if we dont have the correct code? – William Martens Jul 17 '22 at 18:25
-2

You can't have two variables with the same name in the same scope (this part has nothing to do with what the variables are or how they are used). Simply give the second shellcode a different name.

Note I am not going to comment at all on what you are trying to do, other than that I would not think of manually created machine code as "shell code" (which I would usually think of as code intended for a command shell like bash).

SoronelHaetir
  • 14,104
  • 1
  • 12
  • 23
  • Hi, note that variable names are different (the second is with an underscore). The reason for the segfault is not how the variables are named (not sure that the program would even compile with duplicate variables). – asmquestions Jul 14 '22 at 18:03
  • 2
    "shellcode" is machine code you can inject via a code-execution vulnerability, typically which executes `/bin/sh` (with its stdin connected to the network connection you exploited, so you can then send shell commands on the same connection as the exploit.) It's a well-established term. It often gets generalized (arguably mis-used) to describe any snippet of machine-code that's been hexdumped into a C string, regardless of opening a shell. Sometimes even if it's just a plain function that will return, but I'd consider that a misuse. – Peter Cordes Jul 15 '22 at 11:00
  • 1
    https://en.wikipedia.org/wiki/Shellcode – Marco Bonelli Jul 15 '22 at 14:01
  • I know what shellcode is, see update to the question - you are the values provided too literally where some pseudo code as been provided for readability. – asmquestions Jul 15 '22 at 15:08