Sunday, December 29, 2013

Two exploits added to ExploitHub

Hi,

I added two Metasploit exploits to the online ExploitHub non-0day exploit store. I am more than open to feature requests or bug reports.

The first abuses an open upload handler that was common across most, if not all, of Orange Themes Wordpress themes. It has been patched, but is unknown exactly when and seemed to span many older versions as well.

https://exploithub.com/catalog/product/view/id/448/

The second abuses a post-auth remote command execution vuln within Gitlab. The vuln is technically present within the gitlab-shell project which is separate from Gitlab itself. I tested the vulnerable version of gitlab-shell with versions 6.4, 6.3, and 6.2 and was able to pop shells on all three. If the admin simply updated Gitlab and not gitlab-shell as well, they may still be vulnerable. The patch is available here.

https://exploithub.com/catalog/product/view/id/449/

Tuesday, November 26, 2013

Thoughts on vulnerability scans with indirect connections

A long while back, I gave a talk at AHA about various thoughts I had on sort of an "inversion of control" notion of managing vulnerability scans on a network. The high level point was to be decentralized and let the network manage discovering and scanning itself, and to allow remote machines to ask for scans from the vulnerability management system (as opposed to having scans shoved down their throat).

There some problems with monolithic vulnerability management systems. Firstly, they are only ever discovering new hosts for a very short amount of time compared to the amount of time spent actually assessing hosts (or sitting idle in between scans). They cannot give you a good idea of how volatile your networks are. In a BYOD world like today, I am sure there are devices popping on and off you have no idea about and that you cannot gauge risk on. This means that the VMS has only a small picture of your network in most cases. In fact, it only has a picture of the static machines on your network. Now, there are things like the Nexpose vDiscover technology that greatly aid in virtualized environments and helps remediate this problem. But this might solve the problem for a small fraction of home or business owners.

Secondly, being able to let the clients ask for scans means that the VMS no longer has the responsibility of discovering (or being told about) the asset before using it. Many enterprise solutions use computer images to sustain homogenous environments (even if this mean being lax on patches) and having a small agent that automagically pings the VMS when brought up allows network admins to work on something better than adding hosts to their VMS, like watching videos of cats.

Lastly, most VMS solutions today require the VMS be on-premise since it needs to be able to log in to the other machines via SSH or SMB. There is no real support for a connect-back scan, where the VMS listens on a port for a connection from the machine, which would help cloud offerings bypass NAT firewalls. This is a major hurdle for breaking into home end-users and small/medium-sized businesses who just can't maintain a VMS solution and can't hire someone to do it. Some cloud offerings exist (I won't call them out, you can Google), and I am not sure how they work. However, the method I will propose is technically agnostic to the VMS you are using and would allow you to use multiple systems transparently.


I took a weekend a few weeks ago to hammer out a system that allowed an arbitrary VMS to performs authenticated scans with no knowledge of the credentials needed by the remote machine and no direct connection between the two. I accomplished this using the SSH protocol only, but have some ideas on accomplishing a similar goal with SMB.

I first set up a middleman server. This middleman server would essentially be a proxy between the VMS and the machine being scanned. When the remote machine decides it wants a scan, it tells the middleman server it wants to be scanned. The middleman server sets up a temporary local user that will be used by the VMS. This temporary user will have a special, very simple shell:

#!/bin/sh
mkfifo /tmp/{FIFO}-$$.in
mkfifo /tmp/{FIFO}-$$.out

echo "$@" > /tmp/{FIFO}-$$.in

cat /tmp/{FIFO}-$$.out


When the user is created, the middleman service creates a target on the VMS and provides the credentials for this special user. When the VMS logs in, all commands will be written to the FIFO. These will be read by a small C# application that has a file-system watcher watching for FIFO's matching a regex. This service also manages the connection with the agent and knows how to talk to each major VMS (yay bindings). It will pass the commands to the remote machine, and the agent runs them and returns the results. These results are written to the FIFO with the .out extension and the special shell returns the output to the VMS by reading the out FIFO.

I use a FIFO to reduce the possibility of race conditions. I don't want the agent or the VMS getting ahead of one another.

Using this, I was successfully able to scan the machine as root with the VMS never knowing the root password of the machine. This method would allow a home computer behind a router to be fully scanned with no work on the end-user besides installing the agent. The agent has no idea which VMS has scanned it as that was all managed by the middleman service.

There are a few caveats. This method is about 3x slower than a normal scan by my rough tests. I am sure a large bottleneck is the FIFO mechanism, this could be performed in memory.

Second caveat is the VMS still portscans the middleman. Not sure how to resolve this.

Third caveat is it isn't obvious how to tell the difference between report items for the middle (port scan results) and authed results. You can infer it using XML reports and various data, but with PDF reports you would probably have no idea. You can also get around this simply by taking an XML diff of a port scan of the VMS with no authed reported vulns.

No github code yet, really a pile right now and not worth putting up yet. This serves a technical explanation of what my code does.

Sunday, September 22, 2013

metafang 1.0

Last night, I released a small project I have been working on called metafang. It offers a service that generates dynamic .NET executables with Metasploit x86/x86_64 payloads that can be run on Unix/Windows, and provides the source code of the payload with the executable itself, in case you are worried about backdoors. :)

