Polish: do the sum operation or the elementary arithmetic (prefix expression)
Infix: do the elementary arithmetic (infix expression)
Reverse Polish: do the elementary arithmetic (postfix expression)
Sign: input a number and see if it is a positive/negative number
First we found that the Read note function doesn't work well:
This is because the program use a stack address as the note's buffer. After we take a note and leave the function, the buffer will be filled with some (useful) addresses (due to the function epilogue). And because of this, we're able to leak the stack address & text's base address.
Now it's time to try controlling the EIP. There's a program logic vulnerability in the sign function:
It handles both positive & negative numbers. But what about 0 ?
The reason why the program crash is because the program did not assigned a value to v1 (since it did not handle 0), so when it ran to line v1(), it will set the EIP to 0x0 and crash the program. Let's check the assembly code:
It shows that if we can control the value of [ebp-0x20], we'll be able to control the EIP and hijack the program control flow.
I found that the stack frame of the sign function is "higher" (or "lesser") than the other functions. If we can't "reach that high" in other functions, we won't be able to control the function pointer.
After done some fuzzing, I finally found that in the Polish function, if we do the sum operation and keep entering number, the program will keep pushing number to the stack, making us able to "reach the height" and control the function pointer (and the parameters !) in the sign function.
So here's how we gonna exploit the service:
Take a note & Read the note, leak the text's base address
Use Polish's sum operation to control the function pointer & the function parameter. We first set the function pointer to puts and the parameter to __libc_start_main@got (there's no .got.plt due to the FULL RELRO protection)
Goto sign function and input 0, it will call puts(__libc_start_main@got) and gave us the libc's base address
Repeat step 2, this time we set the function pointer to system and the parameter to "pointer to /bin/sh"
Goto sign function and input 0, call system("/bin/sh") and get the shell
Here's the exploit. The libc's information are provided by libc-database