Weird execution path caused by stack buffer overflow - c

I read some articles about Stack Buffer Overflow, like this one, and learned how attackers can exploit a Stack Buffer-Overflow bug by overwriting function pointers. Then I wrote a small program to demonstrate an attack:
#include <stdio.h>
#include <string.h>
void fun1 ( char * input ) {
char buffer[10];
strcpy( buffer, input );
printf( "In fun1, buffer= %s\n", buffer );
}
void fun2 ( void ) {
printf ( "HELLO fun2!\n" );
}
int main ( int argc, char * argv[] )
{
printf ( "Address of fun2: %p\n", fun2 );
fun1( "abcdefghijklmnopqrstuv\x52\x84\x04\x08" );
return 0;
}
The program was compiled with GCC 4.5.1, under Fedora 14 x86. Below is the output:
$ ./exp01
Address of fun2: 0x8048452
In fun1, buffer= abcdefghijklmnopqrstuvR�
HELLO fun2!
HELLO fun2!
We can see that fun2() was called successfully, but I don't know why it ran twice. Then I GDBed it (See Below). (I know only some basic instruction about GDB ╮( ̄▽ ̄)╭ )
I Googled some key words such as "__libc_csu_fini ()", but didn't find a clear way that can help me to understand the program's execution path. I know too little about compiler and the inner structure of a process, so I consider that I may have to find some books or articles that describe these stuff in detail. Any suggestion? Thank you!
GDB Record:
(gdb) list
7 printf( "In fun1, buffer= %s\n", buffer );
8 }
9
10 void fun2 ( void ) {
11 printf ( "HELLO fun2!\n" );
12 }
13
14 int main ( int argc, char * argv[] )
15 {
16 printf ( "Address of fun2: %p\n", fun2 );
(gdb)
17 fun1( "abcdefghijklmnopqrstuv\x52\x84\x04\x08" );
18 return 0;
19 }
(gdb) break 16
Breakpoint 1 at 0x804846f: file hello.c, line 16.
(gdb) run
Starting program: /home/yuliang/test/hello
Breakpoint 1, main (argc=1, argv=0xbffff394) at hello.c:16
16 printf ( "Address of fun2: %p\n", fun2 );
Missing separate debuginfos, use: debuginfo-install glibc-2.13-2.i686
(gdb) step
Address of fun2: 0x8048452
17 fun1( "abcdefghijklmnopqrstuv\x52\x84\x04\x08" );
(gdb)
fun1 (input=0x804859a "abcdefghijklmnopqrstuvR\204\004\b") at hello.c:6
6 strcpy( buffer, input );
(gdb)
7 printf( "In fun1, buffer= %s\n", buffer );
(gdb)
In fun1, buffer= abcdefghijklmnopqrstuvR�
8 }
(gdb)
fun2 () at hello.c:10
10 void fun2 ( void ) {
(gdb)
11 printf ( "HELLO fun2!\n" );
(gdb)
HELLO fun2!
12 }
(gdb)
0x08048500 in __libc_csu_fini ()
(gdb)
Single stepping until exit from function __libc_csu_fini,
which has no line number information.
fun2 () at hello.c:10
10 void fun2 ( void ) {
(gdb)
11 printf ( "HELLO fun2!\n" );
(gdb)
HELLO fun2!
12 }
(gdb)
Cannot access memory at address 0x76757477
(gdb)
Single stepping until exit from function __libc_csu_init,
which has no line number information.
0x009aae36 in __libc_start_main () from /lib/libc.so.6
(gdb)
Single stepping until exit from function __libc_start_main,
which has no line number information.
Program exited with code 0241.
(gdb)

When running your program in gdb break shortly before the strcpy() and have a look at the stack-frame (that is where the save eip is stored). then run until shortly after the printf() and again have a look at the stored eip (command is info frame).
since you pass the address of function fun2() to fun1() it will overwrite the saved eip and as soon as return is called (implicit in your case) the next instruction will be executed (which is given by eip and in your case it is the address of fun2())
And don't forget to read Smashing the stack for fun and profit by aleph1

Related

gdb debugging segmentation fault, arguments count showing false

