Zum Inhalt springen

„Shellcode“ – Versionsunterschied

aus Wikipedia, der freien Enzyklopädie
[gesichtete Version][gesichtete Version]
Inhalt gelöscht Inhalt hinzugefügt
K fix WP:WLW +1lf; 1 externer Link geändert
Keine Bearbeitungszusammenfassung
Zeile 1: Zeile 1:
'''Shellcode''' ist ein Begriff aus der [[Software]]-Programmierung und bezeichnet die in [[Opcode]]s umgewandelte Form von [[Assemblersprache]]nbefehlen, die einen oder mehrere bestimmte Befehle ausführen soll. In der Regel wird eine [[Kommandozeileninterpreter|Shell]] gestartet, daher auch der Name. Shellcodes werden in [[Pufferüberlauf]]- und anderen Dateninjektions-Attacken benutzt.
'''Shellcode''' ist ein Begriff aus der [[Programmierung]] und bezeichnet einen zumeist sehr kleinen Patch von in [[Opcode]]s umgewandelten [[Assemblersprache|Assemblerbefehlen]], mit denen beabsichtigt wird, ein Programm oder System zu manipulieren, oder für nicht vorgesehene Zwecke auszunutzen. Dabei wird oft versucht, eine [[Kommandozeileninterpreter|Shell]] zu starten, daher auch der Name. Shellcodes haben ihren Ursprung in [[Pufferüberlauf]]- und anderen Code-Injektions-Attacken, sie können aber auch bei [[Softwaretest|Software-]], insbesondere [[Penetrationstest (Informatik)|Penetrationstests]] zum Einsatz kommen, beim Experimentieren und in der Didaktik.

Die Umwandlung findet hierbei nur zu dem Zweck statt, die Anweisung so im Speicher zu platzieren (dies wird meist über einen sogenannten [[Pufferüberlauf]] erreicht), dass der Prozessor sie ausführt.


== Erstellen von Shellcodes ==
== Erstellen von Shellcodes ==
Zur Erzeugung von Shellcode kann der auszuführende Befehl in [[C (Programmiersprache)|C]] geschrieben und mit einem [[Compiler]] übersetzt werden. Das erzeugte Programm wird nun disassembliert (rückübersetzt) und die Funktionsweise des Programms in Assemblersprache nachprogrammiert. Viele Instruktionen können aber weggelassen oder verkürzt werden. Bei vielen Sicherheitslücken darf im Shellcode kein 0-Byte enthalten sein, weil dieses in C das String-Ende markiert. Manchmal müssen noch weitere Filter umgangen werden, beispielsweise werden nur Buchstaben und Zahlen zugelassen oder die Groß- und Kleinschreibung verändert.
Zur Erzeugung von Shellcode kann der auszuführende Befehl in [[C (Programmiersprache)|C]] geschrieben und mit einem [[Compiler]] übersetzt werden. Das erzeugte Programm wird nun disassembliert (rückübersetzt) und die Funktionsweise des Programms in Assemblersprache nachprogrammiert. Viele Instruktionen können aber weggelassen oder verkürzt werden. Bei vielen [[Exploit]]s darf im Shellcode kein [[Nullzeichen|0-Byte]] enthalten sein, weil dieses in C das String-Ende markiert. Im Allgemeinen müssen weitere Hindernisse umgangen werden, beispielsweise werden nur Buchstaben und Zahlen zugelassen oder die Groß- und Kleinschreibung verändert, oder es müssen bestimmte Offsets eingehalten werden, was etwa durch Auffüllen mit mehr oder minder kreativen Ketten von [[Nulloperation]]en (sog. ''NOP Slides'') erreicht werden kann.


Anstatt eigenen Code auszuführen, was nicht immer möglich ist (zum Beispiel bei [[OpenBSD]] oder unter Verwendung von [[Speicherschutz]]), kann man auch direkt zu gewünschten Funktionen springen, die beispielsweise im Programm selber oder einer geladenen [[Programmbibliothek|Bibliothek]], beispielsweise der libc vorhanden sind. Dieses Verfahren wird [[return into libc]] genannt.
Anstatt eigenen Code auszuführen, was nicht immer möglich ist (zum Beispiel bei Verwendung von [[Speicherschutz]]), kann man auch direkt zu gewünschten Funktionen springen, die beispielsweise im Programm selber oder einer geladenen [[Programmbibliothek|Bibliothek]], beispielsweise der libc vorhanden sind. Dieses Verfahren wird [[return into libc]] genannt.


== Beispiel ==
== Beispiel ==
Zeile 45: Zeile 43:


Dieser Code ist jedoch nicht sonderlich geschickt, da er Nullbytes enthält und recht lang ist. Zur Vermeidung von „unerwünschten Zeichen“ werden häufig auch Encoder verwendet, welche eine Maskierung und spätere Demaskierung dieser Zeichen ermöglichen und den Shellcode eventuell noch zusätzlich komprimieren. Es gibt auch noch andere Techniken, die Adresse des Strings herauszufinden, als einen „jmp“ oder „call“. Es ist beispielsweise möglich, lediglich <code>/bin/sh</code> auf den Stack zu pushen. Danach enthält der ''esp'' die Adresse.
Dieser Code ist jedoch nicht sonderlich geschickt, da er Nullbytes enthält und recht lang ist. Zur Vermeidung von „unerwünschten Zeichen“ werden häufig auch Encoder verwendet, welche eine Maskierung und spätere Demaskierung dieser Zeichen ermöglichen und den Shellcode eventuell noch zusätzlich komprimieren. Es gibt auch noch andere Techniken, die Adresse des Strings herauszufinden, als einen „jmp“ oder „call“. Es ist beispielsweise möglich, lediglich <code>/bin/sh</code> auf den Stack zu pushen. Danach enthält der ''esp'' die Adresse.

