# pico ctf are you root

Let's take a look at the binary:

```
$	file auth 
auth: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=42ebad5f08a8e9d227f3783cc951f2737547e086, not stripped
$	pwn checksec auth 
[*] '/Hackery/pod/modules/heap_grooming/pico_areyouroot/auth'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
$	./auth 
Available commands:
	show - show your current user and authorization level
	login [name] - log in as [name]
	set-auth [level] - set your authorization level (must be below 5)
	get-flag - print the flag (requires authorization level 5)
	reset - log out and reset authorization level
	quit - exit the program

Enter your command:
> 
```

So we can see that we are dealing with a `64` bit binary, with a Stack Canary and NX. When we run it, we are prompted with a console where we can input arguments.

## Reversing

When we look at the main function in Ghidra, we see this:

```

undefined8 main(void)

{
  int cmdCheck;
  int iVar1;
  int setauthCheck;
  int getflagCheck;
  int resetCheck;
  int quitCheck;
  char *cmdBytesRead;
  char *__nptr;
  char *pcVar2;
  ulong uVar3;
  long in_FS_OFFSET;
  void **loggedIn;
  char cmd [6];
  char acStack530 [3];
  char acStack527 [511];
  long canary;
  
  canary = *(long *)(in_FS_OFFSET + 0x28);
  setbuf(stdout,(char *)0x0);
  menu();
  loggedIn = (void **)0x0;
  while( true ) {
    puts("\nEnter your command:");
    putchar(0x3e);
    putchar(0x20);
    cmdBytesRead = fgets(cmd,0x200,stdin);
    if (cmdBytesRead == (char *)0x0) break;
    cmdCheck = strncmp(cmd,"show",4);
    if (cmdCheck == 0) {
      if (loggedIn == (void **)0x0) {
        puts("Not logged in.");
      }
      else {
        printf("Logged in as %s [%u]\n",*loggedIn,(ulong)*(uint *)(loggedIn + 1));
      }
    }
    else {
      iVar1 = strncmp(cmd,"login",5);
      if (iVar1 == 0) {
        if (loggedIn == (void **)0x0) {
          __nptr = strtok(acStack530,"\n");
          if (__nptr == (char *)0x0) {
            puts("Invalid command");
          }
          else {
            loggedIn = (void **)malloc(0x10);
            if (loggedIn == (void **)0x0) {
              puts("malloc() returned NULL. Out of Memory\n");
                    /* WARNING: Subroutine does not return */
              exit(-1);
            }
            pcVar2 = strdup(__nptr);
            *loggedIn = (void *)(long)(int)pcVar2;
            printf("Logged in as \"%s\"\n",__nptr);
          }
        }
        else {
          puts("Already logged in. Reset first.");
        }
      }
      else {
        setauthCheck = strncmp(cmd,"set-auth",8);
        if (setauthCheck == 0) {
          if (loggedIn == (void **)0x0) {
            puts("Login first.");
          }
          else {
            __nptr = strtok(acStack527,"\n");
            if (__nptr == (char *)0x0) {
              puts("Invalid command");
            }
            else {
              uVar3 = strtoul(__nptr,(char **)0x0,10);
              if ((uint)uVar3 < 5) {
                *(uint *)(loggedIn + 1) = (uint)uVar3;
                printf("Set authorization level to \"%u\"\n",uVar3 & 0xffffffff);
              }
              else {
                puts("Can only set authorization level below 5");
              }
            }
          }
        }
        else {
          getflagCheck = strncmp(cmd,"get-flag",8);
          if (getflagCheck == 0) {
            if (loggedIn == (void **)0x0) {
              puts("Login first!");
            }
            else {
              if (*(int *)(loggedIn + 1) == 5) {
                give_flag();
              }
              else {
                puts("Must have authorization level 5.");
              }
            }
          }
          else {
            resetCheck = strncmp(cmd,"reset",5);
            if (resetCheck == 0) {
              if (loggedIn == (void **)0x0) {
                puts("Not logged in!");
              }
              else {
                free(*loggedIn);
                loggedIn = (void **)0x0;
                puts("Logged out!");
              }
            }
            else {
              quitCheck = strncmp(cmd,"quit",4);
              if (quitCheck == 0) break;
              puts("Invalid option");
              menu();
            }
          }
        }
      }
    }
  }
  if (canary == *(long *)(in_FS_OFFSET + 0x28)) {
    return 0;
  }
                    /* WARNING: Subroutine does not return */
  __stack_chk_fail();
}
```

So we can see that it prompts us for input, and checks if it is equal to a command. If it is, then it will run the command. Let's walk through the commands.

For `login` we see this:

```
      iVar1 = strncmp(cmd,"login",5);
      if (iVar1 == 0) {
        if (loggedIn == (void **)0x0) {
          __nptr = strtok(acStack530,"\n");
          if (__nptr == (char *)0x0) {
            puts("Invalid command");
          }
          else {
            loggedIn = (void **)malloc(0x10);
            if (loggedIn == (void **)0x0) {
              puts("malloc() returned NULL. Out of Memory\n");
                    /* WARNING: Subroutine does not return */
              exit(-1);
            }
            pcVar2 = strdup(__nptr);
            *loggedIn = (void *)(long)(int)pcVar2;
            printf("Logged in as \"%s\"\n",__nptr);
          }
        }
        else {
          puts("Already logged in. Reset first.");
        }
      }
```

So we can see, it does a check if we are already logged in. If we aren't then it will log us in, which will create a struct in the heap, which contains the following things:
```
0x0:	ptr to username (stored in heap)
0x8:	int representing auth level
```

For `reset` we see this:

```
            if (resetCheck == 0) {
              if (loggedIn == (void **)0x0) {
                puts("Not logged in!");
              }
              else {
                free(*loggedIn);
                loggedIn = (void **)0x0;
                puts("Logged out!");
              }
            }
```

So for this, if we are logged in, it will log us out. What that does is it frees the pointer for our username, and zeroes it out. However it does not free the user struct itself. For `set-auth` we see this:

```
        if (setauthCheck == 0) {
          if (loggedIn == (void **)0x0) {
            puts("Login first.");
          }
          else {
            __nptr = strtok(acStack527,"\n");
            if (__nptr == (char *)0x0) {
              puts("Invalid command");
            }
            else {
              uVar3 = strtoul(__nptr,(char **)0x0,10);
              if ((uint)uVar3 < 5) {
                *(uint *)(loggedIn + 1) = (uint)uVar3;
                printf("Set authorization level to \"%u\"\n",uVar3 & 0xffffffff);
              }
              else {
                puts("Can only set authorization leve