B站 XMCVE Pwn入门课程学习笔记(6)

先介绍一个很好用的yige wangzhan 贝壳风暴 Shell-Storm 更难一点的题目会用到

不光有大佬的博客,他还搭建了两个在线网站

一个是汇编反汇编器,还有一个是shellcode database,包含了各种各样的架构特性

在linux中一般攻击的架构是X86-64,X86

ret2libc2:

checksec一下

拖入ida中,这一题跟上一题很相似,可以先试着做一下

这题难度肯定比上一题有提高,没有bin/sh

可以先试着把第一题的攻击脚本放到第二题运行,由于没有bin/sh,就行不通,那么需要写一个bin/sh,

对于ROP,第一步将bin/sh写入程序中,第二步继续控制程序执行流,到system传进去,并且把刚刚写的地址传进去

回到main函数,需通过ROP写,我们需要思考怎样通过程序执行流读入我们自定义的字符串bin/sh,写到哪,要写到确定可写的区域,这样就会想到bss段,在buf2这个位置

接下来就是怎样通过ROP将bin/sh读入程序的buf2中呢,类似于ROP调用system函数

这个漏洞是gets触发,就ROP到gets函数,在gets函数读取bin并放入buf2,继续ROP控制执行流到system plt即可

构造payload:
第一种方法:

如图,填写一堆垃圾数据,覆盖到返回地址,控制程序执行的第一条指令,先是get plt,参数是向上数两个位置填写buf2,get完了就是system plt,参数向上数两个字长,填写bin/sh字符串,把地址当作参数传给system能执行system bin/sh

算出地址间的距离,填入数据,找其对应的地址,ida、pwntools、gdb都可以

以下就是构造payload的内容

payload发过去之后会执行get函数,需要我们构造一些输入,把bin/sh发送给他,才能执行接下来的函数

新elf命令,获取buf2地址

下面是攻击本地,还要有get,system地址,构造垃圾数据,进行远程交互,获得shell

命令sendline是send后直接加一个换行符,send是不加换行符,get函数在读取用户输入时到换行符就结束,而read是都读取包括换行符

攻击远程

第二种方法:

上面是调用两个和两个以下的,而这个是通用的。

在ROP过程中,每调用一次库函数后,就要使用特殊的gadget平衡栈,这里用pop ret

这是一个动态链接的程序,缺乏gadget,pop ret只要一个,满足弹出栈中数据,ret即可。以下是很有限的,但是能获得pop ret的,用来平衡栈

栈,从下往上,从低地址指向高地址

思路就是用完就扔,向buf2里读取bin/sh,向buf2中get字符串,而用完后,buf2还留在这里,需要清理,以便后面的进程,所以当get使用完buf2这个参数后,把栈清理掉

首先gets这个函数本身执行的时候主函数就有个ret来将它pop到eip,相当于已经清理了gets函数。gets函数下面的空白显然会由gets函数执行ret来清理。

我们可以用pop|ret来清理。pop ebp有点不合适,ebp还有其他的用处(虽然已经被覆盖了),我们用pop ebx这样的通用寄存器来清理栈吧。

进入下一部分,system plt,同以上步骤一样

ret2libc3:

checksec,看着好像跟上一题一样,但是增加了更多保护措施

ida反编译

我的天,这看着就不那么妙了,它还有另一个可执行文件libc

看代码,输入了一些东西,如你想从内存中知道些什么吗。fflush函数是清理缓冲区,这里没有set buf函数。就是把上面一系列输入放入stout缓冲区里,使用ffliush函数将其输出到屏幕上,接下来read 0xA 到buf(A后面u表示无符号)。strtol将字符串转化为long型长整型,第一个参数是0,表示标准输入,标准输出是1,标准错误是2

**补充:**ida里一些快捷转换,右键,第一个转为十进制,第二个事八进制,第三个是字符,用R将字符转化为字符串,10对应换行符

u是unsigned int,后面会讲到整数溢出漏洞,下图看着就是个数字,但是这是错误的

想看地址为12对应的值,输入的并不是1100,而是一个字符串

如果输入12,得到的并不是12对应整数的值,而是对应ASCLL码的值,而strtol就可以转

回到正题,继续向下看有个see_something函数,跟进,它接收了一个指针,把指针对应的内容按指针格式打印了出来

继续回到主函数看有个v8,为了便于分辨将其改为address,按n键可以改,还有不想看到DWORD按 / 删去,int 64是8字节的int

下面代码和上面相似,就有个自定义的输出内容

找漏洞思路:

找栈溢出漏洞的技巧,在输入内容的地方输超长垃圾数据,如果栈溢出,就会进行控制覆盖,程序就会崩溃。但是无效地址也会崩溃,所以要用有效地址

一大堆j造成栈溢出,在代码中寻找。从第二个read,寻找漏洞位置,可以画栈结构,src与ebp距离0x10E,大于0x100,并不是这里。

栈帧:

