picoGym Practice Challenges messy-malloc を勉強した記録

picoGym Practice Challenges messy-malloc
解けない。
一時撤退する。

# 問題

Can you take advantage of misused malloc calls to leak the secret through this service and get the flag? Connect with nc jupiter.challenges.picoctf.org 1541. Source.

入手ファイル

```
auth
auth.c
```

```
$ checksec ./auth
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
    FORTIFY:  Enabled
```

```c:auth.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#define LINE_MAX 256
#define ACCESS_CODE_LEN 16
#define FLAG_SIZE 64

struct user {
  char *username;
  char access_code[ACCESS_CODE_LEN];
  char *files;
};

struct user anon_user;
struct user *u;

void print_flag() {
  char flag[FLAG_SIZE];
  FILE *f = fopen("flag.txt", "r");
  if (f == NULL) {
    printf("Please make sure flag.txt exists\n");
    exit(0);
  }

  if ((fgets(flag, FLAG_SIZE, f)) == NULL){
    puts("Couldn't read flag file.");
    exit(1);
  };

  unsigned long ac1 = ((unsigned long *)u->access_code)[0];
  unsigned long ac2 = ((unsigned long *)u->access_code)[1];
  if (ac1 != 0x4343415f544f4f52 || ac2 != 0x45444f435f535345) {
    fprintf(stdout, "Incorrect Access Code: \"");
    for (int i = 0; i < ACCESS_CODE_LEN; i++) {
      putchar(u->access_code[i]);
    }
    fprintf(stdout, "\"\n");
    return;
  }
  
  puts(flag);
  fclose(f);
}

void menu() {
  puts("Commands:");
  puts("\tlogin - login as a user");
  puts("\tprint-flag - print the flag");
  puts("\tlogout - log out");
  puts("\tquit - exit the program");
}
 
const char *get_username(struct user *u) {
  if (u->username == NULL) {
    return "anon";
  }
  else {
    return u->username;
  }
}

int login() {
  u = malloc(sizeof(struct user));

  int username_len;
  puts("Please enter the length of your username");
  scanf("%d", &username_len);
  getc(stdin);

  char *username = malloc(username_len+1);
  u->username = username;

  puts("Please enter your username");
  if (fgets(username, username_len, stdin) == NULL) {
    puts("fgets failed");
    exit(-1);
  }

  char *end;
  if ((end=strchr(username, '\n')) != NULL) {
    end[0] = '\0';
  }
  
  return 0;
  
}

int logout() {
  char *user = u->username;
  if (u == &anon_user) {
    return -1;
  }
  else {
    free(u);
    free(user);
    u = &anon_user;
  }
  return 0;
}

int main(int argc, char **argv) {

  setbuf(stdout, NULL);

  char buf[LINE_MAX];

  memset(anon_user.access_code, 0, ACCESS_CODE_LEN);
  anon_user.username = NULL;

  u = &anon_user;
  
  menu();

  while(1) {
    puts("\nEnter your command:");
    fprintf(stdout, "[%s]> ", get_username(u));

    if(fgets(buf, LINE_MAX, stdin) == NULL)
      break;

    if (!strncmp(buf, "login", 5)){
      login();
    }
    else if(!strncmp(buf, "print-flag", 10)){
      print_flag();
    }
    else if(!strncmp(buf, "logout", 6)){
      logout();
    }
    else if(!strncmp(buf, "quit", 4)){
      return 0;
    }
    else{
      puts("Invalid option");
      menu();
    }
  }
}
```

# とりあえず動かしてみる

```
  if (ac1 != 0x4343415f544f4f52 || ac2 != 0x45444f435f535345) {
```

0x4343415f544f4f52
0x45444f435f535345

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/b47cc5fa-308d-a659-4a32-dff1d151d339.png)

アクセスコードは
ROOT_ACCESS_CODE

```
$ nc jupiter.challenges.picoctf.org 1541
Commands:
	login - login as a user
	print-flag - print the flag
	logout - log out
	quit - exit the program

Enter your command:
[anon]> login
Please enter the length of your username
33
Please enter your username
AAAAAAAAAAAAAAAAROOT_ACCESS_CODE

Enter your command:
[AAAAAAAAAAAAAAAAROOT_ACCESS_CODE]> Invalid option
Commands:
	login - login as a user
	print-flag - print the flag
	logout - log out
	quit - exit the program

Enter your command:
[AAAAAAAAAAAAAAAAROOT_ACCESS_CODE]> logout

Enter your command:
[anon]> login
Please enter the length of your username
33
Please enter your username
AAAAAAAAAAAAAAA

Enter your command:
[AAAAAAAAAAAAAAA]> print-flag
Incorrect Access Code: "ROOT_ACC"
```

失敗。

# 地道に行く


login

```
u = malloc(sizeof(struct user));
RAX: 0x603670
0x603670:	0x0000000000000000	0x0000000000000000
0x603680:	0x0000000000000000	0x0000000000000000
0x603690:	0x0000000000000000	0x0000000000020971
```

33