I am trying to debug the segmentation fault of a menu program written in 'C' and the main function is shown in the below screen shot.
int main( int ac, char **av ) {
/* TDT,II - 02 May 2006 - Added this check to see if there is a Debug level passed in */
if ( ac > 0 ) {
iDebug = atoi( av[1] );
sprintf( cLogText, "Setting Debug Level to ~%d~", iDebug );
WriteTrace( cLogText );
};
initscr();
clear();
t1=time(NULL);
local =localtime(&t1);
Svc_Login();
for ( ; ; ) {
cases_on_pc=FALSE;
if ( !Process_security() ) break;
menu1();
};
wrap_up(0);
endwin( );
exit(0);
}
when i try to debug (run using gdb), without any arguments, getting halted at 0x00007ffff34c323a in ____strtoll_l_internal () from /lib64/libc.so.6 as shown below. if(ac>0) becomes true, only when i pass any arguments. but i haven't passed any runtime arguments. still that 'f block is being executed and function atoi(av[1]) is called and resulted in segmentation fault. I am unable to figure it out. how to proceed further to identify and correct the issue so that i could run the menu program successfully. could somebody give any suggestions on this?
-rw-rw-r--. 1 MaheshRedhat MaheshRedhat 2275270 Jan 10 03:09 caomenu.c
-rw-rw-r--. 1 MaheshRedhat MaheshRedhat 0 Jan 10 03:09 caomenu.lis
-rwxr-xr-x. 1 root root 796104 Jan 10 03:10 scrmenu
[MaheshRedhat#azureRHEL MenuPrograms]$
[MaheshRedhat#azureRHEL MenuPrograms]$ gdb ./scrmenu
(gdb) run
Starting program: /home/MaheshRedhat/MenuPrograms/scrmenu
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff34c323a in ____strtoll_l_internal () from /lib64/libc.so.6
Missing separate debuginfos, use: yum debuginfo-install glibc-2.28-189.5.0.1.el8_6.x86_64 libnsl-2.28-189.5.0.1.el8_6.x86_64 ncurses-libs-6.1-9.20180224.el8.x86_64
(gdb)
(gdb) bt
#0 0x00007ffff34c323a in ____strtoll_l_internal () from /lib64/libc.so.6
#1 0x00007ffff34bfce4 in atoi () from /lib64/libc.so.6
#2 0x0000000000401674 in main (ac=1, av=0x7fffffffe228) at caomenu.pc:541
(gdb)
Update
The above issue has been resolved. Here is another encounter of segmentation fault.
from this backtrace of system calls, in WriteTrace (cEntryText=0x6f4d20 <cLogText> in my main function lead to call fputs() from library file /lib64/libc.so.6
Starting program: /home/MaheshRedhat/MenuPrograms/scrmenu 1
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff34f7f5c in fputs () from /lib64/libc.so.6
(gdb)
(gdb) bt
#0 0x00007ffff34f7f5c in fputs () from /lib64/libc.so.6
#1 0x0000000000472efc in WriteTrace (cEntryText=0x6f4d20 <cLogText> "Setting Debug Level to ~1~") at caomenu.pc:18394
#2 0x00000000004016a0 in main (ac=2, av=0x7fffffffe208) at caomenu.pc:543
(gdb)
The below is the declaration of cLogText
char cLogText[250];
The below is code for WriteTrace:
/**************************************************************************
routine to write an entry in the trace file
**************************************************************************/
void WriteTrace( char *cEntryText ) {
char cTimeStamp[40]; /* time stamp variable */
char cTimeFormat[]="%H:%M:%S: "; /* time stamp format */
GetTimeStamp( &cTimeStamp[0], sizeof(cTimeStamp), &cTimeFormat[0] );
TrcFile = fopen( cTraceFile, cTrcOpenFlag ); /* open the file */
cTrcOpenFlag[0] = 'a'; /* after first, always app} */
fprintf(TrcFile, "%s", cTimeStamp); /* write the time stamp */
fprintf(TrcFile, "%s\n", cEntryText); /* write the entry */
fclose(TrcFile); /* close the trace file */
return; /* return to caller */
}
From C11:
The value of argc shall be nonnegative. argv[argc] shall be a null
pointer. If the value of argc is greater than zero, the array members
argv[0] through argv[argc-1] inclusive shall contain pointers to
strings, which are given implementation-defined values by the host
environment prior to program startup. The intent is to supply to the
program information determined prior to program startup from elsewhere
in the hosted environment. If the host environment is not capable of
supplying strings with letters in both uppercase and lowercase, the
implementation shall ensure that the strings are received in
lowercase.
If the value of argc is greater than zero, the string
pointed to by argv[0] represents the program name; argv[0][0] shall be
the null character if the program name is not available from the host
environment. If the value of argc is greater than one, the strings
pointed to by argv[1] through argv[argc-1] represent the program
parameters.
The condition
( ac > 0 )
would be true even if you provided 0 program arguments, with argv[0] pointing to the program name (if it was available).
This statement:
atoi( av[1] );
tries to access av[1] which the Standard defines to be NULL when no program arguments were provided. Hence the segmentation violation signal.
fopen returns NULL to indicate failure.
TrcFile = fopen( cTraceFile, cTrcOpenFlag );
You do not check its return value here, before passing it to fprintf.
Perhaps:
TrcFile = fopen( cTraceFile, cTrcOpenFlag );
if (!TrcFile) {
deal with error here..
}
if (ac > 0) {
iDebug = atoi(av[1]); // out of bounds here, when you run `./scrmenu`
}
when you run ./scrmenu, you will have ac=1 and av[0]=./scrmenu
You may misunderstand ac and av mean in the main function.
how to fix:
if (ac == 2) {
iDebug = atoi(av[1]); // parse the second argument
}
then you can run: ./scrmenu or ./scrmenu 1 something like this.
you can check this post about command line argument

Cant access a specific memory address. on C program

I am working on the book "HACKING Art Of Exploitation " exercise Convert2.c page 61.
Here's my code. Below is my question.
#include <stdio.h>
void usage(char *program_name) {
printf("Usage: %s <message> <# of times to repeat>\n", program_name);
exit(1);
}
int main(int argc, char *argv[]) {
int i, count;
// if(argc < 3) //if fewer than 3 arguments is used
// usage(argv[0]); // display usage message and exit
count = atoi(argv[2]); //convert the second arg into an interger
printf("Repeating %d times\n", count);
for(i=0; i < count; i++)
printf("%3d - %s\n", i, argv[1]); // print the first arg
}
GDB OUTPUT...
➜ git:(master) ✗ 👽 gdb -q a.out
Reading symbols from a.out...done.
(gdb) run test
Starting program: /home/fruitdealer/clones/C_zombie/hacking/a.out test
Program received signal SIGSEGV, Segmentation fault.
__GI_____strtol_l_internal (nptr=0x0, endptr=endptr#entry=0x0, base=base#entry=10, group=group#entry=0,
loc=0x7ffff7dd0560 <_nl_global_locale>) at ../stdlib/strtol_l.c:292
292 ../stdlib/strtol_l.c: No such file or directory.
(gdb) break main
Breakpoint 1 at 0x555555554707: file convert.c, line 14.
(gdb) where
#0 __GI_____strtol_l_internal (nptr=0x0, endptr=endptr#entry=0x0, base=base#entry=10, group=group#entry=0,
loc=0x7ffff7dd0560 <_nl_global_locale>) at ../stdlib/strtol_l.c:292
#1 0x00007ffff7a29122 in __strtol (nptr=<optimized out>, endptr=endptr#entry=0x0, base=base#entry=10)
at ../stdlib/strtol.c:106
#2 0x00007ffff7a24690 in atoi (nptr=<optimized out>) at atoi.c:27
#3 0x000055555555471f in main (argc=2, argv=0x7fffffffdeb8) at convert.c:14
(gdb) run test
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/fruitdealer/clones/C_zombie/hacking/a.out test
Breakpoint 1, main (argc=2, argv=0x7fffffffdeb8) at convert.c:14
14 count = atoi(argv[2]); //convert the second arg into an interger
(gdb) cont
Continuing.
Program received signal SIGSEGV, Segmentation fault.
__GI_____strtol_l_internal (nptr=0x0, endptr=endptr#entry=0x0, base=base#entry=10, group=group#entry=0,
loc=0x7ffff7dd0560 <_nl_global_locale>) at ../stdlib/strtol_l.c:292
292 ../stdlib/strtol_l.c: No such file or directory.
(gdb) x/3xw 0x7fffffffdeb8
0x7fffffffdeb8: 0xffffe220 0x00007fff 0xffffe250
(gdb) x/s 0xffffe220
0xffffe220: <error: Cannot access memory at address 0xffffe220>
(gdb) x/s 0xffffe250
0xffffe250: <error: Cannot access memory at address 0xffffe250>
(gdb) x/sw 0xffffe250
0xffffe250: <error: Cannot access memory at address 0xffffe250>
(gdb)
I posted all of gdb output because i wasn't sure how much of it you would need. My problem lies at the bottom of my GDB output when i run "x/s" on gdb and get the <error: Cannot access memory at address 0xffffe250> error.
On the book Jon Erickson is able to access 0xffffe220 and 0x00007fff and then he has an error on 0xffffe250 this part of memory.
What am i missing?
Why can't i access any of the three addresses in 0x7fffffffdeb8?
The first half of the address is cut off. If you notice, it takes 8 bytes to store the addresses because you are on a 64 bit machine, not 32. You are trying to access a truncated address.
Rather than three addresses at 0x7fffffffdeb8, you are looking at one and a half. Try accessing a byte that starts with 0x00007fff...

GDB doesn't let me read argv memory segment

I have this simple script written in C:
#include <stdio.h>
void usage(char *program_name) {
printf("Usage: %s <message> <# of times to repeat>\n", program_name);
exit(1);
}
int main(int argc, char *argv[]) {
int i, count;
// if(argc < 3) // If less than 3 arguments are used,
// usage(argv[0]); // display usage message and exit.
count = atoi(argv[2]); // convert the 2nd arg into an integer
printf("Repeating %d times..\n", count);
for(i=0; i < count; i++)
printf("%3d - %s\n", i, argv[1]); // print the 1st arg
}
And I'm making some test with GDB.
I did this:
(gdb) run test
Starting program: /home/user/Desktop/booksrc/convert2 test
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a56e56 in ____strtoll_l_internal () from /usr/lib/libc.so.6
Obviusly it goes in segmentation fault because to work the program needs three argv. And I commented the lines that do the control. So it goes in error.
(gdb) where
#0 0x00007ffff7a56e56 in ____strtoll_l_internal () from /usr/lib/libc.so.6
#1 0x00007ffff7a53a80 in atoi () from /usr/lib/libc.so.6
#2 0x00005555555546ea in main (argc=2, argv=0x7fffffffe958) at convert2.c:14
(gdb) break main
Breakpoint 1 at 0x5555555546d2: file convert2.c, line 14.
(gdb) run test
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/user/Desktop/booksrc/convert2 test
Breakpoint 1, main (argc=2, argv=0x7fffffffe958) at convert2.c:14
14 count = atoi(argv[2]); // convert the 2nd arg into an integer
(gdb) cont
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a56e56 in ____strtoll_l_internal () from /usr/lib/libc.so.6
(gdb) x/3xw 0x7fffffffe958 // this is memory of the "argv" some line before
0x7fffffffe958: 0xffffebfe 0x00007fff 0xffffec22
(gdb) x/s 0xffffebfe
0xffffebfe: <error: Cannot access memory at address 0xffffebfe>
(gdb) x/s 0x00007fff
0x7fff: <error: Cannot access memory at address 0x7fff>
(gdb) x/s 0xffffec22
0xffffec22: <error: Cannot access memory at address 0xffffec22>
In theory, with "x/s" I should have seen the commandline in the first address and "test" in the second address and the null in the third. But nothing. If I copy paste that address to a ascii to string converter, it gives me data without any sense. What am I doing wrong?
Your platform uses 64bit pointers, so try :
(gdb) x/3xg 0x7fffffffe958
to display the 64bit pointers in the argv array, and then :
(gdb) x/s 0x00007fffffffebfe
or just :
(gdb) p argv[0]
First of all always check if the command line is correct
Uncomment the check from your code.
Then in the gdb set the arguments (before running it)
(gdb) set args "hello world" 12

GCC based SIGSEGV error?

So I have been writing a handful of C libraries for my own personal use and I have been doing swell until my latest library, which just contains a bunch of string functions. As you can probably tell by the question title, I am getting a SIGSEGV signal. The problem is this: my research indicates that about 99% of all SIGSEGV errors are due to stack overflow, itself due to bad recursion, but as you will see, I am not using any recursion. Furthermore, there are a few odd problems that occur. For one, printf is exhibiting a lot of funky behavior. GDB encounters printf calls but does not actually seem to execute them until a few lines of code later. Likewise, one of my printf statements is being broken up somehow, and only a part is being called, with another part being chopped off apparently.
Here are the key code snippets, some stuff is named funny because I suspected name clashing may be the cause at one point and may have gone a little overboard...
"firstIndexOf" function (finds the first index of a character in a string, if that character is in said string), found at line 31:
int firstIndexOfFUNCTION(char thisChar, char* inThisString)
{
int lengthABC = strlen(inThisString);
printf("\nLength of %s is %d",inThisString,lengthABC);
int thisFunctionsIndex;
for (thisFunctionsIndex=0;thisFunctionsIndex<lengthABC;thisFunctionsIndex++)
{
printf("\n%dth iteration:\n-char 1 is %c\n-char2 is %c",thisFunctionsIndex,inThisString[thisFunctionsIndex],thisChar);
if (inThisString[thisFunctionsIndex] == thisChar)
{
printf("\nMatch found on iteration %d!",thisFunctionsIndex);
return thisFunctionsIndex;
}
}
printf("\nNo matches detected...");
return -3;
}
The "string_functions_test" function (a function just meant to test the other functions) at line 62:
int string_functions_test()
{
printf("PROGRAM INITIALIZED!\n\n");
char* sft_string;
int sft_index;
sft_string = malloc(sizeof(char)*100);
sft_string = "B um sbm. Sbm B bm.";
printf("2nd BREAKPOINT");
sft_index = firstIndexOfFUNCTION('B',sft_string);
sft_string[sft_index] = 'I';
return 0;
}
and last but not least, good ol' main, at line 107:
int main(int argc, char* argv[])
{
string_functions_test();
return 0;
}
Here is the gdb output for a step-through of my code:
(gdb) b 105
Breakpoint 1 at 0x400970: file string_functions.c, line 105.
(gdb) run
Starting program: /home/user/Development/projects/c/string_functions/source/c/a.out
Breakpoint 1, main (argc=1, argv=0x7fffffffde98) at string_functions.c:109
109 string_functions_test();
(gdb) step
string_functions_test () at string_functions.c:64
64 printf("PROGRAM INITIALIZED!\n\n");
(gdb) next
PROGRAM INITIALIZED!
68 sft_string = malloc(sizeof(char)*100);
(gdb) next
69 sft_string = "B um sbm. Sbm B bm.";
(gdb) next
71 printf("2nd BREAKPOINT");
(gdb) next
73 sft_index = firstIndexOfFUNCTION('B',sft_string);
(gdb) step
firstIndexOfFUNCTION (thisChar=66 'B', inThisString=0x400ab9 "B um sbm. Sbm B bm.") at string_functions.c:33
33 int lengthABC = strlen(inThisString);
(gdb) next
34 printf("\nLength of %s is %d",inThisString,lengthABC);
(gdb) next
2nd BREAKPOINT
36 for (thisFunctionsIndex=0;thisFunctionsIndex<lengthABC;thisFunctionsIndex++)
(gdb) next
38 printf("\n%dth iteration:\n-char 1 is %c\n-char2 is %c",thisFunctionsIndex,inThisString[thisFunctionsIndex],thisChar);
(gdb) next
Length of B um sbm. Sbm B bm. is 19
0th iteration:
-char 1 is B
39 if (inThisString[thisFunctionsIndex] == thisChar)
(gdb) next
41 printf("\nMatch found on iteration %d!",thisFunctionsIndex);
(gdb) next
-char2 is B
42 return thisFunctionsIndex;
(gdb) next
47 }
(gdb) next
string_functions_test () at string_functions.c:75
75 sft_string[sft_index] = 'I';
(gdb) next
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400883 in string_functions_test () at string_functions.c:75
75 sft_string[sft_index] = 'I';
(gdb) next
Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
(gdb) quit
You may notice that the printf which prints "2nd Breakpoint" is called, and then the program steps into a different function before the results are seen. I am assuming this is some whacky behavior on the part of the gcc compiler meant to serve as a cpu optimization, but it is sort of messing me up right now obviously. Likewise, the printf in my for loop is being broken up after the first formatted char. These two things are making it super hard to detect what exactly is happening. Has anyone experienced similar behavior?
In case it matters, I am including:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
You are first pointing the pointer sft_string to what is returned from malloc. In the next line you make it point to a literal string. You need to copy it. A literal is built into the source code and cannot be changed during execution. Otherwise it raises a segment fault, which means that an area of memory that has code is being changed. Use strcpy.

Stack-Based Buffer Overflow Vulnerabilities

I am reading a book titled Hacking: The Art of Exploitation, and I have a problem with the section Stack-Based Buffer Overflow Vulnerabilities.
I am following the instructions given by the author, but I don't get the expected results.
First, here is the program auth_overflow2.c, copied from the book:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int check_authentication(char *password) {
char password_buffer[16];
int auth_flag = 0;
strcpy(password_buffer, password);
if(strcmp(password_buffer, "brillig") == 0)
auth_flag = 1;
if(strcmp(password_buffer, "outgrabe") == 0)
auth_flag = 1;
return auth_flag;
}
int main(int argc, char *argv[]) {
if(argc < 2) {
printf("Usage: %s <password>\n", argv[0]);
exit(0);
}
if(check_authentication(argv[1])) {
printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
printf(" Access Granted.\n");
printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
} else {
printf("\nAccess Denied.\n");
}
}
This is a copy of my Ubuntu terminal:
(gdb) break 19
Breakpoint 1 at 0x40077b: file auth_overflow.c, line 19.
(gdb) break 7
Breakpoint 2 at 0x4006df: file auth_overflow.c, line 7.
(gdb) break 12
Breakpoint 3 at 0x40072a: file auth_overflow.c, line 12.
(gdb) run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Starting program: /home/test/a.out AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Breakpoint 1, main (argc=2, argv=0x7fffffffdf08) at auth_overflow.c:19
19 if(check_authentication(argv[1])) {
(gdb) i r esp
esp 0xffffde10 -8688
(gdb) x/32xw $esp
0xffffffffffffde10: Cannot access memory at address 0xffffffffffffde10
(gdb) c
Continuing.
Breakpoint 2, check_authentication (password=0x7fffffffe2cc 'A' <repeats 30 times>) at auth_overflow.c:7
7 strcpy(password_buffer, password);
(gdb) i r esp
esp 0xffffddc0 -8768
(gdb) x/32xw $esp
0xffffffffffffddc0: Cannot access memory at address 0xffffffffffffddc0
(gdb) p 0xffffde10 - 0xffffddc0
$1 = 80
(gdb) x/s password_buffer
0x7fffffffdde0: "\001"
(gdb) x/x &auth_flag
0x7fffffffdddc: 0x00
(gdb)
When i try x/32xw $esp i get:
0xffffffffffffde10: cannot access memory at address 0xffffffffffffde10
Same thing happens when i continue to the second break point.
When author types x/s password_buffer the output is:
0xbffff7c0: "?o??\200????????o???G??\020\205\004\b?????\204\004\b????\020\205\004\bH???????\002"
but my output looks like this:
0x7fffffffdde0: "\001"
My i r esp result is also different from the book.
in the book there are two hexadecimal numbers:
esp 0xbffff7e0 0xbffff7e0
I am using Ubuntu and GCC and GDB.
I think I might have the answer - your argv[ 1 ] is pointing to the 30 'A's - and you have a password buffer of 16. The strcpy() will just fill the buffer and beyond.
I would increase the buffer size to a larger size (say 255 bytes).
In practise, you should review your code, even examples, and make them more robust (example: allowing for larger passwords then 16 )
Please less the number of As try A(17) times it will work

Resources