`
hgfghww6
  • 浏览: 42095 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

格式化字符串攻击原理及示例

 
阅读更多

  一、类printf函数簇实现原理
  类printf函数的最大的特点就是,在函数定义的时候无法知道函数实参的数目和类型。
  对于这种情况,可以使用省略号指定参数表。
  带有省略号的函数定义中,参数表分为两部分,前半部分是确定个数、确定类型的参数,第二部分就是省略号,代表数目和类型都不确定的参数表,省略号参数表中参数的个数和参数的类型是事先的约定计算出来的,每个实参的地址(指针)是根据确定参数表中最后一个实参的地址算出来的。
  这里涉及到函数调用时的栈操作。函数栈的栈底是高地址,栈顶是底地址。在函数调用
  时函数实参是从最后一个参数(最右边的参数)到第一个参数(最左边的参数)依次被压入栈顶方向。也就是说函数调用时,函数实参的地址是相连的,并且从左到右地址是依次增加的。如: 在上面的例子中,void fun(int a, ...)函数约定第一个确定参数表示省略号参数表中参数的个数,省略号参数表中的参数全都是int 类型的,这样fun函数就可以正常工作了。
  类printf函数簇的工作原理和fun函数是一样的,只不过更为复杂和精巧。
  如printf的函数形式为 int printf(const char *fmt, …)。
  由于printf函数实现的功能比较复杂,我们来看一个我们自己实现的myprintf函数,改函数不涉及低层系统io操作。 #include   
  #include      
  void myprintf(char* fmt, ...) //一个简单的类似于printf的实现,//参数必须都是int 类型  
  {  
  char* pArg=NULL; //等价于printf原始实现的va_list  
  char c;  
  pArg = (char*) &fmt; //注意不要写成p = fmt !!因为这里要对//参数取址,而不是取值  
  pArg += sizeof(fmt); //等价于原来的va_start  
  do       {  
  c =*fmt;  
  if (c != '%')  
  {  
  putchar(c); //照原样输出字符  
  }  
  else  
  {  
  //按格式字符输出数据  
  switch(*++fmt)  
  {  
  case 'd':  
  printf("%d",*((int*)pArg));  
  break;  
  case 'x':  
  printf("%#x",*((int*)pArg));  
  break;  
  default:  
  break;  
  }  
  pArg += sizeof(int); //等价于原来的va_arg  
  }  
  ++fmt;  
  }while (*fmt != '\0');  
  pArg = NULL; //等价于va_end  
  return;   }     
  int main(int argc, char* argv[])  
  {  
  int i = 1;  
  int j = 2;  
  myprintf("the first test:i=%d\n",i,j);  
  myprintf("the secend test:i=%d; %x;j=%d;\n",i,0xabcd,j);   
  return 0;   }  
  myprintf函数中也有类似的约定,确定参数表中最后一个参数是一个const char* 类型的字符串,在这个字符串中出现"%d"和"%x"次数的和就是省略号参数表中参数的个数,省略号参数表中的参数类型也都是int类型。
  同样的,实际的printf函数也有这样的约定:确定参数表中最后一个参数是一个const char* 类型的字符串,省略号参数表中参数个数就是这个字符串中出现的"%d","%x","%s"…次数的和,省略号参数表中参数的类型也是由"%d","%x","%s"……等格式化字符来指示的。
  因此,类printf函数中省略号参数表中参数的个数和类型都是由类printf函数中的那个格式化字符串来决定的。
  二、格式化字符串攻击原理
  因为类printf函数中省略号参数表中参数的个数和类型都是由类printf函数中的那个格式化字符串来决定的,所以攻击者可以利用编程者的疏忽或漏洞,巧妙构造格式化字符串,达到攻击目的。
  如果一个程序员的任务是:打印输出一个字符串或者把这个串拷贝到某缓冲区内。他可以写出如下的代码:printf("%s", str);但是为了节约时间和提高效率,并在源码中少输入6个字节,他会这样写:printf(str);
  为什么程序员写的是错误的呢?他传入了一个他想要逐字打印的字符串。实际上该字符串被printf函数解释为一个格式化字符(formatstring),printf就会根据该字符串来决定printf函数中省略号参数表中参数的格式和类型,如果这个程序员想要打印的字符串中刚好有"%d","%x"之类的格式化字符,那么一个变量的参数值就从堆栈中取出。
  比如: 当./a.out "hello world"时一切正常,但是当./a.out "%x"时,就会有莫名其妙的数字被打印出来了。
  很明显,攻击者至少可以通过打印出堆栈中的这些值来偷看程序的内存。但是有些事情就不那么明显了,这个简单的错误允许向运行中程序的内存里写入任意值。
  printf有一个比较另类的用法:%n,当在格式化字符串中碰到"%n"的时候,在%n域之前输出的字符个数会保存到下一个参数里。例如,为了获取在两个格式化的数字之间空间的偏量: 输出4("235 "的长度)
  %n格式返回应该被输出的字符数目,而不是实际输出的字符数目。当把一个字符串格式化输出到一个定长缓冲区内时,输出字符串可能被截短。不考虑截短的影响,%n格式表示如果不被截短的偏量值(输出字符数目)。为了说明这一点,下面的代码会输出100而不是20: 而%n和%d,%x,%s的显著的不同就是%n是会改变变量的值的,这也就是格式化字符串攻击的爆破点。
  三、一个实际的例子
  下面这个例子至少可以X86的Redhat和arch linux下面进行演示。 #include   
  #include   
  #include      
  char daddr[16];  
  int main(int argc, char **argv)  
  {  
  char buf[100];  
  int x;  
  x = 1;  
  memset(daddr,'\0',16);  
  printf("before format string x is %d/%#x (@ %p)\n", x, x, &x);  
  strncpy(daddr,"PPPPPPP%n",9);         
  snprintf(buf,sizeof(buf),daddr);   //实施格式化字符串攻击  
  buf[sizeof(buf) - 1] = 0;  
  printf("after format string x is %d/%#x (@ %p)\n", x, x, &x);  
  return 0;   }  
  运行的结果是:x被成功的改成了7。
  上面的例子利用了linux函数调用时的内存残像,来实现格式化字符串攻击的。(参考的经典文章是用猜地址的方法来实现的,猜的一头雾水)
  这里我们来分析一下main函数中的堆栈变化情况:
  
  如上图所示,在调用snprintf函数之前,首先调用了printf函数,printf的函数第四个参数是&x,这样在main函数的堆栈内存中留下了&x的内存残像。当调用snprintf时,系统本来只给snprintf准备了3个参数,但是由于格式化字符串攻击,使得snprinf认为应该有四个参数传给它,这样snprintf就私自把&x的内存残像作为第4个参数读走了,而snprintf所谓的第4个参数对应的"%n",于是snprintf就成功的修改了变量x的值。
  而在实际网络环境中可利用的格式化字符串攻击也是很多的。下图就是一个实际网络攻击的截图。
  
  http://blog.csdn.net/sealyao/archive/2010/10/23/59 61330.aspx
分享到:
评论

相关推荐

    Windows 平台下的堆溢出、格式化字符串漏洞利用技术

    格式化字符串漏洞通常发生在程序使用格式化字符串功能来输出数据的时候,如果程序没有正确地验证用户的输入,那么攻击者就可以通过特定的格式化字符串来控制程序的输出行为,甚至直接修改程序的内存。 - **格式化...

    Windows格式化字符串漏洞利用[汇编].pdf

    本文旨在深入探讨格式化字符串漏洞的基本概念、利用原理以及具体的实践步骤,帮助读者更好地理解和防御此类漏洞。 #### 二、格式化字符串漏洞概述 ##### 2.1 定义 格式化字符串漏洞发生于程序中使用如`printf`等...

    ACCESS加密后的连接字符串

    在ACCESS中,连接字符串是一种用于指定与数据库建立连接所需参数的格式化文本。这些参数包括数据库的位置、使用的提供程序(Provider)、安全设置等。正确的连接字符串对于应用程序能够成功访问和操作数据库至关重要...

    使用MD5或者SHA算法对字符串加密

    根据提供的文件信息,本文将详细解析使用MD5与SHA算法对字符串进行加密的相关知识点,包括这些算法的基本原理、应用场景以及代码实现方式。 ### MD5与SHA算法简介 #### MD5算法 MD5(Message-Digest Algorithm 5)...

    QT C++ AES字符串加密解密类库,引入即可使用

    4. 错误处理和边界检查:确保输入的字符串长度和格式符合要求,防止空指针、内存溢出等问题。 5. 示例代码:为了方便用户快速上手,类库通常会提供示例代码,展示如何创建密钥、设置IV、调用加密和解密函数,以及...

    JSTL 字符串处理函数

    对字符串进行XML转义,防止XSS攻击。例如: ```jsp ${fn:escapeXml('<script>alert("Hello");</script>')} <!-- 输出:<script>alert("Hello");</script> --> ``` 12. **fn:unescapeXml*...

    js校验特殊字符

    特殊字符过滤就是创建一个包含不允许的字符的正则表达式,然后使用该正则表达式去测试输入的字符串,看是否包含这些特殊字符。 2. **正则表达式转义** 在正则表达式中,某些字符具有特殊的含义,例如`.`、`[]`、`{...

    Perl-Format-String-Bugs.zip_Bugs

    如果格式字符串允许用户输入,而没有适当验证,攻击者可以插入非标准的转换说明符,例如`%x`(十六进制整数)或`%n`(用于写入格式化字符串已使用的字符数)。`%n`是一个特别危险的指示符,因为它允许攻击者获取或...

    js eval函数使用,js对象和字符串互转实例

    在本文中,我们将深入探讨`eval()`的工作原理,以及如何在JavaScript中进行对象与字符串之间的转换。 首先,让我们看看`eval()`的基本用法。`eval()`接收一个字符串参数,这个字符串被当作JavaScript代码执行。例如...

    AES.rar_AES解密_aes string_aes 加密 解密_c++ AES_字符串 加密

    为了使用这些字符串,我们需要将它们转换为二进制格式,这通常通过字节编码(如ASCII或UTF-8)完成。然后,这些二进制密钥会用于加密或解密128位的数据块。 "www.pudn.com.txt"可能是提供额外信息或示例用法的文本...

    仿淘宝,拍拍等查询关键词字符串编码算法实现(PHP版)

    6. **组合**:将处理后的关键词以特定格式组合成一个字符串,比如用特定分隔符连接。 以下是一个简单的`StringUtil.php`实现示例,仅包含预处理和URL编码部分: ```php class StringUtil { public static ...

    SQL注入攻击原理及在数据库安全中的应用.pdf

    在上述示例中,一个典型的登录页面使用了GET方法,将用户提交的用户名和密码信息拼接到查询字符串中。如果攻击者在用户名输入框中填入“sysop’ and 1=1 --”,那么在后端执行的SQL语句将会被修改为: ```sql ...

    JSTL示例代码,x,xml,sql,fmt

    `<x:parse>`可以将XML字符串解析为DOM对象,`<x:out>`用于安全地输出XML内容,防止XSS攻击,`<x:transform>`则可以对XML进行XSLT转换。这些标签使得JSP可以直接处理XML,无需额外的XML处理库。 3. **SQL标签库(sql...

    gson转义字符

    例如,我们需要将一个包含特殊字符的列表转换成JSON字符串。假设有一个简单的例子: ```java List<String> list = new ArrayList(); list.add("ƷƷ&"); list.add("Ʒ&"); ``` 在这个例子中,`"ƷƷ&"` 和 `"Ʒ&"`...

    buffer overflow

    3. **格式化字符串溢出(Format String Overflow):** 特殊类型的缓冲区溢出,利用格式化字符串漏洞进行攻击。 4. **整型溢出(Integer Overflow):** 当整数运算结果超出其表示范围时发生。 #### 三、攻击原理及案例...

    黑客之道:漏洞发掘的艺术

    格式化字符串漏洞是指程序在处理输入输出时,对格式化字符串的控制不严格,攻击者通过构造特定的格式化字符串,有可能读取或修改内存中的数据。Shellcode是一段用于控制程序执行流程的代码片段,通常用于漏洞利用...

    bufbomb,缓冲区溢出定义.pdf

    3. 格式化字符串漏洞攻击:攻击者可以通过格式化字符串漏洞攻击来溢出缓冲区,然后覆盖返回地址的值,控制程序的控制流。 四、缓冲区溢出的防御方法 缓冲区溢出的防御方法有很多种,常见的有: 1. 栈保护机制:...

    XStream示例(含jar包)

    4. **XML 到对象**:使用 `fromXML()` 方法将 XML 字符串反序列化回 Java 对象。 ```java YourObject obj = (YourObject) xstream.fromXML(xml); ``` 5. **JSON 支持**:通过 Jettison 库,XStream 也支持 JSON ...

    SQL注入原理以及Spring Boot如何防止SQL注入(含详细示例代码)

    1. 参数化查询:使用预编译的SQL语句(如PreparedStatement),将用户输入作为参数传递,而不是直接拼接到SQL字符串中。这样可以防止恶意代码改变SQL语句的结构。 2. 使用存储过程:通过存储过程与数据库交互,减少...

Global site tag (gtag.js) - Google Analytics