CTF中SQL注入类题总结与心得

CTF中SQL注入类题总结与心得

摘要:截止到4月3日本人对sql注入的总结与心得

0x01写在前头

从入坑CTF到现在刷过的web题已经快到150道左右了,印象里,其中的sql注入类的题目占的比重还是蛮大的。而sql注入在安全圈内外都可以说是知名度极高,尽管近些年来,随着人们安全意识的提高、程序员技术水平的提升、大量成熟的具有安全机制的框架被采用,sql注入所发生的的情况极大的减少了。在我看来,sql注入漏洞可能会“死”,但有些元思想层级的东西,比方说:如何去寻找一个利用点,它们是不会死的。那么,想要获取这些元思想,停下脚步来,好好进行下复盘那就是必要的了。这也就是我打算写这篇博客的原因。

0x02本文主要结构

写本文的主要目的是想去提炼自己的思维过程以及其中的一些闪光点,同时在复盘的时候对以前没太弄懂的知识点做点探究。故本文的面向对象可能更多的是我自己,从而不会有太多图文并茂实战例子在这里,当然也希望在看这篇博文的你也能收获些什么。本文主要分为以下几个结构:一、对自己以往做过的与sql注入相关的Web题进行一个归纳与总结;二、对以上自己做过的题中所体现出来的知识点与思想点做一个归纳与总结;三、总结出一套自己的思维框架。

0x03第一部分:CTF赛题整理归纳

下面相当于是自己列一个清单了,以下的题目皆由buuoj复现:

强网杯2019 随便注

知识点:预编译绕过waf对select、insert的过滤,预编译可以和hex编码结合

SUCTF2019 EasySql

知识点一:oracle中的PIPES_AS_CONCAT参数使得||变为了字符连接符
知识点二:堆叠注入
Mark下,其实可以通过跑字典来确认输入框中被过滤的词

网鼎杯2019 fakebook

知识点一:运用 /**/ 的方式绕过waf对union的拦截,从而可以进行联合注入
知识点二:基于updatexml()报错的注入

第十届极客大挑战 Babysql

知识点一:双写绕过,例如:union->uniunionon,select->selselectect
知识点二:information_schema表的结构

SWPU2019 Web1

知识点一:二次注入
知识点二:当information_sechma被过滤时,mysql.innodeb_table_stats的使用

CISCN2019总决赛 day2 easyWeb

知识点一:与其说是知识点不妨说是想象力吧。id=’\‘ or path=’{$path}’。转移字符\的妙用
知识点二:基于布尔的盲注——根据回显判断语句正确与否

第十届极客大挑战 Hardsql

知识点一:基于报错的注入
知识点二:order by检查字段数

GYCTF2020 Blacklilst

知识点一:堆叠注入
知识点二:handler用来替代被过滤的select

第十届极客大挑战 FinalSQL

知识点一:注入点的寻找:这题是url上的?id=
知识点二:基于布尔盲注
知识点三:这个算是自己踩的坑,在where子句中XXX=’xxx’记得加’’

RoarCTF2019 OnlineProxy

知识点一:注入点的寻找:这题是放到了X-Forward-For头里了
知识点二:二次注入

RCTF2015 EasySQL

知识点一:注入点的寻找:这题是在修改密码处
知识点二:sql语句的双引号闭合,当初省赛的时候也被这个坑过
知识点三:基于报错的注入
知识点四:or、and被过滤可以用||、&&
知识点五:reverse()逆转输出字符串,类似的字符串处理还有left、right、substr、mid等

CISCN2019 华北赛区 Web2

知识点一:基于报错的注入
知识点二:mysql中loadfile()的使用,但有文件ax权限以及文件大小小于1G的要求

网鼎杯2018 comment

知识点一:二次注入
知识点二:多行书写的代码闭合要用多行注释

SWPU2019 Web4

知识点一:堆叠注入发现与利用。发现可以传个“;”进去试试看看后台发挥的报文;
知识点二:利用可以和预编译结合

GYCTF2020 Ezsqlli

知识点一:or被过滤时可以用sys库来替代。前提是mysql版本在5.7以上且具有root权限
知识点二:无列名注入。这个点可以布尔盲注结合,打一套组合拳

网鼎杯2018 Unfinished

知识点一:二次注入
知识点二:二次注入与hex以及预编译的结合

CISCN2019 华东北赛区 Web2

