printf函数的纰漏,格式化字符串攻击原理及示范

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

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

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

开创时间:200一-0三-0三
小说属性:转发
小说来源:作者:isno (isno@sina.com)
小说提交:xundi (xundi_at_xfocus.org)

1、类printf函数簇达成原理

类printf函数的最大的表征正是,在函数定义的时候不可能知晓函数实参的数据和等级次序。

对此那种气象,可以动用省略号内定参数表。

带有省略号的函数定义中,参数表分为两有的,前半有的是规定个数、显明项目标参数,第二局地就是省略号,代表数量和项目都不明显的参数表,省略号参数表中参数的个数和参数的品类是预先的约定总计出来的,每一个实参的地方(指针)是凭仗规定参数表中最后一个实参的地址算出来的。

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

时函数实参是从最后3个参数(最右侧的参数)到第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,
…)函数约定首个规定参数表示省略号参数表中参数的个数,省略号参数表中的参数全都是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函数中也有类似的预订,明确参数表中最后一个参数是3个const char*
类型的字符串,在那么些字符串中出现“%d”和“%x”次数的和正是简约号参数表中参数的个数,省略号参数表中的参数类型也都以int类型。

平等的,实际的printf函数也有诸如此类的约定:分明参数表中最终二个参数是一个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函数中也有像样的预订,明显参数表中最终贰个参数是二个const char*
类型的字符串,在这几个字符串中冒出“%d”和“%x”次数的和便是大约号参数表中参数的个数,省略号参数表中的参数类型也都是int类型。

同样的,实际的printf函数也有那般的预定:明显参数表中最后3个参数是2个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函数也有那般的预订:鲜明参数表中最后一个参数是1个const
char*
类型的字符串,省略号参数表中参数个数正是其一字符串中出现的“%d”,“%x”,“%s”…次数的和,省略号参数表中参数的类型也是由“%d”,“%x”,“%s”……等格式化字符来提醒的。

故而,类printf函数中省略号参数表中参数的个数和类型都是由类printf函数中的那么些格式化字符串来支配的。

浅析格式化串漏洞

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

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

若是3个程序猿的任务是:打字与印刷输出3个字符串只怕把这几个串拷贝到某缓冲区内。他得以写出如下的代码:printf(“%s”,
str);可是为了节省时间和进步功效,并在源码中少输入四个字节,他会这么写:printf(str);

