diff --git a/Deserial/.gitignore b/Deserial/.gitignore new file mode 100644 index 0000000..9b5e2e8 --- /dev/null +++ b/Deserial/.gitignore @@ -0,0 +1,2 @@ +*~ +__pycache__ diff --git a/Deserial/NodeChallenge/docker-compose.yaml b/Deserial/NodeChallenge/docker-compose.yaml new file mode 100644 index 0000000..5ec25e2 --- /dev/null +++ b/Deserial/NodeChallenge/docker-compose.yaml @@ -0,0 +1,9 @@ +version: "3.7" +services: + node: + build: + context: webapp + ports: + - "5000:3000" + expose: + - 5000 diff --git a/Deserial/NodeChallenge/webapp/Dockerfile b/Deserial/NodeChallenge/webapp/Dockerfile new file mode 100644 index 0000000..c7bcd50 --- /dev/null +++ b/Deserial/NodeChallenge/webapp/Dockerfile @@ -0,0 +1,16 @@ +FROM node:buster-slim + +WORKDIR /opt/app + +#Requirements +ADD package.json /opt/app +ADD server.js /opt/app + +RUN npm install + +EXPOSE 3000 + +RUN apt-get update && apt-get install -y ncat +ADD serverflag.txt / + +CMD ["node", "server.js"] \ No newline at end of file diff --git a/Deserial/NodeChallenge/webapp/package.json b/Deserial/NodeChallenge/webapp/package.json new file mode 100644 index 0000000..2ef2d6e --- /dev/null +++ b/Deserial/NodeChallenge/webapp/package.json @@ -0,0 +1,16 @@ +{ + "name": "Vulnerable_Deserialisation_App", + "version": "1.0.0", + "description": "Node.js on Docker", + "author": "First Last ", + "main": "server.js", + "scripts": { + "start": "node server.js" + }, + "dependencies": { + "express": "^4.16.1", + "cookie-parser": "latest", + "escape-html": "latest", + "node-serialize": "latest" + } +} diff --git a/Deserial/NodeChallenge/webapp/server.js b/Deserial/NodeChallenge/webapp/server.js new file mode 100644 index 0000000..88d0dcb --- /dev/null +++ b/Deserial/NodeChallenge/webapp/server.js @@ -0,0 +1,25 @@ +var express = require('express'); +var cookieParser = require('cookie-parser'); +var escape = require('escape-html'); +var serialize = require('node-serialize'); +var app = express(); +app.use(cookieParser()) + +app.get('/', function(req, res) { + if (req.cookies.profile) { + var str = new Buffer(req.cookies.profile, 'base64').toString(); + var obj = serialize.unserialize(str); + if (obj.username) { + res.send("Hello " + escape(obj.username)); + } + } else { + res.cookie('profile', "eyJ1c2VybmFtZSI6IkFkaXR5YSIsImNvdW50cnkiOiJpbmRpYSIsImNpdHkiOiJEZWxoaSJ9", { + maxAge: 900000, + httpOnly: true + }); + } + res.send("Hello World"); +}); +app.listen(3000); +console.log("Listening on port 3000..."); + diff --git a/Deserial/NodeChallenge/webapp/serverflag.txt b/Deserial/NodeChallenge/webapp/serverflag.txt new file mode 100644 index 0000000..3088637 --- /dev/null +++ b/Deserial/NodeChallenge/webapp/serverflag.txt @@ -0,0 +1 @@ +245{NodeRCEExample} diff --git a/Deserial/PickleDemo/docker-compose.yaml b/Deserial/PickleDemo/docker-compose.yaml new file mode 100644 index 0000000..ccea637 --- /dev/null +++ b/Deserial/PickleDemo/docker-compose.yaml @@ -0,0 +1,12 @@ +version: "3.7" +services: + flask: + build: + context: webapp + ports: + - "5000:5000" + expose: + - 5000 + environment: + - FLASK_ENV=development + - FLASK_APP=/opt/webapp/app.py diff --git a/Deserial/PickleDemo/webapp/Dockerfile b/Deserial/PickleDemo/webapp/Dockerfile new file mode 100644 index 0000000..f25bd47 --- /dev/null +++ b/Deserial/PickleDemo/webapp/Dockerfile @@ -0,0 +1,21 @@ +FROM cueh/flask + +USER root +#Netcat for the Shell +RUN apt-get update && apt-get install -y ncat + +WORKDIR /opt + +#Copy Files +ADD REQUIREMENTS.txt /opt + +#Install Requirements +RUN pip install -r REQUIREMENTS.txt + +ADD serverflag.txt / + +ADD app.py /opt/webapp/ +ADD templates/* /opt/webapp/templates/ + +CMD ["flask", "run", "--host=0.0.0.0"] + diff --git a/Deserial/PickleDemo/webapp/REQUIREMENTS.txt b/Deserial/PickleDemo/webapp/REQUIREMENTS.txt new file mode 100644 index 0000000..0b85942 --- /dev/null +++ b/Deserial/PickleDemo/webapp/REQUIREMENTS.txt @@ -0,0 +1,3 @@ +pyyaml +flask + diff --git a/Deserial/PickleDemo/webapp/app.py b/Deserial/PickleDemo/webapp/app.py new file mode 100644 index 0000000..ef22315 --- /dev/null +++ b/Deserial/PickleDemo/webapp/app.py @@ -0,0 +1,91 @@ +""" +Flask Based Rework of our app + +So much easier with a web interface +""" +import flask +from flask import request +import pickle + +class ShoppingItem: + def __init__(self, name, cost, number = 1): + self.name = name + self.cost = cost + self.number = number + +class ShoppingList: + def __init__(self): + self.shoppingList = [] + + def addItem(self, item): + self.shoppingList.append(item) + + def calcCost(self): + totalCost = 0 + for item in self.shoppingList: + totalCost += item.cost * item.number + + return totalCost + + +def createList(): + """Helper Function to create a list""" + theList = ShoppingList() + + item = ShoppingItem("foo widget", 100) + theList.addItem(item) + item = ShoppingItem("bar widget", 10, 5) + theList.addItem(item) + return theList + + +# ------------ AND THE APP ITSELF ----------- +app = flask.Flask(__name__) +app.theList = createList() + +@app.route('/') +def main(): + return flask.render_template('index.html', theList = app.theList) + +@app.route("/save") +def save(): + #We can save the basket to a file + with open("/opt/webapp/backup.pkl","wb") as fd: + out = pickle.dump(app.theList, fd) + #fd.write(out) + + return flask.send_file('backup.pkl', + mimetype='application/octet-stream', + attachment_filename='backup.pkl', + as_attachment=True) + + +@app.route("/load", methods=["GET","POST"]) +def load(): + message = None + if request.method == "POST": + print (request.files) + if 'uploadFile' in request.files: + + theFile = request.files['uploadFile'] + try: + data = pickle.load(theFile)#, Loader=yaml.Loader) + app.theList = data + message = "Upload Successful" + except Exception as ex: + message = "Error Loading List {0}".format(ex) + + + else: + message = "You must select a file to upload" + + + return flask.render_template('load.html', message=message) + +@app.route("/pay") +def pay(): + + totalCost = app.theList.calcCost() + + return flask.render_template("pay.html", cost=totalCost) + diff --git a/Deserial/PickleDemo/webapp/serverflag.txt b/Deserial/PickleDemo/webapp/serverflag.txt new file mode 100644 index 0000000..891e7f9 --- /dev/null +++ b/Deserial/PickleDemo/webapp/serverflag.txt @@ -0,0 +1 @@ +CUEH{"R0tten_P1ckLes"} diff --git a/Deserial/PickleDemo/webapp/templates/index.html b/Deserial/PickleDemo/webapp/templates/index.html new file mode 100644 index 0000000..9e2d9cf --- /dev/null +++ b/Deserial/PickleDemo/webapp/templates/index.html @@ -0,0 +1,59 @@ + + + + + + + The Dodgy Shopper + + + + + +
+

