Pwn_patch
Charmersix

此篇参考合天网安实验室的这篇文章

IDA安装keypatch插件

下载地址:https://github.com/keystone-engine/keypatch

1
2
pip install keystone-engine
pip install six

image-20230611133831017

keypatch.py文件复制到 IDA的plugins文件夹下,重启IDA

image-20230611135751846

安装成功

跳转指令

无符号跳转

汇编指令描述
JA无符号大于则跳转
JNA无符号不大于则跳转
JAE无符号大于等于则跳转(同JNB)
JNAE无符号不大于等于则跳转(同JB)
JB无符号小于则跳转
JNB无符号不小于则跳转
JBE无符号小于等于则跳转(同JNA)
JBNE无符号不小于等于则跳转(同JA)

有符号跳转

汇编指令描述
JG有符号大于则跳转
JNG有符号不大于则跳转
JGE有符号大于等于则跳转(同JNL)
JNGE有符号不大于等于则跳转(同JL)
JL有符号小于则跳转
JNL有符号不小于则跳转
JLE有符号小于等于则跳转(同JNG)
JNLE有符号不小于等于则跳转(同JG)

Patch-整数 溢出

img

scanflong int长整形读取输入到unsigned int变量v2中, 然后将v2强制转化为int再与int 48比较

但从scanf读入一个负数时, 最高位为1, 从unsigned int强制转换为int结果是负数, 必定比48小, 在后面read读入会造成栈溢出

方法

将第九行的if跳转汇编指令patch为无符号的跳转指令, 具体参考跳转指令表

使用keypatch进行修改

jle-->jbe

img

patch-栈溢出

对于栈溢出加固,x64 更容易一些,因为是使用寄存器传参,而x86 使用栈传参,需要用 nop 等保持加固前后的空间不变

x64

方法

100是第三个参数, 存储寄存器是rdx, 找到给rdx传参的汇编指令进行patch

使用ida默认修改插件修改(Edit-Patch Program-Change word), 也可以使用keypatch

0x64 是长度

0xBA 是操作符

img

1
0x64->0x20

img

x86

不需要对齐

img

找到压栈的指令, 修改压入的数值

img
  • 修改数值需要补上 0x
  • 这里修改前 size 为 2 ,修改后 size 也为 2 ,所以这题 patch 不需要用 nop 保持 size
需要对齐

img

找到压栈的指令, 修改压入的数值

img

直接修改0x20后, size 长度不对齐, 会引起栈空间变化, 需要用nop进行对齐

img

更方便快捷的方法是勾选NOPs padding until next instruction boundary进行自动填充

patch-格式化字符串

img

修改函数

printf改为puts, 将call的地址改为puts plt地址:

img

这个方法局限性在于: puts会在原字符串多加\n, 主办方check可能因此而不通过

修改printf参数

printf(format)修改为`printf(“%s”,format)

修改printf前面的传参指令:

img

1
2
mov edi, offset 0x400c01; 
mov esi,offset format;

img

patch-UAF

img

修改逻辑是劫持call指令跳转到.eh_frame段上写入的自定义汇编程序

先在.eh_frame段上写入代码, 首先是call free完成释放, 然后对chunk_list进行置零. 取chunk_list地址的汇编可以从call free前面抄过来

1
2
3
4
5
6
7
8
9
10
11
12
call 0x900;           #调用free函数(plt地址)


mov eax, [rbp-0xc]; #取出下标值
cdqe;
lea rdx, ds:0[rax*8];
lea rax, qword ptr [heap];


mov r8,0; #段地址不能直接赋予立即数
mov [rdx+rax],r8;
jmp 0xD56; #跳回原来的地址

img

patch-if范围

假设需要将图上第二个if放到if结构内, 修改跳转的地址即可:

img

原始跳转代码:

img

1
js 0x40081C --> js 0x400845

img

patch-更换危险函数

类似与 uaf 一样写汇编实现功能调用,将危险函数替换为其他函数,如果程序中没有目标函数,就通过系统调用方式调用。

将 gets 替换为 read 输入

img

.eh_frame写入汇编,将 rdi 的写入地址移动到 rsi ,把其他寄存器也传参之后进行系统调用:

img

img

img

pwn通防小工具

注意: 这里由于编译方式不同的原因, 作者写的工具目前仅适配Ubuntu16;18;20

基于pwntools和seccomp-tools的awd pwn通防小工具, 原创在这

GitHub地址: https://github.com/TTY-flag/evilPatcher

环境需要

运行需要依赖seccomps-tools和pwntools

pwntools安装

这里要在python2下安装,因为工具是基于python2的

1
2
3
4
5
sudo apt install python2
sudo apt install python2
curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py
sudo python2 get-pip.py
sudo python2 -m pip install pwntools

seccomps-tools安装

1
2
3
sudo gem install seccomp-tools
#如果在编译时失败,请尝试:
sudo apt install gcc ruby-dev

test

结束后我们可以随便找一个pwn题试一下

1
2
python2 exp1.py
cat flag.txt

image-20230621190055118

然后

1
python2 evilPatcher.py pwn1 sandboxs/mini_sandbox.asm 1

试一下通防脚本

image-20230621190247222

生成后的pwn1.patch修改为pwn1, 再运行一下exp

1
2
python2 exp1.py
cat flag.txt

成功!

image-20230621190431656

 Comments