Just added this writeup to show an unintended solution for this challenge. At least the flag, you’ll get for solving the challenge points to using UAF for it, but there’s another (much shorter) way to do this.
When a note gets added, you can specify the size for the note, which will be stored in its own array.
This will resulting in the following data in the bss
Now, let’s take a look at the edit function:
If you paid attention, you’ll might see, that the verify function doesn’t check for negative indices. So we can access table entries before the table entry itself.
Also we can specify arbitrary values for the sizes of an entry, so why not just create an entry with a size of 0x602020 (you see where we’re going?).
We can adjust the sizes of an entry, so that it results in an address of a got entry. Then we’ll specify a negative value, so the size is used as a note address. Since the binary also uses the negative index on the size array, it will also look before the size array (where the got table happens to be :)) and use an address (better said, the lower dword of the address) from the got table as the size for our memo.
Let’s do the basic skeleton and create two notes, with sizes 0x602020 and 0x602050.
This will change the data in the bss to
So, now we have two valid and known addresses in the bss (though in the sizes array).
Now, since we can specify negative indices, we can access the “note” in the first sizes entry by passing -12 as the note index. The binary will then try to print the note at that address, which happens to be the got entry for puts.
Since we now have successfully resolved libc, we can just use the same functionality to overwrite values in the got entry. We just have to make sure, that it hits a good value as size for our size entry ?-)
The binary will search for the size at offset -0x60 to the current size slot.
That’s the reason, I put the second address into the third slot of the size array. This will make it use the content of 0x602070 as size for read. At 0x602070 is exit got, which isn’t resolved by now, so it will always be 0x400746 and thus the read will succeed.
Really? UAF? Instead of just overwriting atoi got directly? :D
So, atoi will be called to convert the selected menu entry to a number, so we just have to select the option /bin/sh.
Flag was inctf{U4f_f0r_l1f3_m8} (the flag was a little confusing after this)