This is intended as a public reference of steps I used to get OWASP Juice Shop running with CTFd. Thanks so much to all the open source contributers that make this process both possible and straightforward.
Juice Shop does have a scoreboard built in, but CTFd allows support for teams, and better hints.
Installation Steps
Installing and running Juice Shop via docker image
In order to make sure that your CTF flags are the same in Juice Shop as CTFd, make sure to set CTF_KEY. For use in CTFd, I’d recommend putting it in a URL on Pastebin/Github Gist/whatever. I put mine at https://pastebin.com/raw/vc5av96m.
You can pull the project from their docker image:
docker pull bkimminich/juice-shopThen, run the docker image:
docker run -e "CTF_KEY=Tfs3GfbiwYxy1C4jHEYo8wV4xqoqeJSQ7YW8CvCm" -e "NODE_ENV=ctf" -p 3000:3000 bkimminich/juice-shopNote that you may want to consider running ctfd as a daemon, so it persists in the background (you can view the logs of the instance with docker logs $INSTANCE_HASH where INSTANCE_HASH is the output from the command below):
docker run -d -e "CTF_KEY=Tfs3GfbiwYxy1C4jHEYo8wV4xqoqeJSQ7YW8CvCm" -e "NODE_ENV=ctf" -p 3000:3000 bkimminich/juice-shopGreat! Now we should be able to see the juice shop webpage when we navigate to http://localhost:3000:
Installing juice-shop-ctf-cli
Assuming you have npm installed, you can run:
sudo npm install -g juice-shop-ctf-clito globally install the CLI for Juice Shop.
The docker container section has more information on ways to link your configurations to the juice shop instance.
In our case, we should navigate to a directory we’re comfortable storing new files in:
cd YOUR_PATHThen, you can create your nkcyberconfig.yml based on the example configuration file:
ctfFramework: CTFdjuiceShopUrl: http://localhost:3000ctfKey: https://pastebin.com/raw/vc5av96m # can also be URL instead of keyinsertHints: free # we make hints free for beginner CTFsinsertHintUrls: free # optional for FBCTF; "paid" handled as "free" for CTFdinsertHintSnippets: free # optional for FBCTF; "paid" handled as "free" for CTFdBash command to generate `nkcyberconfig.yml`
cat << 'EOF' > nkcyberconfig.ymlctfFramework: CTFdjuiceShopUrl: http://localhost:3000ctfKey: https://pastebin.com/raw/vc5av96m # can also be URL instead of keyinsertHints: free # we make hints free for beginner CTFsinsertHintUrls: free # optional for FBCTF; "paid" handled as "free" for CTFdinsertHintSnippets: free # optional for FBCTF; "paid" handled as "free" for CTFdEOF(ensure that juice-shop is running at this time)
juice-shop-ctf --config nkcyberconfig.yml --output challenges.csvYou should see:
Generate OWASP Juice Shop challenge archive for setting up CTFd, FBCTF or RootTheBox score server
Backup archive written to YOUR_PATH/challenges.csv
After the import you will have to set up the CTF name and administrator credentials again!
For a step-by-step guide to import the ZIP-archive into CTFd, please refer tohttps://pwning.owasp-juice.shop/part1/ctf.html#running-ctfd$ file challenges.csvchallenges.csv: CSV textNote that the url it gives you currently returns a 404.

However, the instructions can still be found on the Internet Archive.
Unfortunately, there are some bugs with the current import version (see #1988 and #131). As such, we can’t import a full zip file from juice-shop-ctf-cli, and can only import specific elements by .csv file.
Filtering these challenges
By default, there are quite a lot of challenges to get through.
Thus, it’s worth filtering them down for this Friday.
I wrote this Python script to filter everything down by topic:
"""This script takes challenges.csv and filters it into filtered.csv"""
import csv # csv is a python built-in; no installation required
# choose topics and challenge names to filter fortopics = ("XSS")selected_challenge_names = ("Score Board")
with open('challenges.csv', newline='') as input_file: with open('filtered.csv', 'w', newline='') as output_file: csv_reader = csv.reader(input_file, delimiter=',', quotechar='"') csv_writer = csv.writer(output_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) # copy header from challenges header = next(csv_reader) csv_writer.writerow(header) # filter rows for row in csv_reader: if row[0] in selected_challenge_names or row[2] in topics: csv_writer.writerow(row)Installing and running CTFd
We can pull CTFd from their docker image:
docker pull ctfd/ctfdThen, we can run CTFd:
docker run -p 8000:8000 -it ctfd/ctfdNote that you may want to consider running ctfd as a daemon, so it persists in the background:
docker run -d -p 8000:8000 -it ctfd/ctfdOther docker parameters to consider:
- You only need
-itfor an interactive terminal. Consider removing it if you’re not running interactively. - You might want to add
--restart alwaysor--restart unless-stoppedto ensure that the container restarts if anything goes wrong. (Read more)
Now, we should see the “Setup” page for CTFd.

Make sure to enter valid data for all of this. Despite what other sources may claim, we’re not going to be overwriting this.
After you get it set up, go to http://localhost:8000/admin/config to load the nkcyberconfig.yml as a backup:

Use “Import CSV” to import the generated filtered.csv from above.
This will give us all of the challenges for our teams to work through:

To resolve the issues with importing into CTFd, we need to stop using the docker container’s default SQLite, and use something like MySQL instead. From the documentation, it should be as simple as:
# Install Docker ...# Install Docker Compose ...git clone https://github.com/CTFd/CTFd.githead -c 64 /dev/urandom > .ctfd_secret_keydocker compose upYou should now be able to view CTFd, and upload previous .zip backups.
The End
From here, you should be able to submit flags from Juice Shop into CTFd.
Example:
Solve a challenge in Juice Shop:

Then go to CTFd:

Enter the Flag:

Get the score:

Troubleshooting
If you copy and paste the flag, and it says that the flag is incorrect, you likely need to sync the CTF_KEY between CTFd and Juice Shop.
If you hit submit and nothing happens, you likely need to log in.
Hosting multple instances
Juice Shop isn’t intended to have multiple people on one instance.
Multi Juicer exists to solve this issue, but I think it’s easier for our setup to host a bunch of VMs instead.
Setup needed
- A bunch (e.g. 20) of VMs set up for each user, set up to start an instance of Juice Shop on startup.
- 1 instance of CTFd running for everyone
To install Virtual Machines onto Ubuntu Machines
If you don’t have your Proxmox cluster ready in time, you can install all of the images onto Ubuntu machines using the following script. It will download VirtualBox onto the machine, and add Juice Shop as a virtual machine.
#!/bin/bash
set -e
install_path="/tmp/install_juice"mkdir -p "$install_path"cd "$install_path"echo "installing Virtual Box & Juice Shop VM"sudo apt-get update -ysudo apt-get install virtualbox -yecho "downloading..."wget "YOUR_ONEDRIVE_SHARE_LINK&download=1" -O JuiceShop.ovaecho "importing..."vboxmanage import JuiceShop.ova
echo "Done!"dateIf you’re hosting the .ova file on OneDrive, then ensure you’re using &download=1 is appended to the end of your share link for a direct download.
Setting up HTTPS on Digital Ocean for CTFd
Imagine, because your Proxmox server wasn’t up in time, that you had to host CTFd on a cheap Digital Ocean Droplet.
To ensure CTFd has an authenticated connection, and all your users get the little padlock that makes the site feel official, you’re going to need to add HTTPS to CTFd.
Following this tutorial worked perfectly for me. I have no notes.