printf函数的狐狸尾巴,格式化字符串攻击原理及示范

By admin in 4858.com on 2019年4月22日

格式化字符串攻击原理及示范

格式化字符串攻击原理及示范

格式化字符串攻击原理及示范

创办时间:200壹-0叁-03
文章属性:转发
小说来源:笔者:isno (isno@sina.com)
文章提交:xundi (xundi_at_xfocus.org)

1、类printf函数簇实现原理

类printf函数的最大的特征就是,在函数定义的时候不能够精通函数实参的数目和类型。

对此那种场馆,能够动用省略号钦命参数表。

带有省略号的函数定义中,参数表分为两片段,前半片段是规定个数、明确项目标参数,第二部分便是省略号,代表数量和档案的次序都不显著的参数表,省略号参数表中参数的个数和参数的品类是事先的约定总括出来的,各样实参的位置(指针)是依靠规定参数表中最后贰个实参的地方算出来的。

此处涉及到函数调用时的栈操作。函数栈的栈底是高地址,栈顶是底地址。在函数调用

时函数实参是从最后3个参数(最左侧的参数)到第三个参数(最左侧的参数)依次被压入栈顶方向。也便是说函数调用时,函数实参的地方是频频的,并且从左到右地址是各种扩张的。如:

 1 #include <stdio.h>  
 2 #include <stdlib.h>  
 3   
 4 void fun(int a, ...)  
 5 {  
 6     int i;  
 7     int *temp = &a;  
 8     temp++;  
 9     for (i = 0; i < a; ++i)  
10     {  
11         printf("%d ",*temp);  
12         temp++;  
13     }  
14     printf("/n");  
15 }  
16   
17 int main()  
18 {  
19     int a = 1;  
20     int b = 2;  
21     int c = 3;  
22     int d = 4;  
23     fun(4, a, b, c, d);  
24     return 0;  
25 }   

在地点的例证中,void fun(int a,
…)函数约定第一个规定参数表示省略号参数表中参数的个数,省略号参数表中的参数全都以int
类型的,那样fun函数就足以健康干活了。

类printf函数簇的行事规律和fun函数是同样的,只可是更为复杂和精细。

如printf的函数方式为 int printf(const char *fmt, …)。

鉴于printf函数完成的作用相比较复杂,大家来看三个咱们谐和达成的myprintf函数,改函数不关乎低层系统io操作。

 1 #include <stdio.h>  
 2 #include <stdlib.h>  
 3   
 4 void myprintf(char* fmt, ...) //一个简单的类似于printf的实现,//参数必须都是int 类型  
 5 {  
 6     char* pArg=NULL; //等价于printf原始实现的va_list  
 7     char c;  
 8     pArg = (char*) &fmt; //注意不要写成p = fmt !!因为这里要对//参数取址,而不是取值  
 9      pArg += sizeof(fmt); //等价于原来的va_start  
10   
11     do  
12     {  
13         c =*fmt;  
14         if (c != '%')  
15         {  
16             putchar(c); //照原样输出字符  
17           }  
18         else  
19         {  
20             //按格式字符输出数据  
21                switch(*++fmt)  
22             {  
23                 case 'd':  
24                     printf("%d",*((int*)pArg));  
25                     break;  
26                 case 'x':  
27                     printf("%#x",*((int*)pArg));  
28                     break;  
29                 default:  
30                     break;  
31             }  
32             pArg += sizeof(int); //等价于原来的va_arg  
33         }  
34         ++fmt;  
35     }while (*fmt != '/0');  
36     pArg = NULL; //等价于va_end  
37     return;  
38 }  
39   
40 int main(int argc, char* argv[])  
41 {  
42     int i = 1;  
43     int j = 2;  
44     myprintf("the first test:i=%d/n",i,j);  
45     myprintf("the secend test:i=%d; %x;j=%d;/n",i,0xabcd,j);   
46     return 0;  
47 }  

myprintf函数中也有周边的预订,鲜明参数表中最后2个参数是1个const char*
类型的字符串,在那一个字符串中冒出“%d”和“%x”次数的和正是粗略号参数表中参数的个数,省略号参数表中的参数类型也都以int类型。

同样的,实际的printf函数也有这么的预订:鲜明参数表中最后1个参数是三个const
char*
类型的字符串,省略号参数表中参数个数就是这些字符串中冒出的“%d”,“%x”,“%s”…次数的和,省略号参数表中参数的项目也是由“%d”,“%x”,“%s”……等格式化字符来提醒的。

因而,类printf函数中省略号参数表中参数的个数和等级次序都以由类printf函数中的那么些格式化字符串来调节的。

1、类printf函数簇完结原理

类printf函数的最大的性状正是,在函数定义的时候无法知道函数实参的数量和种类。

对此那种景观,能够使用省略号内定参数表。

带有省略号的函数定义中,参数表分为两有些,前半有个别是规定个数、鲜明项目标参数,第二有的正是省略号,代表数量和品种都不明确的参数表,省略号参数表中参数的个数和参数的类型是优先的预订计算出来的,每种实参的地址(指针)是基于规定参数表中最终叁个实参的地方算出来的。

那边涉及到函数调用时的栈操作。函数栈的栈底是高地址,栈顶是底地址。在函数调用

时函数实参是从最终2个参数(最左侧的参数)到第①个参数(最左边的参数)依次被压入栈顶方向。也正是说函数调用时,函数实参的地址是无休止的,并且从左到右地址是种种扩展的。如:

 1 #include <stdio.h>  
 2 #include <stdlib.h>  
 3   
 4 void fun(int a, ...)  
 5 {  
 6     int i;  
 7     int *temp = &a;  
 8     temp++;  
 9     for (i = 0; i < a; ++i)  
10     {  
11         printf("%d ",*temp);  
12         temp++;  
13     }  
14     printf("/n");  
15 }  
16   
17 int main()  
18 {  
19     int a = 1;  
20     int b = 2;  
21     int c = 3;  
22     int d = 4;  
23     fun(4, a, b, c, d);  
24     return 0;  
25 }   

在上边的事例中,void fun(int a,
…)函数约定第3个规定参数表示省略号参数表中参数的个数,省略号参数表中的参数全皆以int
类型的,这样fun函数就足以健康工作了。

类printf函数簇的做事原理和fun函数是一样的,只然则更为复杂和精密。

如printf的函数格局为 int printf(const char *fmt, …)。

