Let's Pretend to be Hackers
Tags: cybersecurity, devops, docker, cloudcomputing
Published: 2024-06-21 04:18:08

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_

```

3.  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

```
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"]

```
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)
    

```


4.	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"


```
Just before running compose up, verify your files and directory structure. Heres what mine looks like:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9e4yh0bj42xvxm7vlwzf.JPG)
Now run docker compose up

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l3xaahec6405cdxwlu54.JPG)
Verify the containers are running with docker ps

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jaxyf3db50qpw8ozs7du.png)

If any of your containers are not running, follow these steps:
1.	Run docker ps –a. Copy the container id
2.	Run docker logs <container id>. 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:[](https://docs.python.org/3/library/socket.html)

```
#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)

```

Testing time:
Run `python3 <file name>`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/63jmq2w67fxrygo72vbs.png)
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 []( https://pypi.org/project/requests/)

```
#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")

```
lets test this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xafvibej8ainmc9r0bpl.png)

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