0

I work on a online program in which I should do a buffer Overflow.
When I run the program, I have to complete a sum of two numbers generated randomly) :

>>> 451389913 + 1587598959 =

If I put the right result, I get a "That's okay". Otherwise the console writes "Try it again".

I decompiled the program with Ghidra and get the following code in the main() function :

{
  int iVar1;
  char local_9 [36];
  int local_42;
  uint local_6;
  uint local_f;
  
  local_f = rand();
  local_6 = rand();
  local_42 = local_6 + local_f;
  printf(">>> %d + %d = ",(ulong)local_f,(ulong)local_6);
  fflush(stdout);
  fgets(local_9,100,stdin);
  iVar1 = atoi(local_9);
  if (local_42 == iVar1) {
    puts("That's ok");
  }
  else {
    puts("Try it again");
  }
  return 0;
}

I notice a fgets function that make me suppose I can do the buffer overflow just before the sum. I also see that the local9 variable is composed of 36 characters. So I suppose that at the beginning of the payload, there must be 36 characters.

I began to write the following snippet with the pwntools Python library :

import pwn
offset = 36
payload = b'A'*offset + b'[.....]'
c = pwn.remote("URL",Port)
c.sendline(payload)
c.interactive()

The thing is I know I have to write something after the b'A'*offset but I don't really see what to add.. My difficulty is to join that sum of random numbers to the payload.
Is it possible to do it ?

Any ideas would be very appreciated, thanks

Julien
  • 699
  • 3
  • 14
  • 30
  • The ending of your payload changes depending on some parameters. If you have a "get_flag" function, you have just to put its address. If not you should try to inject some code somewhere and jump to it. If the executable is NX (pages can't be both witeable and executable) you have to rop. – Marco Balo May 06 '22 at 12:09
  • Be aware that the offset is something more than 36. It is **at least** `36 + sizeof(addr($rbp))`. You can find out how much by using cyclic: just run `cyclic 100` and put its output as the executable imput. Then see in `dmesg` the crash `$rip` and use the command `cyclic -l 0x...`. It will return to you a number `n`. The payload you need will be `payload = b"a"*n+b"..."` – Marco Balo May 06 '22 at 12:16
  • Thanks for your answer ! Should I use gdb to run the cyclic and dmesg commands ? – Julien May 06 '22 at 12:29
  • Without gdb, you should run them in bash. `cyclic` should be installed since you have pwntools. `dmesg` is linux crash log. – Marco Balo May 06 '22 at 16:56

1 Answers1

0

Of course, it's possible, pwn is the swiss army knife for CTFs.

# string = c.recv()
# assuming the string you receive is this
string = b">>> 451389913 + 1587598959 ="

# receive expression as bytes
# convert it into utf8 string for convenience
# split() splits the string at whitespaces and store them as array elements
expression = string.decode("utf8").split()

# covert string to int for to get logical sum instead of literal
solution = int(expression[1])+int(expression[3])
c.sendline(payload)

However, in a more challenging scene, where the server might ask you multiple answers with division or difference you'd have to change operators as needed. And I'd rather use operator lib than write a bunch of ifs.

import operator

ops = {
    '+' : operator.add,
    '-' : operator.sub,
    '*' : operator.mul,
    '/' : operator.truediv
}

string = b">>> 451389913 + 1587598959 ="
expression = string.decode("utf8").split()

solution = ops[expression[2]](int(expression[1]), int(expression[3]))
c.sendline(solution)
xicc
  • 1
  • 2