Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added whatcms_scan module #304

Merged
merged 3 commits into from
Jul 4, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/language/messages_en.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ def all_messages():
"select_language": "select a language {0}",
"range": "scan all IPs in the range",
"subdomains": "find and scan subdomains",
"Invalid_whatcms_api_key": "{0}",
"searching_whatcms_database": "Searching Whatcms.org...",
"thread_number_connections": "thread numbers for connections to a host",
"thread_number_hosts": "thread numbers for scan hosts",
"save_logs": "save all logs in file (results.txt, results.csv, results.html, results.json)",
Expand Down
1 change: 1 addition & 0 deletions lib/scan/whatcms/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pass
296 changes: 296 additions & 0 deletions lib/scan/whatcms/engine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: Aman Gupta , github.com/aman566

import socket
import socks
import time
import json
import threading
import string
import random
import sys
import struct
import re
import os
from OpenSSL import crypto
import ssl
from core.alert import *
from core.targets import target_type
from core.targets import target_to_host
from core.load_modules import load_file_path
from lib.socks_resolver.engine import getaddrinfo
from core._time import now
from core.log import __log_into_file
import requests
from six import text_type


def extra_requirements_dict():
return {
"whatcms_ports": [443],
"whatcms_api_key": ["test_api_key"],
aman566 marked this conversation as resolved.
Show resolved Hide resolved
}


def conn(targ, port, timeout_sec, socks_proxy):
try:
if socks_proxy is not None:
socks_version = (
socks.SOCKS5 if socks_proxy.startswith("socks5://") else socks.SOCKS4
)
socks_proxy = socks_proxy.rsplit("://")[1]
if "@" in socks_proxy:
socks_username = socks_proxy.rsplit(":")[0]
socks_password = socks_proxy.rsplit(":")[1].rsplit("@")[0]
socks.set_default_proxy(
socks_version,
str(socks_proxy.rsplit("@")[1].rsplit(":")[0]),
int(socks_proxy.rsplit(":")[-1]),
username=socks_username,
password=socks_password,
)
socket.socket = socks.socksocket
socket.getaddrinfo = getaddrinfo
else:
socks.set_default_proxy(
socks_version,
str(socks_proxy.rsplit(":")[0]),
int(socks_proxy.rsplit(":")[1]),
)
socket.socket = socks.socksocket
socket.getaddrinfo = getaddrinfo()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sys.stdout.flush()
s.settimeout(timeout_sec)
s.connect((targ, port))
return s
except Exception:
return None


def whatcms(
target,
port,
timeout_sec,
log_in_file,
language,
time_sleep,
thread_tmp_filename,
socks_proxy,
scan_id,
scan_cmd,
whatcms_api_key,
):
try:
try:
s = conn(target, port, timeout_sec, socks_proxy)
except Exception:
return False
if not s:
return False
else:
global cms_name
headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:77.0) Gecko/20100101 Firefox/77.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.7,ru;q=0.3",
"Accept-Encoding": "gzip, deflate",
"Connection": "Keep-Alive",
"Upgrade-Insecure-Requests": "1",
"X-Requested-With": "XMLHttpRequest",
}
check_api_key_is_valid = (
"https://whatcms.org/API/Status?key=" + whatcms_api_key
)
check = requests.get(
check_api_key_is_valid, headers=headers, verify=False, timeout=10
)
api_result = json.loads(check.text)["result"]["msg"]
if text_type(api_result).lower() == "invalid api key":
warn(
messages(language, "Invalid_whatcms_api_key").format(
"Invalid API Key"
)
)
return
info(messages(language, "searching_whatcms_database").format(target))
requests_url = (
"https://whatcms.org/API/CMS?key=" + whatcms_api_key + "&url=" + target
)
try:
req = requests.get(requests_url, verify=False, headers=headers)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs timeout=timeout_sec

cms_name = json.loads(req.text)["result"]["name"]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also would be good to add cms version to cms_name
current result: (CMS Name:WordPress)
Please add version, so it looks like this: (CMS Name:WordPress version 5.2.7)

return cms_name
except Exception:
return
except Exception:
return False


def __whatcms(
target,
port,
timeout_sec,
log_in_file,
language,
time_sleep,
thread_tmp_filename,
socks_proxy,
scan_id,
scan_cmd,
whatcms_api_key,
):
if whatcms(
target,
port,
timeout_sec,
log_in_file,
language,
time_sleep,
thread_tmp_filename,
socks_proxy,
scan_id,
scan_cmd,
whatcms_api_key,
):
info(messages(language, "found").format(target, "CMS Name", cms_name))
__log_into_file(thread_tmp_filename, "w", "0", language)
data = json.dumps(
{
"HOST": target,
"USERNAME": "",
"PASSWORD": "",
"PORT": port,
"TYPE": "whatcms_scan",
"DESCRIPTION": messages(language, "found").format(
target, "CMS Name", cms_name
),
"TIME": now(),
"CATEGORY": "scan",
"SCAN_ID": scan_id,
"SCAN_CMD": scan_cmd,
}
)
__log_into_file(log_in_file, "a", data, language)
return True
else:
return False


