Protostar-栈溢出学习-覆盖栈函数指针和ret指令控制eip

By xia0

#0x00 序

接着之前的系列,下面研究两种控制eip的方式

#0x01 C语言源代码

Stack3 looks at environment variables, and how they can be set, and overwriting function pointers stored on the stack (as a prelude to overwriting the saved EIP)

Hints:
both gdb and objdump is your friend you determining where the win() function lies in memory.

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void win()
{
  printf("code flow successfully changed\n");
}

int main(int argc, char **argv)
{
  volatile int (*fp)();
  char buffer[64];

  fp = 0;

  gets(buffer);

  if(fp) {
      printf("calling function pointer, jumping to 0x%08x\n", fp);
      fp();
  }
}
  • 在main函数下断点,分析可知,1处为fp的地址,2处为fp()的调用,我们需要覆盖掉esp+0x5c处所存的函数指针值,使其跳转到win()函数
    1-0

  • 利用Python编写exp测试脚本,可以发现QQQQ覆盖了函数指针
    1-1
    1-2
    1-3
    1-4

  • 重新编写exp,将QQQQ改为win()函数的地址,即可实现自定义调用,控制eip

1-5
1-6

成功执行win()函数

1-7

#0x02 通过ret指令控制eip

Stack4 takes a look at overwriting saved EIP and standard buffer overflows.

This level is at /opt/protostar/bin/stack4

Hints:
A variety of introductory papers into buffer overflows may help.
gdb lets you do “run < input”
EIP is not directly after the end of buffer, compiler padding can also increase the size.

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void win()
{
  printf("code flow successfully changed\n");
}

int main(int argc, char **argv)
{
  char buffer[64];

  gets(buffer);
}
  • 先分析一下,可以发现这个程序很简单,看上去没有可以直接控制eip的方法,但函数的调用过程在结束的时候会将保存的返回地址存在栈中,ret指令的时候会将传给eip。所以我们可以覆盖对应的返回地址值达到控制eip

    ______________
    |            |  <---esp
    --------------
    |  局部变量1  |
    --------------
    |  局部变量2  |
    --------------
    | ...        |
    --------------
    |            |  <---new ebp
    --------------
    |   old ebp  |
    --------------
    |  返回地址   |  ret --------> eip
    --------------
    
  • 和前面一样,这次我们之间利用Python编写exp测试脚本,可以发现SSSS覆盖了old ebp,TTTT覆盖了返回地址

1-9
1-8
1-10

  • 我们查看win()的地址,重新编写对应exp,然后将TTTT改为其地址,成功达到目的。

1-11

成功执行win()函数
1-12