logo头像

黑客的本质就是白嫖

Web知识巩固(篇二)-SQL注入

前言

本以为该系列的更新要么就要停止了要么就要挺久之后再开,没想到面试连番受挫,最后在某hr的转述下得知,“你的web弱了点”。emmm这个评价让人好生难受啊,不过既然真的这么菜的话,基础知识的巩固貌似又提上了日程,那就还是慢慢的把基础补上来吧。虽然说之前写过一篇SQL注入的文章,不过那似乎还是知其然的时候写的,这次的话就试着能不能知其所以然吧。

SQL注入简介

SQL注入是由于后台程序对于用户的输入等没有进行过滤或过滤做的不够充分等原因,导致了最后拼接执行的SQL语句包含了恶意代码,达到了攻击者的恶意目的。

以上为笔者对于SQL注入的理解,而我们,也就是“攻击者”,要做的事情就是,想方设法绕过后台程序对传入数据的过滤、编码等等,最后让查询的语句中夹带”私货“,且将查询的结果通过某种较为直观的方式(回显、报错、延时等等)返回到我们能观察到的位置,当然也可以通过SQL注入写shell,不过这算是后话,暂且先放在一旁。

SQL注入详解

存在是偶然的

对于一个参数来说,我们要进行sql注入,首先至少得判断这个参数是否存在sql注入的可能,一般网站的参数有这几种

  • 数字型
  • 字符型
  • 搜索处

数字型的参数在构造注入语句时不用考虑闭合前一条语句,因为后台查询处也不存在单引号、双引号等,不过不能单纯的通过我们看到的数据的数据类型来判断,虽然说数字型注入一定是存在于有数字的sql注入当中,但是有数字的sql注入不一定就是数字型的sql注入,如下图

web2_sql_1

我们可以看到,虽然都是查询id,但是查询语句里说不定就有各种引号括号啥的,具体情况还是得具体分析

字符型的话就不用多想了,闭合是一定要闭合的,就看能不能闭合了,而搜索处的也一样是需要闭合的,只不过后台语句会稍微有所不同,测试时的payload也会有所不同

小标题是存在是偶然的,笔者的意思是,不是所有参数都会存在sql注入,毕竟有的参数可能压根就没有涉及到数据库操作,而有的参数对于sql注入的防护又做的比较好没什么机会,按照笔者的经验来看,一般情况下涉及到数据库操作的参数有这些,各种id、用户名、用户的各种数据、搜索处输入,还有一些想想应该无法放在后台程序处,需要数据库交互的参数

当我们找到这样的参数时,首先就是要确定sql注入是否存在了,大部分情况下,我们都是通过闭合看回显的页面是否有差别来判断是否存在sql注入,最简单的一般会使用单引号'来检测,在正常输入后面加上一个单引号,如果返回了数据库的报错信息,这就说明闭合成功了,这时候后台语句大概是类似于这种

1
select * from user where id='1'';

可以看到,sql语句中多了一个单引号,就是我们输入的这个单引号,此时查询出错,服务器要么返回空的数据要么返回服务器报错信息,我们就可以通过在客户端处的回显来判断是否存在注入了

不过实际应用场景里,一个单引号就能判断的情况太少见了,甚至sql注入漏洞都不太常见,且不说那些安全措施做的及其到位的网站,在一些做了一点安全措施,又做的不到位的网站,就需要我们测试看如何闭合语句了(或者使用andor来判断),这种情况下,笔者一般通过fuzz来确认是否存在注入,毕竟这不能算是一个技术含量非常高的部分,能自动化就自动化好,自己收集一些闭合方式、判断注入方式,接着再一股脑地测一遍就好了

本质与现象

判断了注入之后,接下来要做的就是判断数据库的类型(本质)了,而我们需要通过闭合之后的现象或者是测试注入所使用的语句来判断,因为在之后的注入中,不同的数据库所涉及到的库名、函数名、变量名以及语法可能会有些许不同,笔者之前就一直没太在意过这个问题,大概是因为笔者碰到的数据库中,mysql居多,而其他的数据库,碰到的时候可能就借sqlmap直接跑出来了,所以也没太关注过这个问题,恰好前两天面试问到了这个问题,笔者发现自己对这方面的问题一窍不通…所以说,书到用时方恨少啊…

