![CTF实战:技术、解题与进阶](https://wfqqreader-1252317822.image.myqcloud.com/cover/482/47755482/b_47755482.jpg)
1.1.2 SQL注入进阶
1.二次注入
二次注入是一种用来绕过输入点防御的方法。通常开发人员会在用户的输入点进行关键字过滤和特殊字符转义,给我们利用漏洞带来了很大的困难。我们输入的数据插入数据库时会被还原并存储在数据库中,而当Web程序再次调用存储在数据库中的数据时,由于没有将提取出来的数据进行转义和过滤,就会执行我们插入的恶意SQL语句。下面介绍具体方法和步骤。
第一步,插入恶意数据。在向数据库中插入数据时(如创建新用户、添加评论、修改用户信息等),Web程序对插入的数据进行转义和过滤,在写入数据库时又将数据还原。
第二步,引用恶意数据。当Web程序将数据从数据库中取出并调用时,恶意SQL语句被代入原始语句中,造成SQL二次注入,如图1-27所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/31_01.jpg?sign=1739128777-HJTHWKTrVfqKCL8PLwGoShTFoTLUSfZw-0-0de1b6c1cd96caa0e113d247457a6365)
图1-27 二次注入原理示意图
以2019-CISCN华北赛区Day1 Web5-CyberPunk题目为例,通过文件包含漏洞方法读出源码,这里不做详述,如图1-28~图1-30所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/31_02.jpg?sign=1739128777-gAqFnH4QAL2CULUE8ZZCmqXOzchYMs12-0-11fdfbd872f3de0e0d5f89010d08443d)
图1-28 index.php源码
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/32_01.jpg?sign=1739128777-VEDpXrsLdIeQgnJLpvDQsCsH5o1idJNy-0-781d80406f8d50f2f0e3c965cbef494b)
图1-29 change.php源码
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/32_02.jpg?sign=1739128777-RoBPwCMDCVNjMeJuw0xjNpf5v6Lzf66I-0-2d268ba0ceadafffa116eeeec2ebf340)
图1-30 search.php源码
可以看到,address虽然经过了过滤,但是在修改地址的时候从数据库中取出的是没有过滤直接带入的SQL语句,从而导致SQL注入,如图1-31所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/33_01.jpg?sign=1739128777-z5UiGAymQjHVEmBN0L2aa0r7ryfC0cEq-0-2db1fe5f845d40d4d40f4043054d52a7)
图1-31 修改地址处没有过滤
由于这里是update语句,因此我们使用报错注入,代码如下。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/33_02.jpg?sign=1739128777-leASQ9b5XQ4pwazBxSYJMirn7hFujXiM-0-78207b280e650c03be46099f42bb1d70)
结果如图1-32~图1-34所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/33_03.jpg?sign=1739128777-MuD9j1T08cYLtK6k5rSCosjukUIimYCF-0-55b1fd09e2b8673706bd11a831c696d0)
图1-32 插入恶意语句
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/33_04.jpg?sign=1739128777-a1p8FN40LXanBPIr39tB9qaOrwuZKdAJ-0-d817b1a8339876041ec7989ffcb3c635)
图1-33 再次调用
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/34_01.jpg?sign=1739128777-7IoCAUHdYgzzAz5QhLuhRdr3Nbw4AOls-0-c9556d7f57d8f53607f9460e272b5a3a)
图1-34 注入成功
2.无列名注入
通常在注入时我们可以利用information_schema库获取所有库的库名、表名、列名,但是这个库经常被WAF(Web Application Firewall,网站应用级入侵防御系统)过滤。无列名注入适用于已经获取数据表,但无法查询列的情况,在大多数CTF题目中,information_schema库被过滤,使用这种方法可以获取列名。
无列名注入的原理很简单,类似于将我们不知道的列名进行取别名操作,在取别名的同时进行数据查询。
先创建一个数据库demo,再创建一个testuser表,结构如图1-35所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/34_02.jpg?sign=1739128777-hAA4mAJsfMb4AvsxPO361ePUa2PrhMCS-0-856f9d7e71df29cf8ff6b3db36d69aff)
图1-35 创建数据库和数据表
往testuser表里插入一些数据,代码如下。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/34_03.jpg?sign=1739128777-wXb94YX5J2ub6cu1C5t02f8NkFcUcFhP-0-1628212d5b4464ef3545b0d447910421)
正常查询,结果如图1-36所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/34_04.jpg?sign=1739128777-SGix60iv9pZHOvsckTneQSlbTI3UBp7T-0-5a57caad4a6f14e9979b735236dedb2e)
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/34_05.jpg?sign=1739128777-Es590Q9nntw7KA3ZybtuY3S5p7I2mGYM-0-3ffaef87b0e80dcbfc909de5f30b4719)
图1-36 正常查询结果
这时再使用一个union查询,如图1-37所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/35_01.jpg?sign=1739128777-CeTqCEZN2KqVdqPScOi07btpjIwPKFiZ-0-f6826c5634c042493017d5dd4b8547b5)
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/35_02.jpg?sign=1739128777-dnBjrOSzWNxWCVH7N1fTQrrKs8VCO5Vz-0-a34083b0479cf06ee09f6da09b7e1abc)
图1-37 union查询结果
利用数字3代替未知的列名,需要加上反引号。代码后面加了一个a,是为了表示这个表(select 1,2,3 union select*from testuser)的别名,如图1-38所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/35_03.jpg?sign=1739128777-ECdNjOqMUHqmDAHlrarXkUuCnn4G6VeD-0-3c3a8735b285b2985f189d4b94e2fa32)
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/35_04.jpg?sign=1739128777-E4lKPBVXOHLaqexaWPPv1trESEty2dBC-0-3ad92f651d60acb5f280bb15c30b52b5)
图1-38 代替未知列名
当反引号不能使用时,用别名来代替,如图1-39所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/35_05.jpg?sign=1739128777-w9pJ1ubKtXdwEfWwC69S1XV5nckyt5Fm-0-11907df1370c362f070df12ff885b779)
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/35_06.jpg?sign=1739128777-bijPcXXq235kyiRIBzY2BnHbz263aKv1-0-9bf48c74f6cb1dd59fbf2f8a8c895497)
图1-39 列名被替换
以2019-SWPU-Web1题目为例,本题主要考查无列名注入和空格绕过。我们在试出列数后直接注入即可,如图1-40所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/35_07.jpg?sign=1739128777-P01HV1FXUtSmIXZGLRYioe6PEAi2vn0U-0-007e466b44d18569315c382946089602)
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/36_01.jpg?sign=1739128777-sKSSJPbtJAEiOmuWeZy7MngLlFtqvM0M-0-e92b628abffcf03ec4eb6c0789480654)
图1-40 注入成功
3.堆叠注入
顾名思义,堆叠注入就是一堆SQL语句一起执行。在MySQL语句中,每条语句的结尾都有一个“;”,代表一条语句结束。我们将多个SQL语句用“;”连接起来,就可以达到多条语句一起执行的效果,从而造成SQL注入。堆叠注入和union联合查询本质上都是将两条语句连接在一起执行,区别在于union查询只能连接两条查询语句,而堆叠注入可以连接两条任意的语句。当WAF没有过滤show、rename、alert等关键词时,我们就可以考虑使用堆叠注入。
执行下列语句达到堆叠的效果,运行结果如图1-41所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/36_02.jpg?sign=1739128777-CFrlLVF7zuBtU9njdrao1pW3spvH2mg0-0-dd932d43edb21fec14b29896b66a04e8)
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/36_03.jpg?sign=1739128777-7RMx7LhvZiz1xgKRWTUZ2rdnq6TkZts7-0-ec8f62635ca4f47fbf5607105a49a825)
图1-41 列名被替换
以2019-强网杯-随便注题目为例,利用堆叠注入查看表信息,如图1-42所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/36_04.jpg?sign=1739128777-ZhW7Wj6GQVBRVY2wiFeQ7UM18ZYLBEqx-0-15c877d0bac5630f4e78a6068de529c0)
图1-42 查看表名
查看1919810931114514表中的字段(注意,要将表名用反引号引出),如图1-43所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/37_01.jpg?sign=1739128777-84ZJUVVWtoIBFH538hlD39qB1kqmNmnp-0-d6f6910daaace5327682238606ca0f64)
图1-43 获取字段名
发现flag字段后,查看words表中的字段,如图1-44所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/37_02.jpg?sign=1739128777-m2XuWsnyPo5JDmpOro4jkncH1vxhxlen-0-95fa32477c92081d9aebecc7d38c3f52)
图1-44 获取words表的字段名
发现id和data两个字段,因为没有过滤rename和alert,考虑将1919810931114514表改名为words, flag字段改名为data。
流程是将words表名改为其他名字,然后将1919810931114514表改名为words,最后将flag字段更名为data,代码如下。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/38_01.jpg?sign=1739128777-WKNEw17hvaHekXJyJh50huQcl4Qf8xRr-0-bc21b7e126acaefddb94f4182e3e38b7)
查询1即可获得flag,如图1-45所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/38_02.jpg?sign=1739128777-W3MoLlxoNpDIjYQjnvZeEgIexFLkJzhW-0-5e9ea06804ed7d2512c059467f4954b4)
图1-45 获取flag
4.SQL注入与其他漏洞结合
有些时候,SQL注入漏洞并不能直接获取flag,而是为了配合其他漏洞的使用,如SSTI(Server-Side Template Injection,服务端模板注入)、SSRF(Server Side Request Forgery,服务端请求伪造)等,其原理是控制某个漏洞处引用的值,从而达到文件读取或RCE(Remote Command/Code Execute,远程命令/代码执行)的目的。
以2018-科来杯-Web3题目为例,本题考查SQL注入与SSTI利用。注入点并不难发现,使用常规的union联合查询就可以轻松发现注入点,代码如下,运行结果如图1-46所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/38_03.jpg?sign=1739128777-YIsJzrNaFZVqS2PPmP1hZr9tbWx9dMjx-0-9f5a397997342779b62f10f8c7cdf561)
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/38_04.jpg?sign=1739128777-lSwQ0HecYtP5Lj7VAxcEoJwnz8vt7I7F-0-a6111d867d7214cc83e2024f5f6cf4f4)
图1-46 发现注入点
这个时候利用SQL注入去拖库会发现库里什么都没有。利用SSTI漏洞的原理就是在注入点处,Web程序将查询到的内容再次引入具有SSTI漏洞的代码。下面我们进行SSTI的测试(这里可以使用十六进制编码),如图1-47所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/39_01.jpg?sign=1739128777-Kr4ioIL1SeHCksAL7Qx8LNlbePDCM6cc-0-f8a0ed36fcf748d3619151bbd6814726)
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/39_02.jpg?sign=1739128777-JEyW2tSw9jVZLG9vWDUsAjqPFpmXO6rk-0-92c0ca6010009aa87750fe536db109e3)
图1-47 打印出配置信息
接下来就是常规的SSTI获取服务器权限,代码如下,效果如图1-48所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/39_03.jpg?sign=1739128777-KOq3Wncx7ZxLuEhQGXRqh3jXGEty8Y4p-0-af3bc1a07753a2a38ed222669d341e85)
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/39_04.jpg?sign=1739128777-XbH3bGG6kUGBYCU3kdI2Voa467f2QS2W-0-bc5792d65609f0902a35c7000bbf6db2)
图1-48 获取flag
上述代码等同于如下代码。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/39_05.jpg?sign=1739128777-jUPBL3XVZvkw7aYuDxmpUNX5taEo7WeK-0-543cf0c5c0575b338c306fd861c7469a)
以2018-网鼎杯-Fakebook题目为例,本题的原理和上一题基本相同,都是先将可控点的值设为恶意代码,然后由Web程序带入另一段有漏洞的代码中实现利用。可以理解为SQL注入起到的只是控制变量的作用。该题目首先具有源码泄露,如图1-49所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/40_01.jpg?sign=1739128777-uY5LxgXuBP1ktSIIr9oGNd8Ja3PW9FYT-0-e6ebf4b2406db812e565d1341be792a4)
图1-49 备份文件中得到源码
在注册界面输入的blog字段经过了isValidBlog()函数的过滤。由于get()函数存在SSRF漏洞,因此直接在注册界面输入file://var/www/html/flag.php就能拿到flag。
这时我们注册一个账号进入,如图1-50所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/40_02.jpg?sign=1739128777-yBbqsH625HtjGpzucRhAoyW9VqHjEQbx-0-7bebf85fc1b2371ebb5d91d90ad05011)
图1-50 注册用户登录
使用admin账号登录后发现URL里面有参数no,尝试注入、爆库,具体操作不再赘述,直接给出最终获取数据的Payload。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/41_01.jpg?sign=1739128777-9gIOV5WW15MFhRVNHnga5b0mLRwGHskY-0-58b929d966818af956022b28a5ad87be)
获取数据如图1-51所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/41_02.jpg?sign=1739128777-hSGEoJrJHn4NM0yBOMB5ZGFhlzQocU9y-0-f65c5ca9f0f49bba42aabc25757dd68b)
图1-51 获取数据
data数据段是一个序列化串,程序正常应该是从data字段中取出序列化串,然后进行反序列化,最终把信息展示给我们。我们在data字段中将blog的值修改为file:///var/www/html/flag.php,即可触发SSRF漏洞并获取flag,代码如下。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/41_03.jpg?sign=1739128777-t7YGsLfmLOL6Oaj2OorXLyU4Kv3wERvW-0-eb3f5313d33456ab3e8d160d370afbfa)
运行结果如图1-52所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/41_04.jpg?sign=1739128777-GpclJHpyNH8KwSMiGPiJpBDbBQxJHduT-0-de9ccf2f4e80368e5c0c460bb2aabefb)
图1-52 获取flag
最后进行Base64解码即可。
本题还有一种非预期解法,因为出题人忘记对load_file函数进行过滤,导致我们可以直接任意读取文件,如图1-53所示,代码如下。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/42_01.jpg?sign=1739128777-qL8DAuLTjROlqV7Y4kGu1Dh8Qq7whBqz-0-69dc85af75898af9fee102149211e00c)
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/42_02.jpg?sign=1739128777-nYYE1qCpTOP59K9s31QlWbXrHH8AjBmg-0-31b50bb9e0b9300d26b89e316cf05620)
图1-53 用非预期解法获取flag