是因为printf函数落成的功用比较复杂,大家来看二个我们温馨完结的myprintf函数,改函数不关乎低层系统io操作。

 1 #include <stdio.h>  
 2 #include <stdlib.h>  
 3   
 4 void myprintf(char* fmt, ...) //一个简单的类似于printf的实现,//参数必须都是int 类型  
 5 {  
 6     char* pArg=NULL; //等价于printf原始实现的va_list  
 7     char c;  
 8     pArg = (char*) &fmt; //注意不要写成p = fmt !!因为这里要对//参数取址,而不是取值  
 9      pArg += sizeof(fmt); //等价于原来的va_start  
10   
11     do  
12     {  
13         c =*fmt;  
14         if (c != '%')  
15         {  
16             putchar(c); //照原样输出字符  
17           }  
18         else  
19         {  
20             //按格式字符输出数据  
21                switch(*++fmt)  
22             {  
23                 case 'd':  
24                     printf("%d",*((int*)pArg));  
25                     break;  
26                 case 'x':  
27                     printf("%#x",*((int*)pArg));  
28                     break;  
29                 default:  
30                     break;  
31             }  
32             pArg += sizeof(int); //等价于原来的va_arg  
33         }  
34         ++fmt;  
35     }while (*fmt != '/0');  
36     pArg = NULL; //等价于va_end  
37     return;  
38 }  
39   
40 int main(int argc, char* argv[])  
41 {  
42     int i = 1;  
43     int j = 2;  
44     myprintf("the first test:i=%d/n",i,j);  
45     myprintf("the secend test:i=%d; %x;j=%d;/n",i,0xabcd,j);   
46     return 0;  
47 }  

myprintf函数中也有类似的约定,分明参数表中最终多少个参数是2个const char*
类型的字符串,在那个字符串中冒出“%d”和“%x”次数的和即是简单号参数表中参数的个数,省略号参数表中的参数类型也都是int类型。

一致的,实际的printf函数也有那般的预定:分明参数表中最后三个参数是3个const
char*
类型的字符串,省略号参数表中参数个数正是以此字符串中冒出的“%d”,“%x”,“%s”…次数的和,省略号参数表中参数的花色也是由“%d”,“%x”,“%s”……等格式化字符来提醒的。

于是,类printf函数中省略号参数表中参数的个数和花色都以由类printf函数中的那些格式化字符串来决定的。

一、类printf函数簇落成原理

类printf函数的最大的风味正是,在函数定义的时候不能通晓函数实参的多寡和花色。

对此这种情形,可以利用省略号内定参数表。

带有省略号的函数定义中,参数表分为两局地,前半局部是鲜明个数、分明项目标参数,第三片段正是省略号,代表数量和类型都不显明的参数表,省略号参数表中参数的个数和参数的项目是先行的预定总计出来的,种种实参的地方(指针)是依靠规定参数表中最终一个实参的地址算出来的。

此处提到到函数调用时的栈操作。函数栈的栈底是高地址,栈顶是底地址。在函数调用

时函数实参是从最后一个参数(最左边的参数)到第三个参数(最右侧的参数)依次被压入栈顶方向。相当于说函数调用时,函数实参的地方是持续的,并且从左到右地址是逐1扩展的。如:

 1 #include <stdio.h>  
 2 #include <stdlib.h>  
 3   
 4 void fun(int a, ...)  
 5 {  
 6     int i;  
 7     int *temp = &a;  
 8     temp++;  
 9     for (i = 0; i < a; ++i)  
10     {  
11         printf("%d ",*temp);  
12         temp++;  
13     }  
14     printf("/n");  
15 }  
16   
17 int main()  
18 {  
19     int a = 1;  
20     int b = 2;  
21     int c = 3;  
22     int d = 4;  
23     fun(4, a, b, c, d);  
24     return 0;  
25 }   

在地方的例证中,void fun(int a,
…)函数约定第三个规定参数表示省略号参数表中参数的个数,省略号参数表中的参数全都是int
类型的,那样fun函数就可以健康专业了。

类printf函数簇的专门的学问规律和fun函数是同样的,只不过更为复杂和精制。

如printf的函数情势为 int printf(const char *fmt, …)。

出于printf函数落成的功力相比复杂,大家来看一个我们温馨落成的myprintf函数,改函数不涉及低层系统io操作。

 1 #include <stdio.h>  
 2 #include <stdlib.h>  
 3   
 4 void myprintf(char* fmt, ...) //一个简单的类似于printf的实现,//参数必须都是int 类型  
 5 {  
 6     char* pArg=NULL; //等价于printf原始实现的va_list  
 7     char c;  
 8     pArg = (char*) &fmt; //注意不要写成p = fmt !!因为这里要对//参数取址,而不是取值  
 9      pArg += sizeof(fmt); //等价于原来的va_start  
10   
11     do  
12     {  
13         c =*fmt;  
14         if (c != '%')  
15         {  
16             putchar(c); //照原样输出字符  
17           }  
18         else  
19         {  
20             //按格式字符输出数据  
21                switch(*++fmt)  
22             {  
23                 case 'd':  
24                     printf("%d",*((int*)pArg));  
25                     break;  
26                 case 'x':  
27                     printf("%#x",*((int*)pArg));  
28                     break;  
29                 default:  
30                     break;  
31             }  
32             pArg += sizeof(int); //等价于原来的va_arg  
33         }  
34         ++fmt;  
35     }while (*fmt != '/0');  
36     pArg = NULL; //等价于va_end  
37     return;  
38 }  
39   
40 int main(int argc, char* argv[])  
41 {  
42     int i = 1;  
43     int j = 2;  
44     myprintf("the first test:i=%d/n",i,j);  
45     myprintf("the secend test:i=%d; %x;j=%d;/n",i,0xabcd,j);   
46     return 0;  
47 }  

myprintf函数中也有周围的约定,鲜明参数表中最终1个参数是二个const char*
类型的字符串,在那么些字符串中冒出“%d”和“%x”次数的和便是轻松号参数表中参数的个数,省略号参数表中的参数类型也都以int类型。

一样的,实际的printf函数也有如此的预订:分明参数表中最后2个参数是二个const
char*
类型的字符串,省略号参数表中参数个数正是以此字符串中冒出的“%d”,“%x”,“%s”…次数的和,省略号参数表中参数的种类也是由“%d”,“%x”,“%s”……等格式化字符来提示的。

故此,类printf函数中省略号参数表中参数的个数和花色都以由类printf函数中的那几个格式化字符串来决定的。

浅析格式化串漏洞

贰、格式化字符串攻击原理

因为类printf函数中省略号参数表中参数的个数和种类都以由类printf函数中的那么些格式化字符串来决定的,所以攻击者能够动用编制程序者的不经意或漏洞,美妙构造格式化字符串,到达攻击目标。

若是3个程序猿的职务是:打字与印刷输出二个字符串大概把那些串拷贝到某缓冲区内。他能够写出如下的代码:printf(“%s”,
str);但是为了省去时间和提升功效,并在源码中少输入5个字节,他会那样写:printf(str);