A free user can generate 3 payloads a month. Each payload can have up to four fangs (one per arch per os). Each payload can be regenerated 3 times within that same month. No dynamic fang encryption is available for free users, and they are not allowed to redefine fang option defaults.

An advanced user (3.99/month, 19.99/year) can generate 5 payloads a month, and have up to 12 fangs (three per arch per os). You may also regen the payloads 5 times within that same month. If they were encrypted, the keys will change each regen. Optional dynamic encryption/decryption is available to Advanced users, as well as the ability to define new fang option defaults.

An expert user (5.99/month, 29.99/year) can create 25 payloads a month, and have up to 40 fangs (10 fangs per arch per os). You may also regen the payloads 5 times each within the same month. If they are encrypted, the keys will change with each regen. Optional dynamic encryption/decryption is available to Expert users, as well as the ability to define new fang option defaults.

Each user is available in a yearly and monthly flavor, and the users revert back to a free user (with access to previous payloads).

Defining a new default fang option is done in the Edit User page (click on username, top-right) if you are an advanced/expert user. This allows you to define keys such as LHOST or LPORT that will be substituted by default on the Create Payload page.

Opening an advanced/expert account help funds future development! So think of this like a kickstarter request, but I actually already have something that works.

Feedback is always appreciated. You can comment below or send me an email at bperry[dot]volatile[at]gmail[dot]NOSPAM[dot]com.

Wednesday, June 19, 2013

C# byte array of shellcode for msfpayload/msfvenom

If you get latest on metasploit framework, you can now use msfpayload/msfvenom to generate a C# byte array containing the payload that you may copy into your source file:

msfpayload windows/exec CMD=calc.exe H

Monday, May 27, 2013

Simple cross-platform connect-back and binds payloads in C#

I committed some simple connect-back and bind payloads to GitHub this morning. You may find them here: https://github.com/brandonprry/connect_back_bind_payloads

Wednesday, May 22, 2013

Vulnerable SOAP endpoint and related fuzzer on github

I have written a small SOAP endpoint in C# and a corresponding fuzzer that parses the WSDL of the vulnerable endpoint and attempts to find SQL injections. It then passes vulnerable URL's it finds to SQLMap via the RESTful SQLMap API. You can get the source here:

https://github.com/brandonprry/vulnerable_soap_service

Saturday, April 13, 2013

Interacting with SQLMap from C#