知识点:简单联合注入
以上便是我在4月3日前所做过跟sql注入相关的题,前前后后17题。可以发现的是,sql注入这个点在ctf比赛中考察的时候大多都与其他知识点或者能力相结合,比方说HTTP头的知识、相应场景下数据与数据库相结合的可能性的估计(注入点发现)、代码审计的能力、脚本的快速编撰的能力、payload构造的能力等等。同时,我们还要注意到的是,sql注入的知识点是多而杂的,除去基础知识以及大致的框架以外,其中充斥着大量的奇巧淫技与想象力。下面,我将对上面的零散的知识做一个合理的归纳与分类而后再从网络上进行补充,除此之外,我希望能在此过程中总结一个处理sql注入类题的一个大致的思维框架,并将此框架作出一定的推广。

0x04第二部分:知识点整合

一、注入漏洞分类

sql注入的分类繁杂,根据不同的标准可以分成不同的情况,这里我根据自己的理解来对注入进行一个粗糙的分类,根据点是利用的方法。如果在看这篇文章的你有不同的理解或者觉得我有不全面的地方可以评论区告知我。

普通注入

普通的注入是最简单的一类注入,它有报错的回显可以让你根据报错信息来进行注入;它没有对相应的语句进行过滤,比如关键的select、union、or等。因此,这块注入处理起来最为简单。要做出这类型的题,不用考虑太多,sqlmap一把梭或者结合后面我总结的注入技巧直接手注也是可以的。这类题在我上面做过的题里面比较典型的是就是CISCN2019华东北赛区的Web2了,buuoj上有复现,可以去练习下。

基于布尔盲注

基于布尔的盲注分为两种,一种是字符型的、一种是数字型的。不过在我看来,这两种没有什么本质上的区别,无非是是否要对引号进行闭合罢了。

1
2
3
#payload示例
0' or '1' = '1 #字符型
0 or 1 = 1 #数字型

布尔盲注可以同时间盲注相结合,比方说,构造语句:

1
IF(2>1,sleep(5),1)

然后浏览器的开发者工具在NetWork上看返回时间即可。本质上来讲,时间盲注是一种布尔注入,因此我将其归于此类。
一般而言,基于布尔的盲注的核心点在于对“真”与“假”回显的判断,只有这个回显判断对了,布尔盲注才可以发挥大的作用。一般情况下,可以在前期通过fuzz将相应的回显判断出来;如果回显不明显,这个时候就应该考虑利用时间盲注了。在脚本中,两者如下体现:

1
2
3
4
5
6
#布尔盲注
if 'xxx' in r.test:
statements;
#时间盲注
if time.time() - start_time >= time_you_set:
statements;

总结来说,遇到布尔盲注主要考虑两个基础的点:
1、payload的构造。字符型还是数字型?基于回显布尔还是基于时间的布尔?
2、脚本中正确判断的书写

基于报错的注入

这是个很有意思的点,目前为之我自己遇到的以及用过的基于报错相关的注入函数是以下两个:
updateXml(doc_string,Xpath_String,string)和extractvalue(xmldoc_string,xml_path),两者利用的时候本质上差不多,主要讲讲前者:
第一个参数为xml文档的文件名
第二个参数为Xpath及xml文档路径的Xpath表现格式。
第三个参数为要替换的字符串。
重点在第二个参数,这里可以写入相应的sql语句从而导致执行,直接贴一个payload直观点:

1
updatexml(1,concat(0x7e,(select(table_name)from(information_schema.tables)where(table_schema)like'xxx'),0x7e),1)#

执行函数时,会先执行参数2中的sql语句,然后因为无法找到对应的文件,updateXml会报错,将无法找到的“文件”也就是我们sql语句的执行结果打印出来。感兴趣的可以自己搭建环境试一下,不是很复杂。
基于报错的注入,就我的经验来看,一般是在一些普通回显不明显的情况下使用的。当然,我遇到的基于报错注入的情况其实挺少,通过网上的资料来看,基于报错的注入一共存在十几种…具体如何还是得看那些大师傅们的总结了。

二次注入

二次注入也是个很有意思的点。粗浅地讲一下原理吧:
我们假设有这样一个语句:

1
insert into users(username, value) values ('$user''$value');

其中,$user和$value是未过滤的用户输入。假设用户输入为“select * from users;”。那么,当后台执行某一查询数据的指令,例如:

1
select user from users where user = $user;

