对pwn格式化字符串的浅显理解

328 阅读2分钟

格式化字符串原理,浅显理解

  1. 格式化字符串漏洞通常是 printf函数未指明输出格式 例如:

    char buf[20];
    scanf("%s",buf);
    printf(buf);
    

    这时候可以输入格式化字符 %d,%p等控制函数的输出。

    如果程序指明输出的格式,则无法利用格式化字符串漏洞 例如:

    char buf[20];
    scanf("%s",buf);
    printf("%s",buf);
    
  2. 简单解释格式化字符串原理

    1. 这是两段程序的源码:

      • 1️⃣

        #include <stdio.h>
        void main()
        {
            char buf[20];
            scanf("%s",buf);
            printf("%s",buf);
        }
        
      • 2️⃣

        #include <stdio.h>
        void main()
        {
            char buf[20];
            scanf("%s",buf);
            printf("%s",buf);
        }
        
    2. 对应的汇编代码:

      • 1️⃣image-20211117211605950.png

      • 2️⃣image-20211117212240003.png 可以看到两段汇编代码唯一不同的地方在于:

        image-20211117212032354.pngimage-20211117212311633.png

        1️⃣程序的printf有两个参数 是 %s 和 buf,在汇编代码中可以看到 buf 的地址 rbp-0x20被传给了rsi寄存器,那%s这个参数是怎么处理的呢,可以猜测是通过lea rdi,[rip+0xe7c] 传给了rdi寄存器。(rip+0xe7c)这个地址存的值就是 %s)这个探索过程可以通过 gdb 实现,这里就不多赘述。

        2️⃣程序存在格式化字符串漏洞 它的printf 函数只有一个参数 buf,通过汇编代码可以知道 buf 的地址被直接传给了rdi寄存器,如果我们在输入的时候将 buf 的值设为 %x,rdi 所指向的地址的值就为 %x ,这个传参过程类似1️⃣的汇编代码现实的过程,但是这样就缺少了要显示的参数的地址,实际上程序运行时会把后面的栈空间的值显示出来。这个过程若是深入理解需要很多底层的知识,由于我的水平有限,只能先这样简单记忆了。

\