== Siehe auch ==
[[Heap Overflow]], [[return into libc]], [[double free()]], [[Exploit]], [[Assembler (Informatik)|Assembler]]


== Literatur ==
== Literatur ==
Zeile 55: Zeile 50:
== Weblinks ==
== Weblinks ==
* [http://www.shell-storm.org/shellcode/ Shellcode database]
* [http://www.shell-storm.org/shellcode/ Shellcode database]
* [http://www.phrack.org/archives/57/p57_0x05_IA64%20shellcode_by_papasutra.txt Writing ia64 alphanumeric shellcodes]
* [http://wiki.hackerboard.de/index.php/Shellcode_(Exploit) Erstellen eines 32bit-Shellcodes mit Linux]
* [http://www.metasploit.com/ Shellcode generieren.] Metasploit Project


== Einzelnachweise ==
== Einzelnachweise ==

Version vom 8. November 2019, 22:21 Uhr

Shellcode ist ein Begriff aus der Programmierung und bezeichnet einen zumeist sehr kleinen Patch von in Opcodes umgewandelten Assemblerbefehlen, mit denen beabsichtigt wird, ein Programm oder System zu manipulieren, oder für nicht vorgesehene Zwecke auszunutzen. Dabei wird oft versucht, eine Shell zu starten, daher auch der Name. Shellcodes haben ihren Ursprung in Pufferüberlauf- und anderen Code-Injektions-Attacken, sie können aber auch bei Software-, insbesondere Penetrationstests zum Einsatz kommen, beim Experimentieren und in der Didaktik.

Erstellen von Shellcodes

Zur Erzeugung von Shellcode kann der auszuführende Befehl in C geschrieben und mit einem Compiler übersetzt werden. Das erzeugte Programm wird nun disassembliert (rückübersetzt) und die Funktionsweise des Programms in Assemblersprache nachprogrammiert. Viele Instruktionen können aber weggelassen oder verkürzt werden. Bei vielen Exploits darf im Shellcode kein 0-Byte enthalten sein, weil dieses in C das String-Ende markiert. Im Allgemeinen müssen weitere Hindernisse umgangen werden, beispielsweise werden nur Buchstaben und Zahlen zugelassen oder die Groß- und Kleinschreibung verändert, oder es müssen bestimmte Offsets eingehalten werden, was etwa durch Auffüllen mit mehr oder minder kreativen Ketten von Nulloperationen (sog. NOP Slides) erreicht werden kann.

Anstatt eigenen Code auszuführen, was nicht immer möglich ist (zum Beispiel bei Verwendung von Speicherschutz), kann man auch direkt zu gewünschten Funktionen springen, die beispielsweise im Programm selber oder einer geladenen Bibliothek, beispielsweise der libc vorhanden sind. Dieses Verfahren wird return into libc genannt.

Beispiel

Lokaler execve(/bin/sh) Shellcode

Der Assembler Code (x86-Architektur):[1]

void main() {
__asm__("
jmp 0x2a            # 3 bytes - springt direkt vor den String
popl %esi           # 1 byte - Adresse des Strings wird in esi geladen
movl %esi,0x8(%esi) # 3 bytes - die Adresse des Strings wird in den Speicher geschrieben
movb $0x0,0x7(%esi) # 4 bytes - der String wird nullterminiert
movl $0x0,0xc(%esi) # 7 bytes - ein nullpointer für das environment
movl $0xb,%eax      # 5 bytes - syscall-nummer in eax
movl %esi,%ebx      # 2 bytes - ebx enthält die adresse von "/bin/sh"
leal 0x8(%esi),%ecx # 3 bytes - argumente, ein pointer auf den string und ein nullpointer
leal 0xc(%esi),%edx # 3 bytes - environment
int $0x80           # 2 bytes - interrupt wird ausgelöst
movl $0x1, %eax     # 5 bytes - exit-interrupt
movl $0x0, %ebx     # 5 bytes - wird vorbereitet
int $0x80           # 2 bytes - interrupt wird ausgelöst
call -0x2f          # 5 bytes - ein call zurück, dabei wird der eip auf den Stack gepusht
.string \"/bin/sh\" # 8 bytes
");
}

Der Opcode String:

char shellcode[] =
"\xeb\x2a\x5e\x89\x76\x08\xc6\x46\x07\x00\xc7\x46\x0c\x00\x00\x00"
"\x00\xb8\x0b\x00\x00\x00\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80"
"\xb8\x01\x00\x00\x00\xbb\x00\x00\x00\x00\xcd\x80\xe8\xd1\xff\xff"
"\xff\x2f\x62\x69\x6e\x2f\x73\x68\x00\x89\xec\x5d\xc3";

Dieser Code ist jedoch nicht sonderlich geschickt, da er Nullbytes enthält und recht lang ist. Zur Vermeidung von „unerwünschten Zeichen“ werden häufig auch Encoder verwendet, welche eine Maskierung und spätere Demaskierung dieser Zeichen ermöglichen und den Shellcode eventuell noch zusätzlich komprimieren. Es gibt auch noch andere Techniken, die Adresse des Strings herauszufinden, als einen „jmp“ oder „call“. Es ist beispielsweise möglich, lediglich /bin/sh auf den Stack zu pushen. Danach enthält der esp die Adresse.

Literatur

  • Jack Koziol: The Shellcoder’s Handbook. Discovering and Exploiting Security Holes. Wiley, Indianapolis IN 2004, ISBN 0-7645-4468-3.
  • Jon Erickson: Forbidden Code. mitp, Bonn 2004, ISBN 3-8266-1457-7.

Einzelnachweise

  1. Quelle: phrack.org (Memento vom 11. Februar 2008 im Internet Archive)