```
char *username = malloc(username_len+1);
RAX: 0x6036a0
gdb-peda$ x/20xg 0x603670
0x603670:	0x0000000000000000	0x0000000000000000
0x603680:	0x0000000000000000	0x0000000000000000
0x603690:	0x0000000000000000	0x0000000000000031
0x6036a0:	0x0000000000000000	0x0000000000000000
0x6036b0:	0x0000000000000000	0x0000000000000000
0x6036c0:	0x0000000000000000	0x0000000000020941
```

AAAAAAAAAAAAAAAAROOT_ACCESS_CODE [ctrl+d]

```
gdb-peda$ x/20xg 0x603670
0x603670:	0x00000000006036a0	0x0000000000000000
0x603680:	0x0000000000000000	0x0000000000000000
0x603690:	0x0000000000000000	0x0000000000000031
0x6036a0:	0x4141414141414141	0x4141414141414141
0x6036b0:	0x4343415f544f4f52	0x45444f435f535345
0x6036c0:	0x0000000000000000	0x0000000000020941
```

logout

free(u);

```
gdb-peda$ x/20xg 0x603670
0x603670:	0x0000000000000000	0x0000000000603010
0x603680:	0x0000000000000000	0x0000000000000000
0x603690:	0x0000000000000000	0x0000000000000031
0x6036a0:	0x4141414141414141	0x4141414141414141
0x6036b0:	0x4343415f544f4f52	0x45444f435f535345
0x6036c0:	0x0000000000000000	0x0000000000020941
gdb-peda$ heapinfo
(0x30)   tcache_entry[1](1): 0x603670
```

free(user);

```
gdb-peda$ x/20xg 0x603670
0x603670:	0x0000000000000000	0x0000000000603010
0x603680:	0x0000000000000000	0x0000000000000000
0x603690:	0x0000000000000000	0x0000000000000031
0x6036a0:	0x0000000000603670	0x0000000000603010
0x6036b0:	0x4343415f544f4f52	0x45444f435f535345
0x6036c0:	0x0000000000000000	0x0000000000020941
gdb-peda$ heapinfo
(0x30)   tcache_entry[1](2): 0x6036a0 --> 0x603670
```

login

```
RAX: 0x6036a0
gdb-peda$ x/20xg 0x603670
0x603670:	0x0000000000000000	0x0000000000603010
0x603680:	0x0000000000000000	0x0000000000000000
0x603690:	0x0000000000000000	0x0000000000000031
0x6036a0:	0x0000000000603670	0x0000000000000000
0x6036b0:	0x4343415f544f4f52	0x45444f435f535345
0x6036c0:	0x0000000000000000	0x0000000000020941
gdb-peda$ heapinfo
(0x30)   tcache_entry[1](1): 0x603670
```

1

```
RAX: 0x6036d0
gdb-peda$ x/20xg 0x603670
0x603670:	0x0000000000000000	0x0000000000603010
0x603680:	0x0000000000000000	0x0000000000000000
0x603690:	0x0000000000000000	0x0000000000000031
0x6036a0:	0x0000000000603670	0x0000000000000000
0x6036b0:	0x4343415f544f4f52	0x45444f435f535345
0x6036c0:	0x0000000000000000	0x0000000000000021
0x6036d0:	0x0000000000000000	0x0000000000000000
0x6036e0:	0x0000000000000000	0x0000000000020921
```
A

print-flag

```
gdb-peda$ x/x $rax+0x8
0x6036a8:	0x0000000000000000

gdb-peda$ x/x $rax+0x10
0x6036b0:	0x4343415f544f4f52
```

free した後 0x6036a0 に user構造体 が作られる

```
struct user {
  char *username;
  char access_code[ACCESS_CODE_LEN];
  char *files;
};
```

|user構造体  |サイズ  |
|---|---|
|usernameへのポインタ  |8バイト |
|access_code  |16バイト |
|filesへのポインタ  |8バイト |

ということは
AAAAAAAAAAAAAAAAROOT_ACCESS_CODE [ctrl+d]を
AAAAAAAAROOT_ACCESS_CODEAAAAAAAA [ctrl+d]にすればいいの？

```
gdb-peda$ x/20xg 0x603670
0x603670:	0x00000000006036a0	0x0000000000000000
0x603680:	0x0000000000000000	0x0000000000000000
0x603690:	0x0000000000000000	0x0000000000000031
0x6036a0:	0x4141414141414141	0x4343415f544f4f52
0x6036b0:	0x45444f435f535345	0x4141414141414141
0x6036c0:	0x0000000000000000	0x0000000000020941
```

free(user);

```
gdb-peda$ x/20xg 0x603670
0x603670:	0x0000000000000000	0x0000000000603010
0x603680:	0x0000000000000000	0x0000000000000000
0x603690:	0x0000000000000000	0x0000000000000031
0x6036a0:	0x0000000000603670	0x0000000000603010  <-- 消えた
0x6036b0:	0x45444f435f535345	0x4141414141414141
0x6036c0:	0x0000000000000000	0x0000000000020941
```

失敗
free(user);で 0x6036a8 の８バイトが消える