I'm trying to make a buffer overflow on a c program, but I can't manage to find the vulnerability and exploit the code.
I've tried thousands of inputs. Generally I've tried these: 1) I've tried the obvious - giving a very long string as an input. 2) I've tried to give a string so big that strlen() will acually return a negative value. 3)I've tried to give null bytes and EOF as an input, and append string. it wont let me enter those chars as input. 4)I've tried to override something, but nothing gets overridden (if i managed to override something, it's 70% of the way for me)
all of these I've tried with Python.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int secretCode = 123;
#define STATUS_WINNER 'WIN!'
typedef struct _word_struct
{
char word[32 + 24];
char result[48 + 24];
int status;
} word_struct, *word_data;
int get_input(char *word, int len)
{
int wordSize = 0;
char *locWord = malloc(len+4);
if(!locWord)
return -2;
printf("Enter your guess: ");
fgets(locWord,len+4,stdin);
wordSize = strlen(locWord);
// strip newline character
if(locWord[wordSize-1] == '\n')
locWord[wordSize-1] = '\0';
if(strlen(locWord) > len)
{
free(locWord);
return -1;
}
strcpy(word,locWord);
free(locWord);
return 1;
}
void check_input(word_data w)
{
//todo: implement this
printf("Incorrect word!\n");
w->status = strlen(w->word);
}
int main(int argc, char* argv[])
{
//check with sizeof - off by one + strcpy (overwrite the next with 0)
//strcpy that will copy that additional symbol
//strncat that will start later because there is a 0 later
word_struct guess;
int i,offset,len,ret;
printf("Welcome to Alladin's magic cave!\n");
printf("Enter the secret word and get the treasure cave entrance code!\n");
ret = get_input(guess.word, sizeof(guess.word));
if(ret == -1)
{
printf("Exiting due to buffer overflow!\n");
return -1;
}
else if(ret == -2)
{
printf("Out of resources! Exiting...\n");
return -2;
}
check_input(&guess);
printf("STATUS: %d\n", guess.status);
printf("REAL:%d\n", STATUS_WINNER);
if(guess.status == STATUS_WINNER)
strcpy(guess.result,"CORRECT! YOU ENTERED: ");
else
strcpy(guess.result,"WRONG! YOUR WORD: ");
//we don't use unsafe str functions, we copy strings carefully one-by-one!
offset = strlen(guess.result);
len = strlen(guess.word);
for(i = 0; i < len; ++i)
guess.result[offset+i] = guess.word[i];
guess.result[offset+i] = '\0';
printf("%s\n",guess.result);
// give them the flag?
if(guess.status == STATUS_WINNER)
printf("It was cool, wasn't it ?! Go get your treasure, the code is %d\n", secretCode);
else
printf("Better luck next time!\n");
return 0;
}
for input 56 bytes long EXACTLY - I get segfault. for inputs larger than 56 - I get the buffer overflow "error" from the program. for very large inputs (over 10^6 bytes [long more or less]) - the program just sort of stuck.
I expect to manage to override anything, but I can't manage to override anything, maybe jump straight into the address that prints out the code(at 0x804889d)
below is assembly:
080485ab <get_input>:
80485ab: 55 push %ebp
80485ac: 89 e5 mov %esp,%ebp
80485ae: 83 ec 18 sub $0x18,%esp
80485b1: c7 45 f0 00 00 00 00 movl $0x0,-0x10(%ebp)
80485b8: 8b 45 0c mov 0xc(%ebp),%eax
80485bb: 83 c0 04 add $0x4,%eax
80485be: 83 ec 0c sub $0xc,%esp
80485c1: 50 push %eax
80485c2: e8 99 fe ff ff call 8048460 <malloc@plt>
80485c7: 83 c4 10 add $0x10,%esp
80485ca: 89 45 f4 mov %eax,-0xc(%ebp)
80485cd: 83 7d f4 00 cmpl $0x0,-0xc(%ebp)
80485d1: 75 0a jne 80485dd <get_input+0x32>
80485d3: b8 fe ff ff ff mov $0xfffffffe,%eax
80485d8: e9 ac 00 00 00 jmp 8048689 <get_input+0xde>
80485dd: 83 ec 0c sub $0xc,%esp
80485e0: 68 60 89 04 08 push $0x8048960
80485e5: e8 26 fe ff ff call 8048410 <printf@plt>
80485ea: 83 c4 10 add $0x10,%esp
80485ed: a1 40 a0 04 08 mov 0x804a040,%eax
80485f2: 8b 55 0c mov 0xc(%ebp),%edx
80485f5: 83 c2 04 add $0x4,%edx
80485f8: 83 ec 04 sub $0x4,%esp
80485fb: 50 push %eax
80485fc: 52 push %edx
80485fd: ff 75 f4 pushl -0xc(%ebp)
8048600: e8 2b fe ff ff call 8048430 <fgets@plt>
8048605: 83 c4 10 add $0x10,%esp
8048608: 83 ec 0c sub $0xc,%esp
804860b: ff 75 f4 pushl -0xc(%ebp)
804860e: e8 6d fe ff ff call 8048480 <strlen@plt>
8048613: 83 c4 10 add $0x10,%esp
8048616: 89 45 f0 mov %eax,-0x10(%ebp)
8048619: 8b 45 f0 mov -0x10(%ebp),%eax
804861c: 8d 50 ff lea -0x1(%eax),%edx
804861f: 8b 45 f4 mov -0xc(%ebp),%eax
8048622: 01 d0 add %edx,%eax
8048624: 0f b6 00 movzbl (%eax),%eax
8048627: 3c 0a cmp $0xa,%al
8048629: 75 0e jne 8048639 <get_input+0x8e>
804862b: 8b 45 f0 mov -0x10(%ebp),%eax
804862e: 8d 50 ff lea -0x1(%eax),%edx
8048631: 8b 45 f4 mov -0xc(%ebp),%eax
8048634: 01 d0 add %edx,%eax
8048636: c6 00 00 movb $0x0,(%eax)
8048639: 83 ec 0c sub $0xc,%esp
804863c: ff 75 f4 pushl -0xc(%ebp)
804863f: e8 3c fe ff ff call 8048480 <strlen@plt>
8048644: 83 c4 10 add $0x10,%esp
8048647: 89 c2 mov %eax,%edx
8048649: 8b 45 0c mov 0xc(%ebp),%eax
804864c: 39 c2 cmp %eax,%edx
804864e: 76 15 jbe 8048665 <get_input+0xba>
8048650: 83 ec 0c sub $0xc,%esp
8048653: ff 75 f4 pushl -0xc(%ebp)
8048656: e8 c5 fd ff ff call 8048420 <free@plt>
804865b: 83 c4 10 add $0x10,%esp
804865e: b8 ff ff ff ff mov $0xffffffff,%eax
8048663: eb 24 jmp 8048689 <get_input+0xde>
8048665: 83 ec 08 sub $0x8,%esp
8048668: ff 75 f4 pushl -0xc(%ebp)
804866b: ff 75 08 pushl 0x8(%ebp)
804866e: e8 dd fd ff ff call 8048450 <strcpy@plt>
8048673: 83 c4 10 add $0x10,%esp
8048676: 83 ec 0c sub $0xc,%esp
8048679: ff 75 f4 pushl -0xc(%ebp)
804867c: e8 9f fd ff ff call 8048420 <free@plt>
8048681: 83 c4 10 add $0x10,%esp
8048684: b8 01 00 00 00 mov $0x1,%eax
8048689: c9 leave
804868a: c3 ret
0804868b <check_input>:
804868b: 55 push %ebp
804868c: 89 e5 mov %esp,%ebp
804868e: 83 ec 08 sub $0x8,%esp
8048691: 83 ec 0c sub $0xc,%esp
8048694: 68 73 89 04 08 push $0x8048973
8048699: e8 d2 fd ff ff call 8048470 <puts@plt>
804869e: 83 c4 10 add $0x10,%esp
80486a1: 8b 45 08 mov 0x8(%ebp),%eax
80486a4: 83 ec 0c sub $0xc,%esp
80486a7: 50 push %eax
80486a8: e8 d3 fd ff ff call 8048480 <strlen@plt>
80486ad: 83 c4 10 add $0x10,%esp
80486b0: 89 c2 mov %eax,%edx
80486b2: 8b 45 08 mov 0x8(%ebp),%eax
80486b5: 89 90 80 00 00 00 mov %edx,0x80(%eax)
80486bb: 90 nop
80486bc: c9 leave
80486bd: c3 ret
080486be <main>:
80486be: 8d 4c 24 04 lea 0x4(%esp),%ecx
80486c2: 83 e4 f0 and $0xfffffff0,%esp
80486c5: ff 71 fc pushl -0x4(%ecx)
80486c8: 55 push %ebp
80486c9: 89 e5 mov %esp,%ebp
80486cb: 51 push %ecx
80486cc: 81 ec b4 00 00 00 sub $0xb4,%esp
80486d2: 89 c8 mov %ecx,%eax
80486d4: 8b 40 04 mov 0x4(%eax),%eax
80486d7: 89 85 54 ff ff ff mov %eax,-0xac(%ebp)
80486dd: 65 a1 14 00 00 00 mov %gs:0x14,%eax
80486e3: 89 45 f4 mov %eax,-0xc(%ebp)
80486e6: 31 c0 xor %eax,%eax
80486e8: 83 ec 0c sub $0xc,%esp
80486eb: 68 84 89 04 08 push $0x8048984
80486f0: e8 7b fd ff ff call 8048470 <puts@plt>
80486f5: 83 c4 10 add $0x10,%esp
80486f8: 83 ec 0c sub $0xc,%esp
80486fb: 68 a8 89 04 08 push $0x80489a8
8048700: e8 6b fd ff ff call 8048470 <puts@plt>
8048705: 83 c4 10 add $0x10,%esp
8048708: 83 ec 08 sub $0x8,%esp
804870b: 6a 38 push $0x38
804870d: 8d 85 70 ff ff ff lea -0x90(%ebp),%eax
8048713: 50 push %eax
8048714: e8 92 fe ff ff call 80485ab <get_input>
8048719: 83 c4 10 add $0x10,%esp
804871c: 89 85 64 ff ff ff mov %eax,-0x9c(%ebp)
8048722: 83 bd 64 ff ff ff ff cmpl $0xffffffff,-0x9c(%ebp)
8048729: 75 1a jne 8048745 <main+0x87>
804872b: 83 ec 0c sub $0xc,%esp
804872e: 68 e8 89 04 08 push $0x80489e8
8048733: e8 38 fd ff ff call 8048470 <puts@plt>
8048738: 83 c4 10 add $0x10,%esp
804873b: b8 ff ff ff ff mov $0xffffffff,%eax
8048740: e9 77 01 00 00 jmp 80488bc <main+0x1fe>
8048745: 83 bd 64 ff ff ff fe cmpl $0xfffffffe,-0x9c(%ebp)
804874c: 75 1a jne 8048768 <main+0xaa>
804874e: 83 ec 0c sub $0xc,%esp
8048751: 68 08 8a 04 08 push $0x8048a08
8048756: e8 15 fd ff ff call 8048470 <puts@plt>
804875b: 83 c4 10 add $0x10,%esp
804875e: b8 fe ff ff ff mov $0xfffffffe,%eax
8048763: e9 54 01 00 00 jmp 80488bc <main+0x1fe>
8048768: 83 ec 0c sub $0xc,%esp
804876b: 8d 85 70 ff ff ff lea -0x90(%ebp),%eax
8048771: 50 push %eax
8048772: e8 14 ff ff ff call 804868b <check_input>
8048777: 83 c4 10 add $0x10,%esp
804877a: 8b 45 f0 mov -0x10(%ebp),%eax
804877d: 3d 21 4e 49 57 cmp $0x57494e21,%eax
8048782: 75 37 jne 80487bb <main+0xfd>
8048784: 8d 85 70 ff ff ff lea -0x90(%ebp),%eax
804878a: 83 c0 38 add $0x38,%eax
804878d: c7 00 43 4f 52 52 movl $0x52524f43,(%eax)
8048793: c7 40 04 45 43 54 21 movl $0x21544345,0x4(%eax)
804879a: c7 40 08 20 59 4f 55 movl $0x554f5920,0x8(%eax)
80487a1: c7 40 0c 20 45 4e 54 movl $0x544e4520,0xc(%eax)
80487a8: c7 40 10 45 52 45 44 movl $0x44455245,0x10(%eax)
80487af: 66 c7 40 14 3a 20 movw $0x203a,0x14(%eax)
80487b5: c6 40 16 00 movb $0x0,0x16(%eax)
80487b9: eb 2b jmp 80487e6 <main+0x128>
80487bb: 8d 85 70 ff ff ff lea -0x90(%ebp),%eax
80487c1: 83 c0 38 add $0x38,%eax
80487c4: c7 00 57 52 4f 4e movl $0x4e4f5257,(%eax)
80487ca: c7 40 04 47 21 20 59 movl $0x59202147,0x4(%eax)
80487d1: c7 40 08 4f 55 52 20 movl $0x2052554f,0x8(%eax)
80487d8: c7 40 0c 57 4f 52 44 movl $0x44524f57,0xc(%eax)
80487df: c7 40 10 3a 20 20 00 movl $0x20203a,0x10(%eax)
80487e6: 83 ec 0c sub $0xc,%esp
80487e9: 8d 85 70 ff ff ff lea -0x90(%ebp),%eax
80487ef: 83 c0 38 add $0x38,%eax
80487f2: 50 push %eax
80487f3: e8 88 fc ff ff call 8048480 <strlen@plt>
80487f8: 83 c4 10 add $0x10,%esp
80487fb: 89 85 68 ff ff ff mov %eax,-0x98(%ebp)
8048801: 83 ec 0c sub $0xc,%esp
8048804: 8d 85 70 ff ff ff lea -0x90(%ebp),%eax
804880a: 50 push %eax
804880b: e8 70 fc ff ff call 8048480 <strlen@plt>
8048810: 83 c4 10 add $0x10,%esp
8048813: 89 85 6c ff ff ff mov %eax,-0x94(%ebp)
8048819: c7 85 60 ff ff ff 00 movl $0x0,-0xa0(%ebp)
8048820: 00 00 00
8048823: eb 2a jmp 804884f <main+0x191>
8048825: 8b 95 68 ff ff ff mov -0x98(%ebp),%edx
804882b: 8b 85 60 ff ff ff mov -0xa0(%ebp),%eax
8048831: 01 c2 add %eax,%edx
8048833: 8d 8d 70 ff ff ff lea -0x90(%ebp),%ecx
8048839: 8b 85 60 ff ff ff mov -0xa0(%ebp),%eax
804883f: 01 c8 add %ecx,%eax
8048841: 0f b6 00 movzbl (%eax),%eax
8048844: 88 44 15 a8 mov %al,-0x58(%ebp,%edx,1)
8048848: 83 85 60 ff ff ff 01 addl $0x1,-0xa0(%ebp)
804884f: 8b 85 60 ff ff ff mov -0xa0(%ebp),%eax
8048855: 3b 85 6c ff ff ff cmp -0x94(%ebp),%eax
804885b: 7c c8 jl 8048825 <main+0x167>
804885d: 8b 95 68 ff ff ff mov -0x98(%ebp),%edx
8048863: 8b 85 60 ff ff ff mov -0xa0(%ebp),%eax
8048869: 01 d0 add %edx,%eax
804886b: c6 44 05 a8 00 movb $0x0,-0x58(%ebp,%eax,1)
8048870: 83 ec 0c sub $0xc,%esp
8048873: 8d 85 70 ff ff ff lea -0x90(%ebp),%eax
8048879: 83 c0 38 add $0x38,%eax
804887c: 50 push %eax
804887d: e8 ee fb ff ff call 8048470 <puts@plt>
8048882: 83 c4 10 add $0x10,%esp
8048885: 8b 45 f0 mov -0x10(%ebp),%eax
8048888: 3d 21 4e 49 57 cmp $0x57494e21,%eax
804888d: 75 18 jne 80488a7 <main+0x1e9>
804888f: a1 38 a0 04 08 mov 0x804a038,%eax
8048894: 83 ec 08 sub $0x8,%esp
8048897: 50 push %eax
8048898: 68 28 8a 04 08 push $0x8048a28
804889d: e8 6e fb ff ff call 8048410 <printf@plt>
80488a2: 83 c4 10 add $0x10,%esp
80488a5: eb 10 jmp 80488b7 <main+0x1f9>
80488a7: 83 ec 0c sub $0xc,%esp
80488aa: 68 68 8a 04 08 push $0x8048a68
80488af: e8 bc fb ff ff call 8048470 <puts@plt>
80488b4: 83 c4 10 add $0x10,%esp
80488b7: b8 00 00 00 00 mov $0x0,%eax
80488bc: 8b 4d f4 mov -0xc(%ebp),%ecx
80488bf: 65 33 0d 14 00 00 00 xor %gs:0x14,%ecx
80488c6: 74 05 je 80488cd <main+0x20f>
80488c8: e8 73 fb ff ff call 8048440 <__stack_chk_fail@plt>
80488cd: 8b 4d fc mov -0x4(%ebp),%ecx
80488d0: c9 leave
80488d1: 8d 61 fc lea -0x4(%ecx),%esp
80488d4: c3 ret
80488d5: 66 90 xchg %ax,%ax
80488d7: 66 90 xchg %ax,%ax
80488d9: 66 90 xchg %ax,%ax
80488db: 66 90 xchg %ax,%ax
80488dd: 66 90 xchg %ax,%ax
80488df: 90 nop
I work in c9 environment.
also, I've read this topic: Causing a buffer Overflow with fgets not helping.
the buffer overflow happens when you inpout exactly len
characters the characters are copied into guess.word and the nul
terminator overflows past the end.
the
strcpy(guess.result,
"thing" then ovewrites the nul
then the for loop loops until it runs out of memory and you get a segfault.
a successful exploit will write a values to i
and offset
such that
a: the loop terminates without hitting a bad memory address
b: the value in status
matches STATUS_WINNER
To do that LEN must be clobbered with a values less than 70
Thanks everyone for trying to help, all of you gave me great ideas, here is my solution:
In main function, there is this for-loop:
for(i = 0; i < len; ++i)
guess.result[offset+i] = guess.word[i];
offset equals to the length of the string "WRONG! YOUR WORD: " which is 19. therefore, if the user enters a 56 bytes long of string (which is the max length of guess.word), "len" would be 75 (56 of input + 19), and "offset+i" would be between 19 and 74 (actually 75, but the loop will exit). therefore, when "offset+i" would be 72, guess.result would start override guess.status (guess.result is 72 bytes long, and guess.status is right after it), and at "offset+i"=75 - which happens when i=56, guess.word[56] would be guess.result[0], which is "W" (of "WRONG! YOUR..."). from there it's easy.
User contributions licensed under CC BY-SA 3.0