Dodgy PICKLE Shopper v2

+ +

Buy Widgets and Stuff

+ +

Shopping Basket

+ + + + + + + + + + + + {% for item in theList.shoppingList %} + + + + + + + {% endfor %} + + + + + + + +
ItemCostQuantityTotal Cost
{{item.name}}£{{item.cost}}{{item.number}}£{{ item.cost * item.number}}
TOTAL£{{theList.calcCost()}}
+ + + + Pay +
+ + diff --git a/Deserial/PickleDemo/webapp/templates/load.html b/Deserial/PickleDemo/webapp/templates/load.html new file mode 100644 index 0000000..525ba2d --- /dev/null +++ b/Deserial/PickleDemo/webapp/templates/load.html @@ -0,0 +1,38 @@ + + + + + + + The Dodgy Shopper + + + + + +
+ +

Dodgy PICKLE Shopper

+

Back to Home

+
+

Buy Widgets and Stuff

+ +

Load Saved Basket

+ +
+
+ + +
+ +
+ + {% if message %} +
{{message}}
+ {% endif %} +
+ + + + + diff --git a/Deserial/PickleDemo/webapp/templates/pay.html b/Deserial/PickleDemo/webapp/templates/pay.html new file mode 100644 index 0000000..d9f4386 --- /dev/null +++ b/Deserial/PickleDemo/webapp/templates/pay.html @@ -0,0 +1,44 @@ + + + + + + + The Dodgy Shopper + + + + + + +
+ +

