Laundry token hack via DS1992 iButton data backup (and restore)
In the dormitory I was living, they had prepaid laundry machine tokens: You had to charge them by paying real money, and then you could operate all laundry machines by paying with that token.
For operating a machine, you had to hold your token against the machine for some seconds; this transferred a fixed amount of money from your token to the machine. The display showing your temporary credit counted backwards during operation. After the machine had finished, you could place your token on the machine again and the remaining amount was refunded.
The security of the whole system is based on the assumption that the user doesn't have access to a soldering iron. The money tokens are just DS1992 iButtons: simple 1-wire-attached 1 kbit memories, with no tamper-proof-counters or authentication measures.
Since the data sheet is publically available, it's not difficult to build a small device that is able to dump the memory of these tokens, and to write these dumps (or, arbitrary data, actually) to the tokens. This allows the user to backup the contents of the token before paying, and restoring this backup afterwards.
However, when looking at the dumps after multiple transactions, there are multiple blocks of data that contain some probably-encrypted data, and a 4-byte-counter which decreases after every transaction. That way, it would be possible for a laundry machine to detect the tampering (by keeping a database of (userid, counter) tuples), and to possibly invalidate the token. I haven't tried whether they actually do this, because there's a way to circumvent that safety measure:
The dorm has multiple laundry machines, and they seem to not communicate with each other (at least, they don't have a LAN connection or similar, and they look too old for WiFi). The tokens contain, except for the always-decreasing counters, not enough non-constant fields to have one encrypted anti-tamper-counter for each machine, so I assume that the tamper detection algorithm is like this:
when machine #i sees token #j: if token.counter <= machine.last_known_counters[j]: somehow decrypt the probably-encrypted area check some kind of checksum if checksum ok: perform the transaction token.counter-- machine.last_known_counters[j] = token.counter else: tampering detected! end if else tampering detected! end if
Using a single counter, combined with no communication between the machines, is a fatal security flaw. That way, it's possible for a user to do the following:
- backup the token
- use machine 1
- restore the token
- transfer some money on machine 2 (this will work, because machine 2 has never seen the decreased value and thinks that the token is legit)
- instantly get the money back from machine 2
- repeat that another time
- now machine 1 can be used safely again, because the token's current counter is lower than what machine 1 has previously seen
This allows for infinite free laundries, and might even allow you to charge your tokens "for free".
Proof of concept
With a small ATmega8 board, the token can be read from and written to. The firmware is here.
For documentation, please refer to the source code and the README file
It would be quite easy to store one counter for each machine in the probably-encrypted area, if they would use the full 1 kbit the chip offers. That way, restoring any backup would permanently block the token on one machine, effectively limiting the amount of free laundrys to the number of machines available. This could have been done without any changes in hardware, just by software.
Alternatively, they could, as recommended by the data sheet, have used a DS1994 instead, which offers tamper-proof counters, which can only be counted down, but not up. This would at least prevent a simple restore-attack. However, a mildly talented person could still build a device that acts like the DS1994, but allows to actually tamper with the tamper-proof counters.