import pyfiglet
import sys
import os
import requests
import io
import csv
import ssl
import re
import urllib.request
from termcolor import colored

def intro():
    name = pyfiglet.figlet_format("Penetester Helper")
    print(name)
    print("Static Website Analaysis  \nUrl: https://penetesterhelper.github.io/")
    print("--------------------------------------------------------------------------")   

def cmdArgs():
    n =  len(sys.argv)
    if(n==1 or n==2):
        return uses()
    else:
        url =  sys.argv[1]
        cmdArgsVar =  sys.argv[2]
        if(str(cmdArgsVar).startswith("--server")):
            serverFunc(url)

        elif(str(cmdArgsVar).startswith("--options")):
            optionsFunc(url)

        elif(str(cmdArgsVar).startswith("--headers")):
            headersFunc(url)

        elif(str(cmdArgsVar).startswith("--dir")):
            dirFunc(url)

        elif(str(cmdArgsVar).startswith("--weakssl")):
            weakSSlFunc(url)

        elif(str(cmdArgsVar).startswith("--autocomplete")):
            autoFunc(url)

        elif(str(cmdArgsVar).startswith("--host")):
            hostheaderFunc(url)
        else:
            all(url)

def uses():
    print("Uses:")
    print("penetesterhelper.py https://domain.com/ cmdArgs")
    print("cmdArgs: ")
    print(" 1.  --all: Finding All Static vulnerability")
    print(" 2.  --dir: Finding directory and saved CSV file")
    print(" 3.  --server: Finding Platform/Server Name")
    print(" 4.  --host: Finding Host Header Vulnerability")
    print(" 5.  --options: Finding Options Mathod Enable or not")
    print(" 6.  --autocomplete: Finding Autocomplete")
    print(" 7.  --headers: Finding Security Headers and HSTS")
    print(" 8.  --weakssl: Weak Hash Algorithm")

def all(url):
    print("------------------Options Method Checking--------------------")
    optionsFunc(url)
    print("------------------Platform/Server Name Checking--------------")
    try:
        serverFunc(url)
    except:
        pass
    print("------------------Host Header Checking-----------------------")
    hostheaderFunc(url)
    print("------------------Weak SSL Checking--------------------------")
    weakSSlFunc(url)
    print("------------------Autocomplete Checking----------------------")
    autoFunc(url)
    print("------------------Missing HSTS & Security Header-------------")
    headersFunc(url)
    print("------------------Directory Search---------------------------")
    dirFunc(url)

def optionsFunc(url):
    cOptions = PenesterCheckOptions(url)
    if(cOptions.checkOptionsMethods()):
        print(colored(f"Options Method is Enable || {url} ",'red'))
    else:
        print(colored(f"Options Methos is Not Enable || {url} ",'green'))

def headersFunc(url):
            cHeaders = PenesterCheckHeaders(url)
            getList = cHeaders.checkHeader()
            getListLength = len(list(getList))

            for x in getList:
                for y in PenesterCheckHeaders.headersList:
                    if(y==x):
                        PenesterCheckHeaders.newHeaderList.remove(y)
                    else:
                        pass
                    pass

            if(len(PenesterCheckHeaders.newHeaderList)>0):
                print(colored(f"    1.  Missing Security Header || {url}",'red'))
                print(colored(f"    {PenesterCheckHeaders.newHeaderList}",'red'))
            else:
                print(colored(f"    1.  Pefect Headers || {url}",'green'))      
            print("---------------------------------------------------------------------------------------")    
            try:
                print(colored(f"    2.  HSTS is Implement {getList['Strict-Transport-Security']}",'green'))
            except:
                print(colored(f"    2.  HSTS is Missing",'red'))

def serverFunc(url):
    cServer = PenesterCheckServer(url)
    cServer.checkServer()

def dirFunc(url):
    if(str(url).startswith("https://")):
        port = 443
        hostUrl = url.replace("https://","")
        hostUrl = hostUrl.replace("/","")
        hostUrl = hostUrl.replace(".","")
    else:
        port = 80
        hostUrl = url.replace("http://","")
        hostUrl = hostUrl.replace("/","")
        hostUrl = hostUrl.replace(".","")

    cDir = PenesterCheckDir(url,hostUrl)
    cDir.findPath()

def autoFunc(url):
    cAuto = PenesterCheckAutocomplete(url)
    if(cAuto.checkAutocomplete()==None):
        command = input("Login Form is Not Detect Wants to find Form page?? [Y/N]: ")
        if((command.startswith("Y")) or (command.startswith("y"))):
            cAuto.findingFormPage()
        else:
            print("Enjoy...........")
    elif(cAuto.checkAutocomplete()==0):
        print(colored("Autocomplete Is Missing","red"))
    elif(cAuto.checkAutocomplete()==1):
        print(colored("Autocomplete is Implement","green"))
    else:
        print(colored(f"Getting Error || {url} || \n{cAuto.checkAutocomplete()}","red"))
        command = input("Login Form is Not Detect Wants to find Form page?? [y/N]: ")
        if((command.startswith("Y")) or (command.startswith("y"))):
            cAuto.findingFormPage()
        else:
            print("Enjoy...........")    