Dodgy PICKLE Shopper

+

Back to Home

+
+ +

Buy Widgets and Stuff

+ +

PAY FOR STUFF

+ + {% if cost > 0 %} +

You Owe £{{ cost }}

+
+
+ + + +
+ +
+ + {% else %} +
You Win, Have a flag CUEH{M@nual_P1kl_Mods}
+ {% endif %} + +
+ + + + + diff --git a/Deserial/README.md b/Deserial/README.md new file mode 100644 index 0000000..abdb9cd --- /dev/null +++ b/Deserial/README.md @@ -0,0 +1,26 @@ +# Deserialisation Trainers + +Various Training / Demos for Insecure Deserialisation + +## YAML Demo + +This service is vulnerable to insecure deserialisation through PyYaml +and will let you try out the example given in the course materials. + +### Starting Stopping the service + +Start + +``` +$ cd YamlDemo +$ docker-compose up +``` + +Stop + +``` +$ cd YamlDemo +$ docker-compose down +``` + + diff --git a/Deserial/YamlDemo/docker-compose.yaml b/Deserial/YamlDemo/docker-compose.yaml new file mode 100644 index 0000000..ccea637 --- /dev/null +++ b/Deserial/YamlDemo/docker-compose.yaml @@ -0,0 +1,12 @@ +version: "3.7" +services: + flask: + build: + context: webapp + ports: + - "5000:5000" + expose: + - 5000 + environment: + - FLASK_ENV=development + - FLASK_APP=/opt/webapp/app.py diff --git a/Deserial/YamlDemo/webapp/Dockerfile b/Deserial/YamlDemo/webapp/Dockerfile new file mode 100644 index 0000000..f5a6357 --- /dev/null +++ b/Deserial/YamlDemo/webapp/Dockerfile @@ -0,0 +1,20 @@ +FROM cueh/flask + +USER root +#Netcat for the Shell +RUN apt-get update && apt-get install -y ncat + +WORKDIR /opt + +#Copy Files +ADD REQUIREMENTS.txt /opt + +#Install Requirements +RUN pip install -r REQUIREMENTS.txt + +ADD serverflag.txt / + +ADD app.py /opt/webapp/ +ADD templates/* /opt/webapp/templates/ + +CMD ["flask", "run", "--host=0.0.0.0"] diff --git a/Deserial/YamlDemo/webapp/REQUIREMENTS.txt b/Deserial/YamlDemo/webapp/REQUIREMENTS.txt new file mode 100644 index 0000000..cf7cb50 --- /dev/null +++ b/Deserial/YamlDemo/webapp/REQUIREMENTS.txt @@ -0,0 +1,3 @@ +pyyaml + + diff --git a/Deserial/YamlDemo/webapp/app.py b/Deserial/YamlDemo/webapp/app.py new file mode 100644 index 0000000..58c0e5e --- /dev/null +++ b/Deserial/YamlDemo/webapp/app.py @@ -0,0 +1,91 @@ +""" +Flask Based Rework of our app + +So much easier with a web interface +""" +import flask +import yaml +from flask import request + +class ShoppingItem: + def __init__(self, name, cost, number = 1): + self.name = name + self.cost = cost + self.number = number + +class ShoppingList: + def __init__(self): + self.shoppingList = [] + + def addItem(self, item): + self.shoppingList.append(item) + + def calcCost(self): + totalCost = 0 + for item in self.shoppingList: + totalCost += item.cost * item.number + + return totalCost + + +def createList(): + """Helper Function to create a list""" + theList = ShoppingList() + + item = ShoppingItem("foo widget", 100) + theList.addItem(item) + item = ShoppingItem("bar widget", 10, 5) + theList.addItem(item) + return theList + + +# ------------ AND THE APP ITSELF ----------- +app = flask.Flask(__name__) +app.theList = createList() + +@app.route('/') +def main(): + return flask.render_template('index.html', theList = app.theList) + +@app.route("/save") +def save(): + #We can save the basket to a file + with open("/opt/webapp/backup.yaml","w") as fd: + out = yaml.dump(app.theList) + fd.write(out) + + return flask.send_file('backup.yaml', + mimetype='text/yaml', + attachment_filename='backup.yaml', + as_attachment=True) + + +@app.route("/load", methods=["GET","POST"]) +def load(): + message = None + if request.method == "POST": + print (request.files) + if 'uploadFile' in request.files: + + theFile = request.files['uploadFile'] + try: + data = yaml.load(theFile, Loader=yaml.Loader) + app.theList = data + message = "Upload Successful" + except Exception as ex: + message = "Error Loading List {0}".format(ex) + + + else: + message = "You must select a file to upload" + + + return flask.render_template('load.html', message=message) + +@app.route("/pay") +def pay(): + + totalCost = app.theList.calcCost() + + return flask.render_template("pay.html", cost=totalCost) + diff --git a/Deserial/YamlDemo/webapp/serverflag.txt b/Deserial/YamlDemo/webapp/serverflag.txt new file mode 100644 index 0000000..cc4bf4d --- /dev/null +++ b/Deserial/YamlDemo/webapp/serverflag.txt @@ -0,0 +1 @@ +CUEH{Yam1_B4sed_Sh3lls} diff --git a/Deserial/YamlDemo/webapp/templates/index.html b/Deserial/YamlDemo/webapp/templates/index.html new file mode 100644 index 0000000..9b25b9a --- /dev/null +++ b/Deserial/YamlDemo/webapp/templates/index.html @@ -0,0 +1,59 @@ + + + + + + + The Dodgy Shopper + + + + + +
+

