├── README.md └── ShopifySubdomainTakeoverCheck.py /README.md: -------------------------------------------------------------------------------- 1 | # SubDomainTakeoverTools 2 | 3 | In this repository I will put a series of scripts for testing Subdomain Takeover vulnerability. 4 | 5 | # ShopifySubdomainTakeoverCheck.py 6 | The script is using three methods to detect if Subdomain Takeover is possible on Shopify. 7 | We use three methods in order to avoid False Positives because are quite annoying on large scale and automation. 8 | First of all you must understand that on Shopify you have two methods to perform a Subdomain Takeover, more information are available in the following article: 9 | https://medium.com/@thebuckhacker/how-to-do-55-000-subdomain-takeover-in-a-blink-of-an-eye-a94954c3fc75 10 | 11 | How to use: 12 | 13 | python3 ./ShopifySubdomainTakeoverCheck.py sub.domain.to.check 14 | 15 | -------------------------------------------------------------------------------- /ShopifySubdomainTakeoverCheck.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import requests 3 | import dns.resolver 4 | 5 | import urllib3 6 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 7 | 8 | SUBDOMAIN_TAKEOVER_ERROR_MESSAGE = 'Sorry, this shop is currently unavailable.' 9 | 10 | def check_web_page(hostname): 11 | """ Return True if the page looks vulnerable to Subdomain Takeover otherwise return False """ 12 | try: 13 | r = requests.get('https://%s' % hostname, verify=False) 14 | except requests.exceptions.ConnectionError: 15 | return False 16 | 17 | if SUBDOMAIN_TAKEOVER_ERROR_MESSAGE in r.text: 18 | return True 19 | else: 20 | return False 21 | 22 | def get_shop_name(hostname): 23 | """ Return the shop name from the hostname. Return None is no CNAME found. """ 24 | try: 25 | cnames = dns.resolver.query(hostname, 'CNAME') 26 | except: 27 | print("Unexpected error:", sys.exc_info()[0]) 28 | return False 29 | 30 | for cname in cnames: 31 | cname = str(cname)[:-1] 32 | if '.myshopify.com' in cname: 33 | shop_name = cname.replace('.myshopify.com','') 34 | return shop_name 35 | 36 | return None 37 | 38 | def check_shop_name_availability(shop_name): 39 | """ Return True if the shop name is available otherwise return False """ 40 | r = requests.get('https://app.shopify.com//services/signup/check_availability.json?callback=jQuery32106011450060372039_1520363418444&shop_name=%s&email=test@example.comm&_=1520363418450' % shop_name, verify=False) 41 | 42 | # TODO: Fix this check because is super ugly :P 43 | if '"status":"available"' in r.text: 44 | return True 45 | else: 46 | return False 47 | 48 | def check(hostname): 49 | """ Return True if the hostname is vulnerable to Subdomain Takeover, otherwise return False """ 50 | if check_web_page(hostname): 51 | shop_name = get_shop_name(hostname) 52 | if shop_name == 'shops': 53 | print('%s - Vulnerable to Subdomain Takeover via DNS Mapping' % (hostname)) 54 | return True 55 | else: 56 | if check_shop_name_availability(shop_name): 57 | print('%s - Vulnerable to Subdomain Takeover via Shop Name (%s)' % (hostname,shop_name)) 58 | return True 59 | else: 60 | print('Hostname: %s is NOT vulnerable to Subdomain Takeover.' % (hostname)) 61 | return False 62 | 63 | 64 | def help(): 65 | """ Display help """ 66 | print('Use:') 67 | print('./%s hostname' % sys.argv[0]) 68 | 69 | if __name__ == '__main__': 70 | if (len(sys.argv) != 2): 71 | help() 72 | else: 73 | check(sys.argv[1]) 74 | --------------------------------------------------------------------------------