# Defcon Quals 2019 Speedrun-006


Let's take a look at the binary:
```
$    file speedrun-006
speedrun-006: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=69951b1d604dac8a5508bc[PII_REDACTED]8e7af1c1, not stripped
$    pwn checksec speedrun-006
[*] '/Hackery/defcon/s6/speedrun-006'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
$    ./speedrun-006
How good are you around the corners?
Send me your ride
15935728
You ain't ready.
guyinatuxedo@tux:/Hackery/defcon/s6$
```

SO we can see that it is a `64` bit binary with all of the standard binary mitigations, that prompts us for input when we run it. Looking at the main function in Ghidra, we see this:

```
undefined8 main(undefined4 uParm1,undefined8 uParm2)

{
  char *pcVar1;
  long in_FS_OFFSET;
  undefined local_78 [80];
  undefined8 local_28;
  undefined4 local_1c;
  long local_10;
 
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  local_28 = uParm2;
  local_1c = uParm1;
  setvbuf(stdout,(char *)0x0,2,0);
  pcVar1 = getenv("DEBUG");
  if (pcVar1 == (char *)0x0) {
    alarm(5);
  }
  say_hello(local_78);
  get_that_shellcode();
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
}
```

Looking through the code, the `get_that_shellcode` function seems to be the only thing that really interests us.

```
void get_that_shellcode(void)

{
  long lVar1;
  ssize_t bytesRead;
  size_t len;
  long in_FS_OFFSET;
  char input [26];
 
  lVar1 = *(long *)(in_FS_OFFSET + 0x28);
  puts("Send me your ride");
  bytesRead = read(0,input,0x1a);
  if ((int)bytesRead == 0x1a) {
    len = strlen(input);
    if (len == 0x1a) {
      shellcode_it(input,0x1a);
    }
    else {
      puts("You\'re not up to code.");
    }
  }
  else {
    puts("You ain\'t ready.");
  }
  if (lVar1 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}
```

Looking through the `get_that_shellcode` function, we see that it scans in `0x1a` bytes of data into `buf`. If it scans in `26` bytes (and none of them can be null bytes because it checks with a `strlen` call) it will run the `shellcode_it` function with our input as the argument:

```

/* WARNING: Could not reconcile some variable overlaps */

void shellcode_it(undefined5 *puParm1)

{
  long lVar1;
  undefined8 uVar2;
  undefined5 uVar3;
  undefined8 uVar4;
  undefined8 uVar5;
  undefined8 uVar6;
  undefined8 uVar7;
  undefined8 uVar8;
  undefined8 uVar9;
  undefined8 *shellcode;
  long in_FS_OFFSET;
  undefined2 uStack50;
  undefined2 uStack48;
  undefined5 uStack45;
  undefined4 uStack40;
  undefined4 local_24;
  undefined4 uStack32;
  undefined uStack28;
 
  uVar9 = clean._40_8_;
  uVar8 = clean._32_8_;
  uVar7 = clean._24_8_;
  uVar6 = clean._16_8_;
  uVar5 = clean._8_8_;
  uVar4 = clean._0_8_;
  lVar1 = *(long *)(in_FS_OFFSET + 0x28);
  uVar3 = *puParm1;
  uStack50 = (undefined2)*(undefined4 *)(puParm1 + 1);
  uStack48 = (undefined2)((uint)*(undefined4 *)(puParm1 + 1) >> 0x10);
  uStack45 = (undefined5)*(undefined8 *)((long)puParm1 + 9);
  uStack40 = CONCAT13(*(undefined *)((long)puParm1 + 0x11),
                      (int3)((ulong)*(undefined8 *)((long)puParm1 + 9) >> 0x28));
  uVar2 = *(undefined8 *)((long)puParm1 + 0x12);
  uStack32 = (undefined4)((ulong)uVar2 >> 0x18);
  uStack28 = (undefined)((ulong)uVar2 >> 0x38);
  local_24 = CONCAT31((int3)uVar2,0xcc);
  shellcode = (undefined8 *)mmap((void *)0x0,0x4e,7,0x22,-1,0);
  *shellcode = uVar4;
  shellcode[1] = uVar5;
  shellcode[2] = uVar6;
  shellcode[3] = uVar7;
  shellcode[4] = uVar8;
  shellcode[5] = uVar9;
  shellcode[6] = CONCAT26(uStack50,CONCAT15(0xcc,uVar3));
  shellcode[7] = CONCAT53(uStack45,CONCAT12(0xcc,uStack48));
  shellcode[8] = CONCAT44(local_24,uStack40);
  *(undefined4 *)(shellcode + 9) = uStack32;
  *(undefined2 *)((long)shellcode + 0x4c) = CONCAT11(0xcc,uStack28);
  (*(code *)shellcode)();
  if (lVar1 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}

rn *MK_FP(__FS__, 40LL) ^ v1;
}
```