def hostheaderFunc(url):
    cHostHeader = PenesterCheckHostHeaderInjection(url)
    if(cHostHeader.checkHostHeader()):
        print(colored("Vulnerable to HOST Header","red"))
    else:
        print(colored("Not Vulnerable to HOST Header","green"))            

def weakSSlFunc(url):
    if(str(url).startswith("https://")):
        port = 443
        hostUrl = filterUrl(url)
    else:
        port = 443
        hostUrl = filterUrl(url)

    print(hostUrl)
    cWeakSSL = PenesterCheckWeakSSL(hostUrl,port)
    cWeakSSL.checkWeakSSL()

def filterUrl(url):
    hostUrl = str(re.findall('https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+', url))
    hostUrl = hostUrl.replace("https://","")
    hostUrl = hostUrl.replace("http://","")
    hostUrl = hostUrl.replace(":","")
    hostUrl = hostUrl.replace("/","")
    hostUrl = hostUrl.replace("[","")
    hostUrl = hostUrl.replace("]","")
    hostUrl = hostUrl.replace("'","")
    hostUrl = hostUrl.replace("http://","")
    return hostUrl

class PenesterCheckServer:
    headersList = ["X-powered-by", "Server", "Platform", "X-AspNet-Version"]
    hostValue=["*",".in",":123"]
    def __init__(self, url):
        self.url = url

    def findHeaders(x):
        for y in PenesterCheckServer.headersList:
            if(PenesterCheckServer.headersFunc(y,x)==None):
                print(colored(f"{y} : {PenesterCheckServer.headersFunc(y,x)}","green"))
            else:
                print(colored(f"{y} : {PenesterCheckServer.headersFunc(y,x)}","red"))    
                
    def checkServer(self):
        url = self.url
        forHost = url
        x = requests.get(url)
        print(f"-----------Normal requests---------------")
        PenesterCheckServer.findHeaders(x)
        print("-----------POST requests---------------")
        x = requests.post(url)
        PenesterCheckServer.findHeaders(x)
        x = requests.post(url+"/sdefefd*")
        print(f"-----------{x.status_code} requests---------------")
        PenesterCheckServer.findHeaders(x)
        x = requests.post(url+"/js")
        print(f"-----------{x.status_code} requests---------------")
        PenesterCheckServer.findHeaders(x)
        print(f"-----------{requests.get(url, headers={'Host':forHost}).status_code} requests---------------")
        PenesterCheckServer.findHeaders(requests.get(url, headers={'Host':forHost}))
        print("-----------Change headers requests---------------")
        PenesterCheckServer.checkHostHeader(url)

    def checkHostHeader(url):
        if(str(url).startswith("https://")):
            hostUrl = filterUrl(url)
        else:
            hostUrl = filterUrl(url)

        print(f"-----------1 || Host headers || penetesterhelper.github.io ---------------")
        PenesterCheckServer.findHeaders(requests.get(url, headers={'Host':'penetesterhelper.github.io'}))

        count = 2
        for z in PenesterCheckServer.hostValue:
            print(f"-----------{count} || Host headers || {hostUrl+z}---------------")
            PenesterCheckServer.findHeaders(requests.get(url, headers={'Host': hostUrl+z}))
            count = count+1 

    def headersFunc(header,x):
        try:
            return x.headers[header]
        except:
            return None

class PenesterCheckOptions:
    def __init__(self, url):
        self.url = url

    def checkOptionsMethods(self):
        url = self.url
        x = requests.options(url)
        if(x.status_code==200):
            return True
        else:
            return False

class PenesterCheckHeaders:
    headersList=["X-Content-Security-Policy","Content-Security-Policy", "X-Content-Type-Options", "Referrer-Policy", "Cache-Control", "Clear-Site-Data"]
    newHeaderList=["X-Content-Security-Policy","Content-Security-Policy", "X-Content-Type-Options", "Referrer-Policy", "Cache-Control", "Clear-Site-Data"]

    def __init__(self, url):
        self.url = url

    def checkHeader(self):
        url = self.url
        x = requests.get(url)
        if(x.status_code==200):
            print(colored(f"    Getting {x.status_code} from server",'red'))
            return x.headers
        else:
            print(colored(f"    Getting {x.status_code} from server",'green'))
            return False    