I just checked in some basic bindings to the SQLMap RESTful API. Pretty simple, below is an example application. It creates a new task, sets the msfPath option (but stores a copy of the options from before), starts the task using a specific URL set in the options dictionary, watches the scan until it completes, then writes the logs messages to stdout. You can get the bindings on github.
using System;
using sqlmapsharp;
using System.Collections.Generic;

namespace Example
{
 class MainClass
 {
  public static void Main (string[] args)
  {
   using (SqlmapSession session = new SqlmapSession("127.0.0.1", 8775))
   {
    using (SqlmapManager manager = new SqlmapManager(session))
    {
     string taskid = manager.NewTask();

     Console.WriteLine(taskid);

     Dictionary options = manager.GetOptions(taskid);

     manager.SetOption(taskid, "msfPath", "/path/to/msf");

     Dictionary newoptions = manager.GetOptions(taskid);

     Console.WriteLine("Old msfpath: " + options["msfPath"].ToString());
     Console.WriteLine("New msfpath: " + newoptions["msfPath"].ToString());

     options["url"] = "http://192.168.1.254/xslt?PAGE=C_0_0";

     manager.StartTask(taskid, options);

     SqlmapStatus status = manager.GetScanStatus(taskid);

     while (status.Status != "terminated")
     {
      System.Threading.Thread.Sleep(new TimeSpan(0,0,10));
      status = manager.GetScanStatus(taskid);
     }

     List logItems = manager.GetLog(taskid);

     foreach (SqlmapLogItem item in logItems)
      Console.WriteLine(item.Message);

     manager.DeleteTask(taskid);
    }
   }
  }
 }
}

Unofficial SQLmap RESTful API documentation

This isn't comprehensive, just the most useful methods. I haven't found any docs on the API yet but wanted to play with it. :)

The full list of methods available are:
@get("/task/new")
@get("/task/<taskid>/delete")
@get("/admin/<taskid>/list")
@get("/admin/<taskid>/flush")
@get("/option/<taskid>/list")
@post("/option/<taskid>/get")
@post("/option/<taskid>/set")
@post("/scan/<taskid>/start")
@get("/scan/<taskid>/stop")
@get("/scan/<taskid>/kill")
@get("/scan/<taskid>/status")
@get("/scan/<taskid>/data")
@get("/scan/<taskid>/log/<start>/<end>")
@get("/scan/<taskid>/log")
@get("/download/<taskid>/<target>/<filename:path>")


These are the methods I have been using
GET /task/new
Response:
{
    "taskid": "1d47d7f046df1504"
}



GET /task/<task_id>/delete
Response:
{
    "success": true
}



