• 参考博客:[原创]无路远征——GLIBC2.37后时代的IO攻击之道(零)-Pwn-看雪-安全社区|安全招聘|kanxue.com

  • 参考博客:关于gdb源码调试环境搭建 - ZikH26 - 博客园

  • IO也就是输入输出的意思,但是C语言的输入输出的函数有很多,例如:putsprintfwritestdinstdoutscanfread等与输入输出相关的函数。

  • 而我们所说的打IO打的是我们封装到比较上层的函数,比如putsprintf这类的上层封装的函数。

    • readwrite这两个是比较底层的,系统调用syscall的输入输出,一般都是调用这两个函数。
    • putsprintf等这些IO函数最后都会通过write这个底层函数与操作系统交互。
    • 所以我们所说的打IO,打的就是这种上层输入输出函数。在调用这些函数的时候会经过一些指针结构体函数指针等,所以我们通过劫持指针伪造IO结构体绕过检查机制从而getshll或者执行shellcode
    • IO相关的都可以在glibc源码中,/path/to/glibc2.23/libio中可以看到。
  • 由于高版本的glibchook指针被删除了,所以余下可用的函数指针只有io相关的函数指针了,在高版本堆利用的时候IO利用就成了基础了。

IO_FILE起源及结构体

  • 如果出过pwn题或者做过全缓冲pwn题就会了解到这个函数。和缓冲区的三种工作模式,无缓冲行缓冲全缓冲
1
2
3
setvbuf(stdin,NULL,_IONBF,0);
setvbuf(stdout,NULL,_IONBF,0);
setvbuf(stderr,NULL,_IONBF,0);
  • 为什么要设置这三种模式,这就和硬件操作系统程序三者有关。首先程序要读写硬盘或者是输出到屏幕中,这些都是要通过系统调用syscall,进行writeread系统调用。
  • 而何时进行系统调用,这就成为了设计IO的一个重要问题。如果每一个字节都需要使用syscall系统调用(即无缓冲模式)。向硬件进行读写操作,这就会大大降级操作系统的效率,并且硬件频繁读写也会造成更快的损坏。
  • 为了减少这种情况,在设计IO的时候就会出现导致,设置了缓冲区,要输入的数据或者要输出的数据都会先被放入缓冲区,直到缓冲区满了之后,再进行系统调用,将缓冲区存储的内容写入到屏幕或者其他硬件中(全缓冲),以便提高操作系统的效率,提高硬件的使用寿命,这也就出现了现在的IO_FILE结构体。
  • 接下来总结一下glibc封装的上层函数中与输入输出相关的函数,对于IO的攻击一般就攻击这些IO函数的结构体``。
    • 标准输入函数
      • gets()fgets()scanf()fscanf()sscanf()getc()fgetc()getchar()getline()getdelim()
    • 标准输出函数
      • printf()fprintf()sprintf()snprintf()putc()fputc()putchar()puts()
    • 文件操作函数:
      • fopen()freopen()fdopen()fclose()fflush()setbuf()setvbuf()fread()fwrite()fseek()ftell()fewind()rewind()
    • 格式化字符串相关函数:
      • printf()fprintf()sprintf()snprintf()vprintf()vfprintf()vsprintf()vsnprintf()
    • 其他相关函数:
      • perror()tmpfile()clearerr()feof()ferror()stdoutstdout()stdin()stderror()

IO_FILE相关动调

  • 写介绍几个比较重要的IO结构体,并且说明这写结构体在glibc2.23源码的什么位置。

  • 这里先汇总一下与IO_FILE相关动调命令,与IO_FILE相关的调试基本上就是打印结构体。可以在gdb中使用p命令打印出结构体的具体存储的值

1
2
3
4
p stdout
p _IO_2_1_stdout_
p _IO_file_jumps
p *(struct _IO_FILE *) _IO_list_all
  • 接下来调试几个上层的输出函数。来对IO调用有个总体了解。

IO_FILE相关源码

IO_FILE基础