Skip to content

Commit c32880d

Browse files
authored
Add initial implementation (#1)
1 parent de582a3 commit c32880d

File tree

8 files changed

+207
-1
lines changed

8 files changed

+207
-1
lines changed

README.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,27 @@
1-
# flask-webgoat
1+
# flask-webgoat
2+
3+
flask-webgoat is a deliberately-vulnerable application written with the Flask
4+
web framework.
5+
6+
```
7+
(_(
8+
/_/'_____/)
9+
" | |
10+
|""""""|
11+
███████╗██╗ █████╗ ███████╗██╗ ██╗ ██╗ ██╗███████╗██████╗ ██████╗ ██████╗ █████╗ ████████╗
12+
██╔════╝██║ ██╔══██╗██╔════╝██║ ██╔╝ ██║ ██║██╔════╝██╔══██╗██╔════╝ ██╔═══██╗██╔══██╗╚══██╔══╝
13+
█████╗ ██║ ███████║███████╗█████╔╝ ██║ █╗ ██║█████╗ ██████╔╝██║ ███╗██║ ██║███████║ ██║
14+
██╔══╝ ██║ ██╔══██║╚════██║██╔═██╗ ██║███╗██║██╔══╝ ██╔══██╗██║ ██║██║ ██║██╔══██║ ██║
15+
██║ ███████╗██║ ██║███████║██║ ██╗ ╚███╔███╔╝███████╗██████╔╝╚██████╔╝╚██████╔╝██║ ██║ ██║
16+
╚═╝ ╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝ ╚══════╝╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝
17+
```
18+
19+
### Run
20+
21+
```
22+
python -m venv .venv
23+
. .venv/bin/activate
24+
pip install -r requirements.txt
25+
FLASK_APP=run.py flask run
26+
```
27+

flask_webgoat/__init__.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import os
2+
import sqlite3
3+
from pathlib import Path
4+
5+
from flask import Flask, g
6+
7+
8+
def create_app():
9+
app = Flask(__name__)
10+
app.secret_key = 'aeZ1iwoh2ree2mo0Eereireong4baitixaixu5Ee'
11+
12+
db_filename = 'database.db'
13+
db_path = Path(db_filename)
14+
if db_path.exists():
15+
db_path.unlink()
16+
17+
conn = sqlite3.connect(db_filename)
18+
create_table_query = """CREATE TABLE IF NOT EXISTS user
19+
(id INTEGER PRIMARY KEY, username TEXT, password TEXT, access_level INTEGER)"""
20+
conn.execute(create_table_query)
21+
22+
insert_admin_query = """INSERT INTO user (id, username, password, access_level)
23+
VALUES (1, 'admin', 'maximumentropy', 0)"""
24+
conn.execute(insert_admin_query)
25+
conn.commit()
26+
conn.close()
27+
28+
def query_db(query, args = (), one=False, commit=False):
29+
with sqlite3.connect(db_filename) as conn:
30+
cur = conn.execute(query, args)
31+
if commit:
32+
conn.commit()
33+
return cur.fetchone() if one else cur.fetchall()
34+
app.query_db = query_db
35+
36+
with app.app_context():
37+
from . import status
38+
from . import auth
39+
from . import users
40+
from . import actions
41+
app.register_blueprint(status.bp)
42+
app.register_blueprint(auth.bp)
43+
app.register_blueprint(users.bp)
44+
app.register_blueprint(actions.bp)
45+
return app
46+

flask_webgoat/actions.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from pathlib import Path
2+
import subprocess
3+
import uuid
4+
from flask import request
5+
6+
from flask import (
7+
Blueprint, jsonify, request, jsonify, session
8+
)
9+
from werkzeug.security import check_password_hash
10+
from flask import current_app as app
11+
12+
bp = Blueprint('actions', __name__)
13+
14+
15+
@bp.route('/message', methods=['POST'])
16+
def log_entry():
17+
auth = session.get('user_info', None)
18+
if auth is None:
19+
return jsonify({'error': 'no auth found in session'})
20+
access_level = auth[2]
21+
if access_level > 2:
22+
return jsonify({'error': 'access level < 2 is required for this action'})
23+
filename_param = request.form.get('filename')
24+
if filename_param is None:
25+
return jsonify({'error': 'filename parameter is required'})
26+
text_param = request.form.get('text')
27+
if text_param is None:
28+
return jsonify({'error': 'text parameter is required'})
29+
30+
user_id = auth[0]
31+
user_dir = Path("data/" + str(user_id))
32+
if not user_dir.exists():
33+
user_dir.mkdir()
34+
35+
filename = filename_param + ".txt"
36+
path = user_dir / filename
37+
with path.open("w", encoding ="utf-8") as f:
38+
f.write(text_param)
39+
return jsonify({'success': True})
40+
41+
42+
@bp.route('/grep_processes')
43+
def grep_processes():
44+
name = request.args.get('name')
45+
res = subprocess.run(["ps aux | grep " + name + " | awk '{print $11}'"], shell=True, capture_output=True)
46+
if res.stdout is None:
47+
return jsonify({'error': 'no stdout returned'})
48+
out = res.stdout.decode("utf-8")
49+
names = out.split('\n')
50+
return jsonify({'success': True, 'names': names})
51+

flask_webgoat/auth.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from flask import (
2+
Blueprint, jsonify, request, jsonify, session
3+
)
4+
from werkzeug.security import check_password_hash
5+
from flask import current_app as app
6+
7+
bp = Blueprint('auth', __name__)
8+
9+
10+
@bp.route('/login', methods=['POST'])
11+
def login():
12+
username = request.form.get('username')
13+
password = request.form.get('password')
14+
if username is None or password is None:
15+
return jsonify({'error': 'username and password parameter have to be provided'}), 400
16+
17+
query = "SELECT id, username, access_level FROM user WHERE username = '%s' AND password = '%s'" % (username, password)
18+
result = app.query_db(query, [], True)
19+
if result is None:
20+
return jsonify({'bad_login': True}), 400
21+
session['user_info'] = (result[0], result[1], result[2])
22+
return jsonify({'success': True})
23+

flask_webgoat/status.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from flask import (
2+
Blueprint, jsonify
3+
)
4+
5+
bp = Blueprint('status', __name__)
6+
7+
@bp.route('/status')
8+
def status():
9+
return jsonify({'success': True})
10+
11+
12+
@bp.route('/ping')
13+
def ping():
14+
return jsonify({'success': True})

flask_webgoat/users.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from flask import (
2+
Blueprint, jsonify, request, jsonify, session
3+
)
4+
from werkzeug.security import check_password_hash
5+
from flask import current_app as app
6+
7+
bp = Blueprint('users', __name__)
8+
9+
10+
@bp.route('/create_user', methods=['POST'])
11+
def create_user():
12+
auth = session.get('user_info', None)
13+
if auth is None:
14+
return jsonify({'error': 'no auth found in session'})
15+
16+
access_level = auth[2]
17+
if access_level != 0:
18+
return jsonify({'error': 'access level of 0 is required for this action'})
19+
username = request.form.get('username')
20+
password = request.form.get('password')
21+
access_level = request.form.get('access_level')
22+
if username is None or password is None or access_level is None:
23+
return jsonify({'error': 'username, password and access_level parameters have to be provided'}), 400
24+
if len(password) < 3:
25+
return jsonify({'error': 'the password needs to be at least 3 characters long'}), 402
26+
27+
query = "INSERT INTO user (username, password, access_level) VALUES ('%s', '%s', %d)" % (username, password, int(access_level))
28+
29+
try:
30+
app.query_db(query, [], False, True)
31+
return jsonify({'success': True})
32+
except sqlite3.Error as err:
33+
return jsonify({'error': 'could not create user:' + err})
34+

requirements.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
click==7.1.2
2+
Flask==1.1.2
3+
itsdangerous==1.1.0
4+
Jinja2==2.11.3
5+
MarkupSafe==1.1.1
6+
Werkzeug==1.0.1

run.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from flask_webgoat import create_app
2+
3+
app = create_app()
4+
5+
if __name__ == '__main__':
6+
app.run()

0 commit comments

Comments
 (0)