Dictionary Attacks on SSH and Web APIs
In running a mock pen-test I ran into an interesting wall with one of my tools, Burp Suite Free Edition. I also discovered some limitations in ncrack, and metasploit’s auxiliary/scanner/ssh/ssh_login tool.
Let’s start at the beginning.
What I needed was a simple dictionary attack tool that would take a list of usernames and a list of passwords and try them on the target. All of these tools do exactly this, but I ran into some limitations that caused them to be unusable for my purposes — and in this particular use case. My target was a group of VMs that simulated servers that were under higher-than-average load. SSH was enabled and one included a web form to sign into (not using ssh accounts). The servers were prone to dropping connections and timing out.
What this did was wreak havoc on ncrack and ssh_login. There are parameters to help with timing and level of aggressiveness (i.e. ssh_login’s ‘BRUTEFORCE_SPEED’ parameter, and the ‘cd’ and ‘T<0-5>’ flags for ncrack), but if a connection took too long or dropped completely, the tools would simply move on to the next username and password combination. In my particular use-case this was unacceptable. I tried using hydra with better-but-still-limited success (Their -w <time> flag would help). What I decided was to quickly run my own simple script.
Considering my requirements (expecting longer-than-normal wait times/timeouts/etc) I was not worried about writing my script in anything particularly fast (I chose Python). What I did want was a tool that was robust against varying timeouts and lengthy responses. I did this with a linear back-off and retry approach. I didn’t want exponential back-off as I still needed to complete the process — linear would do fine.
The meat of the script simply looked as follows:
connected = False wait_backoff = 1 max_attempts = 5 curr_attempt = 0 for user in userlist: for pw in passlist: while not connected: try: curr_attempt += 1 connect to target with user and pw except ssh problem: reinitialize ssh connection wait for wait_backoff seconds increment wait_backoff check if curr_attempt is at or over max_attempts exit with error message else: connected = True connected = False curr_attempt = 0 wait_backoff = 1
The full code can be seen at https://github.com/calebshortt/sshBF/blob/master/ssh_bruteforce.py. This isn’t a brute-force attack but a dictionary attack. This solved my problem of hydra, ssh_login, and ncrack completely stopping if they encounter some slow/laggy servers.
After I had completed my ssh audit, I turned my attention to the login page web form. It was an HTTP POST to an API endpoint. Burp Suite was my first thought and started it up. I had the free edition and figured this was simple enough to not need a paid version of the tool. I was wrong. Burp Suite Free Edition technically allows dictionary attack on web server but throttles the attack to the point that it is unusable, an obvious ploy to make the user purchase the full version. I decided to modify my script for ssh attacks and use it on web forms instead.
This was surprisingly easy and required little change on my part of the ssh script, and it was significantly faster than BURP Suite. I was able to complete my audit with a few extra tools.
The web form code can be found at: https://github.com/calebshortt/web_dict_bf