Thursday, December 8, 2016

Infinite Login to a Lightspeed-controllled network

If you've never heard of them before, Lightspeed Systems is a company that makes content-filtering appliances for schools and businesses. I happen to frequent a WiFi network that is heavily filtered by one of these devices, and as you can imagine, it is quite bothersome to come across a "this site is blocked" page in the course of doing my work. I understand the necessity of blocking certain pages, but not all blocking rules make sense:


The other big problem that I have on a regular basis with the system is that I have to log in to the internet every day in order to access anything. This becomes a huge problem with a headless device such as a Raspberry Pi. On my laptop, with a GUI web browser and a saved password for the login, it's not a huge issue, but with a Pi-based project that needs to connect to the internet continuously, it becomes a problem.

Last year, with an older version of the content filter, I was able to build a very simple automatic login script with Python and Requests that simply submitted the login form with my credentials and worked very well. This year, the website for the login was changed to dynamically load the login form with a highly-obfuscated and very large Javascript file. While attempting to write a new script that automated the new login system, I came across many of the different pieces of the login page.

The login page loads three Javascript files before it can dynamically render the page. Interestingly, it also loads a font from fonts.gstatic.com, which must be whitelisted to allow access through the filter even before a user is authenticated. Of my interest, however, are the Javascript files. The first one, access-default-<long hex string>.js, which is over 2.4MB, contains all the internationalization data, as well as the functions that load the page dynamically. This file is minified and obfuscated to make it very difficult to read, and its size causes some pretty bad lag in several text editors that I tried.

The second file is called data.js, which holds a base64-encoded json array that contains info about the images and Google authentication data, neither of which would help me log in. The third file, redir.js, was the one that caught my interest, containing this:

$(function(){renderAccessPage('another long base64 string')});

The function renderaccesspage() was somewhere inside the obfuscated js file, and the base64 string was another encoded json array, with more useful data inside it:

{"id":"d661beba-bc95-11e6-85be-00e0ed5686c8","ip":"10.23.25.159","host_id":"00000000-0000-0000-0000-000000000000","ident_id":14742636577554739,"filter_id":null,"tier_id":1,"reason":32769,"url":"portswigger.net/burp/","target":"portswigger.net","policy_id":null,"policy_rule_set_id":6,"cat_id":28,"cat_name":"security.proxy","is_auth":true,"can_auth":true,"auth_expire":600,"user":"redacted","host":"","host_dn":"","host_ou":"","can_override":false,"auth_override":false,"override_list_id":null,"override_time":0,"custom_access_page_id":null}

Clearly, the renderaccesspage() function takes these data and integrates them with a hidden field called redir in the form that is submitted. All my attempts to submit without this field resulted in an error, but without deciphering the Javascript, I had no idea how to generate the right data.

However, you may have already noticed that there is a field called auth_expire that is set to 600. If I'm correct, this is the login lease in minutes, as in my experience, the lease is almost exactly ten hours. Because this value is used by the function to generate the redir info, I thought it may play a part in the server deciding how long to grant a lease. Using Burpsuite and Python to edit redir.js, I was able to change the time of my lease to 60000 minutes, ensuring that I won't have to login again for a very long time.

It has so far worked, as I haven't been prompted for a login page after several days...

In conclusion, I find it strange that certain parts of the login process are left vulnerable like this. If the developers wanted the lease to be set to ten hours for everyone, it would probably be easier to do on the server rather than allow editable data like this to pass through a client device. I don't think that it's a huge vulnerability, but it may allow users access to the internet well after their account has expired, as long as the login persists in the system.

On another note, I believe this opens up an avenue for me to make my Raspberry Pi project work. Because the authentication is linked to a MAC address, I simply need to spoof my MAC address to that of the Pi, login with an arbitrarily long lease period, and then change back. Then I won't have to worry about it any more...



Monday, February 15, 2016

Exploring the OS of a Segate GoFlex Home

