发新话题
打印

[翻译]对错误,漏洞和exploits的说明

[翻译]对错误,漏洞和exploits的说明

文章作者:Mark Vogels
译文作者:黯魂[S.S.T]
信息来源:脚本安全小组(www.cnsst.org

在这篇文档中,我将会试着为你提供一个对于错误,和由于那些错误而产生的漏洞以及它们的exploits的基本认识。那决不意味着能让你完全理解exploits和漏洞,但是能帮助你学会认识可能的漏洞以及怎样处理它们。

一般而言有3种不同类型的错误会可能危及计算机系统和网络的安全。
#编程错误
#配置错误
#设计错误

错误可以被看成是失误,尽管它们并非都是由事故导致的。软件/设备的最初创建者可能就存在错误,用最好的想法却创建了错误,并且没有意识到它可能就是一个潜在的威胁。这听上去可能有点糊涂,但是稍后在文章中都将会被澄清。为了深入探讨关于错误的细节,我们需要创建一个对不同类型的错误的定义以至于我们能更容易认识它们。

不同错误类型的定义

编程错误:

编程错误通常是由程序编写者造成的。最常见的可利用编程错误是缓冲区溢出。把缓冲区溢出想象成一个空的杯子:程序的使用者将要倒咖啡到杯子里,但是程序编写者事先并不知道使用者将会倒多少咖啡在里面。所以程序编写者必须在使用者把咖啡倒进杯子之前检查和测试,以阻止咖啡从杯子里溢出。有时候检查输入大小并不容易,或者由于时间紧迫,程序员没有时间写足够广泛的错误检测函数。那么结果就是:可能的缓冲区溢出和其他的编程错误被创建。

另一个编程错误的例子是:当用户做一些预料之外的事,比如加载一个错误类型的文件到程序中时,程序会崩溃。当然不是所有的编程错误都需要用户输入才能做一些预料之外的事,像使程序崩溃。一个程序也会取决于总是在一个明确位置的特殊文件。如果那个文件被移动,并且程序员没有预料到,他就不可能在程序尝试打开它之前检测文件是否还是在那个位置。假如程序在打开那个文件后尝试用它运行,这就会导致不可预见的行为。

这些类型的错误发生得相当频繁,并且大多时候厂商都会分发补丁包来解决由消费者或者他们自己发现的被报告的错误。

配置错误:

这样想象一个配置错误:如果你是一个网络管理员并且你需要运行一个防火墙来保护你的网络。习惯上,你会允许任何进出的流量,除专门拒绝的流量种类之外。

一个简单的例子是防火墙仅仅阻塞了80端口,然而它将允许来自因特网的任何人连接到防火墙的配置页面重新配置它。其余的端口都是开着的。这明显就是一个配置错误,任何人都能通过使用另一个端口号来绕过防火墙。

幸运的是大多数厂商都知道这个错误,因此他们都正确的做了相反的处理:任何流量都被阻塞除非专门允许的。所以自从端口被关闭以后,网络管理员都不再需要担心发现的新问题,通过一个不使用的端口能访问他的网络。(这里我只使用端口来举例子,不过这在相同的端口上也能应用不同类型的流量。)

另一个配置错误的例子是,在一个网络中的不受管理的hub代替可管理的交换机的用法。不同之处是,hub发送所有进入的数据包到所有的端口,因为它并不知道在它后面的接收者被定位到哪个端口,而交换机知道。所以,在一个使用hub代替交换机的网络中运行一个sniffer,允许一个攻击者查看包含可能的用户名及密码的更多数据包,解决办法就是在网络中使用交换机。即使现在这是一个配置错误,但在过去却不是,因为那时交换机还不存在。
  
设计错误:

设计错误可以被看成是在软件设计阶段发生的错误。即使程序员花足够的时间在软件发布之前编写检测流程来检验所有用户的输入,即使软件被最终用户正确地配置,这些错误仍然会造成对于一个网络的安全的极大危险。

让我们看看这种情况:一个公司决定开发一个软件,这个软件允许远程访问到一个网络。那么他们也不得不支持这个软件,从而他们决定放一些后门在里面以至于能使用公司名字作为密码远程登录。如果公司以外的人发现了那些后门呢,会发生什么?他使用那个软件的远程访问能够登录进任何一个网络。结果将会是损失惨重的!

尽管这些后门在过去被创建的相当频繁,现在一个公司销售类似的软件却不会再带来风险了,因为他要对攻击者的滥用后门负责。

另一个设计错误的例子是使用在安全无线网络中的WEP加密。我不打算深入说明这为什么是一个设计错误,毕竟那超出了这篇文章的范围,但是它的基本流程是这样的:
一个3字节的初始化矢量增加到公钥中来加密每个唯一的数据包。假设公钥是abcde。第一个数据包的初始化矢量是123,因此这个数据包的全部密钥就是123abcde。下一个数据包的初始化矢量是234,那么它的密钥就是234abcde。

设计错误在这里其实也就是,只有3字节的不同初始化矢量,导致了255^3或者说1650万不同的keys以及部分加密算法被使用。通过逆向分析部分算法,能够相当容易地获得公钥中的几个字符。由于这个设计错误,你只需要用唯一的初始化矢量重复发送10万个包(64-bit),发送80万个包(128-bit),就能破解出WEP-key,便可以进入完整的无线网络中。在一个繁忙的无线网络中这能在几小时内做到。

那么你看到了,设计错误有点更难解决。你不能只是期望厂商发布快速更新来解决这个问题,你也不可能通过查阅产品说明书自己解决。针对WEP加密这种情况,一个小组创建了一个新的标准,叫做WPA。这意味着使用WEP加密的产品应该被取代,或者通过硬件更新以允许它们用这个新加密标准工作。对于已发现的WEP上的设计错误的细节描述,可以去看看airscanner。com上面的精华文章。


这些错误如何成为漏洞的?

一个漏洞就是对目标的保护方面的一个弱点。目标可以是连到一个完整网络的一台计算机的任何部分。我不会说明这儿可能的漏洞的所有不同,因为那几乎不可能,但是我将设法指出什么是漏洞,以及漏洞如何产生的。

按照早期的规定,最普遍的会成为漏洞的编程错误是缓冲区溢出。假设一个基于栈的缓冲区溢出,缓冲区被放置在栈中。栈可以被看成是你的处理器存储数据在里面并能与其共同工作的一个临时工作区。现在,当你溢出一个放置在栈里的缓冲区时,你能够写数据到已分配空间的缓冲区之外,因此可以写其它数据到栈中。而其它数据可以是调用函数的返回地址。假设调用函数的返回地址是12345678,并且返回地址直接存储在缓冲区后面的栈中,那么栈看上去可能会像这样:
XXXXXXXXXX12345678

XXXXXXXXXX是将包含我们的输入的缓冲区。如果我们放一些比缓冲区大小要少的数据在里面,没有任何奇怪的事会发生,但是当我们放12个'A'在这只能承载10个字符的缓冲区中时,多余的2个A就会覆盖掉返回地址部分。从而使返回地址变成一个无效地址,然后函数无法返回,程序就崩溃了。

如果这个程序是一个服务端应用程序,有人能放12个A使程序崩溃,并且导致其他所有用户都无法访问。这就成为了一个拒绝服务攻击的例子。既然这样,这个错误就有了拒绝服务漏洞。

如果我们用与上面同样的例子,但换一个更大的缓冲区,那么溢出缓冲区也就意味着更多的数据在一个实际溢出发生之前必须被放进去,可是当那发生时,我们可以写一些计算机代码(汇编指令),将其作为数据的一部分而放在缓冲区中使用。我们通过覆盖它来改变返回地址,以指向我们溢出的缓冲区后面,程序将会试图执行我们的缓冲区。这时,缓冲区包含了我们放进去的代码,程序并不会崩溃,而是转去执行我们的代码。由于那些代码可以是开启一个shell(命令解释程序)的一小段代码,并且会在那台计算机上监听一个特殊端口,因此这种类型的代码经常被称作shellcode。

随着这些代码的运行,有人便能够连接到那个特殊的端口上,并能执行远程命令,同时获得与在远程计算机开启这个存在漏洞的应用程序的用户所拥有的相同访问权的控制权。

对于配置错误,如果我们看看防火墙的例子,漏洞就更加明显。假如那个防火墙能经由telnet远程配置,那么仅仅不允许访问防火墙的80端口会给网络管理员一个安全上的错误认识,攻击者仍旧能够通过连接到防火墙的23端口进行访问而配置它。

然而,自从消费者开始要求他们所购买的产品应具有不同配置选项以后,厂商就开始着手研发高级别的可配置的软件和设备。这可能让一个设备的配置变得专业化而导致错误很容易发生。类似的设备的配置是如此的复杂,而漏洞能被网络管理员看到,因此允许一个潜在的攻击者访问到网络或系统中他本不应该访问到的部分,所以一个简单的配置错误会导致网络和系统中存在一个潜在的漏洞。

我已经给出了一个由设计错误导致漏洞的例子:WEP密钥,但它很容易引出另一个设计错误的例子:设想一个软件公司编写了一个软件用于浏览和创建文本文档。他们想要出售他们的产品,然而由于竞争者的软件公司也开发了一款相同功能的软件,他们不得不设计一个表面上有更强大的功能的程序。因此他们决定增加一个特性以允许用户能对自己创建的文档有更多的控制,那样用户可以编写小型函数(宏),并能被植入文档中,同时能够帮助文档浏览者在他的计算机上做各种各样的事情。如果所有这些功能被一个恶意攻击者使用,创建一个已植入宏的文档,能复制自身到机器上被找到的其他所有文档中去,并且不经过浏览者的同意做各种各样的其他事情呢?那么在这个被设计而创建的程序中,我们又有了一个可能的漏洞。

你可以看到,一个错误会导致产生一个漏洞。在宏被使用在文档中的情况下,帮助软件用户创建更多动态文档的想法很伟大,除设计时没有考虑安全因素以外。


那么什么是一个exploit?

exploit就是一种利用一个已发现的漏洞来改变程序或者系统初始功能的方法。这种方法对于一个攻击者而言更有用处。在计算机安全中,术语"exploit"经常被用于描述一个特殊的程序,它的唯一目的就是自动利用一个漏洞来取得对有漏洞的目标程序的控制权,或者终止目标程序的正常功能。

但是在一个系统或者网络中使用一个错误的配置对要利用它的攻击者来说,也能被叫做一个exploit,尽管它不一定非要是一个实际上能完成工作的特殊程序。

我将通过一些C代码的例子来试着说明一个exploit的作用,其中之一是一个存在缓冲区溢出漏洞的简单的程序,另一个则是exploit。

注意:这里给出的例子可能在不同的编译器和系统上表现不同。你可能需要改变缓冲区中字符的数目才能真正改写返回地址,或者exploitfunction的地址会不同,但是他们仍能工作。

vulnerable_program.c:
复制内容到剪贴板
代码:
#include "stdio。h"
/*利用函数*/
exploitfunction()
{
/*如果缓冲区溢出被成功利用,就会输出此行内容*/
printf("This line will be printed after successfully exploiting the buffer overflow. ");
system("pause");
ExitProcess(0);
}

normalfunction(char *myargument)
{
char buffer[10];
strcpy(buffer,myargument);
}

main(int argc, char *argv[])
{
if(argc>1)
{
normalfunction(argv[1]);
printf(" These lines get printed during normal execution with at least 1 commandline argument.The address of exploitfunction
is 0x%。8X ",&exploitfunction);
}
else
printf("Please provide the program with at least 1 commandline argument. ");
ExitProcess(0);
}
我已经创建了3个函数,一个是主函数,其他2个分别是:在正常情况下执行的normalfunction,以及利用函数exploitfunction。程序的目的是溢出缓冲区以至于返回地址将指向替换了normalfunction后面下一条指令的exploitfunction函数。

现在我们需要指出文本字符串要多大才能完全覆盖栈中的返回地址。有这个作为目标,就好办了!我们每次增加一个字符直到程序崩溃。

当我在Windows系统上使用Dev-cpp编译完程序以后,我知道了在程序崩溃之前最多需要27个A。
exploitfunction函数的地址以16进制形式表示,并且字节值经常表现出:地址是不可打印的字符。我写了一个小程序,它将给这个易受攻击的程序提供必要的字符串以利用它。

在我的环境中,exploitfunction函数的地址(从易受攻击的程序内部我方便地打印得到)是0x00401290。因为栈在Intel x86系统上是以逆序存储所有数据的(这篇文档中那不会被说明),我们需要准备一个相同的字符串。因此可能的值类似于
0x41414141414141414141414141414141414141414141414141414141901240.

你可以看到,这里的字符'A'(0x41)我使用的是16进制的表现形式,那是存储在栈中的真实值。结果就是,exploit非常简单:

Exploit.c:
复制内容到剪贴板
代码:
#include "stdio.h"
main()
{
char workbuffer[200];
char tempbuf[4];
strcpy(workbuffer,"vulnerable_program AAAAAAAAAAAAAAAAAAAAAAAAAAAA");
tempbuf[0]=0x90;
tempbuf[1]=0x12;
tempbuf[2]=0x40;
tempbuf[3]=0;
strcat (workbuffer,tempbuf);
system(workbuffer);
return 0;
}
这段程序所做的就是复制字符串"vulnerable_program AAAAAAAAAAAAAAAAAAAAAAAAAAAA"到一个缓冲区中,并用新的返回地址创建另一个缓冲区,附加在工作缓冲区之上。
在那之后,程序调用system()来执行字符串中的命令。输出结果是:
C:>exploit.exe
This line will be printed after successfully exploiting the buffer overflow.
Press any key to continue……

太棒了,它执行了!

难道那不伟大吗?

虽然我们实际上并没有成功让程序运行我们自己的代码,但经过一些小小的改变就能完成。
关于缓冲区溢出的更多相关信息请参考Aleph One写的著名文章"Smashing the stack for fun and profit"

经过这篇文章的探讨,你通常不得不自己行动来阻止你的系统或者网络被一个已知漏洞所利用。对于配置错误我建议你请一位专家来帮你做必要的配置,因此在使用它之前你不用完全理解产品是如何运作的。对于编程和设计错误,通常有很多人进行产品测试,而其他人则发表他们发现的漏洞到Internet上的一些安全列表上。所以如果你保持持续关注这些安全列表,并确认你一直都在更新你的系统到最新版本,你就已经接近一个安全环境了。

――――――――――――――――――――――――――――――――――――――――――
最近的安全编程文档:

《Exploiting Software How to Break Code》
描述如何编写exploit代码的

《Learning XML, 2nd Edition》

《Writing Secure Code》
微软公司核心推荐,教你怎样编写安全的代码

《OReilly Web Site Cookbook》
建立和管理你的网站的使用手册,包括大量实例及解决方案

TOP

原文如下:

Errors, Vulnerabilities & Exploits explained
2007-3-2 - Mark Vogels
            
In this paper I will try to provide you with a basic understanding of errors, possible vulnerabilities because of those errors and their exploits.It is in no way meant to be a full and complete guide to exploits / vulnerabilities but hopefully it will help you learn to recognize possible vulnerabilities and how to deal with them.

Generally speaking there are 3 different types of errors which could eventually lead to a possible compromise of a computer-based system / network:

# Programming errors
# Configuration errors
# Design errors


Errors can be seen as mistakes, although they don't necessarily have to be created by accident. It is possible that the original creator of the software / device which contains the error, created that error with the best intentions and without realizing that it could be a potential vulnerability.
This might sound a bit confusing, but all should become clear later on in this paper.
To discuss the errors more in dept we need to create a definition of the different types of errors so that we can recognize them easier.


Definitions of the different error types


Programming errors:

Programming errors are errors made by the programmers of a particular piece of software. The most common exploitable programming errors are buffer overflows. Think of a buffer overflow as an empty cup:The user of the program is going to put coffee in the cup, but the programmer does not know in advance how much coffee the user will put in there. So the programmer must check and test this before actually putting the coffee in the cup to prevent the coffee from overflowing the cup. Sometimes it's not that easy to check for input size or due to time pressure a programmer does not have the time to do write extensive error checking functions and so possible buffer overflows and other
programming errors are created.

Another example of a programming error is a program that crashes since the user did something unexpected like load a wrong type of file into the program. Of course not all programming errors require user input to do something unexpected like crash the program. A program could depend on a particular file which is always in a specific location.If that file is moved and the programmer doesn't expect that, he might not check if the file actually is located there before trying to open it. This can result in unexpected behavior if that program tries to work with that file after opening it.

These types of errors occur quite often, and most of the times the manufacturer distributes patches and updates to resolve the errors reported by customers or discovered by themselves.


Configuration errors:

Think of a configuration error as if you were a network administrator and you need to implement a firewall to protect your network from the internet.
It used to be a common practice to allow every traffic in and out except for the specifically denied types of traffic.
A simple example is a firewall which is blocking only port 80 since it will allow anyone from the internet to connect to the configuration page of the firewall and reconfigure it. The rest of the ports are all open.This of course is a configuration error since anyone could bypass that firewall by using another port number.
Luckily most manufacturers are aware of this error so they implemented exactly the opposite: Everything is blocked unless specifically allowed. So now a network administrator does not have to worry about new problems found which can access his network through an unused port since that port is closed already anyway. (I used only ports here as example, but this can apply to different types of traffic on the same port as well.)


Another configuration error example is the usage of unmanaged hub's in a network instead of managed switches. The difference is that a hub is sending all incoming traffic to all ports since it does not know behind which port the receiver is located, a switch knows this. So, running a sniffer in a network where hub's are used instead of switches allows an attacker to view much more traffic with possible username / password combinations then when using switches on a network.
Even though this is a configuration error now, it didn't used to be in the past when switches didn't yet exist.

Since these errors almost always occur because the customer has too little knowledge of the product or simply not enough time to completely configure the product correctly, the customer himself is responsible for resolving the error. The manufacturers often provide detailed manuals and help files for their products which you should have read before configuring and implementing the device or software.


Design errors:

A design error can be seen as an error that occurred during the design period of the particular software. Even when the programmers spent enough time writing routines to verify all user input before taking the software in production, and even when the software has been configured correctly by the end user, these errors can still cause a great risk for the security of a network.


Let's say a company decided to write a piece of software which would allow remote access to a network. Since they have to support the software as well, they decided to put in a little backdoor so that can login remotely by using the companies name as password.
What if someone outside that company would discover that backdoor? He could login to any network that is using that particular piece of software for remote access. The consequences would be disastrous!
Although these backdoors were created quite often in the past, nowadays a company selling such software can't take the risk anymore, since he would be held responsible for misusage of that backdoor by attackers.


Another example of a design error is the WEP encryption used for securing wireless networks. I'm not going to explain in dept how this is a design error since that is beyond the scope of this paper, but basically it comes down to this:A 3 byte initialization vector is added to the (pre-shared encryption key)公钥 to encrypt every packet uniquely. Let's say the pre-shared key is "abcde". The initialization vector for packet one could be "123" so the total encryption key for that packet would be "123abcde". For the next packet the initialization vector could be "234" and so creating the encryption key "234abcde".The design error lies partially in the fact that there are only 3 byte different IV's (Initialization Vector) making a total of 255^3 or 16.5 million different keys and partially in the encryption algorithm used. One could extract several characters of the pre-shared key quite easily by reversing part of the algorithm. Because of this design error you only need around 100,000 packets with unique IV's for 64-bit and around 800,000 unique IV's for 128-bit to crack the WEP-key and be able to participate and read the complete wireless network. On a busy wireless network this can be done in a few hours.

As you can see, design errors are a bit more complicated to resolve. You simply cannot expect the manufacturer to write a quick patch to solve the problem, and you cannot refer to the manual of the product to resolve the issue yourself. In the case of the WEP encryption a team of people created a new standard called WPA as an alternative to WEP encryption. This meant that the products using WEP for encryption should either be upgraded by replacing them, or through firmware updates
which allows them to work with the new encryption standard.
For a more detailed explanation of the design errors discovered in WEP, take a look at the excellent paper from airscanner.com here.


How could these errors become a vulnerability?

A vulnerability is a weak spot in the protection of an object. The object can be anything from a computer to a complete network. I won't be summing and explaining all different possible vulnerabilities here since that's almost impossible, but I will try to point out what a vulnerability is and how that vulnerability could have been created.

As stated earlier, the most common programming error that can be a vulnerability is a buffer overflow. In case of a stack-based buffer overflow the buffer is placed on the stack. The stack can be seen as a temporary workspace where your processor can store data to work with. Now, when you overflow a buffer which is placed on the stack you will be able to write data outside of that buffers allocated space and so overwriting other data on the stack. That other data can be the return address
of the calling function. Let's say the return address of the calling function is 12345678 and that return address is stored on the stack directly after the buffer, then the stack would look something like this:XXXXXXXXXX12345678


Where XXXXXXXXXX is the buffer which will contain our input. If we put in less data then the buffer size then nothing strange will happen, but let's say we put in 12 times the character 'A' in a buffer which can only hold 10 characters, then the 2 remaining A's would overwrite part of the return address. If this makes the return address an invalid address, then the function would have no were to return to and the program would crash.
If this program would be a server application then someone would be able to put in 12 A's to crash the program and making the program inaccessible to all other users. This is an example of a Denial of Service attack, so in this case this error has Denial of Service vulnerability.

If we take the same example as above but then with a larger buffer, then overflowing the buffer would mean that more data has to be put in before an actual overflow occurs, but when it occurs, we could write some computer code (assembly instructions) which we would use as part of our data to put in the buffer. When we would change the return address to point to our overflowed buffer by overwriting it then the program would try to execute our buffer.
Since the buffer now contains computer code the program would not crash but instead execute our code. Because that code can be a small piece of code starting a shell (command interpreter) and listening to a specific port on that computer, this type of code is often referred to as "shellcode".
With this code running one could connect to the specified port and execute remote commands on the computer and so gaining control over the computer with the same access rights as the user has that originally started the vulnerable application on that computer.

For configuration errors the vulnerability can be more obvious if we take a look at the example of the firewall. If that firewall is configurable remotely via telnet as well, then only disallowing access to that firewall via HTTP (port 80) might give the network administrator a false sense of security since an attacker could still access the configuration of the firewall by connecting to the firewall via telnet (port 23).However, since customers require different configuration options for the products they buy, the manufacturers create highly configurable software / devices. This might make the configuration of a specific device so specialized that a mistake is easily made. Since the configuration of such a device is so complicated a vulnerability can be overlooked by the network administrator and so allowing a potential attacker access to parts of the network or system to which the attacker should not have access to, and so a simple configuration error could lead to a potential vulnerability in the network / system.


I already gave an example of a vulnerability caused by a design error with the WEP encryption keys, but it isn't too hard to come up with another example of a vulnerable design error:
Suppose a software company writes a piece of software for viewing and creating text documents. Since they want to sell their product they have to design a program which has more seemingly useful capabilities then the programs written by competitor software companies.They decide to allow users to have more control over their created documents by adding a feature which will allow users
to write small functions (macro's) which can be embedded in the document and which can do various things on the computer to assist the viewer of the document.
What if all this functionality can be used by a malicious attacker to craft a document with embedded functions that will replicate itself by copying itself to all other documents found on the machine and do various other things without the permission of the viewer?
Then we would have a possible vulnerability in this program which is created by design.


As you can see an error could lead to a vulnerability and the error itself doesn't necessarily have to be an error in the way of something that was put there unintentionally. In the case of the macro's used in the document the idea to assist the user of the software in creating more dynamic documents is great, except it was designed without security in mind.


Then what is an exploit?

An exploit is a way to make use of a found vulnerability to change the original functionality of the program or system in such a way that it can be used in the advantage of an attacker.In computer security the term "exploit" is often used for a specially crafted program which sole purpose is to automatically take advantage of a vulnerability to either take control of the target program in which the vulnerability exists or to stop the target program from functioning.But using a wrong configuration in a system or network to an attackers advantage can be called an exploit as well, although it doesn't necessarily have to be a specially crafted program which actually does the work.


I will try to explain the purpose of an exploit a little better by a few examples of C code, one will be a simple program with a buffer overflow vulnerability and the other one will be the exploit.

NOTE: the examples given here may behave different with different compilers / systems. You might need to change the number of characters placed in the buffer before actually overwriting the return address or the address of the exploitfunction might be different, but they will work.


vulnerable_program.c:
复制内容到剪贴板
代码:
#include "stdio.h"

exploitfunction()
{
printf("This line will be printed after successfully exploiting the buffer overflow. ");
system("pause");
ExitProcess(0);
}

normalfunction(char *myargument)
{
char buffer[10];
strcpy(buffer,myargument);
}

main(int argc, char *argv[])
{
if(argc>1)
{
normalfunction(argv[1]);
printf(" These lines get printed during normal execution with at least 1 commandline argument.The address of exploitfunction

is 0x%.8X ",&exploitfunction);
}
else
printf("Please provide the program with at least 1 commandline argument. ");
ExitProcess(0);
}
As you can see I've created 3 functions, one is the main function and the other two are the normalfunction which is executed with normal conditions, and the exploitfunction. The idea behind this program is to overflow the buffer so that the return address will point to the exploitfunction instead of the next instruction after the normalfunction.

Now we need to figure out how big the string of text will need to be to completely overwrite the return address on the stack. We do this by providing a string as argument which we increase with one character every time until the program crashes.
After I compiled the program using Dev-cpp on a Windows system I was able to provide the program with an argument of maximum 27 A's before crashing the program.Since the address of the exploitfunction is in hexadecimal and often the values of the bytes representing the address aren't
printable characters I wrote a small program which will provide the vulnerable program with the necessary argument string to exploit it.

In my case the address of the exploitfunction (which I conveniently printed from within the vulnerable program) is 0x00401290. Since the stack stores everything in reverse order on an Intel x86 system (it won't explain this here in this paper) we need to prepare a string which does the same.
So the eventual value for the argument has to be something similar to
0x41414141414141414141414141414141414141414141414141414141901240.
As you can see I used the hexadecimal representation of the character 'A' here (41) since that will be the actual value stored on the stack.

The resulting exploit can be very simple:

exploit.c:
复制内容到剪贴板
代码:
#include "stdio.h"

main()
{
char workbuffer[200];
char tempbuf[4];
strcpy(workbuffer,"vulnerable_program AAAAAAAAAAAAAAAAAAAAAAAAAAAA");
tempbuf[0]=0x90;
tempbuf[1]=0x12;
tempbuf[2]=0x40;
tempbuf[3]=0;
strcat (workbuffer,tempbuf);
system(workbuffer);
return 0;
}
All this program does is copy the string "vulnerable_program AAAAAAAAAAAAAAAAAAAAAAAAAAAA" to a buffer and creates another buffer with the new return address which it appends to the workbuffer as well.

After that, the program calls system() to execute the command in the string. The resulted output:
引用:
C:>exploit.exe
This line will be printed after successfully exploiting the buffer overflow.
Press any key to continue . . .
So that's great, it worked!
Or isn't it that great?
Unfortunately it isn't from a security point of view. As I just showed you it surely isn't rocket science to exploit a buffer overflow in a program. Although we didn't actually make the program run our own code, this can be achieved with a few minor changes.For more information on buffer overflows take a look at the famous article written by Aleph One "Smashing the stack for fun and profit".


As discussed in this paper you usually have to take action yourself to prevent your system / network from being exploited through a known vulnerability. For configuration errors I would advise you to let a professional make the necessary configurations so you don't have to completely understand how the product works before being able to implement it.
For programming and design errors there often are a lot of people testing products of others and posting their findings to several security-lists on the internet. So if you keep track of these security-lists and make sure you always update your systems to the latest versions of software / firmware, you are well on the way to maintain a secure environment.

--------------------------------------------------------------------------------
Latest Secure programming texts


Exploiting Software How to Break Code
Explanation of how to write exploit code

Learning XML, 2nd Edition

Writing Secure Code
Microsofts, How to write Secure Code.

OReilly Web Site Cookbook
Web Site Cookbook, Solutions & Examples for Building and Administering Your Web Site.

Secure Programming Handouts



--------------------------------------------------------------------------------
Latest Secure programming tools

Inno Setup
Inno Setup is a free installer for Windows programs. Want to give your project more professional look than get Inoo

TOP

顶楼主,辛苦了

TOP

谢谢了,您辛苦了!

TOP

anhun thank you very much!

TOP

今天看了,仍然感动

TOP

发新话题