其他类型的软件漏洞


格式化串漏洞

这本书里面对格式化字符串漏洞只是做了简要介绍,虽然是介绍的windows上的格式化串漏洞,但是终究还是与linux上类似的。这种漏洞的产生源自数据输出函数中对输出格式解析的缺陷,常见的能够引起这些漏洞的函数有:

int printf( const char* format [, argument]... );
int wprintf( const wchar_t* format [, argument]... );
int fprintf( FILE* stream, const char* format [, argument ]...);
int fwprintf( FILE* stream, const wchar_t* format [, argument ]...);
int sprintf( char *buffer, const char *format [, argument] ... );
int swprintf( wchar_t *buffer, const wchar_t *format[, argument] ... );
int vprintf( const char *format, va_list argptr );
int vwprintf( const wchar_t *format, va_list argptr );
int vfprintf( FILE *stream, const char *format, va_list argptr );
int vfwprintf( FILE *stream, const wchar_t *format, va_list argptr );
int vsprintf( char *buffer, const char *format, va_list argptr );
int vswprintf( wchar_t *buffer, const wchar_t *format, va_list argptr );

所以格式化串漏洞的方法其实也是可以通过简单的静态扫描,一般就可以比较容易的发现这类漏洞。

printf函数的格式化串漏洞

对于printf函数,它的参数分为两部分,一是格式控制符,二是输出的数据列表。先看书中给的示例代码:

#include <stdio.h>

int main(void)
{
    int a=44, b=77;
    printf("a=%d, b=%d\n",a,b);
    printf("a=%d, b=%d\n");
}

编译运行结果如下:

Alt

程序编译并没有发生错误,第一次调用printf输出的结果也在预想之中,但是第二次调用的结果就出乎意料了,通过书中的两个示意图可以很清晰的看出原因:

第一次调用printf: Alt

第二次调用printf: Alt

32位下,函数参数传递完全依靠栈来完成所以第一次调用时,对应参数压栈,栈中的数据布局就如图所示。到了第二次调用,由于未传入要输出的数据列表,只是将格式控制符传入,所以调用时也只将格式控制符压栈,这样函数在执行时,根据格式控制符,向上(栈中高址)依次检索数据,将其输出。由于两个printf是连续调用的,所以栈上的数据并未发生改变,所以a就输出了指向a=%d, b=%d的指针,而b就输出了原先a的值。

当我们把第二次的printf调用改成printf("a=%d, b=%d, c=%d\n");,那么以此类推,c的输出就对应b的值77了。

Alt

利用printf函数读取内存内容

其实通过前面的例子,就可以发现,如果想要泄露栈上的数据,可以直接通过一连串的格式控制符如%d来直接打印栈上高地址的数据。

考虑书中的代码:

#include <stdio.h>

int main(int argc, char ** argv)
{
    printf(argv[1]);
}

代码很简单即直接打印命令行输入的参数,我们正常输入内容时可以得到简单的反馈,但是当我们输入一连串的%p时,就可以泄露出栈上的数据了:

Alt

用printf向内存中写数据

这里利用的一个似乎平常不怎么使用的格式控制符%n,这个控制符用于把当前所有的输出数据的长度写回到一个变量中去,考虑下面的这段代码:

#include <stdio.h>

int main(void)
{
    int len_print=0;
    printf("before write: length=%d\n", len_print);
    printf("failwest:%d%n\n", len_print, &len_print);
    printf("after write: length=%d\n", len_print);
}

第二次调用时,使用了%n,它就会将”failwest:0”的长度也就是10写入到len_print,所以就有了如下的输出结果:

Alt

SQL注入攻击

SQL注入原理

SQL命令注入是Web系统特有的一类漏洞,它源于PHP、ASP等脚本语言对用户输入数据和解析时的缺陷。也就是说,它是通过用户输入来影响脚本中SQL命令串的生成,比如通过添加单引号、注释符等特殊字符来改变数据库最终执行的SQL命令。

书中以PHP为例,通过下图清晰的展示了SQL注入的基本原理:

Alt

SQL注入攻击的精髓在于构造巧妙的注入命令串,从服务器不同的反馈结果中,逐步分析出数据库中各个表项直接的关系,知道彻攻破数据库。

针对PHP+MySQL网站的攻击

对于PHP配置文件php.ini中与注入攻击相关的重要选项:

选项 安全配置 说明
safe_mode on 安全模式
display_errors off 是否向客户端返回错误信息。错误信息能够帮助攻击者摸清数据库的表结构和变量类型等重要信息
magic_quotes_gpc on 自动将提交变量中的单引号、双引号、反斜线等特殊符号替换为转义字符的形式。例如,’ 将被转换为 \’

这些配置选项的正确配置可以增加攻击的难度,但并不能从根本上解决问题

MySQL 4.x 及其以上版本中支持UNION 查询。利用联合查询往往可以直接把得到的数据返回到某个变量中,从而在网页中显示出来:

通过以下方式,试探脚本中共有几个变量接收数据。当返回的页面不再出错时,证明变量的数量正好,观察页面中显示出来的数字,可以确定出能够用于显示结果的变量位置

failwest' union select 1#
failwest' union select 1,2#
failwest' union select 1,2,3#
failwest' union select 1,2,3,4,#

除了检索数据,其他常用的攻击测试用例参见下表:

Alt

而对于MySQL 3.x 版本,不支持联合查询语言,无法插入整句的检索语言,因此通常采用盲注入的方式进行攻击,通过服务器对请求的反馈不同,一个字节一个字节地获得数据

