Recover Mifare Classic key from authentication trace - rfid

I have been given a Mifare Classic authentication trace and was wondering if there are any tools or tutorials I could use to obtain the key?
Start | End | Src | Data
---------|---------|-----|--------
0 | 4704 | Rdr | 60 00 f5 7b
6708 | 11380 | Tag | 21 91 c4 03
82240 | 83552 | Rdr | 26
249792 | 250848 | Rdr | 26
252020 | 254388 | Tag | 04 00
333568 | 336032 | Rdr | 93 20
337204 | 343092 | Tag | 45 c7 a6 23 07
446208 | 456672 | Rdr | 93 70 45 c7 a6 23 07 f8 f6
457908 | 461428 | Tag | 88 be 59
1870544 | 1875248 | Rdr | 60 00 f5 7b
1877252 | 1881924 | Tag | be fd 8b 22
1953424 | 1954736 | Rdr | 26
2120208 | 2121264 | Rdr | 26
2122452 | 2124820 | Tag | 04 00
2205152 | 2207616 | Rdr | 93 20
2208788 | 2214676 | Tag | 45 c7 a6 23 07
2317024 | 2327488 | Rdr | 93 70 45 c7 a6 23 07 f8 f6
2328724 | 2332244 | Tag | 88 be 59
2538400 | 2543104 | Rdr | 60 00 f5 7b
2545108 | 2549844 | Tag | b3 38 4c d0
2651552 | 2660864 | Rdr | 55 09 6b fe ec fa ba c2 !crc
2662100 | 2666836 | Tag | a3! bf! 4f 07
17282768 |17287536 | Rdr | ef b6 fc 33 !crc

