[PYTHON] CTF beginner tried to build a problem server (web) [Problem]

Introduction

Do you know CTF (Capture The Flag)? Through CTF, you can learn while experiencing security issues. I thought I would try to explain the problem while creating a vulnerable server by myself. I created a server for CTF's rudimentary problems.

important point

Due to its nature, the server is vulnerable. Please do not implement the content of this article as it is in a production environment.

Premise

What is CTF (Capture The Flag)?

A competition to find hidden flags in problems and earn points. Questions will be asked from various problems related to computer security. This time, we will focus on the field of the Web regarding vulnerabilities in Web applications.

Technology selection

Rules on this issue server

--The format of the flag is myctf {flag}. --Three flags are hidden in the server.

In other words, there are 3 data in the form of myctf {flag} on this web system, so please find it.

Build a server

Docker Network Create a network between containers with docker network.

$ docker network create ctf-network

Docker Compose

docker-compose.yml


version: '3.3'
services:
  app-python:
    container_name: app-python
    build:
      context: ./python
      dockerfile: Dockerfile
    tty: true
    volumes:
      - ${PWD}/python/src:/app
    ports:
      - "80:8000"
    networks:
      - ctf-network    
  db1:
    container_name: mysql
    build:
      context: ./mysql
      dockerfile: Dockerfile
    environment:
      - MYSQL_USER=user
      - MYSQL_PASSWORD=password
      - MYSQL_ROOT_PASSWORD=password
    volumes:
      - ./mysql/mysql_conf:/etc/mysql/conf.d
      - ./mysql/initdb.d:/docker-entrypoint-initdb.d      
    networks:
      - ctf-network
networks:
  ctf-network:

Please change user and password appropriately.

MySQL SQLite seems to be affordable and often used in CTF, but since it is built using Docker, I chose MySQL.

DockerFile

mysql/Dockerfile


FROM mysql:8.0
ADD ./ctf/flag.md /var/ctf/flag.md
RUN mkdir /var/log/mysql
RUN chown mysql:adm /var/log/mysql

File where the flag is described

Embed the flag in /var/ctf/flag.md. If solved in order, this will be the last flag.

mysql/ctf/flag.md


## flag.md
myctf{mission_complete}

setting file

Add a MySQL configuration file.

mysql/mysql_conf/custom.cnf


[mysqld]
default_authentication_plugin=mysql_native_password
character-set-server=utf8
collation-server=utf8_general_ci
general_log=ON
general_log_file=/var/log/mysql/query.log
secure-file-priv = ""

[client]
default-character-set=utf8

Add the secure-file-priv setting to access the file.

Database initialization SQL file

sql:mysql/initdb.d/init.sql


SET CHARSET UTF8;

DROP DATABASE IF EXISTS ctf_db;
CREATE DATABASE ctf_db;
USE ctf_db;
DROP TABLE IF EXISTS users;
 
CREATE TABLE users (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    first_name VARCHAR(30) NOT NULL,
    last_name VARCHAR(30) NOT NULL,
    job VARCHAR(30) NOT NULL,
    delete_flag BOOLEAN NOT NULL DEFAULT FALSE
)DEFAULT CHARACTER SET=utf8;
 
INSERT INTO users (first_name, last_name, job) 
    VALUES 
    ("Taro", "Yamada", "Server-side engineer"),
    ("Jiro", "Suzuki", "Front-end engineer"),
    ("Saburo", "Tanaka", "Infrastructure engineer"),
    ("Hanako", "Sato", "designer");
INSERT INTO users (first_name, last_name, job, delete_flag)
    VALUES ("Ichiro", "Watanabe", "myctf{scf_sql_injection_flag}", TRUE); /*1st flag(Same table) */

DROP TABLE IF EXISTS flag;

CREATE TABLE flag (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    flag VARCHAR(60) NOT NULL,
    create_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    update_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)DEFAULT CHARACTER SET=utf8;

INSERT INTO flag (flag)
    VALUES ("myctf{next_flag_[/var/ctf/flag.md]}"); /*Second flag(Another table) */

Two flags are embedded in the Database. The first flag is that the users table is a logical delete table using delete_flag, which is embedded in the data that is supposed to be deleted. The second flag is embedded in the flag table, which is not referenced on this system.

Python

PHP is mainly used for CTF web problems, but since the backend environment at work is Python, I implemented it in Python. This was sober and difficult. (I made it from the PHP system first) I feel that Python is often used in actual CTF, such as automated scripts for flag acquisition.