def start(
target,
users,
passwds,
ports,
timeout_sec,
thread_number,
num,
total,
log_in_file,
time_sleep,
language,
verbose_level,
socks_proxy,
retries,
methods_args,
scan_id,
scan_cmd,
): # Main function
if (
target_type(target) != "SINGLE_IPv4"
or target_type(target) != "DOMAIN"
or target_type(target) != "HTTP"
):
# requirements check
new_extra_requirements = extra_requirements_dict()
if methods_args is not None:
for extra_requirement in extra_requirements_dict():
if extra_requirement in methods_args:
new_extra_requirements[extra_requirement] = methods_args[
extra_requirement
]
extra_requirements = new_extra_requirements
if ports is None:
ports = extra_requirements["whatcms_ports"]
if target_type(target) == "HTTP":
target = target_to_host(target)
threads = []
total_req = len(ports)
thread_tmp_filename = "{}/tmp/thread_tmp_".format(load_file_path()) + "".join(
random.choice(string.ascii_letters + string.digits) for _ in range(20)
)
__log_into_file(thread_tmp_filename, "w", "1", language)
trying = 0
keyboard_interrupt_flag = False
for port in ports:
port = int(port)
t = threading.Thread(
target=__whatcms,
args=(
target,
int(port),
timeout_sec,
log_in_file,
language,
time_sleep,
thread_tmp_filename,
socks_proxy,
scan_id,
scan_cmd,
extra_requirements["whatcms_api_key"][0],
),
)
threads.append(t)
t.start()
trying += 1
if verbose_level > 3:
info(
messages(language, "trying_message").format(
trying, total_req, num, total, target, port, "whatcms_scan",
)
)
while 1:
try:
if threading.activeCount() >= thread_number:
time.sleep(0.01)
else:
break
except KeyboardInterrupt:
keyboard_interrupt_flag = True
break
if keyboard_interrupt_flag:
break
# wait for threads
kill_switch = 0
kill_time = int(timeout_sec / 0.1) if int(timeout_sec / 0.1) != 0 else 1
while 1:
time.sleep(0.1)
kill_switch += 1
try:
if threading.activeCount() == 1:
break
except KeyboardInterrupt:
break
thread_write = int(open(thread_tmp_filename).read().rsplit()[0])
if thread_write == 1 and verbose_level != 0:
info(messages(language, "not_found"))
data = json.dumps(
{
"HOST": target,
"USERNAME": "",
"PASSWORD": "",
"PORT": "",
"TYPE": "whatcms_scan",
"DESCRIPTION": messages(language, "not_found"),
"TIME": now(),
"CATEGORY": "scan",
"SCAN_ID": scan_id,
"SCAN_CMD": scan_cmd,
}
)
__log_into_file(log_in_file, "a", data, language)
os.remove(thread_tmp_filename)

else:
warn(messages(language, "input_target_error").format("whatcms_scan", target))
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import random

from canari.maltego.transform import Transform
from canari.maltego.entities import URL
from canari.framework import EnableDebugWindow
from common.entities import NettackerScan

from lib.scan.whatcms.engine import start

from database.db import __logs_by_scan_id as find_log

__author__ = 'Shaddy Garg'
__copyright__ = 'Copyright 2018, nettacker_transforms Project'
__credits__ = []

__license__ = 'GPLv3'
__version__ = '0.1'
__maintainer__ = 'Shaddy Garg'
__email__ = 'shaddygarg1@gmail.com'
__status__ = 'Development'


@EnableDebugWindow
class WhatCmsDetectionScan(Transform):
"""TODO: Your transform description."""

# The transform input entity type.
input_type = NettackerScan

def do_transform(self, request, response, config):
# TODO: write your code here.
scan_request = request.entity
scan_id = "".join(random.choice("0123456789abcdef") for x in range(32))
scan_request.ports = scan_request.ports.split(', ') if scan_request.ports is not None else None
start(scan_request.host, [], [], scan_request.ports, scan_request.timeout_sec, scan_request.thread_no,
1, 1, 'abcd', 0, "en", scan_request.verbose, scan_request.socks_proxy, scan_request.retries, [], scan_id,
"Through Maltego")
results = find_log(scan_id, "en")
for result in results:
url = result["DESCRIPTION"].split()[0]
cms = result["DESCRIPTION"].split()[-1][result["DESCRIPTION"].split()[-1].find(':')+1:-1]
response += URL(url=url, title=result["DESCRIPTION"], short_title=cms+" Found!",
link_label='whatcms_scan')
return response

def on_terminate(self):
"""This method gets called when transform execution is prematurely terminated. It is only applicable for local
transforms. It can be excluded if you don't need it."""
pass