并回显数据时,那么,二次注入就实现了。我第一次接触这个操作时,真的感到当年发明二次注入的人的想象力之丰富,当然了,搞安全最需要的就是想象力了。
目前为止,我遇到的二次注入的情况主要有以下几种:
a、通过留言板进行的二次注入
这种情况一般在用户通过留言板写入留言后还有一个“查看详情”的选项,一般遇到这种情况可以想想是不是存在二次注入
b、通过用户名进行的二次注入
登录的时候用邮箱登录,但是登录后看到了用户名,这个时候就要想想二次注入的可能性了。
c、通过修改后台数据进行的二次注入
这种方式在ciscn2019的一道叫cyberpunk的题里面有体现。
BUUOJ上都有相应的复现,可以去做做看。

堆叠注入

堆叠注入值得是一次性在输入框中输入多条用;分割的语句,从而执行多条语句。一般而言,堆叠注入与预编译结合的比较多,而在遇到需要使用预编译的情况,一般都是select语句被过滤的情况。同时,使用预编译的时候需要使用hex函数进行编码,从而绕过对select的过滤。当然了有些变态的题吧set都过滤了,这个时候就是偏门函数的使用了,比如说handler。贴一下预编译语句格式:

1
2
3
4
set @a=0x{xxx} #用于设置变量名和值
prepare hn13 from @a #用于预备一个语句,并赋予名称,以后可以引用该语句
execute hn13 #执行语句
deallocate prepare hn13 #用来释放掉预处理的语句,比赛不用管

贴一下将sql语句转化成hex格式的脚本:

1
2
def str_to_hex(s):
return ''.join([hex(ord(c)).replace('0x', '') for c in s])

二、一些tricks

绕过姿势

/**/,– 注释绕过
() 括号代替空格绕过
hex() 绕过,预编译使用
|| && 对or和and的绕过
uniunionon 双写绕过
SeLeT UnIoN 大小写绕过

一些奇巧淫技

handler函数的使用
首先handler table_name open获得句柄
然后handler table_name read [first|next|]读取字段
一些字符串处理函数的使用mid(),substr(),left(),reverse()等
ascii(),ord()函数的使用
无列名注入。顾名思义,就是在无法获得列名的情况下进行注入。贴一个很有意思的payload吧:

1
2
3
4
5
6
7
8
9
10
11
12
select ((select 1,2) < (select 1,2))
# output:0
select ((select 1,2) = (select '1',2))
# output:1
select ((select 1,2) > (select '!',2))
# output:1
select ((select 1,2) > (select 'a',2))
# output:1
select ((select 1,2) > (select 0,3))
# output:0
select ((select 'a',2) = (select 'A',2))
# output:1

sys库,mysql.inodeb库对information_schema库的替代
运用字典对被过滤的关键字进行fuzz
oracle中的PIPES_AS_CONCAT参数使得||变为了字符连接符

0x05第三部分:sql注入思维框架

那么,到这个阶段,是时候系统化下自己在做sql注入类题时的思维步骤了。
首先,第一步要做的就是对注入点的存在与否进行判断。其实这个点是一个很玄学的点,我个人认为需要你拥有足够的经验才能做出较为准确的判断。同时,你也可以使用像sqlmap这样的工具对某个点进行测试;
然后,如果判断出某个注入点,一般这个时候也能够将大概的注入类型判断清除,其实注入类型就是那几种,这个时候对所有可能存在的注入类型进行枚举即可,从中挑出最有可能的注入类型再进行重点的测试;
之后,这个时候就要进行sql注入的脚本的编写了,在sql注入脚本编写这块,我联想到了sqlmap中丰富的tamper。当然了,作为刚入门的选手这些temper我是没有研究过,以后有机会专门找时间研究下。在这点上,我认为平时要进行积累,积累足够的脚本,到时候使用相应的脚本进行套就行了。同时,要注意sql注入中的各种trick,加以运用,加以结合。在脚本编写这块,我想以后能不能有机会写一篇来说说呢?有机会写写吧。
再后,就是将自己的脚本拿去具体实操了,从实操中进行调整,调至最优。
大致的框架是如此,个人认为关键点在于注入点的寻找以及payload的构造,这不是一朝一夕能够处理好的,得有足够的经验积累。

0x06 写在最后

本人接触信息安全的时间也不到一年———到目前为止大概是八九个月吧,在这八九个月的前几个月完全是十分迷茫的,迷茫地学着、迷茫地玩着、迷茫地比赛着,到目前为止才刚刚感觉真正地将一只脚跨入信息安全、ctf的大门。因此,这篇文章也定有诸多不足,所以,希望正在阅读这篇文章的大佬多多指教了。
人生漫漫,前路长长。希望我在准备考研前能够在这条路上走得尽量“辉煌些吧”。


评论