近年来CTF攻防赛(AWD)趋向于攻防对等,即主办方会想办法让漏洞的修复变难,以此来增强比赛的趣味性(想象一下,如果漏洞修复很简单,大家上来一阵修复、通防,谁还能得分呢)。有时候,打补丁是如此的重要,以至于只要能打好补丁,就可以获取很好的成绩了。
让漏洞修复变难的办法很多,例如复杂的代码逻辑让漏洞发现时间变长、逐渐加强的checker等。复杂代码逻辑的作用是有限的,因为如果搞的太复杂,以至于在比赛时间内没人能写好exp,那题目就没有效果了。所以,变态的checker才是常用的解决方案。
为了对抗通防,目前的checker在静态阶段基本上都会进行hexdiff,例如要求打补丁之后的ELF和原始ELF相差不能超过100字节、补丁不能修改某些关键的寄存器等等。动态阶段的测试用例也会比较严格。因而,稳定可靠的二进制补丁还是要靠手工,以便于精准控制过checker。
提前了解以下几个基础知识,对打补丁很有帮助
Register
状态
含义
RAX
易失的
返回值寄存器
RCX
易失的
第一个整型参数
RDX
易失的
第二个整型参数
R8
易失的
第三个整型参数
R9
易失的
第四个整型参数
R10:R11
易失的
必须根据需要由调用方保留;在 syscall/sysret 指令中使用
R12:R15
非易失的
必须由被调用方保留
RDI
非易失的
必须由被调用方保留
RSI
非易失的
必须由被调用方保留
RBX
非易失的
必须由被调用方保留
RBP
非易失的
可用作帧指针;必须由被调用方保留
RSP
非易失的
堆栈指针
XMM0
易失的
第一个 FP 参数
XMM1
易失的
第二个 FP 参数
XMM2
易失的
第三个 FP 参数
XMM3
易失的
第四个 FP 参数
XMM4:XMM5
易失的
必须根据需要由调用方保留
XMM6:XMM15
非易失的
必须根据需要由被调用方保留
打补丁时要注意,如果需要使用寄存器的话,尽量使用易失寄存器,因为非易失寄存器可能在函数上层有汇编依赖于其值不变。
call xxx : push rip; jmp xxx;
leave: mov rsp,rbp; pop rbp;
ret: pop rip; jmp rip;
[比较]
cmp xx
ja jb :无符号判断
jg jl :有符号判断
jz jnz / je jne
jp jnp :偶判断
[移位]
SHL(Shift Left): 逻辑左移
SHR(Shift Right): 逻辑右移
SAL(Shift Arithmetic Left): 算术左移
SAR(Shift Arithmetic Right): 算术右移
[条件指令]
cmov[a/b/g/l/ae/be/ge/le] xxx, xxx
[strlen]
(to find the length of the string whose starting address is in EDI:)
sub ecx, ecx
ecx值即为strlen的值。
当我们需要插入汇编代码时,往往会使用到这个空闲段,跳进去执行插入代码再跳回来。
有时候我们仅仅需要修改、替换指令,多余的位置nop即可,有时候复杂的patch逻辑就需要插入代码来实现;这两种模式我们称为替换模式和插入模式。
IDA超好用的patch插件,我们只需要在里面写汇编,跳转偏移(机器码)之类的计算该插件会自动帮我们完成。
x64补丁写法:
printf前插入(加入%s参数)
push 0x00007325
printf后插入(栈平衡)
add rsp, 8
x86补丁写法:
762处替换为:
sub esp, 8
769处插入:
pop ecx;
注:如果plt中有puts,可以尝试用puts来修复,不过强checker下可能会校验不通过。
b60处插入:
mov ecx, 0x00007325;
f11处插入:
mov rcx, [rbp-0x20];
修复后效果:
有时候溢出代码异常复杂,只能试出offset和溢出缓冲区(利用FORWORD-2020 blacklist),这时候只能使用通用的patch方法,放大栈不一定彻底,加cookie更彻底,且可以当作通用栈溢出patch使用。
db8处替换为:
sub rsp, 0x48;
dbc处替换为:
lea rax, [rbp - 0x48];
dc0处插入:
mov rcx, 0x4a584e424a584e00;//cookie值可自定义
dcd处插入:
mov rcx, 0x4a584e424a584e00;
nop掉gets调用,下方插入read系统调用实现读取。
在1处插入指针非空的判断:
cmp rax, 0;
在2处插入指针置空逻辑:
mov eax, [rbp-4];
(houseoforange)
上述位置插入以下代码:
lea rax, [0x203068];
patch效果: