So I have never done write-ups for CtF’s before but I am taking the information that I have and putting it all together in some posts. This post and CtF posts before this date are going to be lacking as I never intended to write them up for a blog so don’t be suprised when they don’t meet your expectations.
Discovery of the application:
The h1Thermostat application was discovered by extracting the bit.do URL from the image at https://pbs.twimg.com/media/D0XoThpW0AE2r8S.png:large. The URL https://bit.do/h1therm then led to a Google Drive where the Android application file (h1thermostat.apk) could be downloaded https://drive.google.com/file/d/1u5Mg1xKJMrW4DMGaWtBZ1TJKPdvqCWdJ/view.
Disassembly of the APK
The file h1thermostat.apk was loaded into the Android SDK for analysis. The thermostat application requested a username and password to access the services. The APK code was extracted and it was found that the system would proceed past the login screen if the server responded with ”success”:true in a JSON object.
Use of default/weak administrative credentials:
The thermostat application was loaded into the Android SDK and executed. When the application started it requested a username and password to access the services. The application accepted the credentials:
Although some luck is involved in guessing this username and password combination it can easily be automated as there is no rate limiting or account lockout enabled on the application.
SQL Injection Vulnerability
Looking into the APK code further using jadx-gui the LoginActivity class calls the PayloadRequest class when a user signs in. The process takes the username and password and combines it with a command field in a JSON object. The login JSON object contains the username, password, and command field.
This text string is then encrypted with AES/CBC/PKCS5 and then ran through a base64 encoder. The server (18.104.22.168) then checks the credentials and replies with an encrypted JSON object
It was found that the field “username” in the JSON object was vulnerable to an SQLi attack. A custom Java application was written that would create a JSON object with the desired fields filled in and parse the server’s response. The SQLi vulnerability was blind, meaning that inference was needed to determine what was happening on the server side. It was found that when the success field in the JSON object was true the SQL query completed successfully. When the query was incorrect and failed the sever responded with success as false and the error was “Unknown”. Finally, if the query completed successfully but it returned 0 rows, success would be false and the error that was returned is “Invalid username or password”.
Using the different error messages returned by the server the SQLi vulnerability could be exploited to dump contents from the database. A custom Java application was written to pull the information out of the database using the following queries with the password of “password”:
admin' AND user() LIKE ‘%’;-- admin' AND (database()) LIKE ‘%’;-- admin' AND (SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 1 OFFSET 1") LIKE '%’;-- admin' AND (SELECT column_name FROM information_schema.columns WHERE table_schema=database() AND table_name='users' LIMIT 1 OFFSET 1) LIKE '%’;-- admin' AND (SELECT password FROM users LIMIT 1 OFFSET 0) LIKE '%’;--
The Java application would cycle through every printable character until a right answer was found. Once the first character was found the next character would be attacked. This would continue until the end of the string.
The users table holds a single record. The id is 1, the username is admin, and the password is 5f4dcc3b5aa765d61d8327deb882cf99. It was found that the data stored in the password field is an md5 hash of the word “password”. If there were more accounts stored in the table these could easily be reversed using various methods.
Once the devices table was dumped it was found that all IP addresses in the devices table were in reserved blocks and unrouteable. These addresses fell within the following ranges except for the record with the id 85.
The record with the id “85” in the devices table had an IP address of 22.214.171.124. This was the only accessible IP address in the table. When the address was visited with a web browser it displayed an administrative login page for “FliteThermostat”.
shitty image from cellphone, sorry.
It was found through running a dictionary type attack that some responses from the server were much slower than others. This indicated that the hash could be cracked using a timing attack (and a helpful push in the right direction by 0xc0ffee).
The hash was broken by brute forcing the string by two hexadecimal characters (1 byte) at a time and observing response times from the server. The longer response time that was received it was determined that the more likely the two characters were the next in the series of the string. The attack started with a series of 64 “0”’s and was brought down to the actual string using the response times from the server. After all 255 possible combinations were sent to the server the top 10 – 15 strings were replayed to eliminate false positives. When the string was found to replicate the same response time the process was started again on the next two characters.
The best results were found to be from a virtual machine replaying the POST with Burp although very slow. Settings were configured to only a single thread with 25 milliseconds for throttle. Once again this could be made more difficult by adding a rate limiting or account lockout control within the system.
The hash was then sent to the server and the response gave a redirect and a Session ID. The session ID was added to a browser with the console command
and this enabled access to the web application showing the pages: control, main, update, and diagnostics.
another shitty cellphone picture, sorry.
Thermostat Update Page:
The thermostat page was intended to download and install updates for the application. It was found that the port where the server was sending requests to could be changed by sending the parameter PORT=[port#] in the URL. After a portscan of 65,535 ports on the system and multiple other attempts I ran out of time here.
This CtF was amazing and I would like to thank everyone who helped build it! I learnt so much in this experience including probably the most important lesson of not jumping on the first vulnerability and thinking it is the end. This will help me in future CtF’s and more importantly in bounty hunting.