PWN January 03, 2020

栈溢出入门到放弃1

Words count 2.8k Reading time 3 mins. Read count 0

一、缓冲区溢出原理介绍:

缓冲区:stack、heap

1、栈溢出:当前输入的字符的数量大于buf的大小,造成溢出,ret地址被覆盖,造成任意地址跳转

来道题目直接看看:

1561631832701

这里很清晰,一个main函数,调用puts函数和read函数和puts函数,下面简单的例子演示下参数入栈:

单步走:先调用puts函数,先将参数“give me some thing?”压入栈中

1561624216186

1561625056181

1561625089412

执行完puts函数,借助栈中的0x8048489可回到下一条将要执行的指令的地址(return地址),回到了现场,此过程pop出0x8048489(因为调用结束,没有用了)

1561625218504

接着调用read函数,可以看到栈中压入的参数,从右往左0x40,buf,0,执行完read下一条将要执行的指令的地址0x804849c(return地址)入栈(__cdecl 调用约定,从右往左)

1561625329392

这里,我们知道了函数调用参数从左到右入栈的原理,而且知道栈是往低地址增长的,接着我们要往栈中写入东西呢?

1561625735339

从我们的输入可以看到,写入栈中的内容是往高地址写的,这里理解了:

参数入栈:往低地址增长

写栈:往高地址增长

再次调用puts函数,可以看到参数,下一个将要返回的指令地址以及当前栈的ebp

1561631279640

当执行完了puts,回到前面的栈帧:

1561631504050

开始不断地还原回去:

1561631574566

最后pop出ebp,ret那个libc_start_main的位置。

由于写栈往高地址写,那么意味着可以覆盖ret地址,只要写的足够长,这样,当函数返回时就会执行ret,如果我们恶意修改ret地址为任意地址,就可以实现任意地址跳转~这就是最基础的栈溢出的原理。

接着继续分析64位的情况:

1561637740927

1561634752543

64位的参数是放入到rdi、rsi、rdx、rcx、r8、r9,当这6个参数都放不了时才选择放在栈中,优先放入到寄存器中

继续看read函数调用:

1561634933550

这里我们知道了参数的保存,64位的写栈也是一样的,往高地址写:

1561635020678

这里根据我们之前学的,可以覆盖到ret地址,那我们试着覆盖下:

先找后门函数:

1561635147961

接着填充覆盖(0x20+8个字节覆盖ebp)+ function(ret位置)

1561635118446

程序执行完就可以getshell了:

1561635262332

以上就是有关栈溢出的所有知识点介绍,总结下:

首先是参数入栈图:

1561636734757

然后是写栈图:

1561637611348

写入字符串:

1561637685543

这样就可以getshell了~

0%