Pwn-RET Address Overwrite

Last week, I saw a challenge of pwn. The source code has been provided, and what you are asked to do is to pwn the vulnerable program. 

Here is the source code in C language. Your goal is to exploit the vulnerability and let the program print as many coupons as it can. 

Goal: to print a lot of coupons!
• you can only launch the target once, of course
• Think about how to manipulate address to cause this to go into a loop, without adding a loop.

Try

When I was glancing the challenge at the first beginning, I thought it could not be difficult. After all, I major in Information Security and have some basic knowledge about application security, though my focus is on web security. My init idea is like this.

  1. when the function main() calls the function coupon(), the arguments for  coupon() will be pushed into the stack in the order from right to left. Here, argv[1] is the only argument whose address will be pushed.
  2. program will push the return address, and then call the function coupon() and jump into this function. When the instructions are executed, the final instruction ret will lead the program to jumping to the address in the stack top. This address is the return address pushed in the step 1.
  3. with the existence of the function strcpy() inside the coupon(), we can input a long enough string as the argv[1] to overwrite the return address of the function coupon()
  4. to loop the printing of coupons, we can overwrite the return address as the return address of the function coupon() or main().

Problem

I thought my thought was absolutely correct. However, with this method, the program was only able to print two coupons and exit with an exception.

By debugging step by step with gdb, I located the problem. Actually, overwrite the return address is not enough. Another thing we need to do is to recover the content in the registers and stack to avoid exceptions of reading invalid data. 

To be specific, here are two screenshots taken at the same breakpoint at different time. The first one was taken at the first time the program met the breakpoint,  while the second one was taken after the program was redirected by the overwritten return address. 

1. First time reach breakpoint
2. reach breakpoint after redirection

Obviously, different register value and stack value will lead to a crash. 

Solution

Then I tried to solve this problem. 

After comparing data in the stack and register in two stages, I came up with my solution — use ROP to pop useless data and recover the stack shown as screenshot 2 to screenshot 1. Here I used ropgadget in gdb-peda.

Finally, I got the payload.

With pop4ret twice and popret one time, the stack was recovered. Then overwrite the return address as the beginning address of the function main() and we can run the program in an infinite loop.

Final output

PS: the reason why so many coupons are the same is that the seed of the random function is time. You will get the same coupons in the same second.. 


Google Adv. below

  

Leave a Reply