何以技士写的是谬误的吗?他传播了2个他想要逐字打印的字符串。实际上该字符串被printf函数解释为3个格式化字符(formatstring),printf就会依附该字符串来决定printf函数中省略号参数表中参数的格式和类型,假使那几个程序猿想要打字与印刷的字符串中正好有“%d”,“%x”之类的格式化字符,那么2个变量的参数值就从旅社中抽取。

比如:

 1 #include <stdio.h>  
 2 #include <stdlib.h>   
 3   
 4 int main(int argc, char* argv[])  
 5 {  
 6     if(argc != 2)  
 7         return 0;  
 8     printf(argv[1]);  
 9     return 0;  
10 }

当./a.out “hello world”时1切不荒谬,可是当./a.out
“%x”时,就会有岂有此理的数字被打字与印刷出来了。

很了然,攻击者至少能够经过打字与印刷出仓库中的这个值来窥探程序的内存。但是有些业务就不那么精晓了,那一个差不离的荒唐允许向运转中等射程序的内部存款和储蓄器里写入自便值。

printf有二个相比另类的用法:%n,当在格式化字符串中相遇”%n”的时候,在%n域此前输出的字符个数会保留到下1个参数里。比方,为了博取在三个格式化的数字之间空间的偏量:

1 int main(int argc, char* argv[])  
2 {  
3     int pos, x = 235, y = 93;  
4     printf("%d %n%d/n", x, &pos, y);  
5     printf("The offset was %d/n", pos);  
6     return 0;  
7 }

输出4(“235 ”的长度)

%n格式重回应该被输出的字符数目,而不是事实上出口的字符数目。当把一个字符串格式化输出到三个定长缓冲区内时,输出字符串大概被截短。不缅怀截短的影响,%n格式表示若是不被截短的偏量值(输出字符数目)。为了证实这或多或少,下边包车型大巴代码会输出100而不是20:

1 int main()  
2 {  
3     char buf[20];  
4     int pos, x = 0;  
5     snprintf(buf, sizeof(buf), "%.100d%n", x, &pos);  
6     printf("position: %d/n", pos);  
7     return 0;  
8 }

而%n和%d,%x,%s的引人注指标例外便是%n是会转移变量的值的,那也就是格式化字符串攻击的爆破点。

2、格式化字符串攻击原理

因为类printf函数中省略号参数表中参数的个数和类型都是由类printf函数中的这一个格式化字符串来决定的,所以攻击者能够选择编制程序者的不经意或漏洞,美妙构造格式化字符串,达到攻击目标。

一经3个技士的义务是:打字与印刷输出3个字符串或许把这么些串拷贝到某缓冲区内。他得以写出如下的代码:printf(“%s”,
str);可是为了省去时间和升高成效,并在源码中少输入七个字节,他会这么写:printf(str);

怎么技师写的是大错特错的吗?他传播了三个他想要逐字打字与印刷的字符串。实际上该字符串被printf函数解释为二个格式化字符(formatstring),printf就会依赖该字符串来决定printf函数中省略号参数表中参数的格式和品种,假设这些程序员想要打字与印刷的字符串中恰恰有“%d”,“%x”之类的格式化字符,那么贰个变量的参数值就从饭店中收取。

比如:

 1 #include <stdio.h>  
 2 #include <stdlib.h>   
 3   
 4 int main(int argc, char* argv[])  
 5 {  
 6     if(argc != 2)  
 7         return 0;  
 8     printf(argv[1]);  
 9     return 0;  
10 }

当./a.out “hello world”时一切经常,可是当./a.out
“%x”时,就会有岂有此理的数字被打字与印刷出来了。

很备受瞩目,攻击者至少能够经过打字与印刷出旅社中的那些值来窥探程序的内部存储器。可是某个业务就不那么显明了,这些大约的荒谬允许向运转中等射程序的内部存储器里写入放肆值。

printf有三个相比另类的用法:%n,当在格式化字符串中遇到”%n”的时候,在%n域以前输出的字符个数会保留到下3个参数里。例如,为了获得在七个格式化的数字之间空间的偏量:

1 int main(int argc, char* argv[])  
2 {  
3     int pos, x = 235, y = 93;  
4     printf("%d %n%d/n", x, &pos, y);  
5     printf("The offset was %d/n", pos);  
6     return 0;  
7 }

输出4(“235 ”的长度)

%n格式重返应该被输出的字符数目,而不是事实上出口的字符数目。当把二个字符串格式化输出到1个定长缓冲区内时,输出字符串可能被截短。不考虑截短的震慑,%n格式表示假使不被截短的偏量值(输出字符数目)。为了证实这或多或少,上边包车型地铁代码会输出100而不是20:

1 int main()  
2 {  
3     char buf[20];  
4     int pos, x = 0;  
5     snprintf(buf, sizeof(buf), "%.100d%n", x, &pos);  
6     printf("position: %d/n", pos);  
7     return 0;  
8 }

而%n和%d,%x,%s的显著的两样正是%n是会变动变量的值的,那也正是格式化字符串攻击的爆破点。

2、格式化字符串攻击原理

因为类printf函数中省略号参数表中参数的个数和项目都以由类printf函数中的这一个格式化字符串来支配的,所以攻击者可以动用编程者的忽视或漏洞,美妙构造格式化字符串,达到攻击目标。

假使二个程序猿的天职是:打字与印刷输出二个字符串或然把这些串拷贝到某缓冲区内。他能够写出如下的代码:printf(“%s”,
str);但是为了节约时间和提升功用,并在源码中少输入5个字节,他会这样写:printf(str);

何以程序猿写的是一无所能的吗?他传播了三个她想要逐字打字与印刷的字符串。实际上该字符串被printf函数解释为贰个格式化字符(formatstring),printf就会依据该字符串来支配printf函数中省略号参数表中参数的格式和花色,假设这么些技术员想要打印的字符串中正好有“%d”,“%x”之类的格式化字符,那么2个变量的参数值就从客栈中收取。

比如:

 1 #include <stdio.h>  
 2 #include <stdlib.h>   
 3   
 4 int main(int argc, char* argv[])  
 5 {  
 6     if(argc != 2)  
 7         return 0;  
 8     printf(argv[1]);  
 9     return 0;  
10 }

当./a.out “hello world”时壹切不荒谬,可是当./a.out
“%x”时,就会有莫明其妙的数字被打印出来了。

很醒目,攻击者至少能够通过打字与印刷出货仓中的那个值来窥探程序的内存。然则有个别业务就不那么明显了,这些差不多的错误允许向运维中先后的内部存款和储蓄器里写入任性值。

printf有二个相比较另类的用法:%n,当在格式化字符串中相见”%n”的时候,在%n域在此之前输出的字符个数会保留到下一个参数里。比如,为了得到在多个格式化的数字之间空间的偏量:

