PartialOverwrite

  • 只更改func@got低位两个字节的值,可以替换为前后0x0000~0xffff范围内的地址
  • 修改的两个字节中,ASLR只影响高4位(低12位不受ASLR影响)
  • 也就是说,即使不泄漏地址,也有1/16的概率调用到想要的地址
  • 重写stack上返回地址的低位三个字节也是可能的

CAROP(potetisensei和自己命名)

  • 意思是Calc&AdjustROP,在func@got中,修正必要的差异,更改为想要的函数
  • 首先,需要泄漏一些地址,确定libc,确定函数偏移
  • 只需要pop ecx; pop ebx; add [ecx], ebx; call [ecx]; 这些ROP
  • 不需要泄漏内存就可能调用system,可以用更少的ROP
  • 31c3 CTF – pwn30 cairo

vtable攻略(no-NX时__libc_start_main的Wrapping)

  • 只能任意更改vptr,可以指定成员函数的第一个参数字符串的情况
  • 使vptr指向__libc_start_main@got之前一点,并在第一个参数字符串中写入shellcode
  • 即使无法指定函数自身的地址,__libc_start_main也会作为Wrapper执行
  • SECUINSIDE 2014 final – pwn300 notes

Thiscall攻略

  • 可以控制指向object的指针,像thiscall一样,将第一个参数设置为自身的情况
  • 预先申请大量内存后执行堆喷射,生成的类似地址字符串0xXX006873指向object(“\x73\x68\x00\xXX” == “sh¥0”)
  • 在上面伪造的object指针中,将*object->vptr[i]设置为system()
  • 如果调用该指针函数,会变成*object@0xXX006873->vptr[i]("sh"),可以使用thiscall
  • SECUINSIDE 2014 final – pwn300 numbers

argv[0]泄漏内存

  • canary检查失败异常结束时,stderr会显示错误信息
  • 错误信息包括文件名,也就是argv[0],它是栈上的指针
  • 如果在canary检查前覆盖了argv[0],将显示内存区域泄漏内存
  • CodeGate 2015 – Pwnable400 beef_steak

与网络环境相关的问题

  • pwn问题中,由于题目服务器与选手之间距离造成的问题
  • 在发送1000字节或者更多数据造成溢出的情况下,数据传输失败并且溢出失败
  • read()和recv()以非阻塞模式运行
  • 在这种情况下,可以通过其他pwn问题获取的sell开始对该题目进行exploit
  • 因为题目环境基本是在同一数据中心,相互之间通信速度非常快
  • 即使是巨大的数据,一般也不会产生中断,可以轻松溢出
  • CSAW CTF 2013 – Exploitation2, 30c3 CTF – PWN400 DOGE2

避免将垃圾传递给system()

  • 如果执行system(垃圾+”;sh”),前半部分的垃圾字符串会造成执行错误,后半部分的字符串会调用shell
  • 通过user_input覆盖func@got后,可以立即调用func(user_input,…)等
  • 但是,x86中存在限制条件,地址中不能存在NULL
  • Hack.lu 2014 – Exploit400 oreo

服务器上有帮助的文件

  • 在/proc/self/stat中,有ESP和EIP的值。能够通过这个文件帮助获取特定的栈位置
  • 在/proc/self/maps中,有进程自身的内存映射,ASLR环境下非常有帮助
  • 某些情况下,可以通过进程的完整路径中获取到主目录的名称
  • Hack.lu2014–Exploit500Mario,30c3CTF2013PWN400-DOGE2

dmesg命令

  • 写了进程死因和EIP,可以用来判断进程是否执行了0xCC(=int3命令)
  • CodeGate2015–Pwnable1000icbm(stage2)

I/O缓冲区的ROP

  • scanf或者printf之类的,有一个映射区域作为I/O缓冲区(匿名映射的一部分)
  • 可以利用I/O缓冲区进行stack pivot,相对自由的进行ROP
  • SECUINSIDE 2013 – Pwnable750 Pwn me!!

间接引用FSB

  • 在FSB可以多次使用的情况下有效。通常使用基于堆的FSB
  • 在返回__libc_start_main附近,总有一个,栈上的地址->栈上的地址->栈上的值,这样的引用
  • 通过第一个引用FSB,修改第二个地址的低位两个字节
  • 通过第二个引用FSB,在栈上写入两个字节任意值
  • 通过第一个引用FSB,修改第二个地址末尾两个字节增加的值
  • 通过第二个引用FSB,在栈上写入两个字节任意值
  • 通过这样重复,可以在栈上写入任意N个字节
  • FSB结合栈上生成的值作为地址,可以将任意值写入任意内存
  • Ghost in the shellcode 2015 Teaser – Pwn#1 Citadel, 31c3 CTF – pwn30 pong

environ技术

  • 在GOT按以下顺序多次泄漏,获取stack地址
  • func@got -> libc_base -> _dl_runtime_resolve@libc_got -> ld_base -> environ@ld_bss -> stack
  • 即使对于基于堆的漏洞,也可以通过重复的任意内存泄漏来确定stack地址

DWARF伪造

  • C++的异常处理是写在一个叫DWARF的数据结构中的,并且是从libgcc的bss区域的handler引用
  • 通过伪造整个引用的DWARF,可以从异常处理返回后跳到任意位置
  • 使用名叫katana的一个工具,可以生成手动更改的DWARF字符串
  • CodeGate 2013 – Pwnable800 membership, Hack.lu 2014 – Exploit500 breakout

通过retf替换cs寄存器

  • 在x64机器上运行x86二进制文件时有效
  • 如果通过retf将cs寄存器从0x23修改为0x33,就可以将其更改为解释x64指令的模式
  • 在某些情况下,可以绕过系统调用限制
  • CodeGate 2015 – Pwnable800 rodent (stage2)