栈溢出漏洞利用技术学习笔记
听i春秋上面蓝莲花战队成员Atum的课程 CTF PWN选手的养成 ,了解到不少东西,在此记个笔记~
基础知识
栈的结构:先进后出,在内存中为高地址往低地址增长,栈顶为栈的最上方(低地址区),栈底为栈的最下方(高地址区)
一、寄存器
-
rsp/esp:指向栈顶的栈指针寄存器(低地址)
-
rbp/ebp:指向栈底的指针寄存器(高地址)。栈低通常作为基址,我们可以通过栈底地址和偏移相加减来获取变量地址
栈的结构如图所示(栈由高地址向低地址增长)
函数调用时栈的变化
EBP指向的栈底,ESP指向的栈顶,EBP下面的EIP是函数返回的地址(即return执行后下一条指令的地址),var1是函数的参数. -
pc:程序指针,存储着指向CPU接下来要执行的指令地址
-
rdi rsi rdx rcx:x86中参数都是保存在栈上,但在x64中的前六个参数依次保存在RDI, RSI, RDX, RCX, R8和 R9中,如果还有更多的参数的话才会保存在栈上。
二、栈溢出漏洞介绍
通俗的讲,栈溢出的原理就是不顾堆栈中分配的局部数据块大小,向该数据快写入了过多的数据,导致数据越界,结果覆盖来看老的堆栈数据。
栈溢出漏洞的形式
三、函数调用约定
函数调用: call, ret
调用约定: _stdcall, cdecl, fastcall, thiscall, nakedcall, __pascal
参数传递:取决于调用约定,x86默认从右向左,x64优先寄存器,然后用栈
call func -> push pc, jmp func
leave -> mov esp, ebp, pop ebp
ret -> pop pc
四、栈溢出的保护机制
栈上的数据无法被当成指令来执行
数据执行保护(NX/DEP),将数据和代码区分开,让数据不可以当做代码来执行
绕过方法:ROP
让攻击者难以找到shellcode地址
地址空间布局随机化(ASLR、PIE)
绕过方法:infoleak 、ret2dlresolve 、ROP
检测Stack Overflow
Stack Canary/Cookie,相当于在返回地址和ebp之间加一个cookies,通过检测cookies是否被改变
绕过方法:infoleak
五、栈溢出的利用方法
现代栈溢出的技术基础:ROP(绕过NX和ASLR)
利用signal机制的ROP技术:SROP
没有binary怎么办:BROP(不是很常见)
劫持栈指针:stack pivot //将栈指针劫持到其他区域
利用动态链接绕过ASLR:ret2dlresolve、fake linkmap
利用地址低12bit绕过ASLR:Partial Overwrite(低12位不会被随机化)
绕过Stack canary:改写指针与局部白能量、leak canary、overwrite canary
溢出位数不够怎么办:覆盖ebp,Partial Overwrite
六、现代栈溢出的利用技术
ROP
eg: Ret2libc
一种代码复用技术,通过控制栈调用来劫持控制流
主要思想: 在栈缓冲区溢出的基础上,利用程序中已有的小片段 (gadgets) 来改变某些寄存器或者变量的值,从而控制程序的执行流程。所谓 gadgets 就是以 ret 结尾的指令序列,通过这些指令序列,我们可以修改某些地址的内容,方便控制程序的执行流程。
CTF中ROP常规套路
第一次触发漏洞,通过ROP泄露libc的address(如puts_got),计算system地址 然后返回到一个可以重现触发漏洞的地方(main)再次触发漏洞。通过ROP调用system(‘/bin/sh’)直接execve(“/bin/sh”,[“/bin/sh”],NULL) 这个通常在静态链接比较常用
Defcon 2015 Qual:R0pbaby
AliCTF 2016:vss
PlaidCTF 2013:ropasaurusrex
利用signal机制的ROP技术-SROP
SROP(Sigretum Oriented Programming)
系统Signal Dispatch之前会将所有寄存器压栈,然后调用signal handler, signal handler返回时会将栈内容还原
如果事先填充栈,然后直接调用signal handler,那在返回的时候就可以控制寄存器的值资源
http://angelboy.logdown.com/posts/283221-srop
http://www.2cto.com/article/201512/452080.html
defcon 2015 qualifier: fuckup(较难)
没有binary怎么办-BROP(用的不多)
目标 :在拿不到目标binary的条件下进行ROP
条件 :必须先存在一个已知的stack overflow漏洞,而且攻击者知道如何触发这个漏洞服务器进程在crash之后会重新复活,复活的进程不会被re-rand
http://ytliu.info/blog/2014/05/31/blind-return-oriented-programming-brop-attack-yi/
http://ytliu.info/blog/2014/06/01/blind-return-oriented-programming-brop-attack-er/
HCTF 2016 出题人跑路了(pwn50)
**劫持栈指针-stack pivot
将栈劫持到其他攻击者控制的缓冲区
向目标缓冲区填入栈数据(如ROP chains),然后劫持esp到目标缓冲区。劫持esp的方法有很多种,最常用的就是ROP时利用可以直接改写esp的gadget 如pop esp ,ret ,具体binary具体分析
利用条件
- 存在地址已知且内容可控的buffer
bss段,由于bss段尾端常有大量空余空间,所以bss段尾端也往往是stack pivot的目标
堆块,如果堆地址已泄且堆上的数据可控,那堆也可以作为stack pivot目标 - 控制流可劫持
- 存在劫持栈指针的gadgets
Stack piovt的动机
· 溢出字节数有限,无法完成ROP
· 栈地址未知且无法泄露,但是某些利用技术却要求知道栈地址(ret2dlresolve)
· 劫持esp到攻击者控制的区域,也就变相的控制了栈中的数据,从而可以使非栈溢出的控制流劫持攻击也可以做ROP
EKOPARTY CTF 2016 fuckzing-exploit-200(基于栈溢出)
HACKIM CTF 2015 - Exploitation 5(基于堆溢出)
*利用动态链接绕过ASLR:ret2dlresolve、fake linkmap
用法
动态链接就是从函数名到地址的转换过程,所以可以通过动态链接器解析任何函数,无需leak
理论上任何可以stack pivot且FULLRELRO未开的题目都可以利用这种技术
资源
前置技能:了解动态链接的过程
http://blog.chinaunix.net/uid-24774106-id-3053007.html
《程序员的自我修养》
伪造动态链接的相关数据结构如linkmap、relplt
http://rk700.github.io/2015/08/09/return-to-dl-resolve/
http://angelboy.logdown.com/posts/283218-return-to-dl-resolve
http://www.inforec.org/wp/?p=389
Codegate CTF Finals 2015 yocto(fake relplt)
http://o0xmuhe.me/2016/10/25/yocto-writeup
HITCON QUALS CTF 2015 readable(fake linkmap)
Hack.lu’s 2015 OREO
****** 理论上任何可以stack pivot且FULLRELRO未开的题目都可以使用这种技术
利用低地址低12bit绕过ASLR-Partial Overwrite
用法
PIE开启时,一个32地址的高20位被随机化,低12bit不变。
改写低12bit绕过PIE,不仅在栈溢出使用,各种利用都经常使用。
eg:
return address=0x???abc
system(“/bin/sh”)=0x???def
overwrite abc by def, we can prompt a shell
了解partial overwrite
HCTF 2016 fheap(基于堆溢出)
绕过stack canary
以上所有套路,遇到stack canary均无效
不覆盖stack canary,只覆盖stack canary前的局部变量、指针: 几乎不行,编译器会根据占用内存大小从小到大排列变量;某些极限情况可以,一般都是精心构造的
** leak canary: printf泄露,canary一般从00开始
overwrite canary: canary在TLS, TLS地址被随机化
溢出位数不够怎么办:覆盖ebp、partial overwrite
用法
-可以覆盖Func2的ebp,会影响到Func1的esp,进而影响func1的ip
1 | Func1: |
XMAN 2016 广外女生-pwn
Codegate CTF Finals 2015,chess