Skip to content

Commit

Permalink
Merge pull request #34 from malexmave/dev
Browse files Browse the repository at this point in the history
Version 1.0, as handed in for the final submission.
  • Loading branch information
malexmave committed Mar 5, 2015
2 parents 9e9d6d8 + b9d5be1 commit e4315b3
Show file tree
Hide file tree
Showing 65 changed files with 4,529 additions and 1,625 deletions.
53 changes: 52 additions & 1 deletion README.md
@@ -1,4 +1,55 @@
nfcgate
=======

NFC Wormholing
NFCGate is an Android application meant to relay communication between an NFC reader and a card. That way, NFC cards can be read over longer distances (we successfully read a card in Hamburg with a reader in Darmstadt). This also allows eavesdropping on the communication between card and reader, in order to reverse engineer the protocol, for example.

## Notice
This application was developed for security research purposes by students of the [TU Darmstadt](https://www.tu-darmstadt.de/), [Secure Mobile Networking Lab](https://www.seemoo.tu-darmstadt.de/). Please do not use this application for malicious purposes.

## Requirements
- Two android phones with NFC Chips, running Android 4.4+ (API-Level 19+). Android 5 is untested so far, but *may* work.
- At least one of these devices needs to support HCE (Host Card Emulation). Most NFC-Enabled phones of the lats few years should support that.
- The HCE phone needs to use a Broadcom NFC chip (compatible phones include the Nexus 4 and 5).
- The HCE phone needs to be rooted and have [Cydia Substrate](http://www.cydiasubstrate.com/) installed and enabled (see [here](https://github.com/malexmave/nfcgate/wiki/Cydia-Substrate) for help on how to get that done)
- One server to proxy communication between the two phones (see [nfcgate-misc](https://github.com/malexmave/nfcgate-misc) repository for server code)

## Requirements for compilation
- Android Studio
- Android NDK (required to compile our native code patch)

## Usage
The usage of this application is a bit fiddly right now, so follow these instructions exactly in order to make sure everything works.

After having installed and activated Cydia Substrate on at least one of the devices, install the application. Cydia Substrate will prompt you to reboot your phone, which you should do. Only the HCE device requires Cydia Substrate, the other one can work without it.

Afterwards, launch the app on both phones. Enter the IP and Port of the Server (default Port is 5566, feel free to set default values in the settings to avoid having to type them in each time) and hit "Create session" on one of the devices. The device will connect and display a session token with 6 digits. Hit "Join session" on the other device and enter that code. You should now be connected.

Now take the non-HCE-Phone and hold it to the card you want to read. The phone will detect the tag and read out some information, which will be sent to the HCE-Phone. There, it will be used to initialize and enable our patch to the Android NFC Daemon. Keep the phone attached to the card.

Now (*and only now*), you can hold the HCE-Phone to the reader **The first read may fail.** We are not quite sure why that is, but in our tests, the second read was always successful if the reader was not hardened against this attack. If you have enabled it, the non-HCE-phone will display the raw bytes it received from the card in the debug window. In the future, we will add an option to dump them to a file for later analysis. The server will also display the bytes.

Once you are done, you can remove the card and reader, and disconnect from the server using the disconnect button.

## Caveats
There are some caveats, so read this section carefully before using the application (and especially before filing a bug report).

### Native code patch compatibility
Our patch to the android NFC Daemon only works with Broadcom chips (or, to be more exact, with devices using libnfc-nci, not libnfc-nxp). It has been successfully tested on the Nexus 4 and 5, and may or may not work on other devices using the same libnfc. On incompatible devices, the application may still start, but it will be unable to proxy commands from the NFC reader. This is due to limitations in the Android API.

### Broadcom BCM20793 (Nexus 4) workaround
The android drivers for the Broadcom BCM20793 chip (as used in the Nexus 4) contain a bug which makes it impossible to use our application with MiFare DESFire cards (a common NFC card for payment systems). We are using a workaround to enable us to still read these cards, but that workaround has some side effects. When you start the application, you will get a warning if you are using an affected device. Please read the information carefully.

### Compatibility with cards
Android no longer offers support for MiFare classic chips on many devices. In general, we can only proxy tags supported by android. When in doubt, use an application like NFC Tag info to find out if your tag is compatible. We have done extensive testing with MiFare DESFire cards using a Nexus S, Nexus 4 and Nexus 5 as reader, and a Nexus 4 or Nexus 5 as HCE phone. All other combinations are untested (feedback is welcome).

### Compatibility with readers
This application only works with readers which do not implement additional security measures. One security measure which will prevent our application from working is when the reader checks the time it takes the card to respond. The network transmission adds a noticeable delay to any transaction, so any secure reader will not accept our proxied replies. However, if the reader does not implement any additional checks, it *should*be possible to proxy it.

### Confidentiality of data channel
Right now, all data is sent unencrypted over the network. We may or may not get around to implementing cryptographic protection, but for now, consider everything you send over the network to be readable by anyone interested. Keep that in mind while performing your own tests. Many NFC protocols are resistant to replay attacks, but your mileage may vary.

## Used Libraries
This application uses the following external libraries:
- [Cydia Substrate](http://www.cydiasubstrate.com/) (Licensed under the [LGPLv3](https://www.gnu.org/licenses/lgpl.html))
- [LibNFC](https://android.googlesource.com/platform/external/libnfc-nci/) (Licensed under the [Apache License v2.0](http://opensource.org/licenses/Apache-2.0))
- [Protobuf](https://code.google.com/p/protobuf/) (Licensed under the [BSD 3-Clause license](http://opensource.org/licenses/BSD-3-Clause))
9 changes: 8 additions & 1 deletion app/build.gradle
Expand Up @@ -10,6 +10,12 @@ android {
targetSdkVersion 20
versionCode 1
versionName "1.0"
ndk {
moduleName "nfcipc"
cFlags "-std=c++11 -fexceptions"
ldLibs "log"
abiFilters "armeabi"
}
}
buildTypes {
release {
Expand All @@ -20,5 +26,6 @@ android {
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile fileTree(include: ['*.jar'], dir: 'libs')
compile project(':nfcd')
}
47 changes: 31 additions & 16 deletions app/src/main/AndroidManifest.xml
Expand Up @@ -6,52 +6,55 @@

<!-- < Wifi Direct > -->
<uses-permission
android:required="true"
android:name="android.permission.ACCESS_WIFI_STATE"/>
android:name="android.permission.ACCESS_WIFI_STATE"
android:required="true" />
<uses-permission
android:required="true"
android:name="android.permission.CHANGE_WIFI_STATE"/>
android:name="android.permission.CHANGE_WIFI_STATE"
android:required="true" />
<uses-permission
android:required="true"
android:name="android.permission.INTERNET"/>
<!-- < / Wifi Direct > -->

android:name="android.permission.INTERNET"
android:required="true" />

<!-- < / Wifi Direct > -->
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
android:label="@string/app_name"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="tud.seemuh.nfcgate.main" />

<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

<activity
android:name=".Splash"
android:label="@string/app_name" >
android:label="@string/app_name"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="tud.seemuh.nfcgate.splash" />
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<!-- NFC Klimbim -->
<activity-alias
android:name=".ActivityAlias"
android:targetActivity=".MainActivity"
android:enabled="true">

android:enabled="true"
android:screenOrientation="portrait"
android:targetActivity=".MainActivity" >
<intent-filter>
<action android:name="android.nfc.action.TECH_DISCOVERED" />

<category android:name="android.intent.category.DEFAULT" />
</intent-filter>

<meta-data
android:name="android.nfc.action.TECH_DISCOVERED"
android:resource="@xml/tech" />
Expand All @@ -69,24 +72,36 @@
android:name="android.nfc.cardemulation.host_apdu_service"
android:resource="@xml/hce" />
</service>

<activity
android:name=".AboutActivity"
android:label="@string/app_name" >
android:label="@string/title_activity_about"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="tud.seemuh.nfcgate.about" />

<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

<activity
android:name=".SettingsActivity"
android:label="Settings"
android:screenOrientation="portrait"
android:targetActivity="MainActivity" >
<intent-filter>
<action android:name="tud.seemuh.nfcgate.settings" />

<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".AboutWorkaroundActivity"
android:label="@string/title_activity_about_workaround"
android:parentActivityName=".MainActivity" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="tud.seemuh.nfcgate.MainActivity" />
</activity>
</application>

</manifest>
32 changes: 32 additions & 0 deletions app/src/main/assets/html/WorkaroundInfo.en.html
@@ -0,0 +1,32 @@
<html>
<body style="background-color: #E5FDFC;">
<h3>Information about the workaround</h3>
<p>You are using a device running a Broadcom BCM20793 NFC chip. This chip has some known issues
which make it impossible to properly read MiFare DESFire cards with our application.</p>
<p>In order to enable you to read DESFire cards, we are using a workaround. However, this
workaround also breaks Android's method of detecting if a card has been removed. This means that
you will have to manually tell Android if you remove the card.</p>
<p>In the application, there is a reset button. Once you hold a card to the device, this button will
change to read "Forget card". Once you have removed the card again, please press that button to let
android know about this.</p>
<p><b>Until you have pressed that button, Android will not detect new NFC Tags!</b></p>
<p>That's all you need to know in order to use the application. If you are interested in technical
details, read on.</p>
<h3>Technical details</h3>
<p>Android periodically communicates with attached NFC tags in order to make sure that they are
still present. For this, it sends a command to the card and checks if it receives a reply. These
commands are usually NOPs ("No OPeration", commands that don't do anything).</p>
<p>However, Android devices using the Broadcom BCM20793 chip seem to have a bug that leads to them
sending commands to DESFire cards which lock the card into a specific mode. Once a card is locked
into a mode, it will not accept messages using other modes and will reply with an error (0x6e00).
</p>
<p>For our workaround, we start a thread which resets the keepalive timer of the Android NFC
watchdog thread every 100 milliseconds. That way, no keepalive commands are sent and the card is
not locked into any specific mode.</p>
<p>However, this also means that android will not detect the removal of a tag while the workaround
is active. Accordingly, we have to kill the watchdog thread to allow Android to recognize the
removal of a card. For this, we use the button mentioned above: All it does is to kill the workaround
thread. After that has happened, the Android watchdog thread will resume operation and detect the
removal of the card.</p>
</body>
</html>
36 changes: 36 additions & 0 deletions app/src/main/java/tud/seemuh/nfcgate/AboutWorkaroundActivity.java
@@ -0,0 +1,36 @@
package tud.seemuh.nfcgate;

import android.app.Activity;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.util.Log;
import android.webkit.WebView;

import java.io.IOException;
import java.util.Locale;


public class AboutWorkaroundActivity extends Activity {
private WebView mWebView;

private String TAG = "AboutWorkaroundAct";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about_workaround);

mWebView = (WebView) findViewById(R.id.workaroundDescWebView);
String loc = Locale.getDefault().getLanguage();
AssetManager mg = getResources().getAssets();
String path = "html/WorkaroundInfo." + loc + ".html";
try {
mg.open(path);
Log.i(TAG, "HTML exists for locale " + loc + ", using it.");
mWebView.loadUrl("file:///android_asset/" + path);
} catch (IOException ex) {
Log.i(TAG, "No HTML for locale " + loc + ", using default (en)");
mWebView.loadUrl("file:///android_asset/html/WorkaroundInfo.en.html");
}
}
}

0 comments on commit e4315b3

Please sign in to comment.