0
int play() {

    int a;
    int b;
    char buffer[010];
    a = 0x41414141;
    b = 0x42424242;

    if (write(STDOUT_FILENO, "For a moment, nothing happened. Then, after a second or so, nothing continued to happen.\n> ", 91) < 0) {
        perror("write");
    }

    if (read(STDIN_FILENO, &buffer, 0xC) < 0) {                                              
        perror("read");                                                                   
    }

    if (a == 31337) {
        system(buffer);
    }

    else if (b == 1337) {
        readfile("flag.0");
    }

    else if (b == 42) {
        readfile("vuln1.txt");
    }

    else {
        write(STDOUT_FILENO, "So long and thanks for all the fish.\n", 37);
    }

}


int main(int argc, char *argv[]){
    play();
    exit(EXIT_SUCCESS);
}

I think what is happening is that with a buffer if size of 11, it's trying to add 12 bytes to it? Is that even close?

I'm such a newbie it's scary and I apologise if this isn't the right place for this sort of question. Any footholds into what to do would be greatly appreciated.

I've compiled it and ran it with GDB but getting nowhere fast

2
  • 1
    If you read larger than the buffer size, the following memory addresses will be overwritten. It is allowed and that is what causes buffer overflow. Commented Jan 10, 2017 at 1:45
  • I agree this isn't the right place for it, but some useful questions you might want to answer are: what is the program doing, crashing? What errors are you seeing? Additionally, you might want to reframe the question: what are you trying to accomplish here? Commented Jan 10, 2017 at 17:31

2 Answers 2

3

The 0x414141 and 0x424242 that are placed in books for educational purposes because these are simply the strings "AAAAAAAA" and "BBBBBBB" in hexadecimal notation. Assigning them to integers has nothing to do with buffer overflows.

A much better example can be had by using a full program, and a function call that will allow us to know when the overflow happens. For example, let's alter the program to:

#include <stdio.h>
#include <unistd.h>

void
fun(void)
{
    char buffer[10];

    if (read(STDIN_FILENO, &buffer, 60) < 0) {
        perror("read");
    }
    write(STDOUT_FILENO, "So long and thanks for all the fish.\n", 37);
    return;
}

int
main(void)
{
    fun();
    write(STDOUT_FILENO, "WILL NOT PRINT.\n", 16);
    return 0;
}

Since you're using read and write we are assuming a UNIX system, so let's compile it and run a couple of times. Assuming that the program source is in buf.c:

[~]$ gcc -g -o prog buf.c
[~]$ perl -e 'print "A"x10' | ./prog
So long and thanks for all the fish.
WILL NOT PRINT.
[~]$ perl -e 'print "A"x20' | ./prog
So long and thanks for all the fish.
WILL NOT PRINT.

Perl is handy because we can control exactly the number of bytes that we give the program. Since STDIN is connected to a pipe, we can give a varying amount of bytes, up to the hardcoded 60 bytes in the program source.

The first run gives what we expected, 10 bytes are places in the 10bytes long buffer. In the second run the 10 byte buffer should have overflow with 20 bytes of input. But nothing appears to happen. Well, the buffer did overflow, but did not overflow far enough to hinder process execution. Let's do more:

[grochmal@haps tmp]$ perl -e 'print "A"x30' | ./prog
So long and thanks for all the fish.
Segmentation fault (core dumped)

Good, that's what we expect to see from an overflow. Now that we have a good input we save it and look at how the program works in GDB:

[grochmal@haps tmp]$ perl -e 'print "A"x30' > input
[grochmal@haps tmp]$ gdb -q prog
Reading symbols from prog...done.
(gdb) list
5   fun(void)
6   {
7       char buffer[10];
8   
9       if (read(STDIN_FILENO, &buffer, 30) < 0) {
10          perror("read");
11      }
12      write(STDOUT_FILENO, "So long and thanks for all the fish.\n", 37);
13      return;
14  }
(gdb) list
15  
16  int
17  main(void)
18  {
19      fun();
20      write(STDOUT_FILENO, "WILL NOT PRINT.\n", 16);
21      return 0;
22  }
23  
(gdb) break 9
Breakpoint 1 at 0x40058e: file buf.c, line 9.
(gdb) break 12
Breakpoint 2 at 0x4005b3: file buf.c, line 12.