1 int main(int argc, char* argv[])  
2 {  
3     int pos, x = 235, y = 93;  
4     printf("%d %n%d/n", x, &pos, y);  
5     printf("The offset was %d/n", pos);  
6     return 0;  
7 }

输出4(“235 ”的长度)

%n格式重临应该被输出的字符数目,而不是事实上出口的字符数目。当把贰个字符串格式化输出到2个定长缓冲区内时,输出字符串可能被截短。不思量截短的震慑,%n格式表示只要不被截短的偏量值(输出字符数目)。为了注脚那或多或少,上面包车型地铁代码会输出十0而不是20:

1 int main()  
2 {  
3     char buf[20];  
4     int pos, x = 0;  
5     snprintf(buf, sizeof(buf), "%.100d%n", x, &pos);  
6     printf("position: %d/n", pos);  
7     return 0;  
8 }

而%n和%d,%x,%s的明朗的比不上正是%n是会变动变量的值的,那约等于格式化字符串攻击的爆破点。

                       作者:isno (isno@sina.com)

三、三个实在的例子

下边这些事例至少能够X86的Redhat和arch Linux上面进行出现说法。

 1 #include <stdio.h>  
 2 #include <stdlib.h>  
 3 #include <string.h>  
 4   
 5 char daddr[16];  
 6   
 7 int main(int argc, char **argv)  
 8 {  
 9     char buf[100];  
10     int x;  
11     x = 1;  
12     memset(daddr,'/0',16);  
13     printf("before format string x is %d/%#x (@ %p)/n", x, x, &x);  
14     strncpy(daddr,"PPPPPPP%n",9);         
15     snprintf(buf,sizeof(buf),daddr);   //实施格式化字符串攻击  
16   
17     buf[sizeof(buf) - 1] = 0;  
18     printf("after format string x is %d/%#x (@ %p)/n", x, x, &x);  
19     return 0;  
20 }

运作的结果是:x被成功的更改了7。

地点的事例利用了linux函数调用时的内部存款和储蓄器残像,来得以达成格式化字符串攻击的。(参考的经典小说是用猜地址的措施来完毕的,猜的3头雾水)

此间大家来分析一下main函数中的旅舍变化情状:

4858.com 1

如上图所示,在调用snprintf函数此前,首先调用了printf函数,printf的函数第九个参数是&x,那样在main函数的商旅内部存款和储蓄器中留下了&x的内存残像。当调用snprintf时,系统本来只给snprintf希图了二个参数,不过出于格式化字符串攻击,使得snprinf感到应当有多个参数字传送给它,那样snprintf就私行把&x的内部存款和储蓄器残像作为第四个参数读走了,而snprintf所谓的第6个参数对应的“%n”,于是snprintf就成功的改造了变量x的值。

而在其实互连网意况中可采用的格式化字符串攻击也是繁多的。下图就是八个其实网络攻击的截图。

4858.com 2

 

 

文.RP.URL:http://blog.csdn.net/immcss/article/details/6267849

三、二个实际上的例子

上边那一个例子至少能够X八6的Redhat和arch Linux上边进行出现说法。

 1 #include <stdio.h>  
 2 #include <stdlib.h>  
 3 #include <string.h>  
 4   
 5 char daddr[16];  
 6   
 7 int main(int argc, char **argv)  
 8 {  
 9     char buf[100];  
10     int x;  
11     x = 1;  
12     memset(daddr,'/0',16);  
13     printf("before format string x is %d/%#x (@ %p)/n", x, x, &x);  
14     strncpy(daddr,"PPPPPPP%n",9);         
15     snprintf(buf,sizeof(buf),daddr);   //实施格式化字符串攻击  
16   
17     buf[sizeof(buf) - 1] = 0;  
18     printf("after format string x is %d/%#x (@ %p)/n", x, x, &x);  
19     return 0;  
20 }

运作的结果是:x被成功的改动了7。

地点的事例利用了linux函数调用时的内部存款和储蓄器残像,来完结格式化字符串攻击的。(参考的卓越小说是用猜地址的秘技来贯彻的,猜的1只雾水)

那里我们来分析一下main函数中的旅社变化情状:

4858.com 3

如上海体育场合所示,在调用snprintf函数在此以前,首先调用了printf函数,printf的函数第5个参数是&x,那样在main函数的仓库内存中留下了&x的内部存款和储蓄器残像。当调用snprintf时,系统本来只给snprintf准备了2个参数,然而由于格式化字符串攻击,使得snprinf以为应当有多个参数传给它,那样snprintf就私下把&x的内部存款和储蓄器残像作为第五个参数读走了,而snprintf所谓的第几个参数对应的“%n”,于是snprintf就成功的修改了变量x的值。

而在事实上网络情形中可应用的格式化字符串攻击也是大多的。下图就是四个实际网络攻击的截图。

4858.com 4

 

 

文.RP.URL:http://blog.csdn.net/immcss/article/details/6267849

3、一个其实的例子

上边这一个事例至少能够X8陆的Redhat和arch Linux上边举行出现说法。

 1 #include <stdio.h>  
 2 #include <stdlib.h>  
 3 #include <string.h>  
 4   
 5 char daddr[16];  
 6   
 7 int main(int argc, char **argv)  
 8 {  
 9     char buf[100];  
10     int x;  
11     x = 1;  
12     memset(daddr,'/0',16);  
13     printf("before format string x is %d/%#x (@ %p)/n", x, x, &x);  
14     strncpy(daddr,"PPPPPPP%n",9);         
15     snprintf(buf,sizeof(buf),daddr);   //实施格式化字符串攻击  
16   
17     buf[sizeof(buf) - 1] = 0;  
18     printf("after format string x is %d/%#x (@ %p)/n", x, x, &x);  
19     return 0;  
20 }

运转的结果是:x被成功的变动了七。

4858.com,地点的事例利用了linux函数调用时的内部存款和储蓄器残像,来贯彻格式化字符串攻击的。(参考的经文小说是用猜地址的办法来落到实处的,猜的二头雾水)

那边我们来分析一下main函数中的酒店变化情形:

4858.com 5

如上海体育场地所示,在调用snprintf函数从前,首先调用了printf函数,printf的函数第多少个参数是&x,那样在main函数的仓库内部存款和储蓄器中留下了&x的内部存款和储蓄器残像。当调用snprintf时,系统本来只给snprintf企图了二个参数,可是由于格式化字符串攻击,使得snprinf以为应当有四个参数字传送给它,那样snprintf就私下把&x的内部存款和储蓄器残像作为第四个参数读走了,而snprintf所谓的第4个参数对应的“%n”,于是snprintf就成功的修改了变量x的值。

而在事实上互连网蒙受中可利用的格式化字符串攻击也是许多的。下图正是一个事实上互联网攻击的截图。

4858.com 6

 

 