干什么程序猿写的是谬误的吗?他传播了三个她想要逐字打字与印刷的字符串。实际上该字符串被printf函数解释为3个格式化字符(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域以前输出的字符个数会保留到下一个参数里。举例,为了获得在五个格式化的数字之间空间的偏量:

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格式表示只要不被截短的偏量值(输出字符数目)。为了印证那或多或少,上面包车型地铁代码会输出拾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是会改造变量的值的,那也便是格式化字符串攻击的爆破点。

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

因为类printf函数中省略号参数表中参数的个数和类型都以由类printf函数中的那几个格式化字符串来调整的,所以攻击者能够选拔编制程序者的马虎或漏洞,神奇构造格式化字符串,到达攻击目的。

倘若二个技师的任务是:打印输出1个字符串只怕把那个串拷贝到某缓冲区内。他得以写出如下的代码:printf(“%s”,
str);不过为了节省时间和进步成效,并在源码中少输入五个字节,他会这么写:printf(str);

怎么技士写的是不对的吗?他传播了3个他想要逐字打字与印刷的字符串。实际上该字符串被printf函数解释为1个格式化字符(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域从前输出的字符个数会保留到下七个参数里。举例,为了拿走在五个格式化的数字之间空间的偏量:

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格式表示只要不被截短的偏量值(输出字符数目)。为了申明这点,上面包车型客车代码会输出拾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是会改换变量的值的,那也便是格式化字符串攻击的爆破点。

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

因为类printf函数中省略号参数表中参数的个数和种类都以由类printf函数中的那二个格式化字符串来调整的,所以攻击者能够应用编制程序者的大要或漏洞,美妙构造格式化字符串,到达攻击目的。

如果贰个技士的义务是:打字与印刷输出二个字符串大概把这些串拷贝到某缓冲区内。他得以写出如下的代码:printf(“%s”,
str);可是为了节省时间和进步作用,并在源码中少输入四个字节,他会这么写:printf(str);

为啥工程师写的是不对的吧?他传播了八个他想要逐字打字与印刷的字符串。实际上该字符串被printf函数解释为2个格式化字符(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”时1切符合规律,可是当./a.out
“%x”时,就会有莫明其妙的数字被打字与印刷出来了。

很强烈,攻击者至少可以透过打字与印刷出货仓中的那么些值来窥探程序的内部存款和储蓄器。可是多少业务就不那么明显了,那一个轻便的荒唐允许向运营中先后的内存里写入大4值。

澳门葡京备用网址 ,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格式再次回到应该被输出的字符数目,而不是事实上出口的字符数目。当把二个字符串格式化输出到一个定长缓冲区内时,输出字符串或然被截短。不思索截短的震慑,%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)

3、一个实际上的例子

上边这么些例子至少能够X八陆的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被成功的更改了柒。

地方的例证利用了linux函数调用时的内部存储器残像,来落成格式化字符串攻击的。(参考的精彩小说是用猜地址的格局来贯彻的,猜的2只雾水)

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

澳门葡京备用网址 1

如上海教室所示,在调用snprintf函数以前,首先调用了printf函数,printf的函数第六个参数是&x,那样在main函数的旅社内部存款和储蓄器中留下了&x的内部存款和储蓄器残像。当调用snprintf时,系统本来只给snprintf筹划了贰个参数,不过由于格式化字符串攻击,使得snprinf以为应当有八个参数传给它,那样snprintf就私下把&x的内部存款和储蓄器残像作为第伍个参数读走了,而snprintf所谓的第5个参数对应的“%n”,于是snprintf就马到功成的修改了变量x的值。

而在其实网络意况中可使用的格式化字符串攻击也是广大的。下图便是一个实在网络攻击的截图。

澳门葡京备用网址 2

 

 

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

叁、一个事实上的例证

下边那个例子至少能够X捌陆的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被成功的改变了七。

下面的例子利用了linux函数调用时的内部存款和储蓄器残像,来兑现格式化字符串攻击的。(参考的经文小说是用猜地址的章程来贯彻的,猜的3头雾水)

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

澳门葡京备用网址 3

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

而在事实上网络碰到中可使用的格式化字符串攻击也是许多的。下图正是叁个实际互联网攻击的截图。

澳门葡京备用网址 4

 

 

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

三、二个事实上的事例

上边这几个事例至少能够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被成功的更改了柒。

上面的例证利用了linux函数调用时的内部存款和储蓄器残像,来兑现格式化字符串攻击的。(参考的经文小说是用猜地址的办法来得以完结的,猜的三只雾水)

那边大家来分析一下main函数中的货仓变化境况:

澳门葡京备用网址 5

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

而在实质上网络情形中可使用的格式化字符串攻击也是成都百货上千的。下图便是叁个实际网络攻击的截图。

澳门葡京备用网址 6

 

 

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

printf函数的纰漏,格式化字符串攻击原理及示范。                —————–目录——————-

                  一.前言

                  2.基础知识简单介绍

                  三.格式化串漏洞原理

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

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

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

                    (4)总结

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

                    (1)难点应运而生在何地

                    (2)wu-ftp漏洞的使用

                  五.后记

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

一.前言

    目前游人如织软件被察觉存在格式化串漏洞,其中最有名的是wu-ftp6.0和rpc.statd,由于
一定多的网址缺省安装了那三种软件,而且互连网针对那五个漏洞的攻击程序很多很好用,所
以由这个漏洞而被攻破的网址相当之多。由此越发有必不可缺认真讨论一下格式化串漏洞,但
互连网介绍格式化串漏洞的国语小说却越来越少,就笔者知道的唯有一篇warning三写的和另一篇
xuzq翻译的稿子,笔者又参考了几篇英文作品,费了半天技巧看的头痛了才搞精晓那种漏洞的
机理。

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

二.基础知识简要介绍

    在询问格式化串漏洞此前有供给复习一下关于饭馆的基础知识,网络介绍缓冲区溢出的
文章多数,个中基本上都介绍了仓库的文化,读者能够活动参考那二个作品,作者在此处只是简短
的牵线一下。

    多个先后的动态数据通过1块叫做货仓的区域来存放在。仓库处于内部存款和储蓄器的高档,它有个特
性:后进先出。当程序中调用子函数时,计算机首先把参数依次压入货仓,然后把指令寄存
器(EIP)中的内容做为再次回到地址(RET)压入货仓,第多少个压入宾馆的是基址寄存器(EBP),然后
把当下的栈顶指针(ESP)拷贝到EBP,做为新的营地址。最终把ESP减去料定的数值,用来为本
地变量留出一定空间。
    
    普通的缓冲区溢出就是应用了仓库生长方向和数目存款和储蓄方向相反的性情,用后存入的数
据覆盖先前压栈的数据,一般是覆盖重临地址,从而改换程序的流水生产线,那样子函数重返时就跳到了
黑客钦命的地方,就足以按照黑客意愿做别的业务了。
    
    格式化串漏洞和平常的缓冲溢出有相似之处,但又有所不一样,它们都以应用了技士的
马虎大体来更换程序运维的符合规律流程。上边详细介绍格式化串漏洞的规律,最终对wu-ftp六.0
格式化串漏洞实行一下分析。

三.格式化串漏洞原理
    
    所谓格式化串,便是在*printf()类别函数中根据一定的格式对数码举办输出,能够出口
到正式输出,即printf(),也足以输出到文件句柄,字符串等,对应的函数有fprintf,sprintf,
snprintf,vprintf,vfprintf,vsprintf,vsnprintf等。能被黑客利用的地点也就出在这一层层
的*printf()函数中,恐怕有人会问:那些函数只是把数据输出了,怎么能导致安全隐患呢?
在例行景况下本来不会产生怎么着问题,可是*printf()系列函数有叁条十三分的属性,那个特种
脾气假诺被黑客结合起来使用,就会产生漏洞。

(注:以下测试情状为RedHat Linux 陆.0)

#能够被黑客利用的*printf()种类函数的八特性状:

(一)参数个数不牢固产生访问越界数量

    首先第叁个能够被运用的性质是:*printf()体系函数的参数的个数是不定点的。拿printf()
函数比释迦牟尼讲,若是大家要每种输出叁个整型数据和3个字符串,能够用以下顺序:

#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()函数共有多少个参数,第2个是格式化串”%s %d %d
%d\n”,第3个是字符串buf的
地址,%s对应buf,其后的多个%d分别对应i,j,k,那样就把数据输出了。然则借使大家减弱printf()
函数的参数个数,写成那样:

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

    格式化输出符号依旧是五个,但相应的多少却只剩下3个了(buf,i,j)了,那么意况会怎么着呢?
咱俩编写翻译运转一向下探底访,那么些程序输出:

test 1 2 1953719668

    我们能够了解的见到,固然未有给最终二个%d提供对应的数据,可是它依然出口了3个11人的
平头19伍二7一九陆七捌,这一个大整数到底是什么样呢?大家再修改源程序,把出口的语句改为:

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

    即依照1陆进制输出最终三个参数,那时输出的结果正是:

test 1 2 74736574

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

    那么7473657四到底是什么样玩意儿呢?假设你对ASCII码纯熟的话应该能够反映过来,字符串在内部存款和储蓄器
高级中学级是以ASCII码的样式积攒的,它们有如下对应提到:

十陆进制             10进制            字符
    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()首先找到第
三个参数格式串”%s %d %d
%x\n”,然后就起来遵从对应涉及依次打字与印刷前面酒馆中剧情,%s对应
buf地址,也就打印出了buf[]的剧情,第1个%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()连串函数的第3个特殊的性质。

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

    到近日甘休大家都只是展现内部存储器的内容而从不改变动它,然而使用*printf()的一个新鲜的格式符
%n,大家就向内部存款和储蓄器中写入内容。

    %n是3个在编制程序中不常常使用的格式符,它的职能是把前边早已打字与印刷的尺寸写入有个别内存地址,
为了搞清其实际用法和总体性,我们看1看上边的例程:

#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);

    那样就会产出段访问错误。重申这点很要紧,因为在骨子里运用有个别漏洞时,并不是间接把跳转
地址写入函数的回到地址单元,而是写入3个存放着函数的归来地址的地方当中,即平时说的retloc,
本条存放函数的回来地址的地方平时在大家提供的字符串的前方,这么说或然有点绕,换种说法,正是
说大家并不直接覆盖再次回到地址,而是经过地点来直接的改写重返地址,那一点平常有人歪曲,就算您还没
明亮的话,可以仔细回味一下C语言中指针的用法,它们之间有相似之处。

    好的,到近日停止大家早已知晓能够接纳提交格式串来访问格式串后边酒馆里的内容,并且使用
%n可以向3个内部存款和储蓄器单元中的地址去写入2个值,既然大家能够访问到大家付出的串,就足以在大家提
交的串个中放上有个别函数的归来地址的地方,那样就能够利用%n来改写那个重临地址。

    可是只是,%n向内部存款和储蓄器中写入的值并不是随机的,它不得不写入前边打字与印刷过的字符数量,而作者辈要求的
是写入大家存放shellcode的地址,就象普通溢出做的那样。那么些难点莫过于是费力,大概有人会想:那
就用和跳转地址的数值同样多的数目的%d放在%n的前头不就行了?那样做辩白上有效,但骨子里却百般,
因为货仓在内存的高级,仓库里面包车型地铁内部存储器地址也是三个比异常的大的数,假如我们用3个%d来对号入座四字节内容
即一个整型的话,首先数量太多正是3个主题材料,而且每三个字节的内部存款和储蓄器单元作为整数打字与印刷出来的话,它的
实际上尺寸也是不得已明确的,有的只怕打字与印刷出一人的’1’,有的则或然打字与印刷出5人的’453六7’,那是我们没办法
预料的。

    那时就须要动用到*printf()类别函数的第多少个”卓绝”的习性了。

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

    *printf()种类函数有个天性是:技术员能够定义打字与印刷字符的肥瘦。学过C语言的人必然都晓得那点,
不怕在格式符的高级中学级加上二个平头,*printf()就会把这几个数值作为出口宽度,假使出口的实际上超越钦命宽
度仍按其实增长幅度输出,若是低于钦点宽度,则按内定宽度输出。举例我们能够用上边语句以玖拾捌个字符的宽
度输出整数i:

printf(“%100d”,i);

    而用printf(“%.100f”,i)的花样则是以91十二人的小数输出i。而printf(“%.f”,i)不是以一人小数输出,而是
以累计七人的带小数的数输出i。假设i等于一的话,输出应该是壹.000000。由于这么些”%.f”一次能向前推进6人,所
以它时时在实际攻击时被放在提交的格式串的中级,用来异常快地到达重回地址处。

    大家就能够动用这么些特点来用很少的格式符来输出四个十分大的数值到%n,而且那几个数值是能够由我们
来钦点的。我们所要做的便是作一些总括,把要再次来到的地址转化为整数,放到%n前边的格式串中。举个例子我们要
把200放入num中,则足以应用如下语句:

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

    当那条语句试行完后,num的值就产生200了。假设用跳转地址的值替代200,那么%n就可以把跳转地址写入
num了。

(4)总结

    好了,到此地早已把格式化串漏洞的具备理论依赖都介绍完了。让大家再来回看一下:

    首先,借使程序中的*printf()体系函数中的格式串参数是由用户来提供的话,我们就能够付出给它一串
%d(或%f,%u等)来做客旅馆中格式串前面包车型客车妄动内部存款和储蓄器单元。

    在大家付出的格式串的末尾加上3个%n格式符,大家就能够向货仓中格式串前面包车型客车某部内部存款和储蓄器单元中写入
曾经打字与印刷的字符数量。在事实上攻击时平日是在付给的格式串前边放上存放着有个别函数的归来地址的地址,然后
让%n恰好对应着那一个地址值,那样写入到数值,就存放到函数重临地址个中了。

    大家通过附加格式符来调控向函数重返地址中写入的值,一般是选用%n前边的结尾一个格式符来调节
以此数值,这一般须要有的计量,计算方法一般是用shellcode的地点减去最后3个格式串前的享有格式串的
打字与印刷长度。那样%n写入的数值就刚刚是shellcode的地点了。

    理论上讲的只是理想状态,在实际攻击某些程序时多次会现出愈来愈多的难点。首先要消除的是必须使%n正好
对应存放函数再次来到地址的地址,不然不能改造重临地址的值。这点对于一些可再度运营且能够回到格式串的
次第而言是相比较轻巧化解的,我们得以先不放入跳转地址,而是在付出的格式串前填上多少个特殊字符,比方”abcd”,
下一场在付出的格式串末了用%x取代%n来显示这些奇怪字符串,我们要做的只是不断追加格式串中间的格式符的个
数,直到程序重返的值恰好是大家提交的特殊字符的ASCII码截止。那样大家就通晓用来存放在函数再次来到地址的地
址在如何岗位了,然后我们再把真正的寄放函数再次回到地址的地方位于格式串的前头,用%n作为格式串的末尾,那
样就能够把跳转地址准确的写进函数重返地址了。

    当然那种措施要求被攻击的顺序能够持续的启航而且能够回来提交的格式串的打字与印刷内容,wu-ftp陆.0就是
这么的程序,所以针对wu-ftp陆.0的格式串漏洞的口诛笔伐相比较易于得逞的。而有点程序则万分,比方cfengine,那
个程序被发觉存在格式串漏洞已经很久了,但是一向从未可成功的攻击程序发表,主要正是因为一但向cfengine
发送格式串它就当掉了,所以不或者数次估计。对那种程序必须一回攻击就务须猜中存放函数再次来到地址的地址和
跳转地址,所以在现实的抨击中频仍是不便于得逞的。

    此外二个难以消除的难点是,要求把标准的函数重返地址填在格式串起来,那样%n技能把跳转地址写进
是的的岗位了。那个函数的回到地址一般是在写攻击程序时测试获得的,那在测试的机器上就算能够成功,然而
在不一样机器上那一个重回地址的值是基于意况变量和编写翻译选项的两样而各异的,举例用rpm安装的wu-ftp和从源
代码编译安装的wu-ftp,它们的回来地址往往便是见仁见智的,要求基于被口诛笔伐主机的莫过于情状张开调治。那唯有根
据经验来鲜明,大概索性用暴力法了疑心重临地址,但依据实际测试,即选择暴力法估摸重临地址,成功的概率
也是微小的。

    还有正是跳转地址的难点,即shellcode的地点。因为大家要改写函数的归来地址,使它跳转去实施shellcode。
所以必必要精晓shellcode的地址。那些难点相对轻便化解,我们能够像普通溢出做的那样,在shellcode前边
填上壹串NOP,这样只供给驾驭2个差不离的地点范围就足以了,只要跳转到NOP的限定其中就能够进行shellcode
了。所以一般的抨击程序里的跳转地址往往是不需求调解的,因为假设在1个差不多的地方范围个中就能够了。

    好了,理论就研讨这么多,下边我们来探视Wu-ftp陆.0的格式化串漏洞和采用的艺术。

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

(壹)难题出现在何地

    wu-ftp(华盛顿 University ftp
server)是壹个至极流行的unix/linux系统ftp服务器,它的陆.0版本
留存格式化串漏洞。由于在大许多Linux系统中它是暗许安装的,所以一定多的网址都受这几个漏洞的熏陶,针对它
的攻击也是分外分布的。

    上边我们看看wu-ftp的源代码,终究是哪儿出现了能够被黑客利用的漏洞?

    用户提交的”site exec”命令是由多少个名字为 void site_exec(char *cmd)
的函数来拍卖的,当中cmd是用户
付给的命令。在这一个函数中有那般一个言语:

————–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()系列
函数的格式串参数是由我们来交给的话,那么大家就能够用一串格式符来访问格式串前边
仓库里的内容了,如若大家能访问到温馨交给的始末,就足以在那内容的前面放上存放有些
函数再次来到地址的地方,然后就足以用%n来改写那几个重临地址,使它跳转去实行大家提供
的shellcode。

(二)wu-ftp漏洞的施用

    所以大家要想选择那个漏洞,须要首先登场录上FTP服务器(编制程序完结,不用大家温馨去登入了),
用无名氏用户(ftp,anonymous)登录就足以,然后交给二个之类情势的site
exec命令:

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

    注意:当中的’|’符号是为了使读者看精晓字符串结构而加上的分隔符,实际交付的串里未有’|’。

    这些由大家提交的格式串前边是site
exec命令,后跟的”aa”的机能是为了使retloc以4字节
为单位对齐,正是我们一般所说的align。

    然后紧跟着的retloc便是大家要写入的寄放函数重临地址的地方,呆会儿大家要用%n来对号入座
它,就能够把跳转地址写入函数重临地址了。一般大家要改写的函数应该是近期的一个函数,那里
能够改写vreply()的归来地址,使它回到时跳去执行大家的shellcode。

    在retloc前面放上一串%.f,前面说过%.f一回突显8人数字,在此处它的功效是展现在大家提
交的指令串之后压入商旅的有个别变量,使%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
6.0上的值,在其
它系统中会有所区别。由于大家能够在shellcode在此以前放上一批NOP,所以也没须求知道shellcode的
确切地点,只要让程序跳转到NOP范围里就行了。

    须要证实的是,那里的shellcode必须是含有突破chroot()成效的,因为一旦用佚名用户登入的
话,只可以访问被chroot()珍惜的目录,即无名氏用户登入后的目录,这样就无奈绑定/bin/sh了。所以要
在shellcode中先chroot()到根目录。英特网有为数不少写得不行好的chroot
shellcode,直接拿来用就可
以了。

    以上正是攻击wu-ftp⑥.0格式化串漏洞的法子,未来流传着诸多写得尤其好的wu-ftp陆.0攻击程
序,作者自然想找当中二个来逐条语句解释出来的,但解释了几句之后察觉太TMD麻烦了。而且也绝非必
要表达攻击程序了,因为自身曾经把攻击那么些漏洞的手续都在目前解释过了。

    那里只把作者用过的多少个相比较好的口诛笔伐程序介绍给大家:

    (一)攻击以rpm安装wuftp陆.0的RedHat 陆.0, 陆.壹, 陆.二比较实惠的先后:
    
    

    (贰)攻击安装wuftp陆.0的FreeBSD和SuSe 陆.3, 陆.肆相比实用的程序:
    
    

    (3)攻击安装wuftp陆.0的solaris 2.x相比较灵通的主次:

    

    依据自家的阅历,以rpm格局安装wuftp陆.0的RedHat 六.0, 陆.一,
陆.贰是最轻便攻击成功的了,大概是
因为超过3/陆抨击程序都是在那种系统情形下调节和测试编写的。而用源代码编写翻译安装的wuftp不易于攻击成功,
亟需攻击者调度攻击程序中的某个参数,首要要修改的是retloc,也正是存放函数重返地址的地方,有
时候需求反复调节这几个值才具攻击成功。

五.后记

    本文的目标是把格式化串漏洞尽量用通俗易懂的语言表明出来,所以自个儿在分解原理时从没用gdb等
工具的调试结果来讲,而是尽大概地只讲原理本身,那样对于一些面生调节和测试器的读者来讲恐怕相比较便于
接头。大概有人依然会认为本文写得不是很易懂,因为格式化串漏洞本人正是个比较复杂的事物,起码
亟需读者掌握部分关于C语言以及货仓溢出的基本知识,那样才推向驾驭本文。

    可能有点人会说:”为何非要搞领会那一个漏洞的技巧细节呢?作者不懂细节直接用攻击程序攻击一下
也能打响。”没有错,在其实攻击的时候大家一般都以稍稍思考细节难题的,可是只是只是,你的靶子是成
为一个哈克er呢?依然贰个Scriptkid?假使你的对象是前者,那断定你必要通晓技艺细节。假诺是
后者,你同壹也亟需了然本事细节!!因为精晓的底细愈多,你攻击的成功率就越大了。

多谢warning三等nsfocus的同志,他们写的稿子使作者收益非浅。

参考文献:

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

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

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

相关文章

发表评论

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

*
*
Website