Module: PWN::SDR::Decoder::RFID

Defined in:
lib/pwn/sdr/decoder/rfid.rb

Overview

Pure-Ruby RFID activity detector for LF (125/134 kHz), HF (13.56 MHz) and UHF (860–960 MHz EPC Gen2).

Near-field ASK/load-modulation on LF/HF requires an inductive coupler (not an SDR antenna); UHF backscatter is 40–640 kbps ASK. Native mode reports reader-carrier presence and tag-response bursts by band. parse_line retained for offline text analysis.

Class Method Summary collapse

Class Method Details

.authorsObject

Author(s)

0day Inc. support@0dayinc.com



59
60
61
# File 'lib/pwn/sdr/decoder/rfid.rb', line 59

public_class_method def self.authors
  "AUTHOR(S):\n  0day Inc. <support@0dayinc.com>\n"
end

.decode(opts = {}) ⇒ Object

Supported Method Parameters

PWN::SDR::Decoder::RFID.decode( freq_obj: 'required - freq_obj returned from PWN::SDR::GQRX.init_freq' )



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/pwn/sdr/decoder/rfid.rb', line 19

public_class_method def self.decode(opts = {})
  freq_obj = opts[:freq_obj]
  hz = PWN::SDR.hz_to_i(freq: freq_obj[:freq])
  band = if hz < 1_000_000 then 'LF'
         elsif hz.between?(13_000_000, 14_000_000) then 'HF'
         else 'UHF'
         end
  PWN::SDR::Decoder::Base.run_detector(
    freq_obj: freq_obj,
    protocol: "RFID-#{band}",
    note: 'Native mode reports reader-carrier and tag-backscatter bursts by band.',
    threshold: 6.0,
    describe: proc { |b|
      kind = case band
             when 'LF'  then b[:duration_ms] > 100 ? 'reader-CW' : 'EM4x/HID-response'
             when 'HF'  then b[:duration_ms] > 5   ? 'ISO14443-REQA/frame' : 'ISO15693-slot'
             else            b[:duration_ms] > 20  ? 'reader-Query' : 'EPC-backscatter'
             end
      { band: band, modulation: 'ASK/load-mod', classification: kind }
    }
  )
end

.helpObject

Display Usage for this Module



65
66
67
68
69
70
71
72
73
74
75
# File 'lib/pwn/sdr/decoder/rfid.rb', line 65

public_class_method def self.help
  puts "USAGE (ruby-native detector, no external binaries):
    #{self}.decode(
      freq_obj: 'required - freq_obj returned from PWN::SDR::GQRX.init_freq'
    )

    #{self}.parse_line(line: 'UID: 04 A1 B2 C3 D4 E5 F6  SAK: 08  Mifare Classic 1K')

    #{self}.authors
  "
end

.parse_line(opts = {}) ⇒ Object

Supported Method Parameters

PWN::SDR::Decoder::RFID.parse_line(line: 'UID: 04 A1 B2 C3 D4 E5 F6')



45
46
47
48
49
50
51
52
53
54
55
# File 'lib/pwn/sdr/decoder/rfid.rb', line 45

public_class_method def self.parse_line(opts = {})
  line = opts[:line].to_s
  out  = { protocol: 'RFID' }
  out[:uid]  = ::Regexp.last_match(1).delete(' ') if line =~ /UID[:=]?\s*((?:[0-9A-Fa-f]{2}\s*){4,10})/
  out[:epc]  = ::Regexp.last_match(1) if line =~ /EPC[:=]?\s*([0-9A-Fa-f]+)/
  out[:atqa] = ::Regexp.last_match(1) if line =~ /ATQA[:=]?\s*([0-9A-Fa-f ]+)/
  out[:sak]  = ::Regexp.last_match(1) if line =~ /SAK[:=]?\s*([0-9A-Fa-f]+)/
  out[:tag]  = ::Regexp.last_match(1) if line =~ /(EM4\w+|HID\w*|Mifare\w*|NTAG\w*|ISO\s?\d+)/i
  out[:summary] = "RFID #{out[:tag]} UID=#{out[:uid] || out[:epc]}".squeeze(' ')
  out.compact
end