文.RP.URL:http://blog.csdn.net/immcss/article/details/6267849

                —————–目录——————-

                  一.前言

                  贰.基础知识简要介绍

                  三.格式化串漏洞原理

                    (一)参数个数不牢固变成访问越界数量

                    (2)利用%n格式符写入跳转地址

                    (叁)利用附加格式符调节跳转地址的值

                    (4)总结

                  肆.对wu-ftp 陆.0格式化串漏洞的剖析

                    (一)难点应运而生在哪儿

                    (2)wu-ftp漏洞的施用

                  五.后记

                —————————————-

一.前言

    近期众多软件被开采存在格式化串漏洞,当中最显赫的是wu-ftp6.0和rpc.statd,由于
printf函数的狐狸尾巴,格式化字符串攻击原理及示范。万分多的网址缺省安装了那二种软件,而且网络针对那四个漏洞的口诛笔伐程序好些个很好用,所
以由那五个漏洞而被攻破的网站非常之多。因而尤其有供给认真钻探一下格式化串漏洞,但
网络介绍格式化串漏洞的普通话小说却专门少,就本身驾驭的唯有一篇warning三写的和另壹篇
xuzq翻译的稿子,作者又参考了几篇英文作品,费了半天才干看的头疼了才搞理解那种漏洞的
机理。

    由于那几篇文章写的比较深奥,像本人如此的日常初学者看起来很困难,笔者想就小编的通晓
写壹篇浅显一点的篇章,使其余像自身同样的新手免受头痛之苦,同时也把那篇小说作为备忘
资料,等自身之后忘了再回过头来看看:-)由于自己水平有限,谬误之处再所难免,迎接多多
指教。

二.基础知识简要介绍

    在明白格式化串漏洞在此以前有供给复习一下关于仓库的基础知识,互联网介绍缓冲区溢出的
作品诸多,个中基本上都介绍了库房的学问,读者能够自行参考那个作品,作者在此间只是简短
的牵线一下。

    二个程序的动态数据通过1块叫做仓库的区域来存放在。仓库处于内部存储器的高级,它有个特
性:后进先出。当程序中调用子函数时,Computer首先把参数依次压入货仓,然后把指令寄存
器(EIP)中的内容做为重回地址(RET)压入货仓,第多个压入货仓的是基址寄存器(EBP),然后
把方今的栈顶指针(ESP)拷贝到EBP,做为新的营地址。最终把ESP减去确定的数值,用来为本
地变量留出一定空间。
    
    普通的缓冲区溢出便是采纳了储藏室生长方向和数量存款和储蓄方向相反的特征,用后存入的数
据覆盖先前压栈的多少,一般是覆盖重返地址,从而改造程序的流程,那样子函数重回时就跳到了
黑客钦点的地方,就能够依据黑客意愿做别的工作了。
    
    格式化串漏洞和日常的缓冲溢出有相似之处,但又有所差别,它们都以接纳了技士的
疏忽大体来更改程序运转的平常流程。上边详细介绍格式化串漏洞的原理,最终对wu-ftp陆.0
格式化串漏洞进行一下解析。

3.格式化串漏洞原理
    
    所谓格式化串,正是在*printf()连串函数中服从一定的格式对数据开始展览输出,能够输出
到正式输出,即printf(),也得以出口到文件句柄,字符串等,对应的函数有fprintf,sprintf,
snprintf,vprintf,vfprintf,vsprintf,vsnprintf等。能被黑客利用的地点也就出在那一类别
的*printf()函数中,恐怕有人会问:那些函数只是把数据输出了,怎么能形成安全隐患呢?
在健康情状下自然不会导致哪些难点,不过*printf()类别函数有三条卓殊的习性,那几个万分
属性假使被黑客结合起来使用,就会产生漏洞。

(注:以下测试境况为RedHat Linux 陆.0)

#能够被黑客利用的*printf()体系函数的八个性子:

(一)参数个数不固定变成访问越界多少

    首先第一个能够被应用的属性是:*printf()种类函数的参数的个数是不牢固的。拿printf()
函数比如来讲,假诺大家要依次输出二个整型数据和二个字符串,能够用以下顺序:

#include 
int main(void)
{
int i=1,j=2,k=3;
char buf[]=”test”;
printf(“%s %d %d %d\n”,buf,i,j,k);
return 0;
}

  那是常规的施用方法,程序会输出:

test 1 2 3

    那一个printf()函数共有四个参数,第四个是格式化串”%s %d %d
%d\n”,首个是字符串buf的
地方,%s对应buf,其后的几个%d分别对应i,j,k,那样就把数据输出了。但是假诺我们减少printf()
函数的参数个数,写成这么:

printf(“%s %d %d %d\n”,buf,i,j);

    格式化输出符号照旧是五个,但对应的数据却只剩下三个了(buf,i,j)了,那么情形会怎样呢?
咱俩编写翻译运转一向下探底视,那一个顺序输出:

test 1 2 1953719668

    大家得以掌握的见到,纵然尚未给最后3个%d提供相应的数目,可是它仍旧出口了三个拾位的
平头一玖伍伍7壹9陆陆8,那些大整数到底是什么样吗?大家再修改源程序,把出口的语句改为:

printf(“%s %d %d %x\n”,buf,i,j);

    即依据1陆进制输出最后3个参数,那时输出的结果就是:

test 1 2 74736574

    也正是说,当未有给printf()函数的格式化串提供丰富的呼应参数时,printf()并不曾报错,而
是把内部存款和储蓄器中有些四字节的剧情打字与印刷了出来,那多个字节的始末是7473657四。

    那么7473657四终究是什么样玩意儿呢?假设您对ASCII码熟习的话应该能够展现过来,字符串在内存
中等是以ASCII码的款型积累的,它们有如下对应涉及:

十陆进制             拾进制            字符
    74   ———->   116  ———>  t
    73   ———->   115  ———>  s
    65   ———->   101  ———>  e

    74736574对应的字符串恰好是tset,由于字符串在内部存款和储蓄器在那之中是以反序排列的,7473657四一见青眼的
事实上字符串应该是:test。是或不是看起来有个别眼熟?翻回前边再看看这个程序,对了,正是我们在先后
中定义的字符串buf[]的始末。那绝不是偶发的,纪念一下前面说过的仓库的办事流程,大家能够设想
到这些程序在仓库中的情状:

i)  调用main()函数在此以前率先把再次来到地址压栈;
ii) 然后压入的是EBP,并把ESP拷贝到EBP;
iii)把ESP减去料定的多少,相当于把货仓扩充,给变量i,j,k,buf留出空间;
iv) 起头调用printf(),把printf()的陆个参数j,i,buf和格式串”%s %d %d
%x\n”依次压入货仓;
v)  压入printf()的回到地址;
vi) 压入此时的EBP;
vii)起头实践printf()。

    那时候的货仓看起来应当是这些样子的:

