网络安全综合实践lab3 5

网络安全综合实践-补丁技术-韩兰胜老师

实验环境

  • IDA Pro 7.5
  • WSL Ubuntu 20.04

keypatch插件

从网上下载的IDA Pro 7.5里是已经装了keypatch插件的,但是在安装之后,我手贱点了idapyswitch.exe,然后把整个IDA Pro的Python环境设置成了自己电脑上装的Anaconda,于是keypatch插件不仅消失了,还完全没法正常运行。需要通过以下命令将python环境设置为IDA Pro安装目录下的python.exe

.\idapyswitch.exe --force-path "{IDA_ROOT}\IDA_Pro_v7.5_Portable\python38\python3.dll"

之后再打开IDA Pro就可以找到keypatch插件并可以正常使用了

作业1

行为分析

按照老师给的实验手册,测试验证确实有两个需要打补丁的点

  1. 输入10位字符串后,同时输出对boy和对girl的欢迎语
  2. 输入少于10位字符时,程序直接结束
  3. 输入超出长度后,程序出现段错误

image-20220523202608633

逆向分析

反汇编到C可以看到问题主要出在gets函数上

image-20220525085437235

补丁修改

修补逻辑漏洞

ctrl+alt+k将girl相关内容的语句设置为nop,效果如下

image-20220525090654814

修改后将内容同步到原文件

image-20220525091104126

在WSL里运行一下发现只输出一种

image-20220525091244388

修补栈溢出漏洞

按照指导书第三节、第四节内容,将gets函数修改为跳转到eh_frame段,在eh_frame段里将gets函数修改为只读10个字符的read系统调用,该操作对应汇编代码

mov edx, 0Ah
lea rsi, [rbp+s]
mov rdi, 0
syscall
jmp {原位置的下一条语句}

选定0x0875开始向后的一段位置填充代码,将call _gets修改为jmp 0x0875

image-20220525092134754

由于keypatch识别符号有点麻烦,所以这里将lea rsi, [rbp+s]指令留到main函数中修改,其他内容写入到eh_frame段

image-20220525092831864

在main中,将这里修改

image-20220525092958787

修改后执行,结果符合预期

image-20220525093056042

作业2

行为分析

直接运行getshell程序,结果如下

image-20220524213623067

逆向分析

反汇编看到想要利用的语句printf,需要将这里的"/bin/sh"执行

补丁修改

image-20220525093219873

仿照指导书第五节内容,选择将补丁写入到目标程序的eh_frame段的方式

C代码

由于需要将汇编插入eh_frame段,直接写汇编的话就和作业1一样一样了,所以这里选择在C里写汇编的方法

int qsyPrintf(char *a, int b) {
    asm("mov $0x3b, %rax\n"
        "syscall\n");
}

将其生成为机器指令

gcc qsyPrintf.c -o qsyPrintf.o

Python代码

修改python代码如下(原Python代码是Python2的,但是lief早在2020年停止了对Python2的支持)

(另外由于Python2与Python3对bytes和str的区别,中间做了一些小改动)

import lief
from pwn import *


def patch_call(file, srcaddr, dstaddr, arch="amd64"):
    print(hex(dstaddr))
    length = p32((dstaddr - (srcaddr + 5)) & 0xffffffff)
    order = b'\xe8' + length
    print((disasm(order, arch=arch)))
    file.patch_address(srcaddr, list(order))


binary = lief.parse("./getshell")
hook = lief.parse("./qsyPrintf.o")

sec_ehframe = binary.get_section('.eh_frame')
print(sec_ehframe.content)

sec_text = hook.get_section('.text')
print(sec_text.content)

sec_ehframe.content = sec_text.content
print(binary.get_section('.eh_frame').content)

dstaddr = sec_ehframe.virtual_address
srcaddr = 0x401149

patch_call(binary, srcaddr, dstaddr)

binary.write('getshell.patched')

执行结果

image-20220525102506739

修改段属性

但是这样操作后,执行生成的getshell.patched就会报错

image-20220525102611745

需要用010Editor修改段属性,需要使用010Editor的ELF模板

image-20220525103214560

至于要修改哪儿呢,还得回到linux用readelf查看一下

image-20220525103432711

可以看到.eh_frame段是保存在了04节,对应虚拟地址起始地址0x402000

于是修改这部分的p_flags为可执行

image-20220525103620760

修改后就可以执行了

image-20220525103954114

参考

AWD pwn备忘 | 把不懂的记下来,就懂了 (ohmygodlin.github.io)