class PenesterCheckDir:
    def __init__(self, url,path):
        self.url = url
        self.path = path

    def csvv2xx(csvName,count,status_code,url,contentlength):
        with open(csvName+"2xx.csv", 'a') as f:
            writer = csv.writer(f)
            writer.writerow([count,status_code,url,contentlength])

    def csvv3xx(csvName,count,status_code,url,contentlength):
        with open(csvName+"4xx.csv", 'a') as f:
            writer = csv.writer(f)
            writer.writerow([count,status_code,url,contentlength])

    def csvv4xx(csvName,count,status_code,url,contentlength):
        with open(csvName+"4xx.csv", 'a') as f:
            writer = csv.writer(f)
            writer.writerow([count,status_code,url,contentlength])

    def csvv4xx(csvName,count,status_code,url,contentlength):
        with open(csvName+"5xx.csv", 'a') as f:
            writer = csv.writer(f)
            writer.writerow([count,status_code,url,contentlength])

    def findPath(self):
        url = self.url
        csvName = self.path
        count = 0
        myfile = io.open("big.txt", "r", encoding='latin-1')
        
        with open(csvName+"2xx.csv", 'a') as f:
            writer = csv.writer(f)
            writer.writerow(["S.No","status_code","url","content-Length"])

        with open(csvName+"3xx.csv", 'a') as f:
            writer = csv.writer(f)
            writer.writerow(["S.No","status_code","url","content-Length"])

        with open(csvName+"4xx.csv", 'a') as f:
            writer = csv.writer(f)
            writer.writerow(["S.No","status_code","url","content-Length"])
            
        with open(csvName+"5xx.csv", 'a') as f:
            writer = csv.writer(f)
            writer.writerow(["S.No","status_code","url","content-Length"])    

        with open("big.txt") as f:
            for line in f:
                content = line.strip()
                x = requests.get(url+content)
                if( (str(x.status_code).startswith("3")) or (str(x.status_code).startswith("2"))):
                    try:
                        print(colored(f" {count} || {url+content} || {x.status_code} || {x.headers['Content-Length']}",'red'))
                    except:
                        pass    
                else:
                    try:
                        print(colored(f" {count} || Request Sent but getting || {x.status_code} || {x.headers['Content-Length']}",'green'))
                    except:
                        pass

                count = count+1
                if((str(x.status_code).startswith("404"))):
                    pass
                else:
                    if(str(x.status_code).startswith("4")):
                        try:
                            PenesterCheckDir.csvv4xx(csvName,str(count),str(x.status_code),str(url+content),str(x.headers['Content-Length']))
                        except:
                            pass
                    elif(str(x.status_code).startswith("2")):
                        try:
                            PenesterCheckDir.csvv2xx(csvName,str(count),str(x.status_code),str(url+content),str(x.headers['Content-Length']))
                        except:
                            pass
                    elif(str(x.status_code).startswith("3")):
                        try:
                            PenesterCheckDir.csvv3xx(csvName,str(count),str(x.status_code),str(url+content),str(x.headers['Content-Length']))
                        except:
                            pass
                    elif(str(x.status_code).startswith("5")):
                        try:
                            PenesterCheckDir.csvv5xx(csvName,str(count),str(x.status_code),str(url+content),str(x.headers['Content-Length']))
                        except:
                            pass
                    else: 
                        pass

class PenesterCheckWeakSSL:
    def __init__(self, url,port):
        self.url = url
        self.port = port

    def checkWeakSSL(self):    
        os.system(f'nmap -Pn --script ssl-enum-ciphers {self.url} -p {self.port}')

class PenesterCheckAutocomplete:
    def __init__(self, url):
        self.url = url

    def findingFormPage(self):
        url = self.url
        count = 0
        path = input("Enter 200 request Path if you have (leave blank if not): ")
        if(len(path)==0):
            path = 'big.txt'
        else:
            path = path
        with open(path) as f:
            while True:
                line = f.readline()
                if not line:
                    break
                cAc = PenesterCheckAutocomplete.checkAutocompleteWithoutSelf(url+line.strip())
                if(cAc==None):
                    print(colored(f"{count} || Login Form Not Detect || {url+line.strip()}","green"))
                elif(cAc==0):
                    print(colored(f"{count} || Autocomplete is Missing || {url+line.strip()}","red"))
                elif(cAc==1):
                    print(colored(f"{count} || Autocomplete Detect || {url+line.strip()}","green"))
                    break;
                else:
                    print(colored(f"{count} || Error || {url+line.strip()} || {cAc}","red"))    
                count = count+1;

    def checkAutocomplete(self):
        x = requests.get(self.url)
        if((str(x.status_code).startswith("4")) or str(x.status_code).startswith("5")):
            return x.text
        else:    
            if(re.search('action=',x.text)==None):
                return None
            elif(re.search('type="password"',x.text)==None):
                return None
            else:
                if(re.search('autocomplete',x.text)==None):
                    return 0 #Autocomplete is Missing
                else:
                    return 1 #Autocomplete Implemented

    def checkAutocompleteWithoutSelf(url):
        x = requests.get(url)
        y = x.text
        if(re.search('action=',y)==None):
            return None
        elif(re.search('name="password"',y)==None):
            return None      
        else:
            if(re.search('autocomplete',y)==None):
                return 0 #Autocomplete is Missing
            else:
                return 1 #Autocomplete Implemented

class PenesterCheckHostHeaderInjection:
    def __init__(self, url):
        self.url = url
        
    def checkHostHeader(self):
        url = self.url
        try:
            ssl._create_default_https_context = ssl._create_unverified_context
            r = urllib.request.Request(url, headers={'Host': 'penetesterhelper.github.io'})
            y = urllib.request.urlopen(r)    
            return True
        except:
            return False
