栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

HUST网络攻防实践|5

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

HUST网络攻防实践|5

文章目录
    • 实验要求
    • 实验过程
      • 1. 编写新的printf函数
      • 2. 编写使用LIEF的Python脚本
      • 3. 将`getshell`的`.eh_frame`节设置为可执行
      • 4. 打补丁并运行打补丁后的程序
      • 5. 保证修改前后程序大小不变

实验要求

将printf函数改成新的newprintf函数,要getshell,并执行以下指令:

whoami
echo "学号" > num.txt
cat num.txt
exit

其中/bin/sh字符串就是getshell中printf的参数,因此这个可以直接使用。

实验过程

我采取的实验原理:将补丁程序的.text复制到目标程序的.eh_frame,然后修改目标程序的函数跳转地址,使漏洞程序跳转到.eh_frame来执行补丁代码。

1. 编写新的printf函数

我用的内联汇编。内联汇编使用的语法是AT&T。与平时写的Intel汇编不同。对于内联汇编的编写,我参考了这篇简书:GCC内联汇编基础 - 简书 (jianshu.com)。
再次感谢博主详细细致的讲解!

编写的hook.c代码如下:

void myprintf(char *a, int b) {
  int tmp;
  asm(
    "mov %1,%%rdin"
    :"=r"(tmp)
    :"r"(a)
    :"%rdi"
  );
  asm(
    "mov $0,%rsin"
    "mov $0,%rdxn"
    "mov $59,%raxn"
    "syscalln"
  );
}

主要含义是,构造execve(a,0,0),其中a是原来的printf的参数/bin/sh。execve在64位系统中对应系统调用号59。

将上述代码编译成静态链接库:

gcc -c hook.c -o hook
2. 编写使用LIEF的Python脚本

首先安装依赖:

pip install lief -y
pip install pwn -y

下载python2的lief时,总是报错。上lief官网上看了一下,最新版lief对python2不支持了。所以使用了python3环境。

如果用python2就直接抄指导书脚本。

脚本的思路与指导书上的是一致的:读入并解析getshell、hook文件,将hook的.text节复制到getshell的.eh_frame节,并将call _printf语句修改成call .eh_frame的起始地址。最后,将修改后的可执行文件写入getshell.patched中。

只是由于python版本问题,有3个需要注意修改的地方:

  1. python3的print输出是需要加括号的;
  2. python3中区分bytes 和string这两个数据类型,而在python2中混用,因此在python3中字节型字符串前需要添加b,才能与p32转换结果进行拼接。
  3. ord()这个函数接受的类型是一个长度为1的字符串,当for...in...遍历bytes类型时,得到的已经是int类型的数据,在python2中有必要调用ord,而在python3中则可以不调用它了。

具体脚本lief_test.py如下:

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, [i for i in order])

binary = lief.parse("./getshell")
hook = lief.parse('./hook')

# write hook 's .text content to binary's .eh_frame content
sec_ehrame = binary.get_section( '.eh_frame')
print(sec_ehrame.content)
sec_text = hook.get_section('.text')
print(sec_text.content)
sec_ehrame.content = sec_text.content
print(binary.get_section('.eh_frame').content)

# hook target call
dstaddr = sec_ehrame.virtual_address
srcaddr = 0x401149

patch_call(binary,srcaddr,dstaddr)

binary.write('getshell.patched')
3. 将getshell的.eh_frame节设置为可执行

直接修改.eh_frame节并跳转执行,会报出如下段错误:

改权限:段错误|修改ELF不可执行段权限(010编辑器)。

就行。

4. 打补丁并运行打补丁后的程序

编译补丁程序、打补丁、运行打了补丁的程序:

gcc -c hook.c -o hook
python3 lief_test.py
./getshell.patched

最后,验证是否成功获取shell。

输入:

whoami
echo "学号" > num.txt
cat num.txt
exit

可以看到能够成功地获取shell。

5. 保证修改前后程序大小不变

与同学讨论后,发现程序大小发生非常大的变化,主要是由于LIEF这个库的局限性。这个补丁真的非常简单,所以我决定直接用IDA Pro来打补丁,保证修改前后程序大小不变。(不知道行不行,但我确实不知道别的做法)

和前一个作业overflow一样的原理,具体看这篇HUST网络攻防实践|5_二进制文件补丁技术|实验一 overflow。

我写得比较草率,有学长写的更好的,搜一下就搜到了:
[网安实践III] 实验5.补丁

将call _printf改成jmp 0x402058,也就是跳到.eh_frame的开始位置。再向.eh_frame写入补丁代码,补丁代码最后跳回原来的执行流:

mov rsi,0
mov rdx,0
mov rax,59
syscall
jmp 0x40114E

再将原程序的.eh_frame所在段改成可执行即可。
运行的结果如下,可以看到,既getshell成功,又没有改变文件大小。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/947323.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号