So this function will run our shellcode. However before it does that it will alter our shellcode. It will append a bunch of xor statements before our shellcode, which will clear out all of the registers except for the rip register (this includes rsp, so we can't push/pop without crashing). In addition to that, it will insert the `0xcc` byte four times throughout our shellcode (at offsets 5, 10, 20, & 29). It may be a bit hard to tell here, however if we check with gdb it will tell us everything (that's how I reversed it when I first solved this). I will set a breakpoint for where our shellcode starts executing and look at what the shellcode is:

```
gef➤  b *shellcode_it+325
Breakpoint 1 at 0x9fe
gef➤  r
Starting program: /Hackery/pod/modules/crafting_shellcodePt1/defconquals19_s6/speedrun-006
How good are you around the corners?
Send me your ride
00000000
Program received signal SIGALRM, Alarm clock.[PII_REDACTED]0000000
[ Legend: Modified register | Code | Heap | Stack | String ]
────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x0               
$rbx   : 0x0               
$rcx   : 0x[PII_REDACTED]cc3030
$rdx   : 0x00007ffff7ff6000  →  0x3148e43148ed3148
$rsp   : 0x00007fffffffdd10  →  0x0000001a55554bed
$rbp   : 0x00007fffffffdd90  →  0x00007fffffffdde0  →  0x00007fffffffde60  →  0x[PII_REDACTED]554b40  →  <__libc_csu_init+0> push r15
$rsi   : 0x4e              
$rdi   : 0x0               
$rip   : 0x[PII_REDACTED]5549fe  →  <shellcode_it+325> call rdx
$r8    : 0xffffffff        
$r9    : 0x0               
$r10   : 0x22              
$r11   : 0x246             
$r12   : 0x[PII_REDACTED]554790  →  <_start+0> xor ebp, ebp
$r13   : 0x00007fffffffdf40  →  0x[PII_REDACTED]000001
$r14   : 0x0               
$r15   : 0x0               
$eflags: [zero CARRY PARITY adjust sign trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x0033 $ss: 0x002b $ds: 0x0000 $es: 0x0000 $fs: 0x0000 $gs: 0x0000
────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x00007fffffffdd10│+0x0000: 0x0000001a55554bed   ← $rsp
0x00007fffffffdd18│+0x0008: 0x00007fffffffddb0  →  "[PII_REDACTED][PII_REDACTED]00000"
0x00007fffffffdd20│+0x0010: 0x00007ffff7ff6000  →  0x3148e43148ed3148
0x00007fffffffdd28│+0x0018: 0x00007ffff7ff6000  →  0x3148e43148ed3148
0x00007fffffffdd30│+0x0020: 0x3148e43148ed3148
0x00007fffffffdd38│+0x0028: 0x48c93148db3148c0
0x00007fffffffdd40│+0x0030: 0xff3148f63148d231
0x00007fffffffdd48│+0x0038: 0x314dc9314dc0314d
──────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
   0x5555555