I recently happened upon a Segate GoFlex Home, which is a consumer grade desktop NAS with a single removable drive. I had really no use for it in its original state, since it required proprietary software to manage, so I disassembled the disk module and stuck the disk into one of my servers. The base, which you can pick up for around $35, sat unused until I decided to take off the case and investigate.

Hardware

The inside is fairly simple. The CPU is a Marvell 88F6-281, an ARMv5 running at 1.5GHz. It has a Nanya NT5TU64M16HG-AC 1GB DDR2 ram chip (I am unsure because other sources claim it's only 256 MB, and the official Nanya website is down at time of writing). For storage, it has a Toshiba TC58NVG1S3ETA00 256MB NAND flash chip. There is also a Marvell 88E1116R gigabit ethernet controller, as well as various voltage regulators, Ethernet and USB ports, and a SATA port on the bottom of the board. The power supply is 12V at 2A, likely to support the overhead of a mechanical hard drive.





(I added the heatsink after I disassembled it.)

Software

The process of rooting the device is quite simple and documented in several places. First you need to connect to the webserver on the device to create an account. Simply find the IP of the device, navigate there in a web browser, and follow the prompts. When finished, you should have a username and password. Now look on the bottom of the case and find the product key, look for something like PK: XXXX-XXXX-XXXX-XXXX.

Now, get an SSH client and connect to username_hipserv2_seagateplug_product-key@ip.address, where username is the username you previously created (in lowercase), product-key is the key in the form of XXXX-XXXX-XXXX-XXXX (all uppercase), and ip.address is the ip of the device. You should be able to log in with the password you created earlier. If all went well, a bash prompt should pop up.

Then, in order to gain root access, all you need to do is sudo -E -s

I went exploring into some of the files:

-bash-3.2$ cat /proc/cpuinfo
Processor : ARM926EJ-S rev 1 (v5l)
BogoMIPS : 1192.75
Features : swp half thumb fastmult edsp 
CPU implementer : 0x56
CPU architecture: 5TE
CPU variant : 0x2
CPU part : 0x131
CPU revision : 1
Cache type : write-back
Cache clean : cp15 c7 ops
Cache lockdown : format C
Cache format : Harvard
I size : 16384
I assoc : 4
I line length : 32
I sets : 128
D size : 16384
D assoc : 4
D line length : 32
D sets : 128

Hardware : Feroceon-KW
Revision : 0000

Serial : 0000000000000000

-bash-3.2$ cat /proc/cmdline 
console=ttyS0,115200 ubi.mtd=2,2048 root=ubi0:rootfs rootfstype=ubifs init=/linuxrc

-bash-3.2$ cat /proc/version 
Linux version 2.6.22.18 (ramang@es5x86.axentra.com) (gcc version 4.3.2 (sdk3.2rc1-ct-ng-1.4.1) ) #16 Thu Jun 17 01:37:53 EDT 2010

bash-3.2# uname -a
Linux axentraserver.jimmy.seagateshare.com 2.6.22.18 #16 Thu Jun 17 01:37:53 EDT 2010 armv5tejl armv5tejl armv5tejl GNU/Linux

Linux seems a bit out of date, don't you think? They didn't seem to try to slim it down much:

-bash-3.2$ file /bin/cat
/bin/cat: ELF 32-bit LSB executable, ARM, version 1 (SYSV), for GNU/Linux 2.6.16, dynamically linked (uses shared libs), for GNU/Linux 2.6.16, not stripped

However, It does fit, barely:

-bash-3.2$ df -h
Filesystem            Size  Used Avail Use% Mounted on
rootfs                212M  160M   52M  76% /

bash-3.2# ls /usr
X11R6  bin  etc  games include  kerberos  lib libexec  local sbin  share  src  tmp

What? X11? Games?? There is nothing in those folders, but still...

I'm working on a way to mount the filesystem and dump the whole thing... Might be shared soon.

It appears to be running several services, as indicated by an Nmap scan:

PORT      STATE    SERVICE     VERSION
21/tcp    open     ftp         vsftpd 2.0.7
22/tcp    open     ssh         Seagate GoFlex NAS device sshd 4.3 (protocol 2.0)
80/tcp    open     http        Apache httpd 2.2.3 ((Red Hat))
139/tcp   open     netbios-ssn Samba smbd 3.X (workgroup: SEAGATEGROUP)
443/tcp   open     ssl/http    Apache httpd 2.2.3 ((Red Hat))
445/tcp   open     netbios-ssn Samba smbd 3.X (workgroup: SEAGATEGROUP)
515/tcp   filtered printer
548/tcp   open     afp         Netatalk 2.2.0 (name: GoFlexHome; protocol 3.3)
631/tcp   open     ipp         CUPS 1.2
6689/tcp  open     daap        mt-daapd DAAP svn-1696
8200/tcp  open     upnp        MiniDLNA 1.0 (DLNADOC 1.50; UPnP 1.0)
49152/tcp open     upnp        Portable SDK for UPnP devices 1.4.6 (Linux 2.6.22.18; UPnP 1.0)

I'm confused as to why there are printer daemons, unless it shares a printer plugged into the USB port. As for the various media servers, I assume it indexes your media and serves it up (UPnP worked, but I don't have a disk so I wasn't able to test its full capabilities. As for the FTP and Samba, probably just fileservers. It's a pretty neat system that most people probably wouldn't ever use to full potential...

I'm still confused about most of the filesystem though. There appears to be a huge amount of random empty folders for apps like OpenVPN, Transmission Bittorrent, Gnome, and X11. All the files have been removed, but the folders have been left, cluttering the drive.

Controlling the LEDs

If you're interested in running custom code on this, LED indicators are useful. There are 3 LEDs on the front of the board. In order to set these, call the set-led-status executable like so:

set-led-status <led> <mode>

Where <led> is green_led, orange_led,  or  hdd_led
and <mode> is off, on,  or  blink

To be continued...

Sunday, January 3, 2016

Easy passive host discovery, featuring Scapy

If you've ever Wiresharked a large, high traffic LAN, you may have been overwhelmed by the volume of data. Package captures can easily exceed 500 packets per second, and although there is a lot of useful information, you as a human can't possibly process it fast enough.

Enter the world of Python and Scapy. If you haven't ever heard of Scapy, you're missing out. Among other things, it can send and receive custom packets with whatever layers you desire. It's also capable of dissecting packets, including pcap streaming and live sniffing. The latter is what I'll be talking about today. Most packet sniffing tools, like Wireshark and tcpdump, can dissect packets and do lots of powerful analysis on them. The main problem is that both these tools, and others like them, only can do per-packet analysis. What's really useful is when you can do per-host inspection. That's where Python comes in.

If you understand all this stuff, take a quick look at the Github for this project. If not, read on.

Packet Dissection

To understand the following scripts, you'll have to know a bit about what is going on inside a network packet. Each packet is transmitted as simply a string of binary, but depending on the type of information, this binary packet can have many different layers of information.

The lowest layer (usually) is called the Ethernet layer. It usually contains information like the source MAC address, destination MAC address, and a few other parameters, along with an encapsulated higher-level packet. A MAC address is a unique identifier of an interface card. It's not necessarily unique to each computer though, since your Wifi card, ethernet card, bluetooth module, etc all have different MAC addresses. In the following script, I identify each computer by its MAC address, assuming it only has one interface card connected to the network at one time. A useful feature of knowing a MAC address is that you can take a good guess as to the manufacturer of the network card or device. Manufacturers prefix MAC addresses with identifying information, so the manufacturer of a network card can usually be found.

Often, the next layer up is Internet Protocol, either IPv4 or IPv6. This layer is also used for routing of raw packets, but instead of identifying everything by its MAC address, it identifies by an IP address. This is the primary mode of communication for mainstream internet protocols, like HTTP.

Many different messages can be contained within these two layers of packets. For example, DHCP requests are sent every time a host connects to a network. These help give a host its IP address dynamically when it joins. For our purposes, it associates a hostname with an IP address. This can be extremely useful, since most people by default will leave their name in the hostname of their computer (e.g. JoeSmith-Macbook-Pro).

Passive Versus Active

The benefits of passive scanning over active are immense. Although active scanning can reveal much more information, it is much noisier on the network. Mass portscans are the biggest contender for noise, since most IDS or sysadmins will become suspicious of thousands of packets being sent at random to different hosts. Try Wiresharking while you perform an Nmap scan:


If it's done right, you can passively scan without sending a single packet onto the network. Then, once you have enough info, targeting single hosts and specific ports will likely remain unnoticed.

On To The Script

I have created a Python program to attempt to simplify per-host analysis. It uses Scapy to sniff and dissect packets, and then uses various plugins to process the data. The idea is that each plugin has a specific list of required layers, and if a packet has all those layers, it is sent to the plugin for processing.

For example I have a plugin called "ip" which associates IP addresses with MAC addresses in a table of the database. I also have a DHCP plugin that associates IP addresses with hostnames. There are a few more, and custom add-ons can be made easily.

Running it

Running it is pretty simple. You need to do some prep work the first time, like install a 2.x version of p0f. You also need to build the database of MAC address vendors, by going to analyzers/data and running gendb.py.  Finally, you need to make the data directory inside the main dir. Once that is done, you can run scanner.py <interface> to begin sniffing on the selected interface. You can also specify a pcap file, though I haven't tested that yet. 

The program creates no output until you end it with ctrl-c or similar. It will then spit out a line saying how many packets it captured and then exit. Depending on how long it was running, it will have amassed various amount of data. I recommend leaving it for at least an hour or two, and more than 24 hours is the most preferred since it can grab all the DHCP requests.

Viewing the data

There is also a viewer script, viewer.py, which displays all the database information in an easy-to-browse format. The database works on association, so there is a table associating each MAC address to an IP address, a table associating IP to hostname, etc. Along with simply pulling this kind of thing directly from dissected packets, I wrote a plugin to fingerprint operating systems using Scapy's p0f plugin (note that Scapy's p0f support is only for the p0f 2.x databases, so you can't simply install the latest p0f). It doesn't always work, but sometimes it is useful.

Upon running viewer.py, you get a nice listing of all the hosts that were identified. Unfortunately there is often a lot of traffic that falls below the IP layer, so there are a bunch of listings that only show a MAC address. Here's a sample of some more interesting listings:

mac: a8:bb:cf:07:92:50:
manuf: Apple
ip: 10.0.1.19
hostname: None
os: Linux:2.4.2x
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
mac: 68:64:4b:55:93:8e:
manuf: Apple
ip: 10.0.1.10
hostname: LivingRmAppleTV
os: None
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
mac: 00:16:cb:c1:d9:7f:
manuf: Apple
ip: 10.0.1.70
hostname: None
os: None
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
mac: f8:1e:df:df:8c:41:
manuf: Apple
ip: 10.0.1.16
hostname: <redacted>-MBP
os: None
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
mac: ec:35:86:4e:50:d2:
manuf: Apple
ip: 10.0.1.4
hostname: <redacted>-iMac
os: None

Soon, I hope to sort hosts by the amount of information known about them to make looking through this data a bit easier.

As you can see, the first entry's MAC address identified as Apple, but the OS fingerprint identified it as Linux. I don't usually trust these OS fingerprints because they've never really been accurate in my experience. The hostname is really what I deem as important. As you can see, the default hostname was created for each one, so I can see that there are some Mac computers and an Apple TV. This is somewhat of a vulnerability when it comes to default installations, as the default hostnames for most personal computers are usually based on the computer model and name of the owner. If you know someone's name, you now know their IP.