I've been preparing for a coding contest, and came across this question on the Internet:
#include <stdio.h>
void a();
void b();
void c();
int main() { a(); printf("\n"); return 0; }
void a() { b(); printf("hi "); }
void b() { c(); printf("there "); }
void c()
{
int x;
// code here and nowhere else
}
The solution is to write code that would print out "hi there" instead of "there hi" (no additional printing functions may be used and code only goes in the comment block).
Since I've done some basic assembly coding, I realized that this could be done with stack manipulation using the integer x
as the base.
I tried using gdb to find the return address of the functions and then swapped the return addresses of a
and b
. The compiler throws a segmentation fault, and thus I assume that I haven't used the proper return address.
How do I properly calculate the offset to find the return address? Info frame command on gdb wasn't helpful, as using the stack address value given there didn't work.
I'm running this on Linux using gcc.
I am not sure if the following will count. It's portable on POSIX. Basically you change the buffer of printf before its first call and manipulate that before before it's flushed to terminal
void c()
{
static int first = 1;
if (first) {
first = 0;
char buf0[BUFSIZ];
char buf1[BUFSIZ];
setvbuf(stdout, buf0, _IOFBF, BUFSIZ);
a();
memcpy(buf1, buf0 + 6, 3);
memcpy(buf1 + 3, buf0, 6);
memcpy(buf0, buf1, 9);
buf0[8] = '\n';
fflush(stdout);
exit(0);
}
}
You will get warnings on implicitly declaring library functions memcpy
and exit
. It's legal on C89 though discouraged. But in your case, no trick is too dirty, I guess. You can avoid the memcpy by copy the characters manually. You can avoid exit
by instead redirect stdout
through freopen
. You can change BUFSIZ
to a large constants if the system has a strangely small buffer size (smaller than 9). There are variants of this solution that don't require you to manually insert that \n
and instead let the program exit normally from main and has the printf("\n")
to put that end of line
This problem cannot be solved unless you smash the stack in the same way as an attacker smashes the stack of some process.
And to smesh the stack can be done only if you know each detail of implementation of the compiler, the problem is unsolvable otherwise.
If you know the details of the compilation (the stack structure in particular) you can use the address of the local x variable in order to obtain the addres of the current frame from the stack (of FRAME_C); in each frame is the base pointer of the previous frame and modify it.
The stack looks like that:
FRAME_MAIN = RET_OS some-data
FRAME_A = RET_MAIN some-data
FRAME_B = RET_A some-data
FRAME_C = RET_B some-data(including the variable `x`)
Using the &x
we can detect the position of the FRAME_C.
One solution is
return
The tricky operation is 2. but if each frame has a size that is known, then we can modify the return pointer RET_A of the frame B and detect RET_MAIN something like that:
*(&x+FRAME_C_SIZE+some-small-offset1) = /* *&RET_A = */
*(&x+(FRAME_C_SIZE+FRAME_B_SIZE)+some-small-offset2). /* *&RET_MAIN */
As you can see, you need to know a lot of details about the implementation of the compiler , so this is not at all a portable solution.
Other solution would be to print "hi, there" and redirect the stdout
to /dev/null
. I suppose that exit() or other compiler-depedent tricks are not allowed, otherwise the problem has no meaning for a contest.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With