跳至主要內容

注入攻击详解

gavin-james2019年4月14日开发理论安全相关大约 10 分钟

注入攻击详解

注入攻击最为常见的攻击方式,作为开发而言必须完全避免; 本文会介绍常见的几种注入方式,比如:SQL 注入, xPath 注入, 命令注入, LDAP注入, CLRF注入, Host头注入, Email头注入等等,总结来看其本质其实是一样的,且防御措施也大同小异,具体看下面的内容。

SQL 注入

所谓 SQL 注入,就是通过将 SQL 命令插入应用程序的 http 请求中,并在服务器端被接收后用于参与数据库操作,最终达到欺骗服务器执行恶意的 SQL 命令的效果。理论上来讲,应用程序中只要是与数据库有数据交互的地方,无论是增删改查,如果数据完全受用户控制,而应用程序又处理不当,那么这些地方都是可能存在 SQL 注入的。

什么样的SQL会造成攻击?

直接看下面登录的SQL:

public boolean auth(String userName,String password) throws Exception{
    Connection conn = null;
    try {
        conn = DBUtil.getConnection();
        Statement state = conn.createStatement();
        // 重点看这条SQL,密码输入: ' OR '1'='1时,等同于不需要密码
        String sql = "SELECT * FROM t_user WHERE username='"+userName+"' AND pwd='"+password+"'";       
        ResultSet rs = state.executeQuery(sql);
        if(rs.next()){
            return true;
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally{
        if(conn != null){
            DBUtil.close(conn);
        }
    }
    return false;
}

如何防御?

常见的修复方法:

// 写个大概,帮助你理解
sqlStatement = dbConnection.prepareStatement("select * from users where username= ? and password = ?");
sqlStatement.setString(1, userName);
sqlStatement.setString(1, password); // 加密

// 只是看个思路,都2020年了,谁还自己写JDBC登录...

xPath 注入

XPath 是一种用来在内存中导航整个XML树的语言,它使用路径表达式来选取XML文档中的节点或者节点集。XPath 的设计初衷是作为一种面向 XSLT 和 XPointer 的语言,后来独立成了一种W3C标准。而 XPath 注入是指利用 XPath 解析器的松散输入和容错特性,能够在 URL、表单或其它信息上附带恶意的 XPath 查询代码,以获得权限信息的访问权并更改这些信息。XPath 注入与 SQL 注入类似,均是通过构造恶意的查询语句,对应用程序进行攻击。

xPath是怎么工作的?

实在不喜欢网上乱七八糟的,其实一张图就可以解释:

img
img

如何攻击的?

如果用户传入类似 ’ or 1=1 or ”=’ 的值,那么该查询语句也会得到 true 返回值,将返回所有用户的列表。

img
img

如何防御?

要避免XPath注入,需要注意以下几点:

命令注入

什么是命令注入

命令是指通过提交恶意构造的参数破坏命令语句结构,从而达到执行恶意命令的目的。

命令注入的场景

Java中System.Runtime.getRuntime().exec(cmd);可以在目标机器上执行命令,而构建参数的过程中可能会引发注入攻击。

比如:

// 比如你构建了如下的command语句,传参数request.getParameter("test"),将可能包含·命令分隔符·从而引入注入风险·   
String cmd = "xxxx xxx " + request.getParameter("test")+ " xxx";

// 注意: 试图将如下方法抽象为一个静态方法时,它潜藏着注入风险;如果你用过SonarCube扫描工具,如下代码会有注入攻击的提示。
public static void runCmd(String command){
    Runtime run = Runtime.getRuntime();
    try{
        Process process = run.exec(command);// 在当前服务器上执行command脚本
        InputStream in = process.getInputStream();
        While (in.read() != -1){
            System.out.println(in.read());
        }
        in.close();
        process.waitFor();
    } catch (Exception e){
        e.printStackTrace();
    }
    // ...忽略close操作,只是给你个例子
}

常见注入方式

上述command中会有哪些常见的注入方式呢?

一般如何防御呢

和其它注入防御本质大同小异

LDAP注入

LDAP简介

LDAP(Lightweight Directory Access Protocol):轻量级目录访问协议,是一种在线目录访问协议。LDAP主要用于目录中资源的搜索和查询,是X.500的一种简便的实现。LDAP不定义客户端和服务端的工作方式,但会定义客户端和服务端的通信方式,另外,LDAP还会定义LDAP数据库的访问权限及服务端数据的格式和属性。LDAP有三种基本的通信机制:没有处理的匿名访问;基本的用户名、密码形式的认证;使用SASL、SSL的安全认证方式。LDAP和其他一些协议走的是同一个套路,基于tcp/ip协议通信,注重服务的可用性、信息的保密性等等,除此之外还要回到那个最原始的问题:信任,当然信息安全的本质问题就是信任的问题。部署了LDAP的应用不会直接访问,目录中的内容,一般通过函数调用或者API,应用可以通过定义的C、Java的API进行访问,Java应用的访问方式为JNDI(Java Naming and Directory Interface)。

LDAP以目录信息树形式存储信息,包含入口、对象、属性,关系图如下:

img
img

入口点和属性之间的关系为:

img
img

既然LDAP用于搜索查询服务,那它是怎么搜索的呢?

主要根据属性和值进行搜索,就如浏览网页时我们通常并不会浏览某个目录,而是其下存在的某个文件。

看得出来在URL中这里使用逗号分隔查询,而数据库查询则使用'&'号,这是LDAP特有的,另外这里o表示组织(organization),u表示单元(unit),cn表示country name。

LDAP注入场景

LDAP注入攻击和SQL注入攻击相似,因此接下来的想法是利用用户引入的参数生成LDAP查询。一个安全的Web应用在构造和将查询发送给服务器前应该净化用户传入的参数。在有漏洞的环境中,这些参数没有得到合适的过滤,因而攻击者可以注入任意恶意代码。

一些应用框架在将请求发送给服务器之前会检查过滤器是否正确,在这种情况下,过滤器语义上必须是正确的,其注入如:value)(injected_filter))(&(1=0。这会导致出现两个不同的过滤器,第二个会被忽略:(&(attribute=value)(injected_filter))(&(1=0)(second_filter))

既然第二个过滤器会被LDAP服务器忽略,有些部分便不允许有两个过滤器的查询。这种情况下,只能构建一个特殊的注入以获得单个过滤器的LDAP查询。value)(injected_filter这样的注入产生的结果是:(&(attribute=value)(injected_filter)(second_filter))

测试一个应用是否存在代码注入漏洞典型的方法是向服务器发送会生成一个无效输入的请求。因此,如果服务器返回一个错误消息,攻击者就能知道服务器执行了他的查询,他可以利用代码注入技术。回想一下之前讨论的,我们可以将注入环境分为两种:AND注入环境和OR注入环境。

学习更多LDAP攻防

这里只是简单介绍,如需更详细了解,推荐你看下这篇文章:LDAP注入与防御解析在新窗口打开open in new window

CLRF注入

Host头注入

Email头注入

XXE

https://blog.spoock.com/2018/10/23/java-xxe/open in new window

参考文章