这其中用到的几个MySQL函数:

mid(string, offset, len)

这个API用于取出字符串中的一部分。第一个参数是所要操作的字符串,第二个参数指明要截取字符串的偏移位置,第三个参数代表字符串的长度

下面给出两个使用示例(二者等价):

failwest'and ascii(mid((load_file('etc/host'),1,1))=1#
failwest'and ascii(mid((load_file(char(47,101,116,99,47,104,111,115,116,115),1,1))=1#

针对ASP+SQL Server网站的攻击

与 MySQL 数据库相比,微软的SQL Server 不但支持UNION 查询,而且可以直接使用多语句查询,只要用分号分隔开不同的SQL 语句即可。由于SQL Server 功能更加强大,因此一 旦被攻击者控制,后果往往也更加严重

ASP:即Active Server Pages,用来创建动态交互式网页

注入的攻击测试用例:

Alt

其他注入方式

Cookie注入

在ASP中,通常使用post和get两种方式提交用户数据:

ID = Request.QueryString(id) //获取用户通过GET 方式提交的id 数据
ID = Request.Form(id) //获取用户通过POST 方式提交的id 数据

或者为了同时支持 GET 和POST 方式,使用下面这条“万能”语句:

ID = Request(id)

实际运行中,这条语句会先读取GET 中的数据,如果没有再读取POST 中的数据,如果还没有则会去读取Cookie 中的数据。很多防注入系统会检测GET 和POST 数据中是否存在敏感字符,却忽略了对Cookie 数据的检测。也就是说,攻击者就可以利用Cookie 提交精心构造的注入命令串来进行SQL 注入。

Xpath注入

XPath 是XML路径语言,它通过“引用数据”的方式从XML 文档中读取各种信息,并且具有很好的松散输入特性和容错特性。正是由于这种特性,使得攻击者能够在URL、表单或其他地方附上精心构造好的XPath 查询语句来获得权限

在一个系统中,如果在登录中使用的是数据库验证,那么检索用户的查询可能是类似于这条SQL 语句:Select * from table_name where user='admin' and psw='123',如果存放用户验证信息的是一个XML文件:

<?xml version="1.0" encoding="UTF-8"?>
<users>
    <admin>
        <name>admin</name>
        <password>123</password>
    </admin>
</users>

那么对应的Xpath查询语句为://users/admin[name/text()='admin' and password/text()='123']

其中,,“//”表示选择全部节点,如users/admin 表示列举users/admin 下的全部节点;中括号里面的语句是谓词。所以上面这条查询语句的涵义为:选择users 节点中admin 节点 下的name 属性为’admin’并且password 属性为’123’的所有节点。

如果用户在用户名和密码都输入'or '1'='1',Xpath语句就变成了://users/admin[name/text()='' or '1'='1' and password/text()='' or '1'='1'],显然中括号内部的谓词是True,所以将选择所有admin 用户,用户名密码认证自然就被绕过去了。

XSS攻击

XSS原理

XSS是跨站脚本(Cross Site Script)的意思,由于网站技术中的Cascading Style Sheets 缩写为CSS,为了不至于产生概念混淆,故一般用XSS 来简称跨站脚本

在很多Web 应用中,服务器都将客户端输入或请求的数据“经过简单的加工”后,再以页面文本的形式返回给客户端。 在这些Web 应用中,如果对用户输入的“加工”过于简单,就会产生XSS 漏洞。例如,下面这种代码对用户输入的数据没有经过任何“加工”,就直接返回给了客户端:

<?php
    echo $input
?>

当用户正常请求:http://testapp.com/test.php?input=this is a test,服务器将简单地把“this is a test”返回给客户端的浏览器,浏览器解析后会将这段文本显示在页面中。 但是,当遇到类似这样的请求时:http://testapp.com/test.php?input=<script>alert('xss');</script><script>alert('xss');</script>对于Web 服务器来说,和前一次请求中的输入“this is a test” 没有任何质的区别,都是文本字符串,因此也将直接返回给客户端的浏览器。 客户端的浏览器在解析这次反馈的页面时,发现页面中的是脚本命令,而不是数据,因此会把<script>alert('xss');</script>当做脚本命令进行解析,进而执行,弹出一个警告消息框

XSS Reflection攻击场景

Alt

Stored XSS攻击场景

Alt

路径回溯漏洞

原理

在 Windows 系统中,“../”或者“..\”在路径中都表示“上一级”,比如下面这几个路径实际上是等效的:

C:\WINDOWS\win.ini
C:\WINDOWS\SYSTEM32\..\win.ini
C:\WINDOWS\../WINDOWS\win.ini

在Linux 中,下面这几个路径也是等效的:

/etc/passwd
/home/users/php/templates/../../../../etc/passwd
/home/users/php/templates/../../../../../../../../../../../etc/passwd

当足够多的“..”使得路径跳转到根目录时,多余的“..”将被忽略掉。在URL 中,可以采用“../”和“..\”来表示“上一级”,并且可以用编码的方式进行表述

如果开发者没有对路径回溯进行过滤或者权限控制的话,攻击者可以通过精心构造回溯路径获得服务器上的敏感文件,从而进行进一步的渗透工作。比如下面这个例子:

对于URL:http://www.testsite.com/download.asp?file=document.pdf,功能是下载特定目录下的document.pdf文件,如果没有对路径回溯进行检查的 话,可以构造特定的URL 来下载服务器上的敏感文件:

http://www.testsite.com/download.asp?file=../../../../windows/win.ini
http://www.testsite.com/download.asp?file=../../../../etc/passwd