Skip to content

Commit

Permalink
5.3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
guelfoweb committed Mar 3, 2022
1 parent 1b1b34e commit 41aebd9
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 5 deletions.
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Knock Subdomain Scan v5.2.0
# Knock Subdomain Scan v5.3.0

Knockpy is a python3 tool designed to quickly enumerate subdomains on a target domain through dictionary attack.

Expand Down Expand Up @@ -54,7 +54,9 @@ optional arguments:
--no-http-code CODE [CODE ...]
http code list to ignore
--dns DNS use custom DNS ex. 8.8.8.8
-w WORDLIST wordlist file to import
-o FOLDER report folder to store json results
-t SEC timeout in seconds
Expand All @@ -81,6 +83,11 @@ optional arguments:
- DNS requests only, no http(s) requests will be made. This way the response will be much faster and you will get the IP address and the Subdomain.
- The subdomain will be cyan in color if it is an ```alias``` and in that case the real host name will also be provided.

### Custom DNS
```$ knockpy domain.com --dns 8.8.8.8```

- by default it uses the pre-configured DNS on your system (ex. /etc/resolv.conf).

### Set threads
```$ knockpy domain.com -th 50```

Expand Down
1 change: 1 addition & 0 deletions knockpy/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"remote"
]
},
"dns": "",
"api": {
"virustotal": ""
},
Expand Down
145 changes: 145 additions & 0 deletions knockpy/dns_socket.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import socket
import ipaddress

# https://github.com/1ocalhost/py_cheat/blob/master/dns_lookup.py

def parse_dns_string(reader, data):
res = ''
to_resue = None
bytes_left = 0

for ch in data:
if not ch:
break

if to_resue is not None:
resue_pos = chr(to_resue) + chr(ch)
res += reader.reuse(resue_pos)
break

if bytes_left:
res += chr(ch)
bytes_left -= 1
continue

if (ch >> 6) == 0b11 and reader is not None:
to_resue = ch - 0b11000000
else:
bytes_left = ch

if res:
res += '.'

return res


class StreamReader:
def __init__(self, data):
self.data = data
self.pos = 0

def read(self, len_):
pos = self.pos
if pos >= len(self.data):
raise

res = self.data[pos: pos+len_]
self.pos += len_
return res

def reuse(self, pos):
pos = int.from_bytes(pos.encode(), 'big')
# fix if pos == 107 convert it in -> pos = 75
if chr(pos).islower(): pos = ord(chr(pos).upper())
return parse_dns_string(None, self.data[pos:])


def make_dns_query_domain(domain):
def f(s):
return chr(len(s)) + s

parts = domain.split('.')
parts = list(map(f, parts))
return ''.join(parts).encode()


def make_dns_request_data(dns_query):
req = b'\xaa\xbb\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00'
req += dns_query
req += b'\x00\x00\x01\x00\x01'
return req


def add_record_to_result(result, type_, data, reader):
if type_ == 'A':
item = str(ipaddress.IPv4Address(data))
elif type_ == 'CNAME':
item = parse_dns_string(reader, data)
else:
return

result.setdefault(type_, []).append(item)


def parse_dns_response(res, dq_len, req):
reader = StreamReader(res)

def get_query(s):
return s[12:12+dq_len]

data = reader.read(len(req))
assert(get_query(data) == get_query(req))

def to_int(bytes_):
return int.from_bytes(bytes_, 'big')

result = {}
res_num = to_int(data[6:8])
for i in range(res_num):
reader.read(2)
type_num = to_int(reader.read(2))

type_ = None
if type_num == 1:
type_ = 'A'
elif type_num == 5:
type_ = 'CNAME'

reader.read(6)
data = reader.read(2)
data = reader.read(to_int(data))
add_record_to_result(result, type_, data, reader)

return result


def dns_lookup(domain, address):
dns_query = make_dns_query_domain(domain)
dq_len = len(dns_query)

req = make_dns_request_data(dns_query)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(2)

try:
sock.sendto(req, (address, 53))
res, _ = sock.recvfrom(1024 * 4)
result = parse_dns_response(res, dq_len, req)
except Exception:
return
finally:
sock.close()

return result


def _gethostbyname_ex(domain, address):
result = dns_lookup(domain, address)
if "CNAME" in result:
host = result["CNAME"][-1]
result["CNAME"].remove(host)
result["CNAME"].append(domain)
ipv4 = result["A"]
return (host, result["CNAME"], ipv4)
return (domain, [], result["A"])

11 changes: 9 additions & 2 deletions knockpy/knockpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
import colorama
import argparse
import socket
from . import dns_socket
import requests
import random
import bs4
import bs4
import time
import json
import sys
Expand All @@ -30,6 +31,8 @@
class Request():
def dns(target):
try:
if config["dns"]:
return dns_socket._gethostbyname_ex(target, config["dns"])
return socket.gethostbyname_ex(target)
except:
return []
Expand Down Expand Up @@ -383,7 +386,7 @@ def plot(report):
plt.show()

class Start():
__version__ = "5.2.0"
__version__ = "5.3.0"

def msg_rnd():
return ["happy hacking ;)", "good luck!", "never give up!",
Expand Down Expand Up @@ -482,6 +485,7 @@ def arguments():
parser.add_argument("--no-remote", help="remote wordlist ignore", action="store_true", required=False)
parser.add_argument("--no-http", help="http requests ignore\n\n", action="store_true", required=False)
parser.add_argument("--no-http-code", help="http code list to ignore\n\n", nargs="+", dest="code", type=int, required=False)
parser.add_argument("--dns", help="use custom DNS ex. 8.8.8.8\n\n", dest="dns", required=False)
parser.add_argument("-w", help="wordlist file to import", dest="wordlist", required=False)
parser.add_argument("-o", help="report folder to store json results", dest="folder", required=False)
parser.add_argument("-t", help="timeout in seconds", nargs=1, dest="sec", type=int, required=False)
Expand Down Expand Up @@ -524,6 +528,9 @@ def arguments():
if args.wordlist:
config["wordlist"]["local"] = args.wordlist

if args.dns:
config["dns"] = args.dns

return domain


Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setup(
name="knockpy",
version="5.2.0",
version="5.3.0",
description="Knock is a python tool designed to quickly enumerate subdomains on a target domain through dictionary attack.",
url="https://github.com/guelfoweb/knock",
author="Gianni 'guelfoweb' Amato",
Expand Down

0 comments on commit 41aebd9

Please sign in to comment.