# tamu 2019 pwn2

The goal of this challenge is to get the challenge to print the contents of `flag.txt`, not popping a shell.

Let's take a look at the binary:

```
$    file pwn2
pwn2: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=c3936da4c051f1ca58585ee8b243bc9c4a37e437, not stripped
$    pwn checksec pwn2
[*] '/Hackery/pod/modules/partial_overwrite/tamu19_pwn2/pwn2'
    Arch:     i386-32-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled
$    ./pwn2
Which function would you like to call?
15935728
```

So we can see that we are dealing with a `32` bit binary, with Relro, NX, and PIE. When we run it, it prompts us for input.

## Reversing

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

```

/* WARNING: Function: __x86.get_pc_thunk.bx replaced with injection: get_pc_thunk_bx */

undefined4 main(void)

{
  char input [31];
 
  setvbuf(stdout,(char *)0x2,0,0);
  puts("Which function would you like to call?");
  gets(input);
  select_func(input);
  return 0;
}
```

So we can see that it calls `gets` to scan in data into `input` (so we have one buffer overflow bug there). Before returning it passes our input to the `select_func` function:

```

/* WARNING: Function: __x86.get_pc_thunk.bx replaced with injection: get_pc_thunk_bx */

void select_func(char *param_1)

{
  int cmp;
  char input [30];
  undefined *functionCall;
 
  strncpy(input,param_1,0x1f);
  cmp = strcmp(input,"one");
  functionCall = two;
  if (cmp == 0) {
    functionCall = one;
  }
  (*(code *)functionCall)();
  return;
}
```

So we can see here, it makes an indirect call of the instruction pointer stored in `functionCall`. It is initialized to the function `two`, and if our input starts with `one\x00` it will be changed to the address of the function `one`. The first `0x1f` (`31`) bytes of our input passed in as an argument in copied to the char buffer `input`, which can only hold `30` bytes. This gives us a one byte overflow, which will allow us to overwrite the least significant byte of `functionCall`.

Also one other thing, a bit of the disassembly here is wrong. Specifically where `functionCall` is initialized to be the address of `two`. When we look at the assembly code, we see that it happens before the `strncpy` call:

```
        00010791 8d 83 f5        LEA        EAX,[0xffffe6f5 + EBX]=>two
                 e6 ff ff
        00010797 89 45 f4        MOV        dword ptr [EBP + functionCall],EAX=>two
        0001079a 83 ec 04        SUB        ESP,0x4
        0001079d 6a 1f           PUSH       0x1f
        0001079f ff 75 08        PUSH       dword ptr [EBP + param_1]
        000107a2 8d 45 d6        LEA        EAX=>input,[EBP + -0x2a]
        000107a5 50              PUSH       EAX
        000107a6 e8 a5 fd        CALL       strncpy                                          char * strncpy(char * __dest, ch
                 ff ff
```

Also we can see that if we can call the function `print_flag` at offset `0x6d8`, we get the flag.

```

/* WARNING: Function: __x86.get_pc_thunk.bx replaced with injection: get_pc_thunk_bx */

void print_flag(void)

{
  FILE *__fp;
  int iVar1;
 
  puts("This function is still under development.");
  __fp = fopen("flag.txt","r");
  while( true ) {
    iVar1 = _IO_getc((_IO_FILE *)__fp);
    if ((char)iVar1 == -1) break;
    putchar((int)(char)iVar1);
  }
  putchar(10);
  return;
}
```

## Exploitation

So we have a one byte overflow for the least significant byte of the function pointer that is called. Let's take a closer look at the address we are calling, and the address of `print_flag`:

```
gef➤  pie b *0x7d4
gef➤  pie run
Stopped due to shared library event (no libraries added or removed)
Which function would you like to call?[PII_REDACTED][PII_REDACTED][PII_REDACTED]

Breakpoint 1, 0x565557d4 in select_func ()
[+] base address 0x56555000
[ Legend: Modified register | Code | Heap | Stack | String ]
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$eax   : 0x56555631  →  <register_tm_clones+49> add BYTE PTR [eax], al
$ebx   : 0x56556fb8  →  0x00001ec0
$ecx   : 0x6f      
$edx   : 0xffffd09e  →  "[PII_REDACTED][PII_REDACTED]111111111VUV"
$esp   : 0xffffd090  →  0x00000000
$ebp   : 0xffffd0c8  →  0xffffd108  →  0x00000000
$esi   : 0xf7fb5000  →  0x001dbd6c
$edi   : 0xf7fb5000  →  0x001dbd6c
$eip   : 0x565557d4  →  <select_func+85> call eax
$eflags: [zero carry PARITY adjust SIGN trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x0023 $ss: 0x002b $ds: 0x002b $es: 0x002b $fs: 0x0000 $gs: 0x0063
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0xffffd090│+0x0000: 0x00000000     ← $esp
0xffffd094│+0x0004: 0x0000000a
0xffffd098│+0x0008: 0x00000026 ("&"?)
0xffffd09c│+0x000c: 0x3131de24
0xffffd0a0│+0x0010: "[PII_REDACTED][PII_REDACTED]1111111VUV"
0xffffd0a4│+0x0014: "[PII_REDACTED][PII_REDACTED]111VUV"
0xffffd0a8│+0x0018: "[PII_REDACTED][PII_REDACTED]VUV"
0xffffd0ac│+0x001c: "[PII_REDACTED]111111VUV"
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:32 ────
   0x565557c3 <select_func+68> adc    BYTE PTR [ebp-0x72f68a40], al
   0x565557c9 <select_func+74> sbb    DWORD PTR [edi+eiz*8+0x4589ffff], 0xfffffff4
   0x565557d1 <select_func+82> mov    eax, DWORD PTR [ebp-0xc]
 → 0x565557d4 <select_func+85> call   eax
   0x565557d6 <select_func+87> nop    
   0x565557d7 <select_func+88> mov    ebx, DWORD PTR [ebp-0x4]
   0x565557da <select_func+91> leave  
   0x565557db <select_func+92> ret    
   0x565557dc <main+0>         lea    ecx, [esp+0x4]
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── arguments (guessed) ────
*0x56555631 (
   [sp + 0x0] = 0x00000000,
   [sp + 0x4] = 0x0000000a,
   [sp + 0x8] = 0x00000026,
   [sp + 0xc] = 0x3131de24
)
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "pwn2", stopped, reason: BREAKPOINT
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x565557d4 → select_func()
[#1] 0x5655583d → main()
───────────────────────────────────────────────────────────────────────────────────