GET /option/<task_id>/list Response:
{
    "options": {
        "crawlDepth": null, 
        "osShell": false, 
        "getUsers": false, 
        "getPasswordHashes": false, 
        "excludeSysDbs": false, 
        "uChar": null, 
        "regData": null, 
        "cpuThrottle": 5, 
        "prefix": null, 
        "code": null, 
        "googlePage": 1, 
        "query": null, 
        "randomAgent": false, 
        "delay": 0, 
        "isDba": false, 
        "requestFile": null, 
        "predictOutput": false, 
        "wizard": false, 
        "stopFail": false, 
        "forms": false, 
        "taskid": "73674cc5eace4ac7", 
        "skip": null, 
        "dropSetCookie": false, 
        "smart": false, 
        "risk": 1, 
        "sqlFile": null, 
        "rParam": null, 
        "getCurrentUser": false, 
        "notString": null, 
        "getRoles": false, 
        "getPrivileges": false, 
        "testParameter": null, 
        "tbl": null, 
        "charset": null, 
        "trafficFile": null, 
        "osSmb": false, 
        "level": 1, 
        "secondOrder": null, 
        "pCred": null, 
        "timeout": 30, 
        "firstChar": null, 
        "updateAll": false, 
        "binaryFields": false, 
        "checkTor": false, 
        "aType": null, 
        "direct": null, 
        "saFreq": 0, 
        "tmpPath": null, 
        "titles": false, 
        "getSchema": false, 
        "identifyWaf": false, 
        "checkWaf": false, 
        "regKey": null, 
        "limitStart": null, 
        "loadCookies": null, 
        "dnsName": null, 
        "csvDel": ",", 
        "oDir": null, 
        "osBof": false, 
        "invalidLogical": false, 
        "getCurrentDb": false, 
        "hexConvert": false, 
        "answers": null, 
        "host": null, 
        "dependencies": false, 
        "cookie": null, 
        "proxy": null, 
        "regType": null, 
        "optimize": false, 
        "limitStop": null, 
        "mnemonics": null, 
        "uFrom": null, 
        "noCast": false, 
        "testFilter": null, 
        "eta": false, 
        "threads": 1, 
        "logFile": null, 
        "os": null, 
        "col": null, 
        "rFile": null, 
        "verbose": 1, 
        "aCert": null, 
        "torPort": null, 
        "privEsc": false, 
        "forceDns": false, 
        "getAll": false, 
        "api": true, 
        "url": null, 
        "invalidBignum": false, 
        "regexp": null, 
        "getDbs": false, 
        "freshQueries": false, 
        "uCols": null, 
        "smokeTest": false, 
        "pDel": null, 
        "wFile": null, 
        "udfInject": false, 
        "tor": false, 
        "forceSSL": false, 
        "beep": false, 
        "saveCmdline": false, 
        "configFile": null, 
        "scope": null, 
        "dumpAll": false, 
        "torType": "HTTP", 
        "regVal": null, 
        "dummy": false, 
        "commonTables": false, 
        "search": false, 
        "skipUrlEncode": false, 
        "referer": null, 
        "liveTest": false, 
        "purgeOutput": false, 
        "retries": 3, 
        "extensiveFp": false, 
        "dumpTable": false, 
        "database": "/tmp/sqlmapipc-EmjjlQ", 
        "batch": true, 
        "headers": null, 
        "flushSession": false, 
        "osCmd": null, 
        "suffix": null, 
        "dbmsCred": null, 
        "regDel": false, 
        "shLib": null, 
        "nullConnection": false, 
        "timeSec": 5, 
        "msfPath": null, 
        "noEscape": false, 
        "getHostname": false, 
        "sessionFile": null, 
        "disableColoring": true, 
        "getTables": false, 
        "agent": null, 
        "lastChar": null, 
        "string": null, 
        "dbms": null, 
        "tamper": null, 
        "hpp": false, 
        "runCase": null, 
        "osPwn": false, 
        "evalCode": null, 
        "cleanup": false, 
        "getBanner": false, 
        "profile": false, 
        "regRead": false, 
        "bulkFile": null, 
        "safUrl": null, 
        "db": null, 
        "dumpFormat": "CSV", 
        "alert": null, 
        "user": null, 
        "parseErrors": false, 
        "aCred": null, 
        "getCount": false, 
        "dFile": null, 
        "data": null, 
        "regAdd": false, 
        "ignoreProxy": false, 
        "getColumns": false, 
        "mobile": false, 
        "googleDork": null, 
        "sqlShell": false, 
        "pageRank": false, 
        "tech": "BEUSTQ", 
        "textOnly": false, 
        "commonColumns": false, 
        "keepAlive": false
    }
}



POST /option/<task_id>/set -- Content-Type:application/json
Request:
{ "msfPath" : "/path/to/metasploit/framework" }
Response:
{
    "success": true
}



POST /scan/<task_id>/start -- Content-Type:application/json
Request (optional):
{ "url" : "192.168.1.250/index.php?wut=injectable" }
Response:
{
    "engineid": 16784, 
    "success": true
}



