缓冲区溢出(栈溢出)

pwn是什么

在 CTF 中,PWN 主要通过利用程序中的漏洞造成内存破坏以获取远程计算机的 shell,从而获得 flag。PWN 题目比较常见的形式是把一个用C/C++ 语言编写的可执行程序运行在目标服务器上,参赛者通过网络与服务器进行数据交互。因为题目中一般存在漏洞,攻击者可以构造恶意数据发送给远程服务器的程序,导致远程服务器程序执行攻击者希望的代码,从而控制远程服务器。

栈基础(64位)

寄存器

CPU内部的存储单元,用于存放从内存读取而来的数据(包括指令)和CPU运算的中间结果

不同体系结构的CPU在其内部存在的寄存器的数量、类型以及名称可能会不同,我们现在只看ADM64 CPU这一种体系结构,这种CPU在其内部存在二十多个可直接被汇编语言中使用的调度器,还有几种仅在操作系统代码中才会出现,应用层的话,通常只会用到如下三个分类共19个调度器:

通用寄存器共有rax、rbx、rcx、rdx、rsi、rdi、rbp、rsp、r8、r9、r10、r11、r12、r13、r14、r15这16个寄存器,除了 rsp、rbp CPU对它们的用途没有做特殊规定,可以自定义其用途

rsp:就是常说的栈指针,它永远指向一个进程的栈顶

rbp:保存的是栈帧在内存中的起始地址

程序计数寄存器(rip寄存器,也叫PC寄存器、IP寄存器)用来存放下一条即将用来执行的指令的地址,它决定程序执行的流程。

段寄存器(fs、gs寄存器)用来实现线程本地存储(TLS)

简单汇编

汇编语言可以让我们直接操作寄存器、栈、内存等硬件资源,从而更好理解计算机的工作原理

mov a,b  #将b的值赋给a
add a,b  #a=a+b
sub a,b  #a=a-b
push rax #将rax的值入栈  
pop rax  #将栈中的一个数据入rax

栈结构

栈由高地址向低地址延伸,两个指针:rsp:指向栈顶 rbp:指向栈低

000001栈顶rsp低地址
.......
.......
000010栈低rbp高地址

栈常用指令

举个例子:

mov rax, 123h
mov rbx, 456h
push rax
push rbx
pop rax
pop rbx

原栈

.....低地址
000111rsp
.....高地址

push rax (即rsp=rsp-8),并将rax中的数据 123h 压入到栈当中

...低地址
000123rsp
000111
...高地址

push rbx

...低地址
000456rsp
000123
000111
...高地址

pop 和上面类似,是一个弹出的过程

pop rax:将栈中的值弹出给rax, rsp=rsp+8

pop rbx:将栈中的值弹出给rbx

整体操作下来后rax和rbx的值实现了互换 栈是一个先入后出的数据结构

函数中栈的调用

int func2(){
  return 3;
}
int func1(){
  return func2();
}
int main(){
  return func1();
}

汇编后:

func2():
401106   push   rbp
401107   mov    rbp,rsp
40110a   mov    eax,2
40110f   pop    rbp
401110   ret     
func1():
401111   push   rbp
401112   mov    rbp,rsp
401115   call   func2()
40111a   pop    rbp
40111b   ret
main():
40111c   push   rbp
40111d   mov    rbp,rsp
401120   call   func1()
401125   nop
401126   pop    rbp
401127   ret

栈溢出

读取是从高地址指向低地址,但是栈又是从低地址指向高地址,在局部变量的位置写入内容,如果没有控制好输入长度,会覆盖掉返回的地址

int flow(){
  char buf[8];
  read(0, buf, 16);
}

声明了一个名为 buf 的字符数组,大小为 8 字节。然后,通过调用 read() 函数从标准输入中读取最多 16 个字节的数据,并将其存储到 buf 数组中

需要注意的是,尽管 buf 数组的大小只有 8 字节,但 read() 函数仍然会尝试读取 16 个字节的数据。这可能导致缓冲区溢出的问题,因为读取的数据量超过了 buf 数组的容量。

栈保护

canary(金丝雀)

"Canary" 是一个随机生成的特殊值,它被插入到栈帧的布局中,位于局部变量和返回地址之间。当函数返回时,系统会检查"canary"值是否被修改,如果发现被修改,则会触发异常或终止程序的执行。

NX(堆栈不可执行)

将数据所在内存页(例如堆或栈)表示为不可执行,如果程序产生溢出而转入shellcode时,CPU就会抛出异常

ASLR和PIE(地址随机化)

随机化地址布局,使攻击者堆内存布局一无所知

标准的可执行程序需要固定的地址,并且只有被装载到这个地址才能正确执行,PIE能使程序像共享库一样在主存的任何位置加载,引入PIE的原因就是让程序能装载在随机地址,从而缓解缓冲区溢出攻击

RELRO

设置符号重定向表格为只读或在程序启动时就解析并绑定所有动态符号,从而减少对GOT的攻击

实战例题

  1. BUUCTF在线评测 (buuoj.cn)

  2. BUUCTF在线评测 (buuoj.cn)

  3. BUUCTF在线评测 (buuoj.cn)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值