DEV Community

Cover image for Let's Pretend to be Hackers
Adeyemi Adeleye
Adeyemi Adeleye

Posted on

Let's Pretend to be Hackers

In this article, we will pretend to do some of the things a hacker might do in trying to gain access to a network.

For this, we will run the following services in the network:

  1. Apache service running on port 80
  2. MySQL service running on port 3306
  3. Flask server on port 5000

We will run all these services on a single server using docker containers.
For this:

  1. Create a server with a public IP address on any cloud provider. For this, I used AWS
  2. Install docker and docker compose on the server. I used the script below for the installation.
_for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc;\
 do sudo apt-get remove $pkg; done

# Add Docker's official GPG key:
sudo apt update -y
sudo apt install ca-certificates curl -y
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update -y

sudo apt install docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin git -y

mkdir -p ~/.docker/cli-plugins/
curl -SL https://github.com/docker/compose/releases/download/v2.3.3/\
docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose
chmod +x ~/.docker/cli-plugins/docker-compose_

Enter fullscreen mode Exit fullscreen mode
  1. Write Dockerfile for the apache and flask server:

Apache server

#use the apache image. Latest version
FROM httpd

#delete all files in the root directory
RUN rm -r /usr/local/apache2/htdocs/*

#copy our web file to the root directory. TAKE NOTE OF THE FILE LOCATION
COPY ./index.html /usr/local/apache2/htdocs/

#run apache on port 80
EXPOSE 80

Enter fullscreen mode Exit fullscreen mode

Flask server

#use pyhton3 image
FROM python:3

#set the working directory
WORKDIR /usr/src/app

#install flask module. Since our program needs the flask module to run
RUN pip install Flask

#copy our script into the working directory. TAKE NOTE OF THE FILE LOCATION
COPY server.py .

#run the container on port 5000
EXPOSE 5000

#run the server script
CMD ["python", "server.py"]

Enter fullscreen mode Exit fullscreen mode

Here is the content of the server.py file:


from flask import Flask

app = Flask(__name__)

@app.route('/')

def index():

    return '<h1>Connected</h1>'

if __name__ == '__main__':

    app.run(host='0.0.0.0', port=5000, debug=True)


Enter fullscreen mode Exit fullscreen mode
  1. Write the docker compose file to run the containers
version: '3.8'

services:
#run MySQL container
  mysql:
    image: mysql:5.7
    container_name: mysql-container
#get environment variables from .env file
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
#bind port 3306 to 3306
    ports:
      - "3306:3306"
#run apache container
  apache:
    build:
#build container image from the Dockerfile in /apache
      context: ./apache
    container_name: apache-container
#bind port 80 to 80
    ports:
      - "80:80"
#run flask container
  flask:
    build:
#build container image from the Dockerfile in /flask
      context: ./flask
    container_name: flask-container
#bind port 80 to 80
    ports:
      - "5000:5000"


Enter fullscreen mode Exit fullscreen mode

Just before running compose up, verify your files and directory structure. Heres what mine looks like:
Image description
Now run docker compose up

Image description
Verify the containers are running with docker ps

Image description

If any of your containers are not running, follow these steps:

  1. Run docker ps โ€“a. Copy the container id
  2. Run docker logs . This will give you an insight as to what went wrong. In this case, all services are running. Now its time to test our port scanner. Hereโ€™s the code for the port scanner. FEEL FREE TO MODIFY TO SUIT YOU. I used the socket module from:
#import socket module
import socket
#function to perform the port scan
def scan(host, port_range=6000):

""" 
    performs port scan on the given host/ip-address.
    scans port range 1 - 6000

    Takes two parameters: 
    host: takes ip-address or hostname as a string
    port_range: optional. default is 6000

    """

    try:
        ip = socket.gethostbyname(host)
    except socket.gaierror:
        print(f"Cannot resolve {host}")
        return

    print(f"Scanning host {ip}...")

    for port in range(1, port_range + 1):
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        try:
            result = sock.connect_ex((ip, port))
            if result == 0:
                print(f"Port {port} is open")
            sock.close()
        except socket.error:
            pass

host = input("Enter host to scan: ")
scan(host)

Enter fullscreen mode Exit fullscreen mode

Testing time:
Run python3 <file name>

Image description
Our little scanner is able to detect four open ports on our server.
We can go a step further to try to check what services are running on those ports. For this, we will write another python script.
For this, we will use the requests module from

#import requests module
import requests

def app_version(host, port):

     """ 
    tries to detect the service running on the given address and port

    Takes two parameters: 
    host: takes ip-address or hostname as a string
    port: takes the port number

    """
    try:
        url = f"http://{host}:{port}/"
        response = requests.get(url)
       #we will find the information in the header attribute of the response 
       #from the header metadata, we can retrieve the information 
        header = response.headers.get('Server')

        if header:
            return header, header.split('/')[1]
        else:
            return None

    except Exception as e:
        print(f"Error retrieving application version: {e}")
        return None


host = input ("Enter host to check: ")
port = input ("Enter port to check: ")
app = app_version(host, port)
print(f"{app} running on port: {port} \n \n")

Enter fullscreen mode Exit fullscreen mode

lets test this:

Image description

Our code returns the service and version running on port 80 and 5000.
Port 3306 returned an error because MySQL uses a different protocol from http. We can include that in our code, or write a separate script for that.
But this will do for now. You can go ahead and check the versions detected here for known vulnerabilities.
See you next time

Top comments (2)

Collapse
 
matin_mollapur profile image
Matin Mollapur

This was an insightful exploration into the world of network penetration testing, using Docker containers to mimic hacking attempts. The step-by-step instructions provided a clear understanding of how to detect open ports and identify running services. It's fascinating to see how different protocols, like MySQL, can affect these results. The article serves as a reminder of the importance of regularly checking for vulnerabilities in our systems.

Collapse
 
naruaika profile image
Naufan Rusyda Faikar

Cannot wait to see the next article!