减的越多,离其越远,处于低地址位置。对于ida,写在最下方处于最高地址,从上到下逐渐增大

下图是main函数的栈帧中用来保存局部变量里的local viriable区域的数据分布,中间剩余的是src区域,0x100

找一下漏洞在哪,read没有溢出,继续向下看,puts,return肯定不会栈溢出,那么就在print_message

char后面与ebp相差0X38,dest起始值,将src地址里的内容复制给dest,src是0X100,dest是0X38,其实栈溢出漏洞就在这里

还原一下函数栈的工作过程(部分),将参数压栈,src的地址,看一下函数的汇编代码

第一行push ebp(main函数的)

关于这题的续解:

之前已经知道栈溢出就在strcpy src 和 dest,下一步就要找后门函数,在之前的checksec中,并没有text段时可读可写可执行的,所以shellcode也不行。接下来是systemcall思路,用ROPgadget,也不行

接下来就是libc了,但是并没有本来的bin/sh,需要自己处理。左边栏plt里没有system函数。这就是这道题麻烦了

之前libc中不知道这个地方的system地址,它是在libc的动态链接库,地址被随机化,我们是用plt的地址来代替。就像之前讲的一样,终点就是system libc。但是连plt表象地址都没有

我们只有把libc system的真正地址找到填进去。

plt是代码的填写者,got是代码的保存者

这道题并没有调用system,got表里没有,即使有也不行。got表填写的函数的真实地址第一次被调用之后才可以。got表里保存这个函数plt表象地址,泄露出来的就是elf自己保存的plt保存地址,而不是libc

断点打在第一个read

有一些填写libc里的,说明已经被执行了,可以利用这些地址获取libc里的地址。一般选用puts,因为它的使用次数比较高。输入要把十六进制转为十进制,注意ASLR是打开的,远程libc的地址是随机的,本地只能看出偏移量

那么这就要用到另一个文件找偏移量,根据put的真实地址,得到system的地址

用这道题实战一下:要分析两个elf文件,一个是libc3,一个是libc.so。接着获取puts地址,远程链接,接受数据并输入

得到一个值。

程序接收的是字符串,我们要发的是对应的ASCLL码,就会返回puts的值(注意地址随机化)

后三位是一样的。这里就是页(内存分配的最小单位)。大小是4KB。在虚拟内存中连续但在物理内存中不一定。 但是要页对齐

12个二进制位,12bit,0000 0000 0000,每四个可以转换为一个十六进制数。每1个bit有两种状态,12个就有2的12次方,也是能表示的地址数量,4KB

puts函数在偏移141的位置,puts末三位000 140

知道了puts函数的真实地址,以及静态分析libc函数puts函数和system函数的距离,就能得出system地址。得看libc system和system函数分别的偏移

libc system在puts的低地址位置

得到system函数的真实地址,接下来就是栈溢出,溢出的数据可以用来构造ROP链,整体形成payload。

不能用原来的地址,动态调试,把有效地址找出来。断点下在print_message

计算eax到ebp之间距离,看需要填入多少垃圾数据,接着从ebp构造ROP链,用gets将bin/sh读入到内存中,再system调用内存,进而获取shell。

还有一个重要的事情bin/sh要写到哪里。其实这道题虽然对应数据段没有sh,但是sh也能达到攻击效果。sh通过环境变量执行bin/sh,然后通过绝对地址再执行放在bin目录里的可执行程序。

即使sh段没有字符串,但是如图,例如fflush,是函数名,存在于程序中,是对应的ASCLL码的值,如果把sh截断传给bin/sh,就会向后读sh,0X0,最后就是system("sh") ,也能达到攻击效果。

只要能达到攻击效果,任何可以被我们利用的数据都可以使用的,甚至是函数名,像这题函数名字符串就可以为我们提供sh。

相关推荐
Asu52023 分钟前
链表反转中最常用的方法————三指针法
java·数据结构·学习·链表
牛奶咖啡1335 分钟前
学习设计模式《二十》——解释器模式
学习·设计模式·解释器模式·认识解释器模式·解释器模式的优缺点·何时使用解释器模式·解释器模式的示例
给老吕螺丝1 小时前
C 语言作用域与存储期深度解析:空间与时间的双重维度
c语言·开发语言·经验分享·笔记
dankokoko1 小时前
OPENGLPG第九版学习 - 纹理与帧缓存 part2
学习
墨雨听阁2 小时前
8.1IO进程线程——文件IO函数
学习
使一颗心免于哀伤2 小时前
《设计模式之禅》笔记摘录 - 12.适配器模式
笔记·设计模式
Chef_Chen2 小时前
从0开始学习R语言--Day64--决策树回归
学习·决策树·r语言
无望__wsk3 小时前
ospf笔记
服务器·网络·笔记
Aplis3 小时前
ETCD学习之路
数据库·学习·etcd
玖剹3 小时前
Linux文件系统:从内核到缓冲区的奥秘
linux·c语言·c++·笔记·ubuntu