1

Hello i have such code

#include <stdio.h>
#define SECRET "1234567890AZXCVBNFRT"
int checksecret(){
    char buf[32];
    gets(buf);
    if(strcmp(SECRET,buf)==0) return 1;
    else return 0;
}

void outsecret(){
    printf("%s\n",SECRET);
}
int main(int argc, char** argv){
    if (checksecret()){
        outsecret();
    };
}

disass of outsecret

(gdb) disassemble outsecret 
Dump of assembler code for function outsecret:
   0x00000000004005f4 <+0>: push   %rbp
   0x00000000004005f5 <+1>: mov    %rsp,%rbp
   0x00000000004005f8 <+4>: mov    $0x4006b4,%edi
   0x00000000004005fd <+9>: callq  0x400480 <puts@plt>
   0x0000000000400602 <+14>:    pop    %rbp
   0x0000000000400603 <+15>:    retq   

I have an assumption that i don't know SECRET, so i try to run my program with such string python -c 'print "A" * 32 + "\x40\x05\xf4"[::-1]'. But it fails with segmentation fault. What i am doing wrong? Thank you for any help.

PS

I want to call function outsecret by overwriting return code in checksecret

1
  • It's almost as if you cannot count!! Surely you noticed that the string you passed has more characters than allocated in your buffer! Commented Dec 1, 2014 at 11:11

3 Answers 3

3

You have to remember that all strings have an extra character that terminates the string, so if you input 32 characters then gets will write 33 characters to the buffer. Writing beyond the limits of an array leads to undefined behavior which often leads to crashes.

The gets function have no bounds-checking, and is very dangerous to use. It has been deprecated since long, and in the latest C11 standard it has even been removed.

Sign up to request clarification or add additional context in comments.

5 Comments

I know it, it is a task to teach howto overwriting return code of the function to make an attack to this program
@MikeMinaev Well undefined behavior (which is what you're trying to exploit) is by its very definition undefined, you need to be very precise at what you're trying to do. If you make any mistake then all you will get is the crash (or other weird behavior).
@MikeMinaev Also, the function you should try to exploit is not the outsecret function but the checksecret function, so that's the function you should look at.
i am trying to do smth line this. I want to input some string witch will override return code in checksecret from place where it was called from main to outsecret
@MikeMinaev: AFAIK integer return value is stored directly in %eax register, due to x86 calling conventions (that's assuming that you have x86 or x86-64 CPU). Stack-likely-located array buf is handled by %rbp offsets within current stack frame.
2
$ python -c 'print "A" * 32 + "\x40\x05\xf4"[::1]'
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@

$ perl -le 'print length("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@")'
33

Your input string is too long for buffer size of 32 characters (extra one is needed for '\0' terminating null character). You are victim to buffer or array overflow (sometimes also called as array overrun).

Note that gets() is deprecated in C99 and eventually it has been dropped in C11 Standard for security reasons.


I want to call function outsecret by overwriting return code in checksecret

Beware, you are about to leave relatively safe regions of C Standard. This means that behaviour is relative to compiler, compiler's versions, optimization settings, ABI and so on (maybe inclucing current phase of moon).

As of x86 calling conventions integer return value is stored directly in %eax register (that's assuming that you have x86 or x86-64 CPU). Stack-likely-located array buf is handled by %rbp offsets within current stack frame. Let's consult with gdb disassemble command:

$ gcc -O0 test.c

$ gdb -q a.out
(gdb) b checksecret
(gdb) r
Breakpoint 1, 0x0000000000400631 in checksecret ()
(gdb) disas
Dump of assembler code for function checksecret:
   0x000000000040062d <+0>: push   %rbp
   0x000000000040062e <+1>: mov    %rsp,%rbp
=> 0x0000000000400631 <+4>: sub    $0x30,%rsp
   0x0000000000400635 <+8>: mov    %fs:0x28,%rax
   0x000000000040063e <+17>:    mov    %rax,-0x8(%rbp)
   0x0000000000400642 <+21>:    xor    %eax,%eax
   0x0000000000400644 <+23>:    lea    -0x30(%rbp),%rax
   0x0000000000400648 <+27>:    mov    %rax,%rdi
   0x000000000040064b <+30>:    callq  0x400530 <gets@plt>
   0x0000000000400650 <+35>:    lea    -0x30(%rbp),%rax
   0x0000000000400654 <+39>:    mov    %rax,%rsi
   0x0000000000400657 <+42>:    mov    $0x400744,%edi
   0x000000000040065c <+47>:    callq  0x400510 <strcmp@plt>
   0x0000000000400661 <+52>:    test   %eax,%eax
   0x0000000000400663 <+54>:    jne    0x40066c <checksecret+63>
   0x0000000000400665 <+56>:    mov    $0x1,%eax
   0x000000000040066a <+61>:    jmp    0x400671 <checksecret+68>
   0x000000000040066c <+63>:    mov    $0x0,%eax
   0x0000000000400671 <+68>:    mov    -0x8(%rbp),%rdx
   0x0000000000400675 <+72>:    xor    %fs:0x28,%rdx
   0x000000000040067e <+81>:    je     0x400685 <checksecret+88>
   0x0000000000400680 <+83>:    callq  0x4004f0 <__stack_chk_fail@plt>
   0x0000000000400685 <+88>:    leaveq 
   0x0000000000400686 <+89>:    retq  

There is no way overwrite %eax directly from C code, but what you could do is to overwrite selective fragment of code section. In your case what you want is to replace:

0x000000000040066c <+63>:   mov    $0x0,%eax

with

0x000000000040066c <+63>:   mov    $0x1,%eax

It's easy to accomplish by gdb itself:

(gdb) x/2bx 0x40066c
0x40066c <checksecret+63>:  0xb8    0x00

set {unsigned char}0x40066d = 1

Now let's confirm it:

(gdb) x/i 0x40066c
   0x40066c <checksecret+63>:   mov    $0x1,%eax

From that point checksecret() is returning 1 even if SECRET does not match. However It wouldn't be so easy to do it by buf itself, as you need to know (guess somehow?) correct offset of particular code section instruction.

1 Comment

Thank you a lot, but in the task said that i must manipulate with input text, not with some registers.
0

Above answers are pretty clear and corret way to exploit buffer overflow vulnerability. But there is a different way to do same thing without exploit vulnerability.

mince@rootlab tmp $ gcc test.c -o test
mince@rootlab tmp $ strings test
/lib64/ld-linux-x86-64.so.2
libc.so.6
gets
puts
__stack_chk_fail
strcmp
__libc_start_main
__gmon_start__
GLIBC_2.4
GLIBC_2.2.5
UH-X
UH-X
[]A\A]A^A_
1234567890AZXCVBNFRT
;*3$

Please look at last 2 row. You will see your secret key in there.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.