When creating a web application with Python, it will be difficult if you do not use frameworks such as Django and Flask, but in order to create vulnerabilities, I will make as much as possible without relying on frameworks.

DockerFile

python/Dockerfile


FROM python:3.8
WORKDIR /app
CMD bash -c "pip install -r ./requirements.txt && python app.py"
EXPOSE 8000

Requirements Files

Some use external libraries. Describe the Lyle Rally to be installed in Requirements Files.

python/src/requirements.txt


Jinja2~=2.10
PyMySQL~=0.9

I had a hard time coding the HTML syntax in python, so I use Jinja2 as the template engine.

Executable file

python/src/app.py


import socketserver
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import urlparse, parse_qs

import pymysql.cursors
from jinja2 import Template, Environment, FileSystemLoader

PORT = 8000

class MyHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        conn = pymysql.connect(host='mysql',
                    user='root',
                    password='password',
                    db='ctf_db',
                    charset='utf8',
                    autocommit=True,
                    cursorclass=pymysql.cursors.DictCursor)
        try:
            url = urlparse(self.path)

            if url.path == '/':
                params = parse_qs(url.query)
                query = params.get('q', [''])[0]
                
                with conn.cursor() as cursor:
                    sql = f"SELECT * FROM users WHERE delete_flag=FALSE AND job LIKE '%{query}%';"
                    cursor.execute(sql)
                    users = cursor.fetchall()

                env = Environment(loader=FileSystemLoader('.'))
                template = env.get_template('index.html')
                
                data = {
                    'query': query,
                    'users': users
                }
                disp_text = template.render(data)

                self.send_response(200)
                self.send_header('Content-type', 'text/html')
                self.end_headers()
                
                self.wfile.write(disp_text.encode('utf-8'))
            else:
                self.send_response(404)
                self.send_header('Content-type', 'text/html')
                self.end_headers()
        except Exception as e:
            print(e)

            self.send_response(500)
            self.send_header('Content-type', 'text/html')
            self.end_headers()

            self.wfile.write(str(e).encode('utf-8'))
        finally:
            conn.close()

with socketserver.TCPServer(("", PORT), MyHandler) as httpd:
    print("serving at port", PORT)
    httpd.serve_forever()

Please correct user and password to the values changed by Docker Compose. In the generation of SQL statement, the judgment of delete_flag = FALSE is included because it is a logical deletion.

jinja2 template file

python/src/index.html


<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>CTF experience</title>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
</head>
<body>
  <div class="container">
    <form class="form-inline my-3">
      <div class="form-group mb-2">
        <input type="text" name="q" class="form-control" placeholder="Job type search" value="{{ query }}">
      </div>
      <button type="submit" class="btn btn-primary mb-2 mx-sm-4">Search</button>
    </form>
    {% if query != '' %}
      <p><span class="text-danger">{{ query }}</span>Search results</p>
    {% endif %}

    <table class="table table-bordered">
      <thead>
        <tr>
          <th scope="col">ID</th>
          <th scope="col">Surname</th>
          <th scope="col">Name</th>
          <th scope="col">Occupation</th>
        </tr>
      </thead>
      <tbody>
        {% for user in users %}
          <tr>
            <td>{{ user.id }}</td>
            <td>{{ user.last_name }}</td>
            <td>{{ user.first_name }}</td>
            <td>{{ user.job }}</td>
          </tr>  
        {% endfor %}
      </tbody>
    </table>
  </div>
</body>
</html>

Start and check

This is the structure of the directory.

├─ docker-compose.yml
├─ mysql
│   ├─ Dockerfile
│   ├─ ctf
│   │   └─ flag.md
│   ├─ initdb.d
│   │   └─ init.sql
│   └─ mysql_conf
│       └─ custom.cnf
└─ python
    ├─ Dockerfile
    └─ src
        ├─ app.py
        ├─ index.html
        └─ requirements.txt

Execute

$ docker-compose up -d

Once the container is up, access http: // localhost from your web browser.

2019-12-04 12.06.27 localhost e3de80904c2e.png

You should see a page that looks like the image.

Enter "Engineer" in the job search text box and click the "Search" button.

2019-12-04 12.06.52 localhost c4217ceed7b3.png

It should have been searched.

Other

This time it's just a SQL injection issue, There are also classic web-based cross-site scripting and many other vulnerabilities. Rather, it is full of vulnerabilities, and the problem-solving side may not know what to start with. If I feel like it, I'll try to create a cross-site scripting problem.

