From e543b1cdc0a0861524590eedc348e5d635079a41 Mon Sep 17 00:00:00 2001 From: Conor Horan-Kates Date: Sun, 12 Mar 2017 17:12:58 -0700 Subject: [PATCH] everything except actually rooting the device --- .gitignore | 1 + README.md | 3 +- lametric/README.md | 493 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 496 insertions(+), 1 deletion(-) create mode 100644 lametric/README.md diff --git a/.gitignore b/.gitignore index 8ec8cbd..b7acd56 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ *crx* *.bundle* *squashfs* +*.bin # project files *.iml diff --git a/README.md b/README.md index 196aa02..3fcfbba 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ name | description | url [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) [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) [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) +[Ubiquiti mFi mPower](https://www.ubnt.com/mfi/mpower/) | root access trivially obtained, credential leakage, unnecessary services exposed | [ubiquiti/mFi](ubiquiti/mfi) \ No newline at end of file diff --git a/lametric/README.md b/lametric/README.md new file mode 100644 index 0000000..64aa80c --- /dev/null +++ b/lametric/README.md @@ -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 //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 + + + + + 1 + 0 + + https://172.16.42.219:443 + + urn:schemas-upnp-org:device:LaMetric:1 + LaMetric (LM7817) + LaMetric Inc. + http://www.lametric.com + LaMetric - internet connected clock and smart display + LaMetric Time Battery Edition + SA01 + http://www.lametric.com + + 10478 + 10478 + uuid: + + +``` + +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= 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= +``` + +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 `\`, 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 + +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 +... +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 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 + + + + 1 + 0 + + https://172.16.42.219:443 + + urn:schemas-upnp-org:device:LaMetric:1 + LaMetric (LM7817) + LaMetric Inc. + http://www.lametric.com + LaMetric - internet connected clock and smart display + LaMetric Time Battery Edition + SA01 + http://www.lametric.com + + 10478 + 10478 + uuid: + + +```