Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
unknown authored and unknown committed Apr 1, 2015
0 parents commit 2857881
Show file tree
Hide file tree
Showing 11 changed files with 113,257 additions and 0 deletions.
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# subDomainsBrute

A simple and fast sub domain brute tool for pentesters

##Dependencies
First you need install [dnspython](http://www.dnspython.org/kits/1.12.0/) to do DNS query

## Improvements
* 用小字典递归地发现三级域名,四级域名、五级域名等不容易被探测到的域名
* 字典较为全面,小字典就包括3万多条,大字典多达8万条
* 默认使用114DNS、百度DNS、阿里DNS这几个快速又可靠的公共DNS进行查询,可随时修改配置文件添加你认为可靠的DNS服务器
* 自动筛选泛解析的域名,当前规则是: 超过10个域名指向同一IP,则此后发现的其他指向该IP的域名将被丢弃
* 整体速度还过得去,在我的PC上,每秒稳定扫描100到200个域名(10个线程)

##Usage
```
Usage: subDomainsBrute.py [options] target
Options:
-h, --help show this help message and exit
-t THREADS_NUM, --threads=THREADS_NUM
Number of threads. default = 10
-f NAMES_FILE, --file=NAMES_FILE
Dict file used to brute sub names
-o OUTPUT, --output=OUTPUT
Output file name. default is {target}.txt
```

Output file could be like: [http://www.lijiejie.com/wp-content/uploads/2015/04/baidu.com_.txt](http://www.lijiejie.com/wp-content/uploads/2015/04/baidu.com_.txt)

my[at]lijiejie.com ([http://www.lijiejie.com](http://www.lijiejie.com))
5 changes: 5 additions & 0 deletions dns_servers.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
114.114.114.114
114.114.115.115
180.76.76.76
223.5.5.5
223.6.6.6
Binary file added install/dnspython-1.12.0.tar.gz
Binary file not shown.
Empty file added lib/__init__.py
Empty file.
Binary file added lib/__init__.pyc
Binary file not shown.
90 changes: 90 additions & 0 deletions lib/consle_width.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
""" getTerminalSize()
- get width and height of console
- works on linux,os x,windows,cygwin(windows)
"""

__all__=['getTerminalSize']


def getTerminalSize():
import platform
current_os = platform.system()
tuple_xy=None
if current_os == 'Windows':
tuple_xy = _getTerminalSize_windows()
if tuple_xy is None:
tuple_xy = _getTerminalSize_tput()
# needed for window's python in cygwin's xterm!
if current_os == 'Linux' or current_os == 'Darwin' or current_os.startswith('CYGWIN'):
tuple_xy = _getTerminalSize_linux()
if tuple_xy is None:
print "default"
tuple_xy = (80, 25) # default value
return tuple_xy

def _getTerminalSize_windows():
res=None
try:
from ctypes import windll, create_string_buffer

# stdin handle is -10
# stdout handle is -11
# stderr handle is -12

h = windll.kernel32.GetStdHandle(-12)
csbi = create_string_buffer(22)
res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
except:
return None
if res:
import struct
(bufx, bufy, curx, cury, wattr,
left, top, right, bottom, maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
sizex = right - left + 1
sizey = bottom - top + 1
return sizex, sizey
else:
return None

def _getTerminalSize_tput():
# get terminal width
# src: http://stackoverflow.com/questions/263890/how-do-i-find-the-width-height-of-a-terminal-window
try:
import subprocess
proc=subprocess.Popen(["tput", "cols"],stdin=subprocess.PIPE,stdout=subprocess.PIPE)
output=proc.communicate(input=None)
cols=int(output[0])
proc=subprocess.Popen(["tput", "lines"],stdin=subprocess.PIPE,stdout=subprocess.PIPE)
output=proc.communicate(input=None)
rows=int(output[0])
return (cols,rows)
except:
return None


def _getTerminalSize_linux():
def ioctl_GWINSZ(fd):
try:
import fcntl, termios, struct, os
cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,'1234'))
except:
return None
return cr
cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
if not cr:
try:
fd = os.open(os.ctermid(), os.O_RDONLY)
cr = ioctl_GWINSZ(fd)
os.close(fd)
except:
pass
if not cr:
try:
cr = (env['LINES'], env['COLUMNS'])
except:
return None
return int(cr[1]), int(cr[0])

if __name__ == "__main__":
sizex,sizey=getTerminalSize()
print 'width =',sizex,'height =',sizey
Binary file added lib/consle_width.pyc
Binary file not shown.
113 changes: 113 additions & 0 deletions next_sub.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
test
test2
t
dev
1
2
3
s1
s2
s3
admin
adm
a
ht
adminht
webht
web
gm
sys
system
manage
manager
mgr
b
c
passport
bata
wei
weixin
wechat
wx
wiki
upload
ftp
pic
jira
zabbix
nagios
bug
bugzilla
sql
mysql
db
stmp
pop
imap
mail
zimbra
exchange
forum
bbs
list
count
counter
img
img01
img02
img03
img04
api
cache
js
css
app
apps
wap
m
sms
zip
monitor
proxy
proxy1
proxy2
update
upgrade
stat
data
portal
blog
autodiscover
en
search
so
oa
database
home
sso
help
vip
s
w
down
download
downloads
dl
svn
git
log
staff
vpn
ssl-vpn
sslvpn
ssh
scanner
sandbox
ldap
lab
go
demo
console
cms
auth
crm
130 changes: 130 additions & 0 deletions subDomainsBrute.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# A simple and fast sub domain brute tool
# my[at]lijiejie.com (http://www.lijiejie.com)

import optparse
import Queue
import sys
import dns.resolver
import threading
import time
import optparse
from lib.consle_width import getTerminalSize


class DNSBrute:
def __init__(self, target, names_file, threads_num, output):
self.target = target.strip()
self.names_file = names_file
self.threads_num = threads_num
self.scan_count = 0; self.found_count = 0
self.lock = threading.Lock()
self.console_width, _ = getTerminalSize(); self.console_width -= 2 # Cal width when starts up
self.resolvers = [dns.resolver.Resolver() for i in range(threads_num)]
self._load_dns_servers(); self._load_sub_names(); self._load_next_sub()
outfile = target + '.txt' if not output else output; self.outfile = open(outfile, 'w') # won't close manually
self.ip_dict = {}

def _load_dns_servers(self):
dns_servers = []
with open('dns_servers.txt') as f:
for line in f:
server = line.strip()
if server.count('.') == 3 and server not in dns_servers:
dns_servers.append(server)
self.dns_servers = dns_servers
self.dns_count = len(dns_servers)

def _load_sub_names(self):
self.queue = Queue.Queue()
with open(self.names_file) as f:
for line in f:
sub = line.strip()
if sub: self.queue.put(sub)

def _load_next_sub(self):
next_subs = []
with open('next_sub.txt') as f:
for line in f:
sub = line.strip()
if sub and sub not in next_subs:
next_subs.append(sub)
self.next_subs = next_subs

def _update_scan_count(self):
self.lock.acquire()
self.scan_count += 1
self.lock.release()

def _print_progress(self):
self.lock.acquire()
sys.stdout.write('\r' + '\0' * self.console_width)
msg = '%s found | %s remaining | %s scanned in %.2f seconds' % (
self.found_count, self.queue.qsize(), self.scan_count, time.time() - self.start_time)
sys.stdout.write('\r' + ' ' * (self.console_width -len(msg)) + msg)
sys.stdout.flush()
self.lock.release()

def _scan(self):
thread_id = int( threading.currentThread().getName() )
self.resolvers[thread_id].nameservers = [self.dns_servers[thread_id % self.dns_count]] # must be a list object
while self.queue.qsize() > 0:
sub = self.queue.get(timeout=1.0)
try:
cur_sub_domain = sub + '.' + self.target
answers = d.resolvers[thread_id].query(cur_sub_domain)
is_wildcard_record = False
if answers:
for answer in answers:
self.lock.acquire()
if answer.address not in self.ip_dict:
self.ip_dict[answer.address] = 1
else:
self.ip_dict[answer.address] += 1
if self.ip_dict[answer.address] > 10: # a wildcard DNS record
is_wildcard_record = True
self.lock.release()
if is_wildcard_record: self._update_scan_count(); self._print_progress(); continue
self.lock.acquire()
self.found_count += 1
sys.stdout.write('\r' + '\0' * self.console_width) # clear line
ips = ', '.join([answer.address for answer in answers])
sys.stdout.write('\r' + cur_sub_domain + '\t' + ips + '\n')
self.outfile.write(cur_sub_domain.ljust(30) + '\t' + ips + '\n')
self.lock.release()
for i in self.next_subs:
self.queue.put(i + '.' + sub)
except Exception, e:
pass
self._update_scan_count()
self._print_progress()
self._print_progress()

def run(self):
self.start_time = time.time()
for i in range(self.threads_num):
t = threading.Thread(target=self._scan, name=str(i))
t.start()

if __name__ == '__main__':
parser = optparse.OptionParser('usage: %prog [options] target')
parser.add_option('-t', '--threads', dest='threads_num',
default=10, type='int',
help='Number of threads. default = 10')
parser.add_option('-f', '--file', dest='names_file', default='subnames.txt',
type='string', help='Dict file used to brute sub names')
parser.add_option('-o', '--output', dest='output', default=None,
type='string', help='Output file name. default is {target}.txt')

(options, args) = parser.parse_args()
if len(args) < 1:
parser.print_help()
sys.exit(0)

d = DNSBrute(target=args[0], names_file=options.names_file,
threads_num=options.threads_num,
output=options.output)
d.run()


Loading

0 comments on commit 2857881

Please sign in to comment.