栈顶                                                                      栈底
  ————————————————————————–
  | EBP | EIP | 格式串| buf地址| i | j |buf内容| \0 | k | j | i | EBP |
EIP|
  ————————————————————————–

    看到商旅的其实内容,就简单通晓为何会打字与印刷出7473657肆即”test”了,printf()首先找到第
3个参数格式串”%s %d %d
%x\n”,然后就起来听从对应提到依次打字与印刷后边仓库中内容,%s对应
buf地址,也就打字与印刷出了buf[]的故事情节,第叁个%d对应i,第三个%d对应j,%x本来是应当对应k的,但是
出于大家提须要printf()的参数中从未k,而j前边正好是buf内容,所以就把buf的始末作为1陆进制
数输出了,也正是我们见到的7473657四。可以猜想,假如提供给printf()的格式串中再多多少个%x的话,
printf()还会接二连三打字与印刷前边宾馆里的”\0″(buf的收尾符),k,j,i,EBP,EIP等剧情。

    谈到此处,已经把发生格式化串漏洞的来自揭流露来了:因为*printf()体系函数的参数的个数
是不固定的,借使其首先个参数即格式串是由用户来提供的话,那么用户就足以访问到格式串前边的
仓库里的别的内容了。

    之所以会产出格式化串漏洞,正是因为程序猿把printf()的第陆个参数即格式串,交给用户来
提供,假设用户提供一定数量的%x(或%d,%f,随你的便啦),就能够访问到特定地点的酒店内容。

    有个外人会说:”靠!你费了如此半天劲,就只是为了打字与印刷出了后面仓库里的内容啊?”大家自然不
只是为了看看货仓里的剧情,大家是要改成货仓的始末,改动再次来到地址,使程序跳去推行我们提供的
代码,那就要求联系上*printf()体系函数的第三个奇特的本性。

(贰)利用%n格式符写入跳转地址

    到方今截至我们都只是展现内存的始末而从未改造它,可是使用*printf()的一个特殊的格式符
%n,我们就向内部存储器中写入内容。

    %n是一个在编制程序中不平时应用的格式符,它的作用是把前边已经打字与印刷的尺寸写入有个别内部存款和储蓄器地址,
为了搞清其切实用法和性情,我们看一看上边包车型客车例程:

#include 
int main(void)
{
int num;
int i=1,j=2,k=3;
printf(“%d%d%d%n\n”,i,j,k,&num);
printf(“%d\n”,num);
return 0;
}

运转呈现:
123
3

    能够见见,%n的职能正是把曾经打字与印刷出来字符的数量保存到对应的内存地址在那之中,那里是num个中。
留意,那里不可不相应二个内部存款和储蓄器地址,%n把字符数写入到那些地址的内部存款和储蓄器。如若把上述语句改成:

printf(“%d%d%d%n\n”,i,j,k,num);

    那样就会并发段访问错误。重申那一点很关键,因为在骨子里运用某些漏洞时,并不是一贯把跳转
地方写入函数的回到地址单元,而是写入2个存放着函数的回来地址的地址当中,即平常说的retloc,
以此存放函数的回到地址的地方经常在大家提供的字符串的先头,这么说只怕有点绕,换种说法,正是
说咱俩并不直接覆盖重临地址,而是通过地方来直接的改写重临地址,这点平常有人歪曲,要是你还没
领会的话,能够仔细回味一下C语言中指针的用法,它们中间有相似之处。

    好的,到近期停止我们曾经了然能够利用提交格式串来访问格式串前边旅社里的剧情,并且应用
%n能够向一个内存单元中的地址去写入贰个值,既然大家能够访问到大家提交的串,就足以在咱们提
交的串个中放上有个别函数的回来地址的地方,那样就足以利用%n来改写那个再次来到地址。

    可是只是,%n向内部存款和储蓄器中写入的值并不是轻便的,它只好写入前边打字与印刷过的字符数量,而作者辈供给的
是写入大家存放shellcode的地方,就象普通溢出做的这样。那几个题目实际上是麻烦,只怕有人会想:那
就用和跳转地址的数值同样多的数目标%d放在%n的先头不就行了?那样做辩驳上有效,但骨子里却百般,
因为货仓在内存的高级,饭店里面包车型大巴内部存储器地址也是四个一定大的数,假使我们用三个%d来对号入座四字节内容
即3个整型的话,首先数量太多正是1个难题,而且每几个字节的内存单元作为整数打字与印刷出来的话,它的
实质上尺寸也是迫不得已显明的,有的或然打字与印刷出一个人的’壹’,有的则恐怕打字与印刷出七位的’453陆7’,那是大家无法
预料的。

    那时就供给使用到*printf()体系函数的第三个”突出”的习性了。

(3)利用附加格式符调节跳转地址的值

    *printf()连串函数有个属性是:程序猿能够定义打字与印刷字符的拉长率。学过C语言的人必然都知晓那或多或少,
纵然在格式符的中档加上2个整数,*printf()就会把这么些数值作为出口宽度,假诺出口的其实当先钦点宽
度仍按其实增加率输出,如若低于钦命宽度,则按钦赐宽度输出。比如大家得以用上边语句以9二十二个字符的宽
度输出整数i:

printf(“%100d”,i);

    而用printf(“%.十0f”,i)的款式则是以玖十三位的小数输出i。而printf(“%.f”,i)不是以一位小数输出,而是
以累计八个人的带小数的数输出i。固然i等于1的话,输出应该是一.000000。由于这么些”%.f”三回能向前推进5人,所
以它时时在事实上攻击时被放在提交的格式串的中等,用来快捷地达到重回地址处。

    我们就能够使用这一个特性来用很少的格式符来输出3个一点都不小的数值到%n,而且这些数值是能够由大家
来钦命的。大家所要做的正是作一些测算,把要回来的地方转化为整数,放到%n后边的格式串中。举个例子大家要
把200放入num中,则足以运用如下语句:

printf(“%.200d%n”,i,&num);

    当那条语句实施完后,num的值就成为200了。假诺用跳转地址的值代替200,那么%n就足以把跳转地址写入
num了。

(4)总结

    好了,到那边曾经把格式化串漏洞的保有理论依附都介绍完了。让大家再来回看一下:

    首先,假设程序中的*printf()连串函数中的格式串参数是由用户来提供的话,大家就足以交给给它1串
%d(或%f,%u等)来拜会客栈中格式串前边的任意内部存款和储蓄器单元。

    在我们付出的格式串的前面加上三个%n格式符,大家就能够向货仓中格式串前边的某些内部存款和储蓄器单元中写入