The paper Garcia et al.: Dismantling MIFARE Classic (ESORICS 2008) should give you a good starting point:
"The second and more efficient attack uses a cryptographic weakness of
the CRYPTO1 cipher allowing us to recover the internal state of the
cipher given a small part of the keystream. To mount this attack, one
only needs one or two partial authentication from a reader to recover
the secret key within one second, on ordinary hardware. This attack
does not require any pre-computation and only needs about 8 MB of
memory to be executed.
When an attacker eavesdrops communication
between a tag and a reader, the same methods enable us to recover all
keys used in the trace and decrypt it. This gives us sufficient
information to read a card, clone a card, or restore a card to a
previous state. We have successfully executed these attacks against
real systems, including the London Oyster Card and the Dutch
OV-Chipkaart."
In addition, the CRAPTO1 library (it's based on the above paper and some other discoveries) should give you a starting point on how to implement a tool to recover keys from recorded MIFARE Classic traces.
The interesting parts of this trace are:
446208 | 456672 | Rdr | 93 70 45 c7 a6 23 07 f8 f6
That's the reader's select command, from which you can get the tag's UID: 45 c7 a6 23.
1870544 | 1875248 | Rdr | 60 00 f5 7b
That's an authentication command with Key A for sector 0.
1877252 | 1881924 | Tag | be fd 8b 22
That's the random number sent by the tag in response to the authentication command. THe command is aborted after the tag sent the random number.
2538400 | 2543104 | Rdr | 60 00 f5 7b
That's an authentication command with Key A for sector 0.
2545108 | 2549844 | Tag | b3 38 4c d0
That's the random number sent by the tag in response to the authentication command.
2651552 | 2660864 | Rdr | 55 09 6b fe ec fa ba c2 !crc
That's the reader's random number (enciphered with keystream ks1) and the reader's response to the tag's challenge (random number) based on the authentication key (enciphered with keystream ks2).
2662100 | 2666836 | Tag | a3! bf! 4f 07
That's the tag's response to the reader's challenge (random number) based on the authentication key (enciphered with keystream ks3).
I wonder if my calculation is correct and the key is 36 ... 41!?

Related

How to replace values in a dataframe with values in another dataframe based on certain condition?

I want to replace the values of columns "q1_body" and "q2_body" of dataframe "result" with the values of "body" of the same id in dataframe "df", and the code is like:
def replace_body(x):
id1 = result.loc[x].qid1
result.loc[x].q1_body = df[df["qid"]==id1]["body"]
id2 = result.loc[x].qid2
result.loc[x].q2_body = df[df["qid"]==id2]["body"]
result.index.map(lambda x: replace_body(x))
When I run the code I got the following reminder in my ipython console and the program just stuck here:
//anaconda/lib/python3.6/site-packages/pandas/core/generic.py:3110:
SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame
See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
self[name] = value
Hope anyone can tell me what is wrong here.
Suppose the two dataframe are:
result:
qid1 q1_body qid2 q2_body
1a abc 2a bcd
1a abc 3a cde
2a bcd 3a cde
df:
qid body
1a sfgaks
2a shdfjk
3a adjkwf
And the expected output is like:
result:
qid1 q1_body qid2 q2_body
1a sfgaks 2a shdfjk
1a sfgaks 3a adjkwf
2a shdfjk 3a adjkwf
You need map by Series created by set_index:
s = df.set_index('qid')['body']
result['q1_body'] = result['qid1'].map(s)
result['q2_body'] = result['qid2'].map(s)
print (result)
qid1 q1_body qid2 q2_body
0 1a sfgaks 2a shdfjk
1 1a sfgaks 3a adjkwf
2 2a shdfjk 3a adjkwf
Here:
# Set index and get body as a series
s = df.set_index(qid)['body']
result['q1_body'] = s.loc[result['qid1']].values
result['q2_body'] = s.loc[result['qid2']].values
Result:
qid1 q1_body qid2 q2_body
0 1a sfgaks 2a shdfjk
1 1a sfgaks 3a adjkwf
2 2a shdfjk 3a adjkwf
Timing (10k rows, using auto-generated Lorem):
My method
#Jezareal's method

Multi-records Reading APDU command structure?

I have a card support T0 protocol with an applet is installed on it. The host send a "multi-records reading" command to get records data. Records are read which are specified by record identifiers in this data field of this command. These are steps that I did:
Select DF
Send a command to read sequence of records
00 B2 00 06 16 73 0A 51 02 40 01 54 04 00 10 00 04 73 08 51 02 40 02 54 02 00 01 00
The meaning of the command is as bellow:
INS = 'B2': read record(s)
P1 = '00': references the current record (ISO 7814-4, 7.3.3, table 48)
P2 = '07' = '00000 110' :
'0000' indicate current short EF id (ISO 7814-4, 7.3.2, table 47)
'111' mean read all records from the last up to P1 (ISO 7814-4, 7.3.3, table 49)
Le = 16 : data length
Data field follow the BER-TLV, for example:
73 0A 51 02 40 01 54 04 00 10 00 04
Tag'73' indicate that sequence of bytes above consist hierarchy data object structure in data filed (length = '0A')
Tag'51' reference to 2-byte EF identifier = '40 01'
Tag'54' reference to one or more record identifiers, in this case are '00 10' and '00 04'
Le = '00'
This is expect respond from card:
53 |length of data| record data| 53| length of data| record data|......
I test this command with the card, the card return 'Unknown Error' message.
Could you tell me what is wrong with the command? Am I misunderstood at any points?
Thanks.
This cannot be answered without knowing the actual implementation. 6F00 - the status word indicating an unknown error - should only be returned when the implementation has an internal error. For Java Card implementations - for instance - the 6F00 is returned for uncaught exceptions in the process method handling the APDU's.
But just like the rest of ISO/IEC 7816-4, nothing is set in stone. It's not even defined when a specific error should be returned, so even the above is unsure. ISO/IEC 7816-4 is thoroughly useless in that regard.
Thank you for your answer. My problem is solved
Actually the return SW = 61 XY is not error message. According to ISO 7814-3 it mean:
Process completed normally (SW2 encodes N x , i.e., the number of extra data bytes still available). In cases 1 and 3, the
card should not use such a value. In cases 2 and 4, for transferring response data bytes, the card shall be ready to receive
a GET RESPONSE command with P3 set to the minimum of N x and N e .
So just need to send a GET RESPONSE command to get response data:
00 C0 00 00 XY
XY: the number of extra data bytes still available

How to send a string to server using s_client

How to use s_client of openssl to send a short string to the server?
I have read the s_client manual but didn't find any usable flags.
Or is there any other ways to achieve this?
Does anyone know how to use s_client of openssl to send a short string to the server?
You can echo it in. Below, I used a GET withHTTP/1.0 and tweeter rudely refused my request:
HTTP/1.0 400 Bad Request
Content-Length: 0
The -ign_eof keeps the connection open to read the response.
Tweeter uses Verisign as the CA. You can fetch VeriSign Class 3 Primary CA - G5 from here, and then use it as an argument with -CAfile to ensure the chain verifies.
Here are the OpenSSL docs on s_client(1).
$ echo -e "GET / HTTP/1.0\r\n" | openssl s_client -connect twitter.com:443 -CAfile PCA-3G5.pem -ign_eof
CONNECTED(00000003)
depth=2 C = US, O = "VeriSign, Inc.", OU = VeriSign Trust Network, OU = "(c) 2006 VeriSign, Inc. - For authorized use only", CN = VeriSign Class 3 Public Primary Certification Authority - G5
verify return:1
depth=1 C = US, O = "VeriSign, Inc.", OU = VeriSign Trust Network, OU = Terms of use at https://www.verisign.com/rpa (c)06, CN = VeriSign Class 3 Extended Validation SSL CA
verify return:1
depth=0 1.3.6.1.4.1.311.60.2.1.3 = US, 1.3.6.1.4.1.311.60.2.1.2 = Delaware, businessCategory = Private Organization, serialNumber = 4337446, C = US, postalCode = 94103-1307, ST = California, L = San Francisco, street = 1355 Market St, O = "Twitter, Inc.", OU = Twitter Security, CN = twitter.com
verify return:1
---
Certificate chain
0 s:/1.3.6.1.4.1.311.60.2.1.3=US/1.3.6.1.4.1.311.60.2.1.2=Delaware/businessCategory=Private Organization/serialNumber=4337446/C=US/postalCode=94103-1307/ST=California/L=San Francisco/street=1355 Market St/O=Twitter, Inc./OU=Twitter Security/CN=twitter.com
i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/rpa (c)06/CN=VeriSign Class 3 Extended Validation SSL CA
1 s:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/rpa (c)06/CN=VeriSign Class 3 Extended Validation SSL CA
i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIGCjCCBPKgAwIBAgIQNC7E3U4iWJiTy5wznxxGDDANBgkqhkiG9w0BAQsFADCB
ujELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2Ug
YXQgaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYSAoYykwNjE0MDIGA1UEAxMr
VmVyaVNpZ24gQ2xhc3MgMyBFeHRlbmRlZCBWYWxpZGF0aW9uIFNTTCBDQTAeFw0x
NDA0MDgwMDAwMDBaFw0xNjA1MDkyMzU5NTlaMIIBEjETMBEGCysGAQQBgjc8AgED
EwJVUzEZMBcGCysGAQQBgjc8AgECEwhEZWxhd2FyZTEdMBsGA1UEDxMUUHJpdmF0
ZSBPcmdhbml6YXRpb24xEDAOBgNVBAUTBzQzMzc0NDYxCzAJBgNVBAYTAlVTMRMw
EQYDVQQRFAo5NDEwMy0xMzA3MRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH
FA1TYW4gRnJhbmNpc2NvMRcwFQYDVQQJFA4xMzU1IE1hcmtldCBTdDEWMBQGA1UE
ChQNVHdpdHRlciwgSW5jLjEZMBcGA1UECxQQVHdpdHRlciBTZWN1cml0eTEUMBIG
A1UEAxQLdHdpdHRlci5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
AQDGh6KKnZPGMiX5lC8Me9pev8CWscg5cIifrEV5WVW2v8sCoFlBDdnnIw26tqku
c/uL2aJoB8LAxllik0eNWRq9Q4YDRNuW05YIRQMEgRmAZvIKBpcLCcsB7YVLY7Jp
FBWGOEiUmL2c6GTc2NQWa723Jqwc6VgXZjDiL+wpHKUYc5RZz4IO3SdJ/Xlq38te
t5ZffCp/LBhhYNNUMStjEGdQwZCcnWF1DuaZ5TgxzdSGBSdFhssh5aCQO65TjQVn
cx4g8LNhXHNO7UxNIbEtuPmc0J8amPRHA0euHrgp2wBRZ0tL8Xphm0be3uAoA3DE
dO/d4wTMBNn5pN13Z9kYhzW/AgMBAAGjggGvMIIBqzAnBgNVHREEIDAeggt0d2l0
dGVyLmNvbYIPd3d3LnR3aXR0ZXIuY29tMAkGA1UdEwQCMAAwDgYDVR0PAQH/BAQD
AgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBEBgNVHSAEPTA7MDkG
C2CGSAGG+EUBBxcGMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LnZlcmlzaWdu
LmNvbS9jcHMwHQYDVR0OBBYEFBdQCycEZZ1SEbOZAgDknEo1GgKeMB8GA1UdIwQY
MBaAFPyKULqeuSVae1WFT5UAY4/pWGtDMEIGA1UdHwQ7MDkwN6A1oDOGMWh0dHA6
Ly9FVlNlY3VyZS1jcmwudmVyaXNpZ24uY29tL0VWU2VjdXJlMjAwNi5jcmwwfAYI
KwYBBQUHAQEEcDBuMC0GCCsGAQUFBzABhiFodHRwOi8vRVZTZWN1cmUtb2NzcC52
ZXJpc2lnbi5jb20wPQYIKwYBBQUHMAKGMWh0dHA6Ly9FVlNlY3VyZS1haWEudmVy
aXNpZ24uY29tL0VWU2VjdXJlMjAwNi5jZXIwDQYJKoZIhvcNAQELBQADggEBAIfv
GC219t5efjKTRhtwn2lEtWaQpsYlSyeN8KxLnVJlHRb5z1j8oJER6JmjeqelTvZ1
RlxZ3A8cQdrntpeh9kFkU3wMK6TjaMKYDrIaFzV1M4FXsqBbJ6vAb2GX1lDu7oxS
/FrNXH9ebFclDDlXJ3FWGbABxf+xpeowr9y+Md5xgQ0Lpm82NZFei9zuJayJYh4B
ZbIJ4D9XBa73ZqIBvGXixeahHIvBA9Q0T92gQDJoMXuQ3RkVt63lL4EoJaEQNr1f
JDn2Wb0MFtKokWF1zb86glCCb7nvc/vbotiWzZt+a49XSByZ1F17I49F/N5cU9ZU
DQzsM2ToLAU2fwA6h/U=
-----END CERTIFICATE-----
subject=/1.3.6.1.4.1.311.60.2.1.3=US/1.3.6.1.4.1.311.60.2.1.2=Delaware/businessCategory=Private Organization/serialNumber=4337446/C=US/postalCode=94103-1307/ST=California/L=San Francisco/street=1355 Market St/O=Twitter, Inc./OU=Twitter Security/CN=twitter.com
issuer=/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/rpa (c)06/CN=VeriSign Class 3 Extended Validation SSL CA
---
No client certificate CA names sent
---
SSL handshake has read 3724 bytes and written 446 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES128-GCM-SHA256
Session-ID: 53BE6F30E6C52AAFFC01EAD8D5938C78...
Session-ID-ctx:
Master-Key: 87810BE6303E8EB831EC63E243D4C6E7...
Key-Arg : None
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 129600 (seconds)
TLS session ticket:
0000 - 95 93 d8 f3 27 2f 4c 11-ab 14 ee 04 46 e3 a8 e5 ....'/L.....F...
0010 - 7f 35 16 07 6d 5e 80 7c-fa 1d cd 78 39 7e 82 0b .5..m^.|...x9~..
0020 - 1d ee d6 99 2d d2 03 db-ab b8 37 5d f5 a5 28 62 ....-.....7]..(b
0030 - 3b f6 c7 c3 dc 7c 77 de-0f 60 d8 4c 8c f6 8e 8b ;....|w..`.L....
0040 - c8 8e 65 68 96 ec 27 f1-26 5d 4c 25 49 fd c0 ca ..eh..'.&]L%I...
0050 - c5 86 00 19 f1 26 5a 3e-fd df ca 12 a9 f8 17 bb .....&Z>........
0060 - 77 b8 5b 1c 58 1a 6b 16-d1 16 e0 d9 e8 b2 bf 92 w.[.X.k.........
0070 - 44 07 60 17 a0 11 23 52-3a 14 d0 79 85 a3 ae 8d D.`...#R:..y....
0080 - 17 d1 b8 44 d7 c3 3e ab-67 4c 7a c0 d6 cd 7e fe ...D..>.gLz...~.
0090 - b7 95 56 69 8f 5f 3e ee-2a c1 f9 0e 46 75 a6 79 ..Vi._>.*...Fu.y
Start Time: 1398724229
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
HTTP/1.0 400 Bad Request
Content-Length: 0
closed
echo "YOUR TEXT HERE" | openssl s_client -connect host:port
The openssl s_client application can be used to send data to the web server with some creative bash scripting.
connectToHost="localhost:8443" ; \
dataToPost='{login: "Hello-world", password:"secret"}'; \
dataLen=$(expr length "${dataToPost}" ) ; \
( printf "POST / HTTP/1.1\n" ; \
printf "Host: %s\n" "${connectToHost}"; \
printf "Content-Length: %d\n" "$((dataLen+1))" ; \
printf "Content-Type: application/x-www-form-urlencoded\r\n\r\n" ; \
printf "%s\n" "${dataToPost}" ; \
sleep 1.5 ) | openssl s_client -connect ${connectToHost}
The printf and sleep statements are grouped together with parentheses to keep the pipe open until s_client has had a chance to send the request and receive a response. This delays the end-of-file signal so the -ign_eof option is not needed. The disadvantage of this approach is that the request will always take the specified amount of time regardless the server.
There are many ways to get the length of a string in bash. Using expr is a more verbose than other methods but it easier understand than ${#dataToPost}. The value of dataLen was incremented to include the newline character a few lines later. This is just to make things look pretty.
The first line of the HTTP request header is the action, POST.
The Host directive is often required. Populate this accordingly from the s_client -connect parameter.
The end of HTTP header section is always denoted by \r\n\r\n.
One final note. I may have overused line continuation characters but it is nice to have a single command when manually testing or running inside of a Dockerfile.

Why does hexdump-ing multiple files output differently than hexdumping each file individually?

What is the difference between these commands? Why does the first match, but grepping the individual file hexdumps returns nothing?
$ hexdump -C DRAFT* FAIL* RCV* | grep "49 d0 38 ec 06 a1 c3"
0001f430 49 d0 38 ec 06 a1 c3 7a 10 39 9c 07 bd cd 66 10 |I.8....z.9....f.|
$ hexdump -C RCV* | grep "49 d0 38 ec 06 a1 c3"
$ hexdump -C DRAFT* | grep "49 d0 38 ec 06 a1 c3"
$ hexdump -C FAIL* | grep "49 d0 38 ec 06 a1 c3"
$ ls
DRAFT DRAFT.HDR DRAFTUSED FAILED FAILED.HDR FAILEDUSED RCVD RCVD.HDR RCVDUSED SENT SENT.HDR SENTUSED SMS.html
The files are from my Samsung Sync SGH-A707. I'm trying to parse these sms files so I can make a plain-text backup of my text messages. The string I'm grepping for is a control message I encoded according to http://www.dreamfabric.com/sms/hello.html
Hexdump will concatenate the files, then convert to hex. If the character sequence is split across a line boundary, then it will not match your grep. I suspect this happens in some cases, but not others.
You could try using the -n option with a large number (larger than the files you are using) to put the whole output on a single line.

HEX & Decimal conversion

I have a binary file , the definition of its content is as below : ( all data is stored
in little endian (ie. least significant byte first)) . The example numbers below are HEX
11 63 39 46 --- Time, UTC in seconds since 1 Jan 1970.
01 00 --- 0001 = No Fix, 0002 = SPS
97 85 ff e0 7b db 4c 40 --- Latitude, as double
a1 d5 ce 56 8d 26 28 40 --- Longitude, as double
f0 37 e1 42 --- Height in meters, as float
fe 2b f0 3a --- Speed in km/h, as float
00 00 00 00 --- Heading (degrees ?), as float
01 00 --- RCR, log reason. 0001=Time, 0004=Distance
59 20 6a f3 4a 26 e3 3f --- Distance in meters, as double,
2a --- ? Don't know
a8 --- Checksum, xor of all bytes above not including 0x2a
the data from the Binary file "in HEX" is as below
"F25D39460200269652F5032445401F4228D79BCC54C09A3A2743B4ADE73F2A83"
I appreciate if you can support me to translate this data line based on the instruction before.
Probably wrong, but here's a shot at it using Ruby:
hex = "F25D39460200269652F5032445401F4228D79BCC54C09A3A2743B4ADE73F2A83"
ints = hex.scan(/../).map{ |s| s.to_i(16) }
raw = ints.pack('C*')
fields = raw.unpack( 'VvEEVVVvE')
p fields
#=> [1178164722, 2, 42.2813707974677, -83.1970117467067, 1126644378, 1072147892, nil, 33578, nil]
p Time.at( fields.first )
#=> 2007-05-02 21:58:42 -0600
I'd appreciate it if someone well-versed in #pack and #unpack would show me a better way to accomplish the first three lines.
My Cygnus Hex Editor could load such a file and, using structure templates, display the data in its native formats.
Beyond that, it's just a matter of doing through each value and working out the translation for each byte.

Resources