判断数据库的方法不少,基本上都是通过各个数据库的特性来判断的,下面记录几种常见的判断方法

根据各数据库特有表判断

各数据库中特有的表如下

  • mssql(sqlserver)sysobjects
  • accessmsyobjects
  • mysqlinformation_schema
  • oraclev$version

根据各数据库查看版本方式判断

同样功能的函数在不同的数据库里用法或形式可能会不一样,如

获取数据库版本信息的version函数

  • mysqlselect version()select @@version
  • mssqlselect @@version
  • oracleselect * from v$version

根据返回的错误信息判断

每个数据库的错误信息都不尽相同,如果我们能够看到数据库报错信息,那就很好确认数据库的类型了,如

  • mysql:you have an error in your SQL syntax,check the manual that corresponds to you mysql server version for the right stntax to use near ‘1’’ at line x
  • mssql:Msg 170,level 15, State 1,Line 1
    Line 1:Incorrect syntax near ‘foo
    Msg 105,level 15,state 1,Line 1
    Unclose quotation mark before the character string 1‘
    
  • oracle:ORA-01756:quoted string not properly terminated
    ORA-00933:SQLcommand not properly ended
    

其他方式判断

还有一些大概都是每个数据库独有的东西,也不好分类,索性就一起写了

  • mysql:特有的sleep()函数、benchmark(x,y)函数(用于计算y命令执行x次数所需的时间的函数),使用concat函数拼接字符串
  • mssql:特有的waitfor()函数,默认变量@@servername,拼接字符串直接使用+
  • oracle:拼接字符串使用||,或使用concat()

绕过是为了更加深入

关于绕过的话题其实在下之前写过,虽然不一定全面,但是现在笔者也没有get到太多别的新知识,这里就上一个链接然后稍作补充好了

SQL注入学习笔记

prepare绕过

这里要多提一句的是一个通过prepare进行绕过的手段,存在于可以进行堆叠注入的地方,这个知识来源于强网杯的某题web题的某种解法,文后有链接

我们先看一下prepare的基本语法

1
2
3
4
5
PREPARE statement_name FROM preparable_SQL_statement; /*定义*/

EXECUTE statement_name [USING @var_name [, @var_name] ...]; /*执行预处理语句*/

{DEALLOCATE | DROP} PREPARE statement_name /*删除定义*/ ;

可以先测试一下

web2_sql_2

从图中我们可以看到,就是将变量aa代入了预处理语句中预留的位置?,之后execute时执行的语句就相当于是

1
select * from users where id=1;

但是单纯的一个prepare貌似并不能起到绕过的作用,因为在设置预处理语句时,该过滤的还是会被过滤,而在这道题的这个解法里面,是用char函数来将sql语句拼接后传入,最后的payload里面也不会出现较为敏感的关键词,以下为在我数据库中运行的这个查询语句转化之后的payload

1
2
3
set @aa=concat(char(115,101,108,101,99,116,32),char(42,32),char(102,114,111,109,32),char(117,115,101,114,115,32),char(119,104,101,114,101,32),char(105,100,61,49));
prepare aaa from @aa;
execute aaa;

web2_sql_3

利用的词性辨证

当我们能够绕过waf执行自己构造的命令时,这个漏洞就为我们所用了,至于是继续渗透,还是提交漏洞报告,又或是脱一发再走,这就要因人而异了,漏洞利用的具体细节笔者觉得没有太多讲的必要,一是笔者自身实力所限,无法将这东西写得让人看的愉快,第二就是在笔者碰到的多数授权渗透测试中,一般到这一步继续往下就算是过界了(不排除某些需要继续往下getshell或进行内网渗透的)

后记

sql注入这个话题笔者记得曾写过一次,当初有一点做笔记的味道在里面,没有深究细节,也没有熟记于心,这次虽然不能说精到哪里去,至少算是一次花了点心思的学习过程吧

Reference

手工sql注入判断是否存在注入点

SQL注入WIKI

SQL注入中数据库的判断

MySQL prepare语句的SQL语法

强网杯_supersqli一题三解

评论系统未开启,无法评论!