everything except actually rooting the device

This commit is contained in:
Conor Horan-Kates 2017-03-12 17:12:58 -07:00
parent b0f28083f9
commit e543b1cdc0
3 changed files with 496 additions and 1 deletions

1
.gitignore vendored
View File

@ -6,6 +6,7 @@
*crx* *crx*
*.bundle* *.bundle*
*squashfs* *squashfs*
*.bin
# project files # project files
*.iml *.iml

View File

@ -9,7 +9,8 @@ name | description | url
[CUJO](http://trycujo.com) | purposeful MiTM device for internet 'security' | [cujo](cujo) [CUJO](http://trycujo.com) | purposeful MiTM device for internet 'security' | [cujo](cujo)
[LG webOS](http://www.lge.com) | HTTP phone home is never a good idea | [lg-webOS](lg_webOS) [LG webOS](http://www.lge.com) | HTTP phone home is never a good idea | [lg-webOS](lg_webOS)
[HooToo TripMate series](http://www.hootoo.com) | there are lots of problems, some end up at root access | [hootoo](hootoo) [HooToo TripMate series](http://www.hootoo.com) | there are lots of problems, some end up at root access | [hootoo](hootoo)
[Ubiquiti mFi mPower](https://www.ubnt.com/mfi/mpower/) | root access trivially obtained, credential leakage, unnecessary services exposed | [ubiquiti/mFi](ubiquiti/mfi) [Lametric Time](http://lametric.com) | WiFi/internet enabled clock/LED display, unnecessary services exposed, root access obtainable | [lametric](lametric)
[Philips Hue](http://www.meethue.com) | device communication insecure, Ruby library/CLI to control via REST HTTP | [hued](https://github.com/chorankates/hued) [Philips Hue](http://www.meethue.com) | device communication insecure, Ruby library/CLI to control via REST HTTP | [hued](https://github.com/chorankates/hued)
[RAV FileHub](http://www.ravpower.com/ravpower-rp-wd02-filehub-6000mah-power-bank.html) | a HooToo by any other name.. but with a twist | [rav-filehub](rav-filehub) [RAV FileHub](http://www.ravpower.com/ravpower-rp-wd02-filehub-6000mah-power-bank.html) | a HooToo by any other name.. but with a twist | [rav-filehub](rav-filehub)
[RevoLabs flx UC1000](http://www.revolabs.com/products/conference-phones/wired-conference-phones/flx-uc-phones/flx-uc-1000-speakerphone) | more than just brute forcing the PIN | [revolabs-flx_uc_1000](revolabs-flx_uc_1000) [RevoLabs flx UC1000](http://www.revolabs.com/products/conference-phones/wired-conference-phones/flx-uc-phones/flx-uc-1000-speakerphone) | more than just brute forcing the PIN | [revolabs-flx_uc_1000](revolabs-flx_uc_1000)
[Ubiquiti mFi mPower](https://www.ubnt.com/mfi/mpower/) | root access trivially obtained, credential leakage, unnecessary services exposed | [ubiquiti/mFi](ubiquiti/mfi)

493
lametric/README.md Normal file
View File

@ -0,0 +1,493 @@
# time
- [device](#device)
- [digging](#digging)
- [nmap](#nmap)
- [curl](#curl)
- [wireshark](#wireshark)
- [mobile app](#mobile_app)
- [deeper](#deeper)
- [API](#api)
- [firmware](#firmware)
- [UPNP](#upnp)
## device
name | value
----------------|-----
model | `LM 37X8`
product | `CLOCK`
firmware | API `2.0.0`, OS `1.7.1`
features | WiFi enabled clock
the `TIME LM 37X8` is a 'smart' clock that features:
* internet connectivity to download apps, exchange information
* bluetooth controller to use the internal speaker
* clock with multiple alarms
* web radio tuner
* timer
* stopwatch
initial configuration is similar to Chromecast's, it stands up a WiFi network named `LM7***` based on the serial number of the device.
download the Android/iOS lamteric app and walk through connecting it to another wireless network - they do some external access checks with:
* `ntp` requests to `0.pool.ntp.org`
* `dns` resolution of `developer.lametric.com`
* `icmp` requests to `developer.lametric.com`
which has made tricking the device into talking to another endpoint has been unsuccessful so far, as it also appears to do SSL certification verification, so sslstrip isn't seeing anything.
through lametric's [developer site](https://developer.lametric.com/), once the device is registered, the API key necessary for talking to the device is displayed
## digging
### nmap
from `nmap -PN -p 1-65535 -sV 172.16.42.219`, we get:
```
PORT STATE SERVICE VERSION
22/tcp open ssh Dropbear sshd 2014.66 (protocol 2.0)
80/tcp open http lighttpd 1.4.35
443/tcp open http lighttpd 1.4.35
4343/tcp open ssl/http lighttpd 1.4.35
8080/tcp open http lighttpd 1.4.35
9001/tcp open tor-orport?
9002/tcp open dynamid?
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
```
ssh, 4 web servers (likely 2, one each of HTTP and HTTPS), 2 unknowns and a Linux fingerprint. for a clock.
### curl
#### 80 -> 443
```
$ curl -k -vv http://172.16.42.219
* Rebuilt URL to: http://172.16.42.219/
* Trying 172.16.42.219...
* TCP_NODELAY set
* Connected to 172.16.42.219 (172.16.42.219) port 80 (#0)
> GET / HTTP/1.1
> Host: 172.16.42.219
> User-Agent: curl/7.51.0
> Accept: */*
>
< HTTP/1.1 401 Unauthorized
< WWW-Authenticate: Basic realm="global"
< Content-Type: application/json;charset=UTF8
< Content-Length: 96
< Date: Fri, 10 Mar 2017 23:58:22 GMT
< Server: lighttpd/1.4.35
<
{
"errors":[
{
"message":"Authorization is required"
}
]
}
* Curl_http_done: called premature == 0
* Connection #0 to host 172.16.42.219 left intact
```
so something is listening there, and it's spitting back JSON, but we don't have credentials yet.
#### 4343
```
$ curl https://172.16.42.219:4343 -k -vv
* Rebuilt URL to: https://172.16.42.219:4343/
...
< HTTP/1.1 404 Not Found
< Content-Type: application/json;charset=UTF8
< Content-Length: 67
< Date: Fri, 10 Mar 2017 22:22:18 GMT
<
{
"errors":[
{
"message":"Resource not found"
}
]
}
```
different port, potentially the same underlying service/data, but this time - does not appear to require credentials.
### wireshark
see some communication between the device and it's mobile app:
```
GET /<redacted>/device_description.xml HTTP/1.1
Connection: close
Accept-Encoding: gzip
User-Agent: Google-HTTP-Java-Client/1.22.0 (gzip)
Host: 172.16.42.219:43316
HTTP/1.1 200 OK
DATE: Fri, 10 Mar 2017 16:06:04
Connection: close
HOST: 172.16.42.219:43316
content-length: 791
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<URLBase>https://172.16.42.219:443</URLBase>
<device>
<deviceType>urn:schemas-upnp-org:device:LaMetric:1</deviceType>
<friendlyName>LaMetric (LM7817)</friendlyName>
<manufacturer>LaMetric Inc.</manufacturer>
<manufacturerURL>http://www.lametric.com</manufacturerURL>
<modelDescription>LaMetric - internet connected clock and smart display</modelDescription>
<modelName>LaMetric Time Battery Edition</modelName>
<modelNumber>SA01</modelNumber>
<modelURL>http://www.lametric.com</modelURL>
<serialNumber><redacted></serialNumber>
<serverId>10478</serverId>
<deviceId>10478</deviceId>
<UDN>uuid:<redacted></UDN>
</device>
</root>
```
this port seems to change, but is easy to find as is part of an SSDP [UPNP broadcast](#upnp)
### mobile app
by changing the weather settings, we see:
```
GET /premium/v1/weather.ashx?q=<parameters> HTTP/1.1
Host: api.worldweatheronline.com
Accept: */*
```
parameters broken down:
```
Potrero District, United States of America&
num_of_days=2&
format=json&
fx=yes&
cc=yes&
mca=no&
fx24=no&
tp=24&
includelocation=yes&
showlocaltime=yes&&
extra=isDayTime,utcDateTime&
key=<redacted>
```
looks like a premium API key to [world weather online](worldweatheronline.com)
## deeper
### API
looking at some [docs](http://lametric-documentation.readthedocs.io/en/latest/reference-docs/lametric-time-reference.html) from lametric, was able to determine that the api lives at `http://device:port/api/v2`
authing with `dev` and `\<api key\>`, was got the expected list of routes:
```json
{
"api_version": "2.0.0",
"endpoints": {
"audio_url": "https://172.16.42.219:4343/api/v2/device/audio",
"bluetooth_url": "https://172.16.42.219:4343/api/v2/device/bluetooth",
"concrete_notification_url": "https://172.16.42.219:4343/api/v2/device/notifications{/:id}",
"current_notification_url": "https://172.16.42.219:4343/api/v2/device/notifications/current",
"device_url": "https://172.16.42.219:4343/api/v2/device",
"display_url": "https://172.16.42.219:4343/api/v2/device/display",
"notifications_url": "https://172.16.42.219:4343/api/v2/device/notifications",
"widget_update_url": "https://172.16.42.219:4343/api/v2/widget/update{/:id}",
"wifi_url": "https://172.16.42.219:4343/api/v2/device/wifi"
}
}
```
cool, so we can talk to the API successfully now - unfortunately, there isn't much that appears interesting on the surface, at least from an attack vector.
TODO add some redacted samples
### firmware
searching around for their [firmware](https://developer.lametric.com/getfirmware/download), the latest version shown was 1.7.7 - apparently they version OS and API separately.
binwalk shows us that the file is a nested squashfs:
```
$ binwalk -t -v -e <file>
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------------------------------------
0 0x0 Squashfs filesystem, little endian, version 4.0, compression:gzip, size:
79064386 bytes, 8 inodes, blocksize: 131072 bytes, created: 2017-03-06 17:58:17
$ sudo unsquashfs <file>
...
created 7 files
created 1 directories
created 0 symlinks
created 0 devices
created 0 fifos
$ ls squashfs-root/
rootfs.squash rootfs.squash.sig update.conf.sig
rootfs.squash.md5 update.conf update.conf.md5
$ cd squashfs-root
$ sudo unsquashfs squashfs-root
...
created 3697 files
created 675 directories
created 930 symlinks
created 253 devices
created 0 fifos
$ ls squashfs-root/
bin home libexec opt sbin usr
boot lametric linuxrc proc sys var
dev lib media root tests
etc lib32 mnt run tmp
```
now we're getting somewhere.
```
$ head -n 1 etc/shadow
root:$1$bxtvUSvB$y/SmJDjdq8IL.Q.Gkoobm.:10933:0:99999:7:::
```
started cracking at 5:30 on Friday afternoon <TODO> finish writeup after cracking
```
$ cat lametric/system/services/com.lametric.api/.api
[FastCGI]
portNumber=9001
socketType=FCGI-TCP
$ cat lametric/system/services/com.lametric.push.api/.push_api
[FastCGI]
portNumber=9002
socketType=FCGI-TCP
$ cat lametric/system/gui/com.lametric.notification_server/settings.json
{
"smtp_credentials": {
},
"filter_folder" : "Inbox",
"filter_emails" : ["lsqateam@gmail.com","lsqateam2@gmail.com"],
"filter_keywords" : ["lametric","money"],
"counter_all" : true,
"counter_unread" : true,
"show_subject" : true
}
$ cat etc/lighttpd/pushes/conf.d/fastcgi.conf
fastcgi.debug = 1
fastcgi.server = (
"/" => (
"/" => (
"host" => "127.0.0.1",
"port" => "9002",
"check-local" => "disable",
"min-procs" => 1,
"max-procs" => 1,
"idle-timeout" => 30,
"fix-root-scriptname" => "enable",
"allow-x-send-file" => "enable"
)
)
)
$ cat etc/lighttpd/pushes/conf.d/auth.conf
## type of backend
# plain, htpasswd, ldap or htdigest
auth.backend = "plain"
# filename of the password storage for plain
auth.backend.plain.userfile = "/lametric/data/configs/lighttpd/users.txt"
## for htpasswd
#auth.backend.htpasswd.userfile = "/lametric/data/configs/lighttpd/users.txt"
$ cat etc/init.d/S25install
...
# Checking if it is not empty
if [ "$(ls -A $IPK_SRC_DIR)" ]; then
PACKAGES=$(ls $IPK_SRC_DIR/*.ipk)
# for each ipk file do installation
for entry in $PACKAGES
do
echo Installing $entry
opkg-cl install $entry
if [ "$?" != "0" ]; then
echo Error installing $entry. Code $?
echo timestamp Error installing $entry, code $? >> /tmp/install.errlog
fi
# remove file after installation
rm $entry
done
done
...
$ cat etc/init.d/S31changeUserData
...
start() {
chmode 777 /lametric/data/data
}
...
$ cat etc/init.d/S99defwidgets
...
echo "Creating default widgets..."
su - app -s /bin/sh -c "/usr/bin/widget.sh create com.lametric.clock 08b8eac21074f8f7e5a29f2855ba8060"
su - app -s /bin/sh -c "/usr/bin/widget.sh create com.lametric.weather 380375c4b12c16e3adafb48355ba8061"
su - app -s /bin/sh -c "/usr/bin/widget.sh create com.lametric.radio 589ed1b3fcdaa5180bf4848e55ba8061"
su - app -s /bin/sh -c "/usr/bin/widget.sh create com.lametric.stopwatch b1166a6059640bf76b9dfe0455ba8062"
su - app -s /bin/sh -c "/usr/bin/widget.sh create com.lametric.countdown f03ea1ae1ae5f85b390b460f55ba8061"
$ cat etc/init.d/S99devicestatus
...
BLUETOOTH_MAC_ADDRESS=$(cat /sys/class/bluetooth/hci0/address)
WIFI_MAC_ADDRESS=$(cat /sys/class/net/wlan0/address)
WIFI1_MAC_ADDRESS=$(cat /sys/class/net/wlan1/address)
SD_CARD_SIZE=$(expr `cat /sys/block/mmcblk0/size` \* 512)
$ cat etc/lametric-tools/recovery.conf
# Device for keyboard input
input=/dev/input/event1
$ cat etc/lighttpd/lighttpd.conf
...
$SERVER["socket"] == ":4343" {
ssl.engine = "enable"
ssl.pemfile = "/etc/security/CA/server.pem"
}
$SERVER["socket"] == ":8080" {
ssl.enable = "disable"
}
$ cat etc/ssh/sshd_config
...
# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
# but this is overridden so installations will only check .ssh/authorized_keys
AuthorizedKeysFile /lametric/data/configs/.ssh/authorized_keys
$ cat etc/system.conf
# LaMetric filesystem structure
LAMETRIC_ROOT=/lametric
LAMETRIC_SYSTEM=/lametric/system/services
LAMETRIC_SYSTEM_GUI_APPS=/lametric/system/gui
LAMETRIC_PREINSTALLED_APPS=/lametric/system/apps
LAMETRIC_APPS=/lametric/data/apps
LAMETRIC_WIDGETS=/lametric/data/widgets
LAMETRIC_DATA=/lametric/data/data
LAMETRIC_CONFIGS=/lametric/data/configs
LAMETRIC_FORMAT_FLAG_FILE_NAME=/lametric/data/FORMAT_PARTITION
FIRMWARE_FILE_REGEXP=lm_ota_[a-z0-9._]*_sa1.bin
$ ls lametric/system/apps/com.lametric.radio/res/*.png
lametric/system/apps/com.lametric.radio/res/next.png
lametric/system/apps/com.lametric.radio/res/play.png
lametric/system/apps/com.lametric.radio/res/radio.png
lametric/system/apps/com.lametric.radio/res/screen1.png
lametric/system/apps/com.lametric.radio/res/stop.png
$ find usr/share/sounds/lametric -iname '*.wav' | wc -l
54
$ cat <>
...
{
"version":1,
"alarms" : [ {
"name" : "Alarm 1",
"time" : "15:22:49",
"enabled" : true,
"sound" : {
"source":"system",
"id":"sound1"
},
"daysofweek" : ["sun","mon","tue","wed","fri","sat"]
}],
"timezone" : "Europe/Kiev",
"timeformat24h" : true,
"seconds" : true,
"display_date" : false,
"dayofweek" : true,
"locale":"en_US"
}
...
$ cat usr/lib/xml2Conf.sh
...
XML2_LIBS="-lxml2 -L/var/lib/jenkins/jobs/LaMetric_Image_DVT/workspace/main_image/host/usr/arm-buildroot-linux-gnueabi/sysroot/usr/lib -lz -lm "
...
$ cat usr/share/tests/LEDMatrix.sh
#! /bin/sh
lmledtool -t &> /dev/null
var=$?
return $var
```
lots of interesting bits:
* what look like lametric QA email addresses
* despite ability to use htpasswd or htdigest, they use plaintext
* automatically installs `/etc/install/*.ipk`
* automatically makes all application configuration data readable by all users
* 2 wifi controllers allow for it to act as a hotspot
* it's using an SD card as primary (?) storage
* it has a keyboard controller, does not appear specific to the 3 buttons
* like most devices, has an easily accessible glob/regex of 'allowed' firmware names
* why is there an alarm set for `15:22:49`?
* what is the test that happens when we run `lmledtool -t`
unfortunately, many of the files mentioned live in `/lametric/data/configs` which is mostly unpopulated in the firmware squashfs, so will need to revisit once the root hash is cracked.
find all keys and try to use them to ssh in?
/Users/conor/git/h4ck/lametric/squashfs-root/squashfs-root/etc/wireless-regdb/pubkeys/linville.key.pub.pem
/Users/conor/git/h4ck/lametric/squashfs-root/squashfs-root/etc/ssl/private/192.168.0.180.key
### UPNP
```xml
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<URLBase>https://172.16.42.219:443</URLBase>
<device>
<deviceType>urn:schemas-upnp-org:device:LaMetric:1</deviceType>
<friendlyName>LaMetric (LM7817)</friendlyName>
<manufacturer>LaMetric Inc.</manufacturer>
<manufacturerURL>http://www.lametric.com</manufacturerURL>
<modelDescription>LaMetric - internet connected clock and smart display</modelDescription>
<modelName>LaMetric Time Battery Edition</modelName>
<modelNumber>SA01</modelNumber>
<modelURL>http://www.lametric.com</modelURL>
<serialNumber><redacted></serialNumber>
<serverId>10478</serverId>
<deviceId>10478</deviceId>
<UDN>uuid:<redacted></UDN>
</device>
</root>
```