1- import re
1+ import json
22
33from bbot .modules .templates .subdomain_enum import subdomain_enum
44
@@ -15,78 +15,61 @@ class dnsdumpster(subdomain_enum):
1515
1616 base_url = "https://dnsdumpster.com"
1717
18+ async def setup (self ):
19+ self .apikey_regex = self .helpers .re .compile (r'<form[^>]*data-form-id="mainform"[^>]*hx-headers=\'([^\']*)\'' )
20+ return True
21+
1822 async def query (self , domain ):
1923 ret = []
20- # first, get the CSRF tokens
24+ # first, get the JWT token from the main page
2125 res1 = await self .api_request (self .base_url )
2226 status_code = getattr (res1 , "status_code" , 0 )
23- if status_code in [429 ]:
24- self .verbose (f'Too many requests "{ status_code } "' )
25- return ret
26- elif status_code not in [200 ]:
27+ if status_code not in [200 ]:
2728 self .verbose (f'Bad response code "{ status_code } " from DNSDumpster' )
2829 return ret
29- else :
30- self .debug (f'Valid response code "{ status_code } " from DNSDumpster' )
31-
32- html = self .helpers .beautifulsoup (res1 .content , "html.parser" )
33- if html is False :
34- self .verbose ("BeautifulSoup returned False" )
35- return ret
3630
37- csrftoken = None
38- csrfmiddlewaretoken = None
31+ # Extract JWT token from the form's hx-headers attribute using regex
32+ jwt_token = None
3933 try :
40- for cookie in res1 .headers .get ("set-cookie" , "" ).split (";" ):
41- try :
42- k , v = cookie .split ("=" , 1 )
43- except ValueError :
44- self .verbose ("Error retrieving cookie" )
45- return ret
46- if k == "csrftoken" :
47- csrftoken = str (v )
48- csrfmiddlewaretoken = html .find ("input" , {"name" : "csrfmiddlewaretoken" }).attrs .get ("value" , None )
49- except AttributeError :
50- pass
34+ # Look for the form with data-form-id="mainform" and extract hx-headers
35+ form_match = await self .helpers .re .search (self .apikey_regex , res1 .text )
36+ if form_match :
37+ headers_json = form_match .group (1 )
38+ headers_data = json .loads (headers_json )
39+ jwt_token = headers_data .get ("Authorization" )
40+ except (AttributeError , json .JSONDecodeError , KeyError ):
41+ self .log .warning ("Error obtaining JWT token" )
42+ return ret
5143
52- # Abort if we didn't get the tokens
53- if not csrftoken or not csrfmiddlewaretoken :
54- self .verbose ("Error obtaining CSRF tokens " )
44+ # Abort if we didn't get the JWT token
45+ if not jwt_token :
46+ self .verbose ("Error obtaining JWT token " )
5547 self .errorState = True
5648 return ret
5749 else :
58- self .debug ("Successfully obtained CSRF tokens " )
50+ self .debug ("Successfully obtained JWT token " )
5951
6052 if self .scan .stopping :
61- return
53+ return ret
6254
63- # Otherwise, do the needful
64- subdomains = set ()
55+ # Query the API with the JWT token
6556 res2 = await self .api_request (
66- f" { self . base_url } /" ,
57+ "https://api.dnsdumpster.com/htmld /" ,
6758 method = "POST" ,
68- cookies = {"csrftoken" : csrftoken },
69- data = {
70- "csrfmiddlewaretoken" : csrfmiddlewaretoken ,
71- "targetip" : str (domain ).lower (),
72- "user" : "free" ,
73- },
59+ data = {"target" : str (domain ).lower ()},
7460 headers = {
75- "origin" : "https://dnsdumpster.com" ,
76- "referer" : "https://dnsdumpster.com/" ,
61+ "Authorization" : jwt_token ,
62+ "Content-Type" : "application/x-www-form-urlencoded" ,
63+ "Origin" : "https://dnsdumpster.com" ,
64+ "Referer" : "https://dnsdumpster.com/" ,
65+ "HX-Request" : "true" ,
66+ "HX-Target" : "results" ,
67+ "HX-Current-URL" : "https://dnsdumpster.com/" ,
7768 },
7869 )
7970 status_code = getattr (res2 , "status_code" , 0 )
8071 if status_code not in [200 ]:
81- self .verbose (f'Bad response code "{ status_code } " from DNSDumpster' )
82- return ret
83- html = self .helpers .beautifulsoup (res2 .content , "html.parser" )
84- if html is False :
85- self .verbose ("BeautifulSoup returned False" )
72+ self .verbose (f'Bad response code "{ status_code } " from DNSDumpster API' )
8673 return ret
87- escaped_domain = re .escape (domain )
88- match_pattern = re .compile (r"^[\w\.-]+\." + escaped_domain + r"$" )
89- for subdomain in html .findAll (text = match_pattern ):
90- subdomains .add (str (subdomain ).strip ().lower ())
9174
92- return list ( subdomains )
75+ return await self . scan . extract_in_scope_hostnames ( res2 . text )
0 commit comments