GET /scan/<task_id>/log
Response:
{
    "log": [
        {
            "message": "testing connection to the target URL", 
            "level": "INFO", 
            "time": "14:11:23"
        }, 
        {
            "message": "testing if the target URL is stable. This can take a couple of seconds", 
            "level": "INFO", 
            "time": "14:11:24"
        }, 
        {
            "message": "target URL is stable", 
            "level": "INFO", 
            "time": "14:11:26"
        }, 
        {
            "message": "no parameter(s) found for testing in the provided data (e.g. GET parameter 'id' in 'www.site.com/index.php?id=1')", 
            "level": "CRITICAL", 
            "time": "14:11:26"
        }, 
        {
            "message": "testing connection to the target URL", 
            "level": "INFO", 
            "time": "14:17:30"
        }, 
        {
            "message": "testing if the target URL is stable. This can take a couple of seconds", 
            "level": "INFO", 
            "time": "14:17:31"
        }, 
        {
            "message": "target URL is not stable. sqlmap will base the page comparison on a sequence matcher. If no dynamic nor injectable parameters are detected, or in case of junk results, refer to user's manual paragraph 'Page comparison' and provide a string or regular expression to match on", 
            "level": "WARNING", 
            "time": "14:17:33"
        }, 
        {
            "message": "testing if GET parameter 'PAGE' is dynamic", 
            "level": "INFO", 
            "time": "14:17:33"
        }, 
        {
            "message": "confirming that GET parameter 'PAGE' is dynamic", 
            "level": "INFO", 
            "time": "14:17:33"
        }, 
        {
            "message": "GET parameter 'PAGE' does not appear dynamic", 
            "level": "WARNING", 
            "time": "14:17:33"
        }, 
        {
            "message": "reflective value(s) found and filtering out", 
            "level": "WARNING", 
            "time": "14:17:33"
        }, 
        {
            "message": "heuristic (basic) test shows that GET parameter 'PAGE' might not be injectable", 
            "level": "WARNING", 
            "time": "14:17:33"
        }, 
        {
            "message": "testing for SQL injection on GET parameter 'PAGE'", 
            "level": "INFO", 
            "time": "14:17:34"
        }, 
        {
            "message": "testing 'AND boolean-based blind - WHERE or HAVING clause'", 
            "level": "INFO", 
            "time": "14:17:34"
        }, 
        {
            "message": "testing 'MySQL >= 5.0 AND error-based - WHERE or HAVING clause'", 
            "level": "INFO", 
            "time": "14:17:34"
        }, 
        {
            "message": "testing 'PostgreSQL AND error-based - WHERE or HAVING clause'", 
            "level": "INFO", 
            "time": "14:17:34"
        }, 
        {
            "message": "testing 'Microsoft SQL Server/Sybase AND error-based - WHERE or HAVING clause'", 
            "level": "INFO", 
            "time": "14:17:34"
        }, 
        {
            "message": "testing 'Oracle AND error-based - WHERE or HAVING clause (XMLType)'", 
            "level": "INFO", 
            "time": "14:17:35"
        }, 
        {
            "message": "testing 'MySQL inline queries'", 
            "level": "INFO", 
            "time": "14:17:35"
        }, 
        {
            "message": "testing 'PostgreSQL inline queries'", 
            "level": "INFO", 
            "time": "14:17:35"
        }, 
        {
            "message": "testing 'Microsoft SQL Server/Sybase inline queries'", 
            "level": "INFO", 
            "time": "14:17:35"
        }, 
        {
            "message": "testing 'Oracle inline queries'", 
            "level": "INFO", 
            "time": "14:17:35"
        }, 
        {
            "message": "testing 'SQLite inline queries'", 
            "level": "INFO", 
            "time": "14:17:35"
        }, 
        {
            "message": "testing 'MySQL > 5.0.11 stacked queries'", 
            "level": "INFO", 
            "time": "14:17:36"
        }, 
        {
            "message": "testing 'PostgreSQL > 8.1 stacked queries'", 
            "level": "INFO", 
            "time": "14:17:36"
        }, 
        {
            "message": "testing 'Microsoft SQL Server/Sybase stacked queries'", 
            "level": "INFO", 
            "time": "14:17:36"
        }, 
        {
            "message": "testing 'MySQL > 5.0.11 AND time-based blind'", 
            "level": "INFO", 
            "time": "14:17:36"
        }, 
        {
            "message": "testing 'PostgreSQL > 8.1 AND time-based blind'", 
            "level": "INFO", 
            "time": "14:17:37"
        }, 
        {
            "message": "testing 'Microsoft SQL Server/Sybase time-based blind'", 
            "level": "INFO", 
            "time": "14:17:37"
        }, 
        {
            "message": "testing 'Oracle AND time-based blind'", 
            "level": "INFO", 
            "time": "14:17:37"
        }, 
        {
            "message": "testing 'MySQL UNION query (NULL) - 1 to 10 columns'", 
            "level": "INFO", 
            "time": "14:17:37"
        }, 
        {
            "message": "testing 'Generic UNION query (NULL) - 1 to 10 columns'", 
            "level": "INFO", 
            "time": "14:17:38"
        }, 
        {
            "message": "using unescaped version of the test because of zero knowledge of the back-end DBMS. You can try to explicitly set it using option '--dbms'", 
            "level": "WARNING", 
            "time": "14:17:38"
        }, 
        {
            "message": "GET parameter 'PAGE' is not injectable", 
            "level": "WARNING", 
            "time": "14:17:39"
        }, 
        {
            "message": "all tested parameters appear to be not injectable. Try to increase '--level'/'--risk' values to perform more tests. Also, you can try to rerun by providing either a valid value for option '--string' (or '--regexp')", 
            "level": "CRITICAL", 
            "time": "14:17:40"
        }, 
        {
            "message": "HTTP error codes detected during run:\n404 (Not Found) - 183 times", 
            "level": "WARNING", 
            "time": "14:17:40"
        }
    ]
}