Since we added -g to the compiler line we have all debugging symbols (e.g. program code) we may want. This makes it very easy to setup the break points where the interesting part of the execution happens. We run the program with the input we just saved and check how the buffer looks:

(gdb) run <input
Starting program: /home/grochmal/tmp/prog <input

Breakpoint 1, fun () at buf.c:9
9       if (read(STDIN_FILENO, &buffer, 30) < 0) {
(gdb) p &buffer
$1 = (char (*)[10]) 0x7fffffffe800
(gdb) x/15wx 0x7fffffffe800
0x7fffffffe800: 0x004005f0  0x00000000  0x00400490  0x00000000
0x7fffffffe810: 0xffffe820  0x00007fff  0x004005d3  0x00000000
0x7fffffffe820: 0x004005f0  0x00000000  0xf7a5c291  0x00007fff
0x7fffffffe830: 0xf7dd0798  0x00007fff  0xffffe908

The buffer is only 10 bytes long, and we printed 60 bytes. But that gives away 0xffffe820 which is the location where the program needs to return to (in main) from the fun() call. When the buffer is overflowed, the bytes overwrite that. Let's see it by continuing with the read call.

(gdb) cont
Continuing.

Breakpoint 2, fun () at buf.c:12
12      write(STDOUT_FILENO, "So long and thanks for all the fish.\n", 37);
(gdb) x/15wx 0x7fffffffe800
0x7fffffffe800: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffe810: 0x41414141  0x41414141  0x41414141  0x00004141
0x7fffffffe820: 0x004005f0  0x00000000  0xf7a5c291  0x00007fff
0x7fffffffe830: 0xf7dd0798  0x00007fff  0xffffe908

And now the program will try to return over to 0x41414141, which will cause the segfault.

(gdb) cont
Continuing.
So long and thanks for all the fish.

Program received signal SIGSEGV, Segmentation fault.
0x0000414141414141 in ?? ()

And it did! As a bonus we have the 0x41414141 string you're using as an int assignment in your program, and now can deduce from where it comes.


The security implication of this is that I know exactly which part of the input overwrites that return value on the stack. And, thanks to that, I can drive the program to any instruction within its memory allocation.

(In practice that's much harder today because several measures are there to prevent such overflows from finding useful places to return to. But the concept is the same.)

4
  • I get 50% of that. What reading would you recommend? I'm a developer so not a complete newbie but newbie enough to cry at night with the thoughts of this field. Additionally, I can't trigger a segmentation fault no matter how many characters I pass Commented Jan 10, 2017 at 7:37
  • Also in my example, I need to set the values of A and B... Commented Jan 10, 2017 at 9:24
  • @pee2pee - am aware of some versions of GCC substituing strcpy() by strncpy() to prevent overflows, this is the first time i see it meddling with read() but that's completely possible. Add -O2 to the compiler line to prevent GCC from doing such things (that's code optimisation, which will disregard security). Also you may try increasing that 60 in read() and then keep trying with bigger and bigger strings. Commented Jan 11, 2017 at 0:26
  • I completely omitted two pieces of info, both related to the way how I know what is the return value in memory (printed by x/x in GDB): (1) The process stack is structured in a know and more-or-less deterministic way in memory, although compilers perform some (2) memory alignment to make variables easier to access. Both things vary a lot from machine to machine, but they do not fall too far to guesstimate. Hacking by Erickson is my favourite on memory stuff, the book is mid-level, so you do need to program in C before attempting it. Commented Jan 11, 2017 at 0:29
0

Using the program of @grochmal, I was able to get the segmentation fault on my local machine. Still not being able to solve the main problem.

As it has not been explicitly mentioned in the original question, this is part of a challenge where file vuln1.txt has to be read by causing a overflow through an open port remotely where the above program is executing.

I am trying to figure out how to set the value of B=42. Any help is highly appreciated.

1
  • Welcome to infosec SE! Your post is constructive and adds to the question. Just as note on style, because it doesn't give an answer, it is better suited as a comment. Commented Jan 14, 2017 at 2:14

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.