Finally

Security study session may be a "crime related to fraudulent command electromagnetic records" Although it was sometimes canceled (http://ozuma.sakura.ne.jp/sumida/2019/03/15/77/), This article itself, as an explanation of the vulnerability, I pray that you will not be a "guilty of fraudulent command electromagnetic records."

The completed repository is here The PHP version repository that was created in parallel is here The repository created with go language + PostgreSQL is here Since the go language is a statically typed language, it is difficult to guess the table definition because an error will occur if you UNION with the wrong type.

For the answer method of this question, see CTF beginners tried to build a problem server (web) [Answer].

Recommended Posts

CTF beginner tried to build a problem server (web) [Problem]
Build a web server on your Chromebook
I tried to make a Web API
I tried to build a super-resolution method / ESPCN
I tried to build a super-resolution method / SRCNN ①
I tried to build a super-resolution method / SRCNN ③
I tried to build a super-resolution method / SRCNN ②
Go beginner tried to create a cloud native web application using Datastore / GAE
[Beginner] [Python / Django] A fledgling web engineer tried a Django tutorial-Part 1-
[Beginner] [Python / Django] A fledgling web engineer tried a Django tutorial-Part 2-
[Beginner] [Python / Django] A fledgling web engineer tried a Django tutorial-Part 0-
[Beginner] [Python / Django] A fledgling web engineer tried a Django tutorial-Part 5-
[Part 2] Let's build a web server on EC2 Linux
[Go + Gin] I tried to build a Docker environment
[Beginner] [Python / Django] A fledgling web engineer tried a Django tutorial-Part 4-
[Beginner] [Python / Django] A fledgling web engineer tried a Django tutorial-Part 3-
Source compile Apache2.4 (httpd 2.4.43) + PHP7.4 on Linux to build a Web server --3 MySQL 8.0 introduction
Memo A beginner tried to build a Java environment and Japaneseize it on Ubuntu 18.04.2 LTS.
Build a web API server at explosive speed using hug
I tried to solve a combination optimization problem with Qiskit
Build a speed of light web API server with Falcon
[Introduction to AWS] A memorandum of building a web server on AWS
A python beginner tried to intern at an IT company
I tried to create a server environment that runs on Windows 10
How to build a NEM (current version) node (NIS1: NEM Infrastructure Server)
I made a web server with Raspberry Pi to watch anime
Build a web application with Django
I tried to build a SATA software RAID configuration that boots the OS on Ubuntu Server
I tried to communicate with a remote server by Socket communication with Python.
A beginner of machine learning tried to predict Arima Kinen with python
I tried to build a Mac Python development environment with pythonz + direnv
Start a web server using Bottle and Flask (I also tried using Apache)
I tried to create a linebot (implementation)
Build a Pypi cache server on QNAP
Want to solve a simple classification problem?
How to build my own Linux server
Easily build a DNS server using Twisted
How to build a sphinx translation environment
I tried to create a linebot (preparation)
Build a simple WebDAV server on Linux
I want to build a Python environment
Build a Samba server on Arch Linux
[Django-Extensions] Web development beginners tried to summarize Django-Extensions
I tried benchmarking a web application framework
The programmer tried hard to build a server to overcome it, saying that infrastructure seems to be difficult. WebAP server edition
A python beginner tried to intern at an IT company [Day 2 chatbot survey]
Atcoder Beginner Contest A, B Input summary Python that tends to be a problem
A python beginner tried to intern at an IT company [Day 1 development process]
A programming beginner tried to find out the execution time of sorting etc.
Source compile Apache2.4 + PHP7.4 with Raspberry Pi and build a Web server --2 PHP introduction
Source compile Apache2.4 + PHP7.4 with Raspberry Pi and build a Web server ―― 1. Apache introduction
Source compile Apache2.4 (httpd 2.4.43) + PHP7.4 on Linux and build a Web server ―― 1. Apache introduction
A machine learning beginner tried to create a sheltie judgment AI in one day
[Python] How to create a local web server environment with SimpleHTTPServer and CGIHTTPServer
Source compile Apache2.4 (httpd 2.4.43) + PHP7.4 on Linux and build a Web server --2 PHP introduction
Send a message from Slack to a Python server
Build a local server with a single command [Mac]
I tried web scraping to analyze the lyrics.
Try to calculate a statistical problem in Python
How to open a web browser from python
Book updated: Evolving into a "decent web server"