Dodgy YAML Shopper

+ +

Buy Widgets and Stuff

+ +

Shopping Basket

+ + + + + + + + + + + + {% for item in theList.shoppingList %} + + + + + + + {% endfor %} + + + + + + + +
ItemCostQuantityTotal Cost
{{item.name}}£{{item.cost}}{{item.number}}£{{ item.cost * item.number}}
TOTAL£{{theList.calcCost()}}
+ + + + Pay +
+ + diff --git a/Deserial/YamlDemo/webapp/templates/load.html b/Deserial/YamlDemo/webapp/templates/load.html new file mode 100644 index 0000000..fb3f8d6 --- /dev/null +++ b/Deserial/YamlDemo/webapp/templates/load.html @@ -0,0 +1,38 @@ + + + + + + + The Dodgy Shopper + + + + + +
+ +

Dodgy YAML Shopper

+

Back to Home

+
+

Buy Widgets and Stuff

+ +

Load Saved Basket

+ +
+
+ + +
+ +
+ + {% if message %} +
{{message}}
+ {% endif %} +
+ + + + + diff --git a/Deserial/YamlDemo/webapp/templates/pay.html b/Deserial/YamlDemo/webapp/templates/pay.html new file mode 100644 index 0000000..7e33afc --- /dev/null +++ b/Deserial/YamlDemo/webapp/templates/pay.html @@ -0,0 +1,44 @@ + + + + + + + The Dodgy Shopper + + + + + + +
+ +

Dodgy YAML Shopper

+

Back to Home

+
+ +

Buy Widgets and Stuff

+ +

PAY FOR STUFF

+ + {% if cost > 0 %} +

You Owe £{{ cost }}

+
+
+ + + +
+ +
+ + {% else %} +
You Win, Have a flag CUEH{YAML_1s_Fun}
+ {% endif %} + +
+ + + + +