一度打字与印刷的字符数量。在事实上攻击时平常是在付给的格式串前边放上存放着某些函数的归来地址的地点,然后
让%n恰好对应着那个地址值,那样写入到数值,就存放到函数重回地址个中了。

    我们经过附加格式符来调整向函数再次回到地址中写入的值,一般是采用%n前边的终极多少个格式符来调节
以此数值,这一般要求一些计量,总计方法一般是用shellcode的地址减去最终1个格式串前的享有格式串的
打字与印刷长度。那样%n写入的数值就刚刚是shellcode的地点了。

    理论上讲的只是突出状态,在其实攻击有些程序时数拾3遍会产出越来越多的难点。首先要减轻的是必须使%n正好
对应存放函数再次来到地址的地点,不然无法改动重回地址的值。那或多或少对于一些可再次运行且能够回来格式串的
次第来讲是比较轻松消除的,大家得以先不放入跳转地址,而是在付出的格式串前填上多少个特殊字符,举个例子”abcd”,
下一场在付出的格式串最终用%x取代%n来展现这几个尤其字符串,咱们要做的只是不断加码格式串中间的格式符的个
数,直到程序重回的值恰好是大家提交的特殊字符的ASCII码截止。那样大家就清楚用来存放在函数重返地址的地
址在怎么样岗位了,然后大家再把真正的寄放函数再次回到地址的地址位于格式串的前头,用%n作为格式串的最终,那
样就可以把跳转地址准确的写进函数重回地址了。

    当然那种方法要求被口诛笔伐的顺序能够持续的开发银行而且能够回来提交的格式串的打字与印刷内容,wu-ftp6.0就是
如此的程序,所以针对wu-ftp陆.0的格式串漏洞的攻击比较易于得逞的。而有个别程序则足够,举个例子cfengine,那
个程序被发掘存在格式串漏洞已经很久了,不过平素尚未可成功的抨击程序发表,主要正是因为一但向cfengine
出殡格式串它就当掉了,所以十分的小概数次推断。对那种程序必须一次攻击就必须猜中存放函数重回地址的地点和
跳转地址,所以在切实的口诛笔伐中数次是不便于得逞的。

    其它3个难以化解的主题素材是,须求把准确的函数再次来到地址填在格式串起来,那样%n本领把跳转地址写进
没有错的职分了。这一个函数的归来地址一般是在写攻击程序时测试得到的,那在测试的机械上固然能够成功,可是
在差异机器上这几个再次来到地址的值是遵照蒙受变量和编译选项的两样而各异的,比如用rpm安装的wu-ftp和从源
代码编写翻译安装的wu-ftp,它们的回到地址往往正是不一致的,必要依照被攻击主机的实在景况开始展览调节。那只有根
据经验来显明,或然几乎用暴力法了估算再次回到地址,但基于实际测试,即利用暴力法估算重回地址,成功的概率
也是相当小的。

    还有正是跳转地址的标题,即shellcode的地址。因为大家要改写函数的回到地址,使它跳转去实践shellcode。
于是必要求理解shellcode的地方。这些主题材料相对轻易消除,我们得以像一般溢出做的那样,在shellcode后面
填上1串NOP,那样只需求驾驭八个大概的地点范围就足以了,只要跳转到NOP的限量当中就可以实行shellcode
了。所以一般的攻击程序里的跳转地址往往是不须求调节的,因为只要在八个大意的地方范围在那之中就可以了。

    好了,理论就探究这么多,上面大家来看望Wu-ftp陆.0的格式化串漏洞和行使的秘籍。

肆.对wu-ftp 陆.0格式化串漏洞的分析

(壹)难题出现在哪个地方

    wu-ftp(华盛顿 University ftp
server)是二个卓殊流行的unix/linux系统ftp服务器,它的6.0版本
留存格式化串漏洞。由于在大大多Linux系统中它是暗中认可安装的,所以一定多的网址都受那个漏洞的影响,针对它
的攻击也是格外普及的。

    上面大家看看wu-ftp的源代码,毕竟是什么地方出现了足以被黑客利用的狐狸尾巴?

    用户提交的”site exec”命令是由一个名字为 void site_exec(char *cmd)
的函数来管理的,当中cmd是用户
交付的命令。在这些函数中有那般2个说话:

————–ftpcmd.y文件 第1929行———————-

lreply(200, cmd);

———————–cut here————————–

    site_exec()函数把用户提交的吩咐交给lreply()函数来管理了,大家再看看lreply()函数的定义:

————–ftpd.c文件 第5343行————————

void lreply(int n, char *fmt,…)
{
    VA_LOCAL_DECL

    if (!dolreplies)
    return;

    VA_START(fmt);

    /* send the reply */
    vreply(USE_REPLY_LONG, n, fmt, ap);

    VA_END;
}

———————–cut here————————–

    分明lreply()的第三个参数char
*fmt应该是格式串,而在日前的调用中却把它交由用户命令来
提供,那就是变成难点的位置。继而lreply()有把fmt交给vreply()函数来拍卖,大家再来看看vreply()
的定义:

————–ftpd.c文件 第5275行————————

void vreply(long flags, int n, char *fmt, va_list ap)
{
    char buf[BUFSIZ];

    flags &= USE_REPLY_NOTFMT | USE_REPLY_LONG;

    if (n)
    sprintf(buf, “%03d%c”, n, flags & USE_REPLY_LONG ? ‘-‘ : ‘ ‘);

    /* This is somewhat of a kludge for autospout.  I personally think
that
     * autospout should be done differently, but that’s not my
department. -Kev
     */
    if (flags & USE_REPLY_NOTFMT)
    snprintf(buf + (n ? 4 : 0), n ? sizeof(buf) – 4 : sizeof(buf), “%s”,
fmt);
    else
    vsnprintf(buf + (n ? 4 : 0), n ? sizeof(buf) – 4 : sizeof(buf), fmt,
ap);
        ~~~~~~~~~~~~~~~~~
                                                     !!!注意这一句!!!

    if (debug)
    syslog(LOG_DEBUG, “<— %s”, buf);

    /* Yes, you want the debugging output before the client output;
wrapping
     * stuff goes here, you see, and you want to log the cleartext and
send
     * the wrapped text to the client.
     */

    printf(“%s\r\n”, buf);    /* and send it to the client */
#ifdef TRANSFER_COUNT
    byte_count_total += strlen(buf);
    byte_count_out += strlen(buf);
#endif
    fflush(stdout);
}

———————–cut
here———————————————–

    由于提交给vreply()的首先个参数(即flags)是USE_REPLY_LONG,所以通过&=操作
之后flags仍然为USE_REPLY_LONG。这样(flags &
USE_REPLY_NOTFMT)的值就为0。所以上面包车型大巴
决断语句会进入else实施:

if (flags & USE_REPLY_NOTFMT)
    snprintf(buf + (n ? 4 : 0), n ? sizeof(buf) – 4 : sizeof(buf), “%s”,
fmt);
    else
    vsnprintf(buf + (n ? 4 : 0), n ? sizeof(buf) – 4 : sizeof(buf), fmt,
ap);
        ~~~~~~~~~~~~~~~~~
                                                     !!!注意这一句!!!

    注意看要实行的vsnprintf()函数,它把fmt放在了格式串的参数地点上了。而以此fmt
幸而由用户提交的命令cmd。回想一下前方讲过的格式化串漏洞原理:假诺*printf()系列
函数的格式串参数是由大家来交付的话,那么大家就足以用1串格式符来访问格式串前边
客栈里的剧情了,倘使大家能访问到协调提交的始末,就能够在那内容的先头放上存放有个别
函数重返地址的地方,然后就可以用%n来改写这一个重返地址,使它跳转去实行大家提供
的shellcode。

(贰)wu-ftp漏洞的施用

    所以大家要想选取那么些漏洞,需求首先登场录上FTP服务器(编制程序落成,不用我们同甘共苦去登录了),
用无名氏用户(ftp,anonymous)登入就能够,然后交给三个之类格局的site
exec命令:

    site| exe|c aa|retloc|%.f…%.f|%.(ret)d|%n

    注意:在那之中的’|’符号是为了使读者看精通字符串结构而加上的分隔符,实际交付的串里不曾’|’。

    那几个由我们提交的格式串前边是site
exec命令,后跟的”aa”的机能是为着使retloc以四字节
为单位对齐,正是我们经常所说的align。

    然后跟随的retloc正是大家要写入的存放函数重临地址的地址,呆会儿我们要用%n来对号入座
它,就足以把跳转地址写入函数重临地址了。一般大家要改写的函数应该是方今的一个函数,那里
能够改写vreply()的回来地址,使它回到时跳去施行大家的shellcode。

    在retloc前边放上1串%.f,前面说过%.f一遍呈现八个人数字,在此地它的功用是显得在大家提
交的授命串之后压入货仓的有的变量,使%n能够正好对应retloc。

    然后紧跟着的%.(ret)d的法力是把打字与印刷的字符数量调度为刚刚是shellcode地址的值,使得%n
能够把已打字与印刷的字符数量,即shellcode的地点正好写进vreply()函数的归来地址当中。注意,那里
的ret并不是shellcode的地点,而应当是[shellcode地址-(%.f个数*8)-16]。在那之中的1六是前面包车型客车
“site| exe|c
aa|retloc|”的字符数。那样在%n之前打字与印刷的总符数就应当恰好为shellcode的地址
了。

    最终的%n的作用自然正是为着把跳转地址(shellcode地址)写入vreply()的归来地址,使它返
回时跳转去试行shellcode。正如在讲格式化串漏洞原理时提到过的那么:%n并不是直接对应着赶回
地点实行更换,而是对应着存放在再次来到地址的地方,直接的改变了回来地址。由此固然vreply()的回到
地址是比格式串后压入仓库的,但是大家照样能够改写它的内容。

    还有首要的一点忘记说了。shellcode是哪些时候提交的吧?大家能够把shellcode放进用户的密
码里提交给wu-ftpd,由于无名用户的密码是能够不管内定的,所以这么做并不影响大家运用无名氏登
六进服务器。此时shellcode应该作为全局变量被寄存在程序的Heap/BSS段里,而不是存放在货仓里。
在地头机械上调治一下能够领会shellcode的光景地址为0x8075六xx,那是在RedHat
陆.0上的值,在其
它系统中会有所区别。由于大家得以在shellcode在此以前放上一群NOP,所以也没要求精通shellcode的
规范地点,只要让程序跳转到NOP范围里就行了。

    须要注明的是,那里的shellcode必须是带有突破chroot()功用的,因为一旦用无名氏用户登入的
话,只可以访问被chroot()珍视的目录,即佚名用户登录后的目录,那样就无可如何绑定/bin/sh了。所以要
在shellcode中先chroot()到根目录。英特网有不少写得不得了好的chroot
shellcode,直接拿来用就可
以了。

    以上正是攻击wu-ftp陆.0格式化串漏洞的主意,以后流传着累累写得老大好的wu-ftp陆.0攻击程
序,作者本来想找在那之中2个来逐条语句解释出来的,但解释了几句之后察觉太TMD麻烦了。而且也向来不必
要分解攻击程序了,因为小编早已把攻击那么些漏洞的手续都在头里解释过了。

    那里只把本人用过的多少个比较好的抨击程序介绍给大家:

    (一)攻击以rpm安装wuftp陆.0的RedHat 陆.0, 六.1, 6.二相比较有效的次序:
    
    

    (二)攻击安装wuftp陆.0的FreeBSD和SuSe 陆.3, 6.4相比实惠的主次:
    
    

    (三)攻击安装wuftp陆.0的solaris 2.x比较实用的程序:

    

    依照本身的阅历,以rpm格局安装wuftp六.0的RedHat 陆.0, 陆.一,
六.2是最轻巧攻击成功的了,或许是
因为繁多抨击程序都以在那种系统遭遇下调节和测试编写的。而用源代码编写翻译安装的wuftp不易于攻击成功,
内需攻击者调节攻击程序中的有些参数,重要要修改的是retloc,约等于存放在函数再次来到地址的地方,有
时候须求频仍调解这些值才能攻击成功。

五.后记

    本文的目的是把格式化串漏洞尽量用通俗易懂的言语疏解出来,所以本身在批注原理时不曾用gdb等
工具的调养结果来讲,而是尽量地只讲原理本人,那样对于有个别不熟习调试器的读者来说可能相比便于
清楚。也许有人依旧会以为本文写得不是很易懂,因为格式化串漏洞本人便是个相比复杂的事物,起码
内需读者了解一些有关C语言以及仓库溢出的基本知识,那样才有助于领会本文。

    恐怕有点人会说:”为啥非要搞驾驭这一个漏洞的才能细节呢?作者不懂细节直接用攻击程序攻击一下
也能成功。”没错,在骨子里攻击的时候我们一般都以不怎么思索细节难点的,但是只是只是,你的对象是成
为二个Hacker呢?还是三个Scriptkid?倘使您的靶子是前者,这必将你必要明白手艺细节。固然是
后者,你同样也须求通晓技艺细节!!因为通晓的细节越多,你攻击的成功率就越大了。

感谢warning三等nsfocus的同志,他们写的篇章使本身受益非浅。

参考文献:

<<*printf()格式化串安全漏洞分析>>—warning③
<<格式化字符串攻击>>—Tim Newsham(xuzq译)
<< Format Bugs:What are they,Where did they come from,…How to
exploit them >>—lamagra

应接访问小编的主页:http://isno.yeah.net

(*转发请保持文章完全*)

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有