From cd534f500edd5c04fc8e68e72eae3264dfef34fd Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 16 Aug 2010 13:05:13 +0800 Subject: easytool: ad getopt option parser --- easytool/easytool.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/easytool/easytool.c b/easytool/easytool.c index 67157c8..75cec83 100644 --- a/easytool/easytool.c +++ b/easytool/easytool.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -125,20 +126,64 @@ static void print_help(void) { } +enum mode { + MODE_DUMP_MFACC, + MODE_DUMP, + MODE_RECHARGE, + MODE_PURCHASE, +}; + int main(int argc, char **argv) { + enum mode mode = MODE_DUMP; + int delta = 0; + int option_index = 0; struct stat st; printf(COPYRIGHT); - if (argc < 2) { + while (1) { + int c; + static struct option long_options[] = { + { "dump-access-bits", 0, 0, 'a' }, + { "alter-recharge", 1, 0, 'r' }, + { "alter-purchase", 1, 0, 'p' }, + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "r:p:ha", + long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 'a': + mode = MODE_DUMP_MFACC; + break; + case 'r': + mode = MODE_RECHARGE; + delta = atoi(optarg); + break; + case 'p': + mode = MODE_PURCHASE; + delta = atoi(optarg); + break; + case 'h': + print_help(); + exit(0); + break; + } + }; + + if (argc <= optind) { fprintf(stderr, "ERROR: You must specify the file name of " "a mifare dump file (.mfd)\n"); print_help(); exit(2); } - global.fd = open(argv[1], O_RDONLY); + global.fd = open(argv[optind], O_RDONLY); if (global.fd < 0) { perror("Error opening the MFD file"); exit(1); @@ -155,8 +200,18 @@ int main(int argc, char **argv) exit(1); } - //dump_mfcl(global.mft); - dump_easycard(global.mft); + switch (mode) { + case MODE_DUMP_MFACC: + dump_mfcl(global.mft); + break; + case MODE_DUMP: + dump_easycard(global.mft); + break; + case MODE_RECHARGE: + break; + case MODE_PURCHASE: + break; + } munmap(global.mft, global.size); close(global.fd); -- cgit v1.2.3 From d3c282f9179de48d66b850444ea688bfd02c40d7 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 16 Aug 2010 13:09:04 +0800 Subject: actually call functions to modify the dump file --- easytool/easytool.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/easytool/easytool.c b/easytool/easytool.c index 75cec83..2e7ada3 100644 --- a/easytool/easytool.c +++ b/easytool/easytool.c @@ -42,16 +42,24 @@ /* Easycard specific includes */ #include "easycard.h" -#define VERSION "0.03" +#define VERSION "0.04" #define COPYRIGHT \ "EasyTool "VERSION" (C) 2010 by Harald Welte \n" \ "This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n" \ "Use of this software is authorized for RESEARCH PURPOSE ONLY!\n\n" +enum mode { + MODE_DUMP_MFACC, + MODE_DUMP, + MODE_RECHARGE, + MODE_PURCHASE, +}; + struct { int fd; unsigned long size; mifare_tag *mft; + enum mode mode; } global; static void dump_acc_bits(const struct acc_bits_parsed *abp) @@ -126,19 +134,14 @@ static void print_help(void) { } -enum mode { - MODE_DUMP_MFACC, - MODE_DUMP, - MODE_RECHARGE, - MODE_PURCHASE, -}; - int main(int argc, char **argv) { - enum mode mode = MODE_DUMP; + struct stat st; int delta = 0; int option_index = 0; - struct stat st; + int rc; + + global.mode = MODE_DUMP; printf(COPYRIGHT); @@ -159,14 +162,14 @@ int main(int argc, char **argv) switch (c) { case 'a': - mode = MODE_DUMP_MFACC; + global.mode = MODE_DUMP_MFACC; break; case 'r': - mode = MODE_RECHARGE; + global.mode = MODE_RECHARGE; delta = atoi(optarg); break; case 'p': - mode = MODE_PURCHASE; + global.mode = MODE_PURCHASE; delta = atoi(optarg); break; case 'h': @@ -200,7 +203,7 @@ int main(int argc, char **argv) exit(1); } - switch (mode) { + switch (global.mode) { case MODE_DUMP_MFACC: dump_mfcl(global.mft); break; @@ -208,8 +211,10 @@ int main(int argc, char **argv) dump_easycard(global.mft); break; case MODE_RECHARGE: + rc = easy_alter_last_recharge(global.mft, delta); break; case MODE_PURCHASE: + rc = easy_alter_last_purchase(global.mft, delta); break; } -- cgit v1.2.3 From 6ed439ecb8c09465ad4bdce53aaca59e935cbbd9 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 17 Aug 2010 10:00:27 +0800 Subject: easytool: open file read/write in case we want to modify content --- easytool/easytool.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/easytool/easytool.c b/easytool/easytool.c index 2e7ada3..c504003 100644 --- a/easytool/easytool.c +++ b/easytool/easytool.c @@ -140,6 +140,7 @@ int main(int argc, char **argv) int delta = 0; int option_index = 0; int rc; + int prot, flags = O_RDONLY; global.mode = MODE_DUMP; @@ -166,10 +167,12 @@ int main(int argc, char **argv) break; case 'r': global.mode = MODE_RECHARGE; + flags = O_RDWR; delta = atoi(optarg); break; case 'p': global.mode = MODE_PURCHASE; + flags = O_RDWR; delta = atoi(optarg); break; case 'h': @@ -186,7 +189,7 @@ int main(int argc, char **argv) exit(2); } - global.fd = open(argv[optind], O_RDONLY); + global.fd = open(argv[optind], flags); if (global.fd < 0) { perror("Error opening the MFD file"); exit(1); @@ -196,8 +199,12 @@ int main(int argc, char **argv) exit(1); } global.size = st.st_size; - global.mft = mmap(NULL, global.size, PROT_READ, MAP_SHARED, - global.fd, 0); + + prot = PROT_READ; + if (flags == O_RDWR) + prot |= PROT_WRITE; + + global.mft = mmap(NULL, global.size, prot, MAP_SHARED, global.fd, 0); if (!global.mft) { perror("Error mmap()ing the MFD file"); exit(1); -- cgit v1.2.3 From aa0de9c6ae42de1e8528f73af9d99568e7a6aef0 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 17 Aug 2010 10:00:47 +0800 Subject: easytool: Add BUS transaction type (we don't know more details) --- easytool/data.c | 1 + easytool/easycard.h | 1 + 2 files changed, 2 insertions(+) diff --git a/easytool/data.c b/easytool/data.c index 9b20930..425f0f2 100644 --- a/easytool/data.c +++ b/easytool/data.c @@ -118,6 +118,7 @@ const struct value_string taipei_mrt_stn_id[] = { /* Easycard Transaction Type names */ const struct value_string easy_tt_names[] = { { EASY_TT_MRT_ENTER, "Enter MRT" }, + { EASY_TT_BUS, "Bus ride" }, { EASY_TT_MRT_REENTER, "ReEnter MRT" }, { EASY_TT_MRT_EXIT, "Leave MRT" }, { EASY_TT_PURCHASE, "Shop Purchase" }, diff --git a/easytool/easycard.h b/easytool/easycard.h index 8979524..1631c60 100644 --- a/easytool/easycard.h +++ b/easytool/easycard.h @@ -6,6 +6,7 @@ #include "utils.h" #define EASY_TT_MRT_ENTER 0x00 +#define EASY_TT_BUS 0x01 #define EASY_TT_MRT_REENTER 0x80 #define EASY_TT_MRT_EXIT 0x11 #define EASY_TT_PURCHASE 0x20 -- cgit v1.2.3 From e268c5b72e40da936cdea7cb846adde6ceca522e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 17 Aug 2010 10:02:51 +0800 Subject: easytool: fix calculation of 'remaining' when modifying log record --- easytool/easycard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/easytool/easycard.c b/easytool/easycard.c index 980735d..a98c280 100644 --- a/easytool/easycard.c +++ b/easytool/easycard.c @@ -52,7 +52,7 @@ time_t easy_timestamp2time(const uint8_t *easy_ts) int easy_update_log_rec(struct easy_log_rec *elr, int16_t delta) { int32_t sum = elr->amount + delta; - int32_t remaining = elr->remaining = delta; + int32_t remaining = elr->remaining + delta; if ((sum < 0 || sum > 0xffff) || (remaining < 0 || remaining > 0xffff)) -- cgit v1.2.3 From 5e5f77962ffc3fe4f99248627046d097e245e639 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 17 Aug 2010 10:07:52 +0800 Subject: alter the last recharge of easycard #2 from 100 NTD -> 1000 NTD The real value of the card is 137 NTD. However, it should now appear to have 1037 NTD on it. --- easycard.2/201008142200-recharge500ntd-increased.mfd | Bin 0 -> 4096 bytes easycard.2/log.hex | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 easycard.2/201008142200-recharge500ntd-increased.mfd diff --git a/easycard.2/201008142200-recharge500ntd-increased.mfd b/easycard.2/201008142200-recharge500ntd-increased.mfd new file mode 100644 index 0000000..4374a49 Binary files /dev/null and b/easycard.2/201008142200-recharge500ntd-increased.mfd differ diff --git a/easycard.2/log.hex b/easycard.2/log.hex index af7cf84..f21fa00 100644 --- a/easycard.2/log.hex +++ b/easycard.2/log.hex @@ -6,9 +6,9 @@ 0000050 0000 1000 1027 0027 64de 0001 0000 bb00 0000060 f1d6 b4e8 0012 0000 0000 6400 0064 6900 0000070 2e64 f724 bd57 7708 008f 8917 3d48 5dcd -0000080 0089 0000 ff76 ffff 0089 0000 ff00 ff00 -0000090 0089 0000 ff76 ffff 0089 0000 ff00 ff00 -00000a0 c408 6708 304c 0064 0089 5b42 c50b 0031 +0000080 040d 0000 fbf2 ffff 040d 0000 ff00 ff00 +0000090 040d 0000 fbf2 ffff 040d 0000 ff00 ff00 +00000a0 c408 6708 304c 03e8 040d 5b42 c50b 0031 00000b0 0d3d 782b 33cd 7708 008f 2411 4ce7 ea3f 00000c0 0007 0003 0000 0000 0000 0000 0000 0000 00000d0 6b07 6593 114c 0012 0025 0811 6cf9 0002 -- cgit v1.2.3 From 1f31dfc7050d566b5ce8de128a810bfed4a7f977 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 17 Aug 2010 10:45:41 +0800 Subject: Card dump after a purchase of NTD 174 The card _really_ only had NTD 137 left, and was artificially increased to 1037 NTD balance. Thus, a purchase of NTD 174 would never have been possible, if the shop terminal would have known the true balance of the card as it is kept in the backend database. --- easycard.2/201008171045-after_174_ntd_purchase.mfd | Bin 0 -> 4096 bytes easycard.2/log.hex | 12 ++++++------ 2 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 easycard.2/201008171045-after_174_ntd_purchase.mfd diff --git a/easycard.2/201008171045-after_174_ntd_purchase.mfd b/easycard.2/201008171045-after_174_ntd_purchase.mfd new file mode 100644 index 0000000..313e5fb Binary files /dev/null and b/easycard.2/201008171045-after_174_ntd_purchase.mfd differ diff --git a/easycard.2/log.hex b/easycard.2/log.hex index f21fa00..cc944e8 100644 --- a/easycard.2/log.hex +++ b/easycard.2/log.hex @@ -6,11 +6,11 @@ 0000050 0000 1000 1027 0027 64de 0001 0000 bb00 0000060 f1d6 b4e8 0012 0000 0000 6400 0064 6900 0000070 2e64 f724 bd57 7708 008f 8917 3d48 5dcd -0000080 040d 0000 fbf2 ffff 040d 0000 ff00 ff00 -0000090 040d 0000 fbf2 ffff 040d 0000 ff00 ff00 +0000080 035f 0000 fca0 ffff 035f 0000 ff00 ff00 +0000090 035f 0000 fca0 ffff 035f 0000 ff00 ff00 00000a0 c408 6708 304c 03e8 040d 5b42 c50b 0031 00000b0 0d3d 782b 33cd 7708 008f 2411 4ce7 ea3f -00000c0 0007 0003 0000 0000 0000 0000 0000 0000 +00000c0 0009 0004 0000 0000 0000 0000 0000 0000 00000d0 6b07 6593 114c 0012 0025 0811 6cf9 0002 00000e0 9f06 658b 004c 0000 0037 2911 6c06 0002 00000f0 2fb1 511f 85b4 7708 008f 8dc8 eef5 2850 @@ -19,11 +19,11 @@ 0000120 9f06 658b 004c 0000 0037 2902 6c06 0002 0000130 4587 96bd 1f22 7708 008f 47ce 7619 1558 0000140 6b07 6593 114c 0012 0025 0802 6cf9 0002 -0000150 f004 6417 004c 0000 0061 2402 6a1c 0002 +0000150 5e09 6a64 204c 00ae 035f 0150 d092 0050 0000160 a605 6418 114c 0010 0051 2402 6d2c 0002 0000170 5583 7616 749e 7708 008f 9bf3 c129 8eb6 0000180 0a00 0200 0022 0000 0000 0000 1800 3200 -0000190 0200 2200 0022 0000 0000 0000 1600 1400 +0000190 0200 2200 0022 0000 0000 0000 1a00 1800 00001a0 0008 0003 0000 0000 0000 0000 0000 0000 00001b0 af5f 6aeb 3a2c 7708 008f c039 7a1d d248 00001c0 0000 0000 0000 0000 0000 0000 0000 0000 @@ -60,7 +60,7 @@ 00003b0 3320 9074 e84c 7708 008f 0094 85d5 7aaa 00003c0 8000 c926 0071 0000 0000 0000 0064 0064 00003d0 0000 0000 0000 0000 0000 0000 0000 0000 -00003e0 0000 0000 0000 0000 0000 0c00 233d 0001 +00003e0 0000 0000 0000 0000 0000 1100 ae3d 0000 00003f0 ea02 0bda b62a 7708 008f 0000 0000 0000 0000400 0000 0000 0000 0000 0000 0000 0000 0000 0000410 0000 0000 0000 0000 0000 0000 0000 0000 -- cgit v1.2.3 From d72bcdb8f9630ece273978d4979ea25a63e15997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henryk=20Pl=C3=B6tz?= Date: Tue, 17 Aug 2010 06:01:45 +0200 Subject: Typos and typography --- paper/easycard.tex | 58 +++++++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/paper/easycard.tex b/paper/easycard.tex index 1b57627..c87b3dd 100644 --- a/paper/easycard.tex +++ b/paper/easycard.tex @@ -4,7 +4,7 @@ \usepackage{subfigure} \pagestyle{plain} -%\usepackage{url} +\usepackage{url} \setlength{\oddsidemargin}{0in} \setlength{\evensidemargin}{0in} @@ -24,7 +24,7 @@ \maketitle \begin{abstract} -The EasyCard system, established in 2001, is the most popular store-valued card +The EasyCard system, established in 2001, is the most popular store-valued card % FIXME: "store-valued"? Meinten Sie: "stored-value"? in Taiwan. With more than 18 million issued cards, it is the predominant means of paying for public transportation services in the capital Taipei. @@ -59,7 +59,7 @@ validate it. This paper is also directed at the legislator and the regulatory authorities, in the hope that it will help them to produce better rules and requirements on -the technology designed for and usedby operators of security relevant systems +the technology designed for and used by operators of security relevant systems such as banking. \section{Introducing the EasyCard} @@ -107,12 +107,12 @@ they key of at least one different sectors. \subsection{Recovering the MIFARE CRYPTO1 keys} Since none of the sector keys was known, the publicly available MFCUK (MiFare -Classic Universal toolKit) implementation of the "Dark Side" attack (Nicolas T. +Classic Universal toolKit) implementation of the ``Dark Side'' attack (Nicolas T. Courtois) was used as a card-only attack. All that was required was the MFCUK Free Software, as well as a RFID reader as supported by libnfc. Compatible readers are widely available, -among them one for EUR 30 from http://www.touchatag.com/e-store. +among them one for EUR 30 from \url{http://www.touchatag.com/e-store}. Using the MFCUK key recovery tool, the A and B keys for all sectors have been recovered within FIXME. This attack can definitely be optimized @@ -132,6 +132,7 @@ with the nfc-mfclassic program (part of libnfc). A full dump of the newly-purchased, unused EasyCard revealed the following content: +\begin{verbatim} 0000000 a193 c031 88c3 0004 ba46 1214 1051 1004 0000010 140e 0100 0207 0308 0409 1008 0000 0000 0000020 0000 0000 0000 0000 0000 0000 0000 0000 @@ -196,6 +197,7 @@ content: 00003d0 0000 0000 0000 0000 0000 0000 0000 0000 00003e0 0000 0000 0000 0000 0000 0000 0000 0000 00003f0 ea02 0bda b62a 7708 008f 0000 0000 0000 +\end{verbatim} \subsection{Re-engineering the on-card data format} @@ -245,7 +247,7 @@ transportation as well as stores use key A for this sector, as key A is sufficient to read and decrement the VALUE block. Re-charging the card must happen using authentication with key B, as only -Key B has permissions to increment and/or write to this sector. +key B has permissions to increment and/or write to this sector. \subsubsection{Sector 3 through 5: The transaction log} @@ -299,7 +301,7 @@ FIXME: Transaction log pointer \subsubsection{Sector 7: The last MRT entry/exit record} -Block 2 (Offset 0x1e0) contains a record dscribing the last MRT station +Block 2 (Offset 0x1e0) contains a record describing the last MRT station that was entered using this EasyCard. \begin{itemize} \item Bytes 0...3 are unknown @@ -319,7 +321,7 @@ applicable discount in case a connection is made from MRT into a bus. \subsubsection{Sector 15: Maximum daily spending} -Sector 2 (Offset 0x3e0) contains a record used for keeping track of +Block 2 (Offset 0x3e0) contains a record used for keeping track of the amount of money spent on a single day. This is needed in order to impose a daily spending limit of (currently) NTD 3,000. @@ -357,13 +359,13 @@ balance. Re-reading the card after the purchase indicates the full success of the operation. The purchase has left exactly the same changes in the card like it would have with a card that has a genuine lower value. None of the -erroneosly increased (or decreased) numbers had been updated. +erroneously increased (or decreased) numbers had been updated. This specifically confirms that the vending terminal did not have an online connection to a centralized database. In that case, the erroneous values on the card would have been corrected and the original value restored. -\subsection{Increaing the value of the card} +\subsection{Increasing the value of the card} The approach works similar to the previous one. First, a purchase in a store is being made, preferrably with relatively high value. Later, the transaction @@ -400,8 +402,8 @@ system. The underlying Mifare Classic product was launched in 1994, and thus already relatively old and outdated technology at that time. -It was publicly documented by NXP that the security of the system is baesd on a -{\em prorprietary, symmetric, 48bit cipher}. Symmetric 48-bit encryption +It was publicly documented by NXP that the security of the system is based on a +{\em proprietary, symmetric, 48bit cipher}. Symmetric 48-bit encryption was definitely no longer state-of-the-art in the year 2000. At that time, the popular web-browser Netscape Navigator (used e.g. for web-based online banking) had already introduced support for symmetric 128bit ciphers. @@ -413,11 +415,11 @@ design} and {\em Security by obscurity}. In the former systems, security is achieved by using well-designed systems that have undergone public peer review and have been subject to cryptanalysis. -As a result, the system is secure because it has undergond the review and +As a result, the system is secure because it has undergone the review and scrutiny of the international community of cryptographers and security experts. So, despite making all details of the system, particularly the cryptographic -algorithms open, an attacker is not able to circumvent the systems security. +algorithms open, an attacker is not able to circumvent the system's security. A system relying on {\em Security by obscurity} is only secure because nobody knows the details of how it works. As soon as this information @@ -469,18 +471,18 @@ technically, cards can be re-charged without making actual payment for it. As far as cards are only used for public transportation, the incentive for fraudulent use is relatively small and contained. Also, the amount -of money for each transaction is realtively small. +of money for each transaction is relatively small. Thus, while the author would still disagree, it might be the case that the business risk analysis inside EasyCard Corporation would have deemed the risk of fraud in the public transport sector as acceptable. When such a card is used as an electronic payment system in stores where -goods of much higher value can be purcased, the threat model is quite +goods of much higher value can be purchased, the threat model is quite different, though. The 2010 introduction of the EasyCard as means of payment in retail -stores - while still relying on known-broken, 16 year old technology - +stores -- while still relying on known-broken, 16 year old technology -- can thus only be seen as ignorant and incompetent. It does not help that EasyCard corporation has to provide a full refund @@ -530,21 +532,23 @@ The author of this paper expresses his gratitude to the many people involved in trying to uncover the weaknesses of proprietary and ultimately insecure RFID systems worldwide. -Milosch and Brita Meriac +\begin{description} +\item[Milosch and Brita Meriac] for their great work on OpenPCD and OpenPICC -Henryk Ploetz, Karsten Nohl, starbug +\item[Henryk Ploetz, Karsten Nohl, starbug] for their work on MIFARE, Crypto1 and tiresome research into all kinds of proprietary snake-oil -Jonathan Westhues +\item[Jonathan Westhues] for designing and openly publishing the Proxmark -Nethemba +\item[Nethemba] for the Open Source implementation of the nested key attack in MFOC -Roel Verdult - for his research on RFID security at Radbound University and libnfc -Nicolas T. Courtois +\item[Roel Verdult] + for his research on RFID security at Radboud University and libnfc +\item[Nicolas T. Courtois] for his {\em darkside} paper -Andrei Costin - for his Open Sourc implementation of the darkside paper (MFCUK) - http://andreicostin.com/ +\item[Andrei Costin ] + for his Open Source implementation of the darkside paper (MFCUK) + \url{http://andreicostin.com/} +\end{description} \section{Bibliography} -- cgit v1.2.3