There are other blogs regarding this problem and they had been solved in a different way than the way in which is shown below. Most of these blogs got the flag by predicting the output of rand() and thus winning 50 games.
But the method that I used is a little different from these methods.
The first thing that I tried to do when I got the binary was to try and get a shell. But then I saw that NX and ASLR were enabled. That is not what every security enthusiast wants to hear.
So I figured that a 50 point problem couldn’t be that hard to solve. I kept on checking the dissasembly of the binary and found out that we just needed to open the file “flag.txt” and read its contents.
The program calls the file “flag.txt” by itself once you have won 50 games in a row.
The vulnerability in this binary is a gets() function which is basically the best thing that could have happened to any binary exploitation enthusiast.
So ASLR is on and NX is also enabled. Why not overwrite the saved instruction pointer with an address within the binary? Or better, why not overwrite it with the starting address of instructions which eventually open the file “flag.txt”, read its contents and print them out to the screen?
So 84 A’s would overwrite the saved frame pointer. The next 4 bytes should be the address of O-R-P (open the file, read contents and print).
But, it seems that we can’t just trash the value of saved frame pointer since these instructions are also executed:
mov QWORD PTR [rbp-0x18],rax
mov rax,QWORD PTR [rbp-0x18]
But then again, a problem which arises is the address which we’re supposed to give ie 0x400aa4. It might not seem like a big problem but on close inspection, we can find a byte ‘0x0a’ which causes the problem (0x0a is basically a newline character which means that gets() stops receiving once it finds this character).
So back to square one. Again an address which we can use popped up which is:
0x4008b4 <+174>: jmp 0x400a7a <main+628>
Which basically jumps an address a few instructions above O-R-P
No bad bytes there. The final problem here is a checking done after the jump is taken.
So what we need to do is to overwrite the saved frame pointer with an address which is valid and such that it contains a value greater than 0x31 at a position of 4 bytes before it. And then overwrite the saved instruction pointer with the address 0x4008b4.
So the final payload would be:
from pwn import * context.binary="rps" context.bits=64 addr1=0x00000000006010e8 addr2=0x00000000004008b4 payload="A"*80 payload+=pack(addr1) payload+=pack(addr2) p=remote("milkyway.chal.mmactf.link",1641) msg=p.recvuntil(':') print msg p.sendline(payload) msg=p.recvlines(2) print msg p.sendline("I") msg=p.recvall() print msg
And running it gives the flag
Leave a Reply