Day1 - Patch

在国赛半决赛中出现过的要求,就是修补漏洞,但是不能对原文件改动太大,不然过不了check。然后昨天看到今年国赛的决赛赛制,是awd。似乎是一队维护>=10个gamebox额,第一次打awd,听起来想放弃23333不如删掉flag文件算了,或者关机orz还是学学吧2333

IDA

对于缓冲区溢出的漏洞,可以使用IDA。啊,这个魅力无处安放的女人。

比如缓冲区大小比可读入的字节小,这时候就可以直接使用IDA,在对应的汇编指令处修改读入的字节数。然后应用到原文件中,这样改动不大也能完成修补,就很简便。

[此处应有例子]

LIEF

一个开源的跨平台库,可以解析、修改和抽象ELF、PE和MachO格式

安装

1
2
pip install setuptools --upgrade
pip install lief

使用LIEF增加段

源代码(64位)

1
2
3
4
5
6
7
8
9
10
//vuln.c
#include <stdio.h>
#include <stdlib.h>

int main()
{
printf("/bin/sh");
puts("a test");
return 0;
}

目的是将printf修改成自己的函数

首先编写自己的函数

使用gcc -Os -nostdlib -nodefaultlibs -fPIC -Wl,-shared func.c -o hook编译

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//func.c
__asm(
"mov $0x0, %rdx\n"
"mov $0x0, %rsi\n"
"mov $0x3b,%rax\n"
"syscall\n"
);
}

void my_printf(char *a)
{
asm(
"mov %rdi,%rsi\n"
"mov $0,%rdi\n"
"mov $0x20,%rdx\n"
"mov $0x1,%rax\n"
"syscall\n"
);
}

方式一,修改got表

然后使用LIEF注入到文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python3
#-*- coding:utf-8 -*-

import lief

binary = lief.parse('./vuln')
hook = lief.parse('./hook')

segment_added = binary.add(hook.segments[0])

my_printf = hook.get_symbol('myprintf')
my_printf_addr = segment_added.virtual_address + my_printf.value

binary.patch_pltgot('printf', my_printf_addr)
binary.write('vunl.patd')

然后执行注入后的程序

1.png

但是两个文件大小相差很大。。。

2.png

方式二,修改指定位置的call函数

使用以下脚本可以修改指定位置的call函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/env python3
#-*- coding:utf-8 -*-

import lief
from pwn import *

binary = lief.parse('./vuln')
hook = lief.parse('./hook')

segment_added = binary.add(hook.segments[0])

my_printf = hook.get_symbol('myprintf')
my_printf_addr = segment_added.virtual_address + my_printf.value

#binary.patch_pltgot('printf', my_printf_addr)

def patch_call(file, sour, dist, arch = "amd64"):
print(hex(dist))
length = p32((dist - (sour + 5 )) & 0xffffffff)
order = b'\xe8'+length
print(disasm(order,arch=arch))
file.patch_address(sour ,[i for i in order])

tar_addr = 0x400574
patch_call(binary,tar_addr,my_printf_addr)

binary.write('vuln.patched')

3.png

修改.eh_frame段

这个段本身有可执行权限,而且本身作用不大(貌似跟处理异常相关)。这样可以将代码写在这个部分,然后程序变化也不会很大。

就可以直接将hook函数中的代码写到eh_frame段中去,然后修改call的跳转,完成patch

1
2
3
4
5
6
7
8
bin_frame = binary.get_section('.eh_frame')
hook_text = hook.get_section('.text')
bin_frame.content = hook_text.content

disaddr = bin_frame.virtual_address
taraddr = 0x400574

patch_call(binary, taraddr, disaddr)

这样就能直接跳转过来了

参考链接

P4nda

e3pem