GET /scan/<task_id>/status
Response:
{
    "status": "terminated", 
    "returncode": 0
}

Friday, February 15, 2013

Corelan Training

This week, I took the Corelan Exploit Development Training. It was a two day training, on Tuesday and Wednesday, and very fun. I will admit, it is not for the weak of heart. Tuesday, we started at 9am, and I ended up leaving around 11pm, and other guys stayed even later. Wednesday, we started at 9am again and went until around 8pm.

During the first day, we discussed classic buffer overflows resulting is pointer overwrites and the like, and how to exploit them using Immunity Debugger and mona.py. Luckily, I already had experience with most of the materials for the first day through personal experience, and was able to help out other guys taking the class with using mona and how the buffer overflows worked.

During the second day, we discussed DEP, ASLR, and ROP chains. I do not have much experience with these, so the learning curve was higher, although I did understand the fundamentals of how these worked. We also discussed heap sprays, which was great as well. Heap sprays had been on my todo-list for quite a while and are incredibly interesting to me.

Peter is a great teacher and understands the materials well enough to answer tangential questions that aren't really covered in the materials. He understands his students very well, so he is able to relate information in meaningful ways, which is infinitely more helpful than just presenting information and expecting the students to  remember by simple rote memory. It also helps that he presents materials that he wrote himself, rather than simply using someone else's work.

Overall, I highly recommend the class if you have the means. In order to really get the most out of the class, you should absolutely have a basic understanding of assembly and how stacks and heaps work. You can read up on these on the corelan website.

Thursday, January 17, 2013

First Ubuntu apps published

Check out the VolatileMinds Registry Reader or the VolatileMinds Pagefile Analyzer in the Ubuntu app store.

The registry reader is a GTK/Mono application that allows the user to read offline hives with an easy to use UI.

The pagefile analyzer is a GTK/mono application that allows the user to analyze a pagefile.sys from a computer, and search for email addresses, filepaths, environment variables, and more.