zoukankan      html  css  js  c++  java
  • 20199324《Linux内核原理与分析》第十二周作业

    格式化字符串漏洞实验

    一、 实验描述

    格式化字符串漏洞是由像 printf(user_input) 这样的代码引起的,其中 user_input 是用户输入的数据,具有 Set-UID root 权限的这类程序在运行的时候,printf 语句将会变得非常危险,因为它可能会导致下面的结果:

    • 使得程序崩溃
    • 任意一块内存读取数据
    • 修改任意一块内存里的数据(这种结果是非常危险的,因为它允许用户修改 set-UID root 程序内部变量的值,从而改变这些程序的行为)

    本实验将会提供一个具有格式化漏洞的程序,我们将制定一个计划来探索这些漏洞。

    二、 实验内容

    2.1 实验一

    户需要输入一段数据,数据保存在 user_input 数组中,程序会使用 printf 函数打印数据内容,并且该程序以root权限运行。这个程序存在一个格式化漏洞。让我们来看看利用这些漏洞可以搞些什么破坏。

    在/home/shiyanlou/目录下,新建vul_prog.c文件,输入以下代码内容:

    /* vul_prog.c */ 
    #include <stdlib.h>
    #include <stdio.h>
    
    #define SECRET1 0x44
    #define SECRET2 0x55
    
    int main(int argc, char *argv[])
    {
      char user_input[100];
      int *secret;
      long 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)
    ", &secret);
      printf("The variable secret's value is 0x%8x (on heap)
    ", secret);
      printf("secret[0]'s address is 0x%8x (on heap)
    ", &secret[0]);
      printf("secret[1]'s address is 0x%8x (on heap)
    ", &secret[1]);
    
      printf("Please enter a decimal integer
    ");
      scanf("%d", &int_input);  /* getting an input from user */
      printf("Please enter a string
    ");
      scanf("%s", user_input); /* getting a string from user */
    
      /* Vulnerable place */
      printf(user_input);  
      printf("
    ");
    
      /* Verify whether your attack is successful */
      printf("The original secrets: 0x%x -- 0x%x
    ", SECRET1, SECRET2);
      printf("The new secrets:      0x%x -- 0x%x
    ", secret[0], secret[1]);
      return 0;
    }
    

    程序说明

    程序内存中存在两个秘密值,我们想要知道这两个值,但发现无法通过读二进制代码的方式来获取它们(实验中为了简单起见,硬编码这些秘密值为0x44和0x55)。尽管我们不知道它们的值,但要得到它们的内存地址倒不是特别困难,因为对大多数系统而言,每次运行程序,这些内存地址基本上是不变的。实验假设我们已经知道了这些内存地址,为了达到这个目的,程序特意为我们打出了这些地址。

    有了这些前提以后我们需要达到以下目标:

    • 找出 secret[1] 的值
    • 修改 secret[1] 的值
    • 修改 secret[1] 为期望值

    注意:因为实验环境是 64 位系统,所以需要使用 %016llx 才能读取整个字。但为了简便起见,对程序进行了修改了,使用 %08x 也能完成实验。

    编译运行:

    $ gcc -z execstack -fno-stack-protector -o vul_prog vul_prog.c 
    $ sudo chmod u+s vul_prog
    

    :这里会报出一些警告 warning,可以忽略。

    2.1.1 找出 secret[1]的值

    1.运行 vul_prog 程序去定位 int_input 的位置,这样就确认了 %s 在格式字符串中的位置。

    12和后面的 %016llx都是自己随意输入的, %016llx的个数最好在10个以上。

    12的十六进制码就是0x000C,可以看到输出中12的十六进制在第8个位置上,这样我们就能确定格式化字符串的位置了。

    2.输入 secret[1] 的地址,记得做进制转换,同时在格式字符串中加入 %s

    可以看到 secret[1] 的地址是 0x602014 ,转换成十进制就是 6299668。

    第八个位置上替换成 %s 就能打印出 secret[1] 的值了。

    U 的 ascii 码就是 55。

    2.1.2 修改 secret[1]的值

    只要求修改,不要求改成什么。可以看到已经变成 0x77 了。

    2.1.3 修改 secret[1]为期望值

    要改成自己期望的值,比如改成十进制1000,手动填充1000太累了!这里可以用格式化字符填充。

    从图上得知,secret[1] 的地址是 0x602014,换算成十进制就是6299668。

    我们在第7位用%.897u这种设置精度的方式填充字符,897是怎么来的呢?
    在 %.897u 前有 6 个 64 位地址,每个地址对应 16 个字符,加上逗号一共就是 6*(16+1)=102 ,在 %.897u 后面的地址上还有一个 , 占一个字符。所以一共是 102+1=103 个字符,要改成 1000 的话,我们就还差 1000-103=897 个字符。

    0x3e8 的 10 进制就是 1000 。

    2.2 实验二

    现在修改vul_prog.c程序,把第一个scanf语句去掉,并去掉与int_input变量相关的所有语句,程序如下:

    /* vul_prog.c */ 
    #include <stdlib.h>
    #include <stdio.h>
    
    #define SECRET1 0x44
    #define SECRET2 0x55
    
    int main(int argc, char *argv[])
    {
      char user_input[100];
      int *secret;
      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)
    ", &secret);
      printf("The variable secret's value is 0x%8x (on heap)
    ", secret);
      printf("secret[0]'s address is 0x%8x (on heap)
    ", &secret[0]);
      printf("secret[1]'s address is 0x%8x (on heap)
    ", &secret[1]);
    
      printf("Please enter a string
    ");
      scanf("%s", user_input); /* getting a string from user */
    
      /* Vulnerable place */
      printf(user_input);  
      printf("
    ");
    
      /* Verify whether your attack is successful */
      printf("The original secrets: 0x%x -- 0x%x
    ", SECRET1, SECRET2);
      printf("The new secrets:      0x%x -- 0x%x
    ", secret[0], secret[1]);
      return 0;
    }
    

    同时在 xfce 终端使用 linux 命令设置关闭地址随机化选项:

    sudo sysctl -w kernel.randomize_va_space=0
    

    关闭地址随机化后,这样每次运行程序得到的 secret 地址就都一样了。

    在 /home/shiyanlou 目录新建一个程序write_string.c。以下程序将一个格式化字符串写入了一个叫 mystring 的文件,前4个字节由任意你想放入格式化字符串的数字构成:

    /* write_string.c */
    
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    int main()
    {
        char buf[1000];
        int fp, size;
        unsigned int *address;
        /* Putting any number you like at the beginning of the format string */
        address = (unsigned int *) buf;
        *address = 0x113222580;
        /* Getting the rest of the format string */
        scanf("%s", buf+4);
        size = strlen(buf+4) + 4;
        printf("The string length is %d
    ", size);
        /* Writing buf to "mystring" */
        fp = open("mystring", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
        if (fp != -1) {
            write(fp, buf, size);
            close(fp);
        } else {
            printf("Open failed!
    ");
        }
    }
    

    编译 vul_prog.c 与 write_string.c:

    rm vul_prog
    gcc -z execstack -fno-stack-protector -o vul_prog vul_prog.c 
    gcc -o write_string write_string.c
    

    然后通过 write_string 程序将内容输入进 mystring 文件中,文件内容包括代码中加入的头四个字节和你之后输入的内容。

    先运行 vul_prog 程序,输入 4 个 %016llx 。再运行 write_string 程序,输入 8 个 %016llx 和 1 个 %n ,此操作会生成一个 mystring 文件。然后输入如下命令:

    ./vul_prog < mystring
    

    修改成功(0x8c = 140 = 8*16+8 个逗号+开头 4 个字节)。

  • 相关阅读:
    数学之美系列十八 矩阵运算和文本处理中的分类问题
    数学之美系列一 统计语言模型
    数学之美系列十三 信息指纹及其应用
    数学之美系列十六 谈谈最大熵模型
    数学之美系列十五 繁与简 自然语言处理的几位精英
    数学之美系列十七 谈谈搜索引擎作弊问题(Search Engine AntiSPAM)
    数学之美系列三 隐含马尔可夫模型在语言处理中的应用
    数学之美系列十四 谈谈数学模型的重要性
    数学之美系列十二 余弦定理和新闻的分类
    数学之美系列十一 Google 阿卡 47 的制造者阿米特.辛格博士
  • 原文地址:https://www.cnblogs.com/yangdd/p/11983968.html
Copyright © 2011-2022 走看看