Webifying CyAn

In the past I have talked about the Web Application Scanner I coded, called CyAn. In 2020 I wanted to expand upon CyAn. I wanted to make it a web platform itself. Because its written almost entirely in Python I decided to go the Django web framework. Learning Django has been quite the experience. Learning Django from scratch took a lot of research, however, the good thing is there is a ton of resources out there on “the googles” to help. I decided to make a very basic Django app, and I decided to strip down the code base of CyAn.

Before we get too far, Django and Django Structure

Django is defined as

“Django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design. Built by experienced developers, it takes care of much of the hassle of Web development, so you can focus on writing your app without needing to reinvent the wheel. It’s free and open source.”

Which means that Django is a web application framework that uses Python instead of Java or .Net (IIS)

Django is split into projects and applications, you can have multiple applications in one project. The folder/file structure looks something like this.

 CyAn
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-37.pyc
│   │   └── views.cpython-37.pyc
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── output
│   │   ├── out.xml
│   │   └── zap_report.xml
│   ├── scripts
│   │   ├── config1.json
│   │   ├── create_config.py
│   │   ├── createin.py
│   │   ├── cyan_small.py
│   │   ├── docker_start_threadfix.py
│   │   ├── in.txt
│   │   ├── local_cleanup.py
│   │   ├── nessus_scan.py
│   │   ├── zap_api.py
│   ├── tests.py
│   ├── views\ copy.py
│   └── views.py
├── CyAn_Web
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-37.pyc
│   │   ├── settings.cpython-37.pyc
│   │   ├── urls.cpython-37.pyc
│   │   └── wsgi.cpython-37.pyc
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py

CyAn_Web is the Django Project (contains settings.py and urls.py). Urls.py contains the web app structure. CyAn is the Django app. The app contains the file views.py, this file is where all your python code sits. I think put all the old CyAn code in a folder called scripts, views.py then pulls from the other .py files in that folder to excuse the program.

Functions and OOP

Throughout my career in IT in general I have always fought the idea of using functions in my code. I have gone to the extend of using separate code files for performing “functions”. However, I do see that when using Django, you need to have 1 program file that has functions embedded within it. Because of this I decide to rewrite CyAn main. In doing this I stripped away much of the code and created CyAn_small.py.

import os
import subprocess
import time
from pprint import pprint
import sys
#import nessus_scan
#import docker_start_threadfix
import json
#import local_cleanup
import sys 
#import create_config

tar = sys.argv[2]
scanner = sys.argv[1]

print (scanner)
def nmapscan(url):
    os.system("nmap -sV " +str(url) + " -oX Cyan/output/out.xml")
    print(url)
def zapscan(url):
    print  ("Zap scan started")
    os.system("python ../CyAn_Web/CyAn/scripts/zap_api.py")
    #import threadfix_upload_ZAP
    #threadfix_upload_ZAP
    #print ("ZAP Scan Uploaded")

def createconfig(url):
    #tar = sys.argv[0]
    tar = url
    data = {}
    data ['target'] = []
    data['target'].append({
    'URL': tar
    })
    with open('config1.json', 'w') as json_data:
        json.dump(data, json_data, indent=4)
        json_data.close()


#answer = menu()
createconfig(tar)
#print ("This is the option: " + answer)
if scanner == "nmap":
    nmapscan(tar)
elif scanner== "zap":
    zapscan(tar)

This code has stripped away the menu process that was integral to the python script. As this is now web (API) driven, the variables are being passed using curl.

curl -i -X POST localhost:8000/cyan_api -d '{"scanner":"nmap","url":"www.sharksec.net"}'

This command will pass the scanner variable and the url to CyAn_small.py through Django and execute the program.

Output of the command looks something like

HTTP/1.1 200 OK
Date: Mon, 24 Feb 2020 20:08:09 GMT
Server: WSGIServer/0.2 CPython/3.7.3
Content-Type: application/json
X-Frame-Options: DENY
Content-Length: 768
X-Content-Type-Options: nosniff

{"status": "Success", "output": "b'Starting Nmap 7.80 ( https://nmap.org ) at 2020-02-24 20:07 UTC\\nNmap scan report for www.sharksec.net (18.234.248.101)\\nHost is up (0.029s latency).\\nrDNS record for 18.234.248.101: ec2-18-234-248-101.compute-1.amazonaws.com\\nNot shown: 997 filtered ports\\nPORT    STATE SERVICE VERSION\\n22/tcp  open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.8 (Ubuntu Linux; protocol 2.0)\\n80/tcp  open  http    Apache httpd (PHP 7.0.31)\\n443/tcp open  ssl/ssl Apache httpd (SSL-only mode)\\nService Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel\\n\\nService detection performed. Please report any incorrect results at https://nmap.org/submit/ .\\nNmap done: 1 IP address (1 host up) scanned in 18.51 seconds\\nnmap\\nwww.sharksec.net\\n'"}%   

Getting a 200 message means the Django web application is functioning correctly and the web server is receiving the curl command correctly. Then the output from the web response is in JSON output.

Next Steps

I have a couple ideas on what I need to do next so here is my list of things to add/complete

  • Add other scanners
    • w3af
    • Burp
    • nikto
  • improve the performance of the curl command execution
  • create a web front end as well, that way its not just an API but a full web application

UPDATE: I have updated the code to work with a GET request that passes URL parameters. Code is in my Github

Stay tuned for more 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *