pwn 0.5.258 → 0.5.259
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +4 -3
- data/README.md +3 -3
- data/bin/pwn_serial_msr206 +0 -5
- data/bin/pwn_serial_son_micro_sm132_rfid +94 -34
- data/lib/pwn/plugins/son_micro_rfid.rb +436 -183
- data/lib/pwn/version.rb +1 -1
- metadata +1 -2
- data/msr206.log +0 -68
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c06971d7679da9c7582786d7fdf1058eb60fffa8e7e3be9a0381e8c64c27669
|
4
|
+
data.tar.gz: 18a09f571db9d4e5f7eccf39a1377afbaacc2b6ac7cedbf065d7efb7dc7c35f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a5cb4e5cba87d9924fd7d8154993fc21c7b2846e219ec7b98437d275264d63e7b67dd811c618964afed1c50f43e3e47a2d497702eaa4ac932357d6c3865e0cb
|
7
|
+
data.tar.gz: cff2183bfc7eaaba2f5069ecaab994c25c3eb672555f885fade51b77b8c46e9ed81ca51c2f350bf390cb691b9edfc60a9c626bf999694abe9e2d487236e68ab7
|
data/.rubocop_todo.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# This configuration was generated by
|
2
2
|
# `rubocop --auto-gen-config`
|
3
|
-
# on 2025-04-21
|
3
|
+
# on 2025-04-22 21:19:03 UTC using RuboCop version 1.75.3.
|
4
4
|
# The point is for the user to remove these configuration records
|
5
5
|
# one by one as the offenses are removed from the code base.
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
@@ -41,7 +41,7 @@ Lint/RedundantTypeConversion:
|
|
41
41
|
- 'lib/pwn/plugins/jenkins.rb'
|
42
42
|
- 'lib/pwn/plugins/repl.rb'
|
43
43
|
|
44
|
-
# Offense count:
|
44
|
+
# Offense count: 303
|
45
45
|
# This cop supports safe autocorrection (--autocorrect).
|
46
46
|
# Configuration parameters: AutoCorrect.
|
47
47
|
Lint/UselessAssignment:
|
@@ -89,7 +89,7 @@ Metrics/MethodLength:
|
|
89
89
|
Exclude:
|
90
90
|
- 'lib/pwn/banner/code_cave.rb'
|
91
91
|
|
92
|
-
# Offense count:
|
92
|
+
# Offense count: 12
|
93
93
|
# Configuration parameters: CountComments, Max, CountAsOne.
|
94
94
|
Metrics/ModuleLength:
|
95
95
|
Exclude:
|
@@ -103,6 +103,7 @@ Metrics/ModuleLength:
|
|
103
103
|
- 'lib/pwn/plugins/open_ai.rb'
|
104
104
|
- 'lib/pwn/plugins/packet.rb'
|
105
105
|
- 'lib/pwn/plugins/repl.rb'
|
106
|
+
- 'lib/pwn/plugins/son_micro_rfid.rb'
|
106
107
|
- 'lib/pwn/plugins/transparent_browser.rb'
|
107
108
|
|
108
109
|
# Offense count: 1
|
data/README.md
CHANGED
@@ -37,7 +37,7 @@ $ cd /opt/pwn
|
|
37
37
|
$ ./install.sh
|
38
38
|
$ ./install.sh ruby-gem
|
39
39
|
$ pwn
|
40
|
-
pwn[v0.5.
|
40
|
+
pwn[v0.5.259]:001 >>> PWN.help
|
41
41
|
```
|
42
42
|
|
43
43
|
[](https://youtu.be/G7iLUY4FzsI)
|
@@ -52,7 +52,7 @@ $ rvm use ruby-3.4.1@pwn
|
|
52
52
|
$ gem uninstall --all --executables pwn
|
53
53
|
$ gem install --verbose pwn
|
54
54
|
$ pwn
|
55
|
-
pwn[v0.5.
|
55
|
+
pwn[v0.5.259]:001 >>> PWN.help
|
56
56
|
```
|
57
57
|
|
58
58
|
If you're using a multi-user install of RVM do:
|
@@ -62,7 +62,7 @@ $ rvm use ruby-3.4.1@pwn
|
|
62
62
|
$ rvmsudo gem uninstall --all --executables pwn
|
63
63
|
$ rvmsudo gem install --verbose pwn
|
64
64
|
$ pwn
|
65
|
-
pwn[v0.5.
|
65
|
+
pwn[v0.5.259]:001 >>> PWN.help
|
66
66
|
```
|
67
67
|
|
68
68
|
PWN periodically upgrades to the latest version of Ruby which is reflected in `/opt/pwn/.ruby-version`. The easiest way to upgrade to the latest version of Ruby from a previous PWN installation is to run the following script:
|
data/bin/pwn_serial_msr206
CHANGED
@@ -31,18 +31,17 @@ OptionParser.new do |options|
|
|
31
31
|
opts[:parity] = p
|
32
32
|
end
|
33
33
|
|
34
|
-
options.on('-fFLOWCTRL', '--flow-control=FLOWCTRL', '<Optional - none
|
34
|
+
options.on('-fFLOWCTRL', '--flow-control=FLOWCTRL', '<Optional - none|hard|soft (defaults to none)>') do |f|
|
35
35
|
opts[:flow_control] = f
|
36
36
|
end
|
37
|
-
end.parse!
|
38
37
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
end
|
38
|
+
options.on('-v', '--verbose', '<Optional - Enable verbose output>') do
|
39
|
+
opts[:verbose] = true
|
40
|
+
end
|
41
|
+
end.parse!
|
43
42
|
|
44
43
|
begin
|
45
|
-
block_dev = opts[:block_dev] if File.exist?(opts[:block_dev])
|
44
|
+
block_dev = opts[:block_dev] if opts[:block_dev] && File.exist?(opts[:block_dev])
|
46
45
|
baud = opts[:baud]
|
47
46
|
data_bits = opts[:data_bits]
|
48
47
|
stop_bits = opts[:stop_bits]
|
@@ -59,9 +58,11 @@ begin
|
|
59
58
|
)
|
60
59
|
|
61
60
|
puts "- Welcome to #{File.basename($PROGRAM_NAME)} -"
|
62
|
-
|
63
|
-
|
64
|
-
|
61
|
+
if opts[:verbose]
|
62
|
+
puts "Connected via: #{block_dev} @ #{son_micro_rfid_obj[:serial_conn].modem_params}"
|
63
|
+
puts "Flow Control: #{son_micro_rfid_obj[:serial_conn].flow_control}"
|
64
|
+
puts "Signals: #{son_micro_rfid_obj[:serial_conn].signals}"
|
65
|
+
end
|
65
66
|
|
66
67
|
exec_resp = PWN::Plugins::SonMicroRFID.exec(
|
67
68
|
son_micro_rfid_obj: son_micro_rfid_obj,
|
@@ -78,11 +79,20 @@ begin
|
|
78
79
|
# Main Menu
|
79
80
|
menu_msg = ''
|
80
81
|
loop do
|
82
|
+
unless menu_msg.include?('ERROR')
|
83
|
+
exec_resp = PWN::Plugins::SonMicroRFID.exec(
|
84
|
+
son_micro_rfid_obj: son_micro_rfid_obj,
|
85
|
+
cmd: :antenna_power,
|
86
|
+
params: :on
|
87
|
+
)
|
88
|
+
end
|
89
|
+
|
81
90
|
puts "\n>> MAIN MENU OPTIONS:"
|
82
|
-
puts '[(R)ead
|
83
|
-
puts '[(B)ackup
|
84
|
-
puts '[(C)
|
85
|
-
puts '[(L)oad
|
91
|
+
puts '[(R)ead Tag]'
|
92
|
+
puts '[(B)ackup Tag]'
|
93
|
+
puts '[(C)lone Tag]'
|
94
|
+
puts '[(L)oad Data from File and Write to Tag]'
|
95
|
+
puts '[(U)pdate Tag]'
|
86
96
|
puts '[(W)arm Reset]'
|
87
97
|
puts '[(Q)uit]'
|
88
98
|
puts menu_msg
|
@@ -92,41 +102,91 @@ begin
|
|
92
102
|
|
93
103
|
case option
|
94
104
|
when :R
|
95
|
-
menu_msg = 'READ
|
96
|
-
|
97
|
-
son_micro_rfid_obj: son_micro_rfid_obj
|
98
|
-
|
105
|
+
menu_msg = 'READ TAG'
|
106
|
+
begin
|
107
|
+
rfid_data = PWN::Plugins::SonMicroRFID.read_tag(son_micro_rfid_obj: son_micro_rfid_obj)
|
108
|
+
puts "\nRFID Data:"
|
109
|
+
puts "Tag ID: #{rfid_data[:tag_id]}"
|
110
|
+
puts "Block Data: #{rfid_data[:block_data]}" if rfid_data[:block_data]
|
111
|
+
rescue StandardError => e
|
112
|
+
menu_msg = "ERROR: Failed to read tag - #{e.message}"
|
113
|
+
end
|
99
114
|
when :B
|
100
|
-
menu_msg = 'BACKUP
|
101
|
-
|
102
|
-
son_micro_rfid_obj: son_micro_rfid_obj
|
103
|
-
|
115
|
+
menu_msg = 'BACKUP TAG TO FILE'
|
116
|
+
begin
|
117
|
+
rfid_data = PWN::Plugins::SonMicroRFID.backup_tag(son_micro_rfid_obj: son_micro_rfid_obj)
|
118
|
+
puts "\nBackup successful. RFID Data:"
|
119
|
+
puts "Tag ID: #{rfid_data[:tag_id]}"
|
120
|
+
puts "Block Data: #{rfid_data[:block_data]}" if rfid_data[:block_data]
|
121
|
+
rescue StandardError => e
|
122
|
+
menu_msg = "ERROR: Failed to backup tag - #{e.message}"
|
123
|
+
end
|
104
124
|
when :C
|
105
|
-
menu_msg = '
|
106
|
-
|
107
|
-
|
108
|
-
|
125
|
+
menu_msg = 'CLONE TAG'
|
126
|
+
print 'This will overwrite the target tag. Continue? [y/N]: '
|
127
|
+
next unless gets.chomp.strip.upcase == 'Y'
|
128
|
+
|
129
|
+
begin
|
130
|
+
rfid_data = PWN::Plugins::SonMicroRFID.clone_tag(son_micro_rfid_obj: son_micro_rfid_obj)
|
131
|
+
puts "\nClone successful. RFID Data:"
|
132
|
+
puts "Tag ID: #{rfid_data[:tag_id]}"
|
133
|
+
puts "Block Data: #{rfid_data[:block_data]}" if rfid_data[:block_data]
|
134
|
+
rescue StandardError => e
|
135
|
+
menu_msg = "ERROR: Failed to clone tag - #{e.message}"
|
136
|
+
end
|
109
137
|
when :L
|
110
138
|
menu_msg = 'LOAD FROM FILE'
|
111
|
-
|
112
|
-
|
113
|
-
|
139
|
+
print 'This will overwrite the target tag. Continue? [y/N]: '
|
140
|
+
next unless gets.chomp.strip.upcase == 'Y'
|
141
|
+
|
142
|
+
begin
|
143
|
+
rfid_data = PWN::Plugins::SonMicroRFID.load_tag_from_file(son_micro_rfid_obj: son_micro_rfid_obj)
|
144
|
+
puts "\nLoad successful. RFID Data:"
|
145
|
+
puts "Tag ID: #{rfid_data[:tag_id]}"
|
146
|
+
puts "Block Data: #{rfid_data[:block_data]}" if rfid_data[:block_data]
|
147
|
+
rescue StandardError => e
|
148
|
+
menu_msg = "ERROR: Failed to load tag - #{e.message}"
|
149
|
+
end
|
150
|
+
when :U
|
151
|
+
menu_msg = 'UPDATE TAG'
|
152
|
+
print 'This will modify the tag\'s data. Continue? [y/N]: '
|
153
|
+
next unless gets.chomp.strip.upcase == 'Y'
|
154
|
+
|
155
|
+
begin
|
156
|
+
rfid_data = PWN::Plugins::SonMicroRFID.update_tag(son_micro_rfid_obj: son_micro_rfid_obj)
|
157
|
+
puts "\nUpdate successful. RFID Data:"
|
158
|
+
puts "Tag ID: #{rfid_data[:tag_id]}"
|
159
|
+
puts "Block Data: #{rfid_data[:block_data]}" if rfid_data[:block_data]
|
160
|
+
rescue StandardError => e
|
161
|
+
menu_msg = "ERROR: Failed to update tag - #{e.message}"
|
162
|
+
end
|
114
163
|
when :W
|
115
164
|
menu_msg = 'WARM RESET'
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
165
|
+
begin
|
166
|
+
exec_resp = PWN::Plugins::SonMicroRFID.exec(
|
167
|
+
son_micro_rfid_obj: son_micro_rfid_obj,
|
168
|
+
cmd: :reset
|
169
|
+
)
|
170
|
+
puts 'Warm reset complete.'
|
171
|
+
rescue StandardError => e
|
172
|
+
menu_msg = "ERROR: Failed to reset - #{e.message}"
|
173
|
+
end
|
120
174
|
when :Q
|
121
175
|
exit
|
122
176
|
else
|
123
177
|
menu_msg = '****** ERROR: Invalid Menu Option Selected ******'
|
178
|
+
exec_resp = PWN::Plugins::SonMicroRFID.exec(
|
179
|
+
son_micro_rfid_obj: son_micro_rfid_obj,
|
180
|
+
cmd: :antenna_power,
|
181
|
+
params: :off
|
182
|
+
)
|
124
183
|
end
|
125
184
|
end
|
126
185
|
rescue StandardError => e
|
186
|
+
puts "ERROR: #{e.message}"
|
127
187
|
raise e
|
128
188
|
rescue SystemExit, Interrupt
|
129
189
|
puts "\nGoodbye."
|
130
190
|
ensure
|
131
|
-
|
191
|
+
PWN::Plugins::SonMicroRFID.disconnect(son_micro_rfid_obj: son_micro_rfid_obj) if son_micro_rfid_obj
|
132
192
|
end
|
@@ -1,11 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'logger'
|
4
|
+
require 'timeout'
|
5
|
+
|
3
6
|
module PWN
|
4
7
|
module Plugins
|
5
8
|
# This plugin is used for interacting with a SonMicro
|
6
|
-
# SM132 USB RFID Reader / Writer (PCB V3) &&
|
7
|
-
# SM2330-USB Rev.0
|
9
|
+
# SM132 USB RFID Reader / Writer (PCB V3) && SM2330-USB Rev.0
|
8
10
|
module SonMicroRFID
|
11
|
+
# Logger instance for auditing and debugging
|
12
|
+
private_class_method def self.logger
|
13
|
+
@logger ||= Logger.new('sonmicro_rfid.log')
|
14
|
+
end
|
15
|
+
|
9
16
|
# Supported Method Parameters::
|
10
17
|
# son_micro_rfid_obj = PWN::Plugins::SonMicroRFID.connect(
|
11
18
|
# block_dev: 'optional - serial block device path (defaults to /dev/ttyUSB0)',
|
@@ -17,24 +24,25 @@ module PWN
|
|
17
24
|
# )
|
18
25
|
|
19
26
|
public_class_method def self.connect(opts = {})
|
20
|
-
|
21
|
-
opts[:
|
22
|
-
opts[:
|
23
|
-
opts[:
|
24
|
-
opts[:
|
25
|
-
opts[:
|
26
|
-
|
27
|
-
|
27
|
+
opts[:block_dev] ||= '/dev/ttyUSB0'
|
28
|
+
opts[:baud] ||= 19_200
|
29
|
+
opts[:data_bits] ||= 8
|
30
|
+
opts[:stop_bits] ||= 1
|
31
|
+
opts[:parity] ||= :none
|
32
|
+
opts[:flow_control] ||= :none
|
33
|
+
|
34
|
+
logger.info("Connecting to #{opts[:block_dev]} at baud #{opts[:baud]}")
|
35
|
+
PWN::Plugins::Serial.connect(opts)
|
28
36
|
rescue StandardError => e
|
37
|
+
logger.error("Connection failed: #{e.message}")
|
29
38
|
disconnect(son_micro_rfid_obj: son_micro_rfid_obj) unless son_micro_rfid_obj.nil?
|
30
39
|
raise e
|
31
40
|
end
|
32
41
|
|
33
42
|
# Supported Method Parameters::
|
34
|
-
#
|
43
|
+
# cmds = PWN::Plugins::SonMicroRFID.list_cmds
|
35
44
|
public_class_method def self.list_cmds
|
36
|
-
|
37
|
-
cmds = %i[
|
45
|
+
%i[
|
38
46
|
reset
|
39
47
|
firmware
|
40
48
|
seek_for_tag
|
@@ -56,13 +64,15 @@ module PWN
|
|
56
64
|
poll_buffer
|
57
65
|
]
|
58
66
|
rescue StandardError => e
|
67
|
+
logger.error("Error listing commands: #{e.message}")
|
59
68
|
raise e
|
60
69
|
end
|
61
70
|
|
62
71
|
# Supported Method Parameters::
|
63
|
-
#
|
64
|
-
# cmd: 'required - cmd returned from #list_cmds method'
|
72
|
+
# params = PWN::Plugins::SonMicroRFID.list_params(
|
73
|
+
# cmd: 'required - cmd returned from #list_cmds method'
|
65
74
|
# )
|
75
|
+
|
66
76
|
public_class_method def self.list_params(opts = {})
|
67
77
|
cmd = opts[:cmd].to_s.scrub.strip.chomp
|
68
78
|
|
@@ -70,17 +80,17 @@ module PWN
|
|
70
80
|
when :reset
|
71
81
|
params = %i[reset_not_implemented]
|
72
82
|
when :firmware
|
73
|
-
params = %i[
|
83
|
+
params = %i[firmware_no_params_required]
|
74
84
|
when :seek_for_tag
|
75
85
|
params = %i[seek_for_tag_no_params_required]
|
76
86
|
when :select_tag
|
77
87
|
params = %i[select_tag_no_params_required]
|
78
88
|
when :authenticate
|
79
|
-
params = %i[
|
89
|
+
params = %i[block key_type key]
|
80
90
|
when :read_block
|
81
|
-
params = %i[
|
91
|
+
params = %i[block]
|
82
92
|
when :write_block
|
83
|
-
params = %i[
|
93
|
+
params = %i[block data]
|
84
94
|
when :write_value
|
85
95
|
params = %i[write_value_not_implemented]
|
86
96
|
when :write_four_byte_block
|
@@ -94,11 +104,11 @@ module PWN
|
|
94
104
|
when :antenna_power
|
95
105
|
params = %i[off on reset]
|
96
106
|
when :read_port
|
97
|
-
params = %i[
|
107
|
+
params = %i[read_port_not_implemented]
|
98
108
|
when :write_port
|
99
109
|
params = %i[write_port_not_implemented]
|
100
110
|
when :halt
|
101
|
-
params = %i[
|
111
|
+
params = %i[halt_no_params_required]
|
102
112
|
when :set_baud_rate
|
103
113
|
params = %i[set_baud_rate_not_implemented]
|
104
114
|
when :sleep
|
@@ -106,148 +116,134 @@ module PWN
|
|
106
116
|
when :poll_buffer
|
107
117
|
params = %i[poll_buffer_not_implemented]
|
108
118
|
else
|
109
|
-
|
119
|
+
logger.error("Unsupported command: #{cmd}")
|
120
|
+
raise "Unsupported Command: #{cmd}. Supported commands are:\n#{list_cmds.join("\n")}\n"
|
110
121
|
end
|
111
122
|
|
112
123
|
params
|
113
124
|
rescue StandardError => e
|
125
|
+
logger.error("Error listing parameters for #{cmd}: #{e.message}")
|
114
126
|
raise e
|
115
127
|
end
|
116
128
|
|
117
129
|
# Supported Method Parameters::
|
118
130
|
# parsed_cmd_resp_arr = parse_responses(
|
119
|
-
# son_micro_rfid_obj: 'required - son_micro_rfid_obj returned from #connect method'
|
120
|
-
#
|
131
|
+
# son_micro_rfid_obj: 'required - son_micro_rfid_obj returned from #connect method',
|
132
|
+
# cmd: 'required - command symbol'
|
121
133
|
# )
|
122
134
|
|
123
135
|
private_class_method def self.parse_responses(opts = {})
|
124
136
|
son_micro_rfid_obj = opts[:son_micro_rfid_obj]
|
125
137
|
cmd = opts[:cmd].to_s.scrub.strip.chomp
|
126
138
|
|
127
|
-
|
128
|
-
|
129
|
-
all_cmd_responses = []
|
130
|
-
a_cmd_r_len = 0
|
131
|
-
last_a_cmd_r_len = 0
|
132
|
-
|
133
|
-
parsed_cmd_resp_arr = []
|
134
|
-
bytes_in_cmd_resp = 0
|
135
|
-
cmd_resp = ''
|
136
|
-
|
137
|
-
# Parse All Responses and add them to parsed_cmd_resp_arr
|
138
|
-
while keep_parsing_responses
|
139
|
-
until next_response_detected
|
140
|
-
all_cmd_responses = PWN::Plugins::Serial.response(
|
141
|
-
serial_obj: son_micro_rfid_obj
|
142
|
-
)
|
143
|
-
cmd_resp = all_cmd_responses.last
|
144
|
-
bytes_in_cmd_resp = cmd_resp.split.length if cmd_resp
|
145
|
-
a_cmd_r_len = all_cmd_responses.length
|
146
|
-
|
147
|
-
# Dont proceed until the expected_cmd_resp_byte_len byte appears
|
148
|
-
next_response_detected = true if bytes_in_cmd_resp > 3 &&
|
149
|
-
a_cmd_r_len > last_a_cmd_r_len
|
150
|
-
end
|
139
|
+
Timeout.timeout(5) do
|
140
|
+
keep_parsing_responses = true
|
151
141
|
next_response_detected = false
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
142
|
+
all_cmd_responses = []
|
143
|
+
a_cmd_r_len = 0
|
144
|
+
last_a_cmd_r_len = 0
|
145
|
+
|
146
|
+
parsed_cmd_resp_arr = []
|
147
|
+
bytes_in_cmd_resp = 0
|
148
|
+
cmd_resp = ''
|
149
|
+
|
150
|
+
while keep_parsing_responses
|
151
|
+
until next_response_detected
|
152
|
+
all_cmd_responses = PWN::Plugins::Serial.response(serial_obj: son_micro_rfid_obj)
|
153
|
+
cmd_resp = all_cmd_responses.last
|
154
|
+
bytes_in_cmd_resp = cmd_resp.split.length if cmd_resp
|
155
|
+
a_cmd_r_len = all_cmd_responses.length
|
156
|
+
next_response_detected = true if bytes_in_cmd_resp > 3 && a_cmd_r_len > last_a_cmd_r_len
|
157
|
+
end
|
158
|
+
next_response_detected = false
|
159
|
+
last_a_cmd_r_len = a_cmd_r_len
|
159
160
|
|
160
|
-
|
161
|
-
|
162
|
-
serial_obj: son_micro_rfid_obj
|
163
|
-
)
|
161
|
+
expected_cmd_resp_byte_len = cmd_resp.split[2].to_i(16) + 4
|
162
|
+
cmd_hex = cmd_resp.split[3]
|
164
163
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
# puts "COMMAND HEX: #{cmd_hex}\n\n\n"
|
171
|
-
end
|
164
|
+
while bytes_in_cmd_resp < expected_cmd_resp_byte_len
|
165
|
+
all_cmd_responses = PWN::Plugins::Serial.response(serial_obj: son_micro_rfid_obj)
|
166
|
+
cmd_resp = all_cmd_responses.last
|
167
|
+
bytes_in_cmd_resp = cmd_resp.split.length
|
168
|
+
end
|
172
169
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
parsed_cmd_resp_hash[:hex_resp] = cmd_resp
|
179
|
-
resp_code = '?'
|
180
|
-
|
181
|
-
# TODO: Detect EMV
|
182
|
-
case cmd_hex
|
183
|
-
when '82', '83'
|
184
|
-
resp_code = cmd_resp.split[4]
|
170
|
+
parsed_cmd_resp_hash = {}
|
171
|
+
parsed_cmd_resp_hash[:cmd_hex] = cmd_hex
|
172
|
+
parsed_cmd_resp_hash[:cmd_desc] = cmd.to_sym
|
173
|
+
parsed_cmd_resp_hash[:hex_resp] = cmd_resp
|
174
|
+
resp_code = cmd_resp.split[4] || '?'
|
185
175
|
parsed_cmd_resp_hash[:resp_code_hex] = resp_code
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
' '
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
176
|
+
|
177
|
+
case cmd_hex
|
178
|
+
when '82', '83'
|
179
|
+
case resp_code
|
180
|
+
when '01'
|
181
|
+
parsed_cmd_resp_hash[:resp_code_desc] = :mifare_ultralight
|
182
|
+
parsed_cmd_resp_hash[:tag_id] = cmd_resp.split[5..-2].join(' ')
|
183
|
+
when '02'
|
184
|
+
parsed_cmd_resp_hash[:resp_code_desc] = :mifare_classic_1k
|
185
|
+
parsed_cmd_resp_hash[:tag_id] = cmd_resp.split[5..-2].join(' ')
|
186
|
+
when '03'
|
187
|
+
parsed_cmd_resp_hash[:resp_code_desc] = :mifare_classic_4k
|
188
|
+
parsed_cmd_resp_hash[:tag_id] = cmd_resp.split[5..-2].join(' ')
|
189
|
+
when '4C'
|
190
|
+
parsed_cmd_resp_hash[:resp_code_desc] = :seeking_tag
|
191
|
+
parsed_cmd_resp_hash[:tag_id] = :seeking_tag
|
192
|
+
when '4E'
|
193
|
+
parsed_cmd_resp_hash[:resp_code_desc] = :no_tag_present
|
194
|
+
parsed_cmd_resp_hash[:tag_id] = :not_available
|
195
|
+
when '55'
|
196
|
+
parsed_cmd_resp_hash[:resp_code_desc] = :antenna_off
|
197
|
+
parsed_cmd_resp_hash[:tag_id] = :not_available
|
198
|
+
when 'FF'
|
199
|
+
parsed_cmd_resp_hash[:resp_code_desc] = :unknown_tag_type
|
200
|
+
parsed_cmd_resp_hash[:tag_id] = cmd_resp.split[5..-2].join(' ')
|
201
|
+
else
|
202
|
+
parsed_cmd_resp_hash[:resp_code_desc] = :unknown_resp_code
|
203
|
+
parsed_cmd_resp_hash[:tag_id] = :not_available
|
204
|
+
end
|
205
|
+
when '85' # Assumed for authenticate
|
206
|
+
parsed_cmd_resp_hash[:resp_code_desc] = resp_code == '00' ? :auth_success : :auth_failed
|
207
|
+
when '86' # Assumed for read_block
|
208
|
+
parsed_cmd_resp_hash[:resp_code_desc] = resp_code == '00' ? :read_success : :read_failed
|
209
|
+
parsed_cmd_resp_hash[:block_data] = cmd_resp.split[5..-2].join(' ')
|
210
|
+
when '87' # Assumed for write_block
|
211
|
+
parsed_cmd_resp_hash[:resp_code_desc] = resp_code == '00' ? :write_success : :write_failed
|
216
212
|
else
|
217
|
-
parsed_cmd_resp_hash[:resp_code_desc] = :
|
218
|
-
parsed_cmd_resp_hash[:tag_id] = :not_available
|
213
|
+
parsed_cmd_resp_hash[:resp_code_desc] = :unknown_response
|
219
214
|
end
|
220
|
-
else
|
221
|
-
parsed_cmd_resp_hash[:cmd_desc] = :not_available
|
222
|
-
end
|
223
215
|
|
224
|
-
|
216
|
+
keep_parsing_responses = false unless resp_code == '4C'
|
217
|
+
parsed_cmd_resp_arr.push(parsed_cmd_resp_hash)
|
218
|
+
end
|
225
219
|
|
226
|
-
parsed_cmd_resp_arr
|
220
|
+
parsed_cmd_resp_arr
|
227
221
|
end
|
228
|
-
|
229
|
-
|
222
|
+
rescue Timeout::Error
|
223
|
+
logger.error("Device response timed out for command: #{cmd}")
|
224
|
+
raise 'ERROR: Device response timed out'
|
230
225
|
rescue StandardError => e
|
226
|
+
logger.error("Error parsing response for command #{cmd}: #{e.message}")
|
231
227
|
raise e
|
232
228
|
ensure
|
233
|
-
# Flush Responses for Next Request
|
234
229
|
PWN::Plugins::Serial.flush_session_data
|
235
230
|
end
|
236
231
|
|
237
232
|
# Supported Method Parameters::
|
238
|
-
#
|
239
|
-
# son_micro_rfid_obj: 'required - son_micro_rfid_obj returned from #connect method'
|
233
|
+
# PWN::Plugins::SonMicroRFID.exec(
|
234
|
+
# son_micro_rfid_obj: 'required - son_micro_rfid_obj returned from #connect method',
|
240
235
|
# cmd: 'required - cmd returned from #list_cmds method',
|
241
236
|
# params: 'optional - parameters for specific command returned from #list_params method'
|
242
237
|
# )
|
238
|
+
|
243
239
|
public_class_method def self.exec(opts = {})
|
244
240
|
son_micro_rfid_obj = opts[:son_micro_rfid_obj]
|
245
241
|
cmd = opts[:cmd].to_s.scrub.strip.chomp
|
246
|
-
params = opts[:params]
|
242
|
+
params = opts[:params]
|
247
243
|
|
248
|
-
|
244
|
+
logger.info("Executing command: #{cmd} with params: #{params.inspect}")
|
249
245
|
|
250
|
-
|
246
|
+
params_bytes = []
|
251
247
|
case cmd.to_sym
|
252
248
|
when :reset
|
253
249
|
cmd_bytes = [0xFF, 0x00, 0x01, 0x80, 0x81]
|
@@ -258,32 +254,40 @@ module PWN
|
|
258
254
|
when :select_tag
|
259
255
|
cmd_bytes = [0xFF, 0x00, 0x01, 0x83, 0x84]
|
260
256
|
when :authenticate
|
261
|
-
|
262
|
-
|
257
|
+
raise "Parameters must be a hash with :block, :key_type, :key for #{cmd}" unless params.is_a?(Hash)
|
258
|
+
|
259
|
+
# Placeholder: [block, key_type, key]
|
260
|
+
cmd_bytes = [0xFF, 0x00, 0x07, 0x85]
|
261
|
+
block = params[:block].to_i
|
262
|
+
key_type = params[:key_type] == :key_a ? 0x60 : 0x61
|
263
|
+
key = params[:key] || [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
|
264
|
+
params_bytes = [block, key_type] + key
|
263
265
|
when :read_block
|
264
|
-
#
|
265
|
-
cmd_bytes = [0xFF, 0x00,
|
266
|
+
# Placeholder: [block]
|
267
|
+
cmd_bytes = [0xFF, 0x00, 0x02, 0x86]
|
268
|
+
params_bytes = [params[:block].to_i] if params.is_a?(Hash) && params[:block]
|
266
269
|
when :write_block
|
267
|
-
#
|
268
|
-
|
270
|
+
raise "Parameters must be a hash with :block, :data for #{cmd}" unless params.is_a?(Hash) && params[:block] && params[:data]
|
271
|
+
|
272
|
+
# Placeholder: [block, data]
|
273
|
+
cmd_bytes = [0xFF, 0x00, 0x06, 0x87] # Adjust length based on data
|
274
|
+
block = params[:block].to_i
|
275
|
+
data = params[:data].is_a?(Array) ? params[:data] : params[:data].split.map { |b| b.to_i(16) }
|
276
|
+
params_bytes = [block] + data
|
277
|
+
cmd_bytes[2] = params_bytes.length + 2 # Update length
|
269
278
|
when :write_value
|
270
|
-
# Last two bytes not correct
|
271
279
|
cmd_bytes = [0xFF, 0x00, 0x01, 0x00, 0x03]
|
272
280
|
when :write_four_byte_block
|
273
|
-
# Last two bytes not correct
|
274
281
|
cmd_bytes = [0xFF, 0x00, 0x01, 0x00, 0x04]
|
275
282
|
when :write_key
|
276
|
-
# Last two bytes not correct
|
277
283
|
cmd_bytes = [0xFF, 0x00, 0x01, 0x00, 0x05]
|
278
284
|
when :increment
|
279
|
-
# Last two bytes not correct
|
280
285
|
cmd_bytes = [0xFF, 0x00, 0x01, 0x00, 0x06]
|
281
286
|
when :decrement
|
282
|
-
# Last two bytes not correct
|
283
287
|
cmd_bytes = [0xFF, 0x00, 0x01, 0x00, 0x07]
|
284
288
|
when :antenna_power
|
285
289
|
cmd_bytes = [0xFF, 0x00, 0x02, 0x90]
|
286
|
-
case params.to_sym
|
290
|
+
case params.to_s.to_sym
|
287
291
|
when :off
|
288
292
|
params_bytes = [0x00, 0x92]
|
289
293
|
when :on
|
@@ -291,94 +295,212 @@ module PWN
|
|
291
295
|
when :reset
|
292
296
|
params_bytes = [0x02, 0x94]
|
293
297
|
else
|
294
|
-
raise "Unsupported Parameters: #{params} for #{cmd}.
|
298
|
+
raise "Unsupported Parameters: #{params} for #{cmd}. Supported parameters are:\n#{list_params(cmd: cmd).join("\n")}\n"
|
295
299
|
end
|
296
300
|
when :read_port
|
297
|
-
|
298
|
-
cmd_bytes = [0xFF, 0x00, 0x01]
|
301
|
+
cmd_bytes = [0xFF, 0x00, 0x01, 0x00, 0x08]
|
299
302
|
when :write_port
|
300
|
-
|
301
|
-
cmd_bytes = [0xFF, 0x00, 0x01, 0x08]
|
303
|
+
cmd_bytes = [0xFF, 0x00, 0x01, 0x08, 0x09]
|
302
304
|
when :halt
|
303
305
|
cmd_bytes = [0xFF, 0x00, 0x01, 0x93, 0x94]
|
304
306
|
when :set_baud_rate
|
305
|
-
|
306
|
-
cmd_bytes = [0xFF, 0x00, 0x01, 0x09]
|
307
|
+
cmd_bytes = [0xFF, 0x00, 0x01, 0x09, 0x0A]
|
307
308
|
when :sleep
|
308
|
-
|
309
|
-
cmd_bytes = [0xFF, 0x00, 0x01, 0x0a]
|
309
|
+
cmd_bytes = [0xFF, 0x00, 0x01, 0x0A, 0x0B]
|
310
310
|
when :poll_buffer
|
311
311
|
cmd_bytes = [0xFF, 0x00, 0x01, 0xB0, 0xB1]
|
312
312
|
else
|
313
|
-
|
313
|
+
logger.error("Unsupported command: #{cmd}")
|
314
|
+
raise "Unsupported Command: #{cmd}. Supported commands are:\n#{list_cmds.join("\n")}\n"
|
314
315
|
end
|
315
316
|
|
316
|
-
# If parameters to a command are set, append them.
|
317
317
|
cmd_bytes += params_bytes unless params_bytes.empty?
|
318
|
-
# Execute the command.
|
319
318
|
PWN::Plugins::Serial.request(
|
320
319
|
serial_obj: son_micro_rfid_obj,
|
321
320
|
payload: cmd_bytes
|
322
321
|
)
|
323
322
|
|
324
|
-
|
325
|
-
# Return an array of hashes.
|
326
|
-
parse_responses(
|
323
|
+
response = parse_responses(
|
327
324
|
son_micro_rfid_obj: son_micro_rfid_obj,
|
328
325
|
cmd: cmd.to_sym
|
329
326
|
)
|
327
|
+
logger.info("Response for #{cmd}: #{response.inspect}")
|
328
|
+
response
|
330
329
|
rescue StandardError => e
|
330
|
+
logger.error("Error executing command #{cmd}: #{e.message}")
|
331
331
|
raise e
|
332
332
|
ensure
|
333
|
-
# Flush Responses for Next Request
|
334
333
|
PWN::Plugins::Serial.flush_session_data
|
335
334
|
end
|
336
335
|
|
337
336
|
# Supported Method Parameters::
|
338
|
-
# PWN::Plugins::SonMicroRFID.
|
337
|
+
# PWN::Plugins::SonMicroRFID.read_tag(
|
339
338
|
# son_micro_rfid_obj: 'required - son_micro_rfid_obj returned from #connect method'
|
340
339
|
# )
|
341
340
|
|
342
|
-
public_class_method def self.
|
341
|
+
public_class_method def self.read_tag(opts = {})
|
343
342
|
son_micro_rfid_obj = opts[:son_micro_rfid_obj]
|
344
|
-
|
343
|
+
logger.info('Starting read_tag')
|
344
|
+
|
345
|
+
print 'Reader Activated. Please Scan Tag...'
|
345
346
|
exec_resp = exec(
|
346
347
|
son_micro_rfid_obj: son_micro_rfid_obj,
|
347
348
|
cmd: :seek_for_tag
|
348
349
|
)
|
349
350
|
|
350
351
|
rfid_data = exec_resp.last
|
351
|
-
|
352
|
+
logger.info("\n#{rfid_data.inspect}")
|
353
|
+
|
354
|
+
if rfid_data[:resp_code_desc] == :no_tag_present
|
355
|
+
logger.error('No RFID tag detected')
|
356
|
+
raise 'No RFID tag detected'
|
357
|
+
end
|
352
358
|
|
359
|
+
# Read block data (e.g., block 4 for Ultralight, sector 0 block 0 for Classic)
|
360
|
+
case rfid_data[:resp_code_desc]
|
361
|
+
when :mifare_ultralight
|
362
|
+
exec_resp = exec(
|
363
|
+
son_micro_rfid_obj: son_micro_rfid_obj,
|
364
|
+
cmd: :read_block,
|
365
|
+
params: { block: 4 } # Example block
|
366
|
+
)
|
367
|
+
rfid_data[:block_data] = exec_resp.last[:block_data] if exec_resp.last[:resp_code_desc] == :read_success
|
368
|
+
when :mifare_classic_1k, :mifare_classic_4k
|
369
|
+
exec_resp = exec(
|
370
|
+
son_micro_rfid_obj: son_micro_rfid_obj,
|
371
|
+
cmd: :authenticate,
|
372
|
+
params: { block: 0, key_type: :key_a, key: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF] }
|
373
|
+
)
|
374
|
+
if exec_resp.last[:resp_code_desc] == :auth_success
|
375
|
+
exec_resp = exec(
|
376
|
+
son_micro_rfid_obj: son_micro_rfid_obj,
|
377
|
+
cmd: :read_block,
|
378
|
+
params: { block: 0 }
|
379
|
+
)
|
380
|
+
rfid_data[:block_data] = exec_resp.last[:block_data] if exec_resp.last[:resp_code_desc] == :read_success
|
381
|
+
else
|
382
|
+
logger.error("Authentication failed for #{rfid_data[:resp_code_desc]}")
|
383
|
+
raise 'Authentication failed'
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
puts "\n#{rfid_data[:resp_code_desc]} >>> Tag ID: #{rfid_data[:tag_id]}"
|
388
|
+
puts "Block Data: #{rfid_data[:block_data]}" if rfid_data[:block_data]
|
389
|
+
logger.info("Read tag successful: #{rfid_data.inspect}")
|
353
390
|
rfid_data
|
354
391
|
rescue StandardError => e
|
392
|
+
logger.error("Error reading tag: #{e.message}")
|
393
|
+
puts "ERROR: Failed to read tag - #{e.message}"
|
355
394
|
raise e
|
356
395
|
end
|
357
396
|
|
358
397
|
# Supported Method Parameters::
|
359
|
-
# PWN::Plugins::SonMicroRFID.
|
360
|
-
# son_micro_rfid_obj: 'required - son_micro_rfid_obj returned from #connect method'
|
398
|
+
# PWN::Plugins::SonMicroRFID.write_tag(
|
399
|
+
# son_micro_rfid_obj: 'required - son_micro_rfid_obj returned from #connect method',
|
400
|
+
# rfid_data: 'required - RFID data to write (see #read_tag for structure)'
|
361
401
|
# )
|
362
402
|
|
363
|
-
public_class_method def self.
|
403
|
+
public_class_method def self.write_tag(opts = {})
|
364
404
|
son_micro_rfid_obj = opts[:son_micro_rfid_obj]
|
365
405
|
rfid_data = opts[:rfid_data]
|
366
|
-
|
367
|
-
|
406
|
+
logger.info('Starting write_tag')
|
407
|
+
|
408
|
+
unless rfid_data.is_a?(Hash) && rfid_data[:resp_code_desc] && rfid_data[:tag_id]
|
409
|
+
logger.error('Invalid rfid_data: must be a hash with :resp_code_desc and :tag_id')
|
410
|
+
raise 'Invalid rfid_data: must be a hash with :resp_code_desc and :tag_id'
|
411
|
+
end
|
412
|
+
|
413
|
+
puts "\nWriting to tag with Tag ID: #{rfid_data[:tag_id]}"
|
414
|
+
print 'This will overwrite the tag. Continue? [y/N]: '
|
415
|
+
unless gets.chomp.strip.upcase == 'Y'
|
416
|
+
logger.info('Write cancelled by user')
|
417
|
+
puts 'Write cancelled.'
|
418
|
+
return rfid_data
|
419
|
+
end
|
420
|
+
|
421
|
+
# Select tag
|
422
|
+
exec_resp = exec(
|
423
|
+
son_micro_rfid_obj: son_micro_rfid_obj,
|
424
|
+
cmd: :select_tag
|
425
|
+
)
|
426
|
+
if exec_resp.last[:resp_code_desc] == :no_tag_present
|
427
|
+
logger.error('No RFID tag detected for writing')
|
428
|
+
raise 'No RFID tag detected for writing'
|
429
|
+
end
|
430
|
+
|
431
|
+
# Write block data
|
432
|
+
case rfid_data[:resp_code_desc]
|
433
|
+
when :mifare_ultralight
|
434
|
+
if rfid_data[:block_data]
|
435
|
+
data = rfid_data[:block_data].split.map { |b| b.to_i(16) }
|
436
|
+
exec_resp = exec(
|
437
|
+
son_micro_rfid_obj: son_micro_rfid_obj,
|
438
|
+
cmd: :write_block,
|
439
|
+
params: { block: 4, data: data }
|
440
|
+
)
|
441
|
+
unless exec_resp.last[:resp_code_desc] == :write_success
|
442
|
+
logger.error('Failed to write block for Ultralight')
|
443
|
+
raise 'Failed to write block'
|
444
|
+
end
|
445
|
+
end
|
446
|
+
when :mifare_classic_1k, :mifare_classic_4k
|
447
|
+
exec_resp = exec(
|
448
|
+
son_micro_rfid_obj: son_micro_rfid_obj,
|
449
|
+
cmd: :authenticate,
|
450
|
+
params: { block: 0, key_type: :key_a, key: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF] }
|
451
|
+
)
|
452
|
+
if exec_resp.last[:resp_code_desc] == :auth_success
|
453
|
+
if rfid_data[:block_data]
|
454
|
+
data = rfid_data[:block_data].split.map { |b| b.to_i(16) }
|
455
|
+
exec_resp = exec(
|
456
|
+
son_micro_rfid_obj: son_micro_rfid_obj,
|
457
|
+
cmd: :write_block,
|
458
|
+
params: { block: 0, data: data }
|
459
|
+
)
|
460
|
+
unless exec_resp.last[:resp_code_desc] == :write_success
|
461
|
+
logger.error('Failed to write block for Classic')
|
462
|
+
raise 'Failed to write block'
|
463
|
+
end
|
464
|
+
end
|
465
|
+
else
|
466
|
+
logger.error("Authentication failed for #{rfid_data[:resp_code_desc]}")
|
467
|
+
raise 'Authentication failed'
|
468
|
+
end
|
469
|
+
else
|
470
|
+
logger.error("Unsupported tag type: #{rfid_data[:resp_code_desc]}")
|
471
|
+
raise "Unsupported tag type: #{rfid_data[:resp_code_desc]}"
|
472
|
+
end
|
473
|
+
|
474
|
+
# Verify write by re-reading
|
475
|
+
read_data = read_tag(son_micro_rfid_obj: son_micro_rfid_obj)
|
476
|
+
if read_data[:block_data] == rfid_data[:block_data]
|
477
|
+
puts 'Write verification successful.'
|
478
|
+
logger.info('Write verification successful')
|
479
|
+
else
|
480
|
+
puts 'ERROR: Written data does not match read data.'
|
481
|
+
logger.error('Written data does not match read data')
|
482
|
+
end
|
368
483
|
|
484
|
+
logger.info("Write tag successful: #{rfid_data.inspect}")
|
485
|
+
puts 'Tag written successfully.'
|
369
486
|
rfid_data
|
370
487
|
rescue StandardError => e
|
488
|
+
logger.error("Error writing tag: #{e.message}")
|
489
|
+
puts "ERROR: Failed to write tag - #{e.message}"
|
371
490
|
raise e
|
372
491
|
end
|
373
492
|
|
374
493
|
# Supported Method Parameters::
|
375
|
-
# PWN::Plugins::SonMicroRFID.
|
494
|
+
# PWN::Plugins::SonMicroRFID.backup_tag(
|
376
495
|
# son_micro_rfid_obj: 'required - son_micro_rfid_obj returned from #connect method'
|
377
496
|
# )
|
378
497
|
|
379
|
-
public_class_method def self.
|
498
|
+
public_class_method def self.backup_tag(opts = {})
|
380
499
|
son_micro_rfid_obj = opts[:son_micro_rfid_obj]
|
381
|
-
|
500
|
+
logger.info('Starting backup_tag')
|
501
|
+
|
502
|
+
rfid_data = read_tag(son_micro_rfid_obj: son_micro_rfid_obj)
|
503
|
+
|
382
504
|
file = ''
|
383
505
|
backup_msg = ''
|
384
506
|
loop do
|
@@ -390,41 +512,64 @@ module PWN
|
|
390
512
|
backup_msg = "\n****** ERROR: Directory #{file_dir} for #{file} does not exist ******"
|
391
513
|
puts backup_msg
|
392
514
|
end
|
393
|
-
File.write(file, "#{JSON.pretty_generate(rfid_data)}\n")
|
394
515
|
|
395
|
-
|
516
|
+
File.write(file, "#{JSON.pretty_generate(rfid_data)}\n")
|
517
|
+
logger.info("Backup saved to #{file}")
|
518
|
+
puts 'Backup complete.'
|
396
519
|
rfid_data
|
397
520
|
rescue StandardError => e
|
521
|
+
logger.error("Error backing up tag: #{e.message}")
|
522
|
+
puts "ERROR: Failed to backup tag - #{e.message}"
|
398
523
|
raise e
|
399
524
|
end
|
400
525
|
|
401
526
|
# Supported Method Parameters::
|
402
|
-
# PWN::Plugins::SonMicroRFID.
|
527
|
+
# PWN::Plugins::SonMicroRFID.clone_tag(
|
403
528
|
# son_micro_rfid_obj: 'required - son_micro_rfid_obj returned from #connect method'
|
404
529
|
# )
|
405
530
|
|
406
|
-
public_class_method def self.
|
531
|
+
public_class_method def self.clone_tag(opts = {})
|
407
532
|
son_micro_rfid_obj = opts[:son_micro_rfid_obj]
|
408
|
-
|
409
|
-
|
533
|
+
logger.info('Starting clone_tag')
|
534
|
+
|
535
|
+
print 'This will overwrite the target tag. Continue? [y/N]: '
|
536
|
+
unless gets.chomp.strip.upcase == 'Y'
|
537
|
+
logger.info('Copy cancelled by user')
|
538
|
+
puts 'Copy cancelled.'
|
539
|
+
return nil
|
540
|
+
end
|
541
|
+
|
542
|
+
rfid_data = read_tag(son_micro_rfid_obj: son_micro_rfid_obj)
|
543
|
+
write_tag(
|
410
544
|
son_micro_rfid_obj: son_micro_rfid_obj,
|
411
545
|
rfid_data: rfid_data
|
412
546
|
)
|
413
547
|
rescue StandardError => e
|
548
|
+
logger.error("Error copying tag: #{e.message}")
|
549
|
+
puts "ERROR: Failed to copy tag - #{e.message}"
|
414
550
|
raise e
|
415
551
|
end
|
416
552
|
|
417
553
|
# Supported Method Parameters::
|
418
|
-
# PWN::Plugins::SonMicroRFID.
|
554
|
+
# PWN::Plugins::SonMicroRFID.load_tag_from_file(
|
419
555
|
# son_micro_rfid_obj: 'required - son_micro_rfid_obj returned from #connect method'
|
420
556
|
# )
|
421
557
|
|
422
|
-
public_class_method def self.
|
558
|
+
public_class_method def self.load_tag_from_file(opts = {})
|
423
559
|
son_micro_rfid_obj = opts[:son_micro_rfid_obj]
|
560
|
+
logger.info('Starting load_tag_from_file')
|
561
|
+
|
562
|
+
print 'This will overwrite the target tag. Continue? [y/N]: '
|
563
|
+
unless gets.chomp.strip.upcase == 'Y'
|
564
|
+
logger.info('Load cancelled by user')
|
565
|
+
puts 'Load cancelled.'
|
566
|
+
return nil
|
567
|
+
end
|
568
|
+
|
424
569
|
file = ''
|
425
570
|
restore_msg = ''
|
426
571
|
loop do
|
427
|
-
print 'Enter File Name to Restore to
|
572
|
+
print 'Enter File Name to Restore to Tag: '
|
428
573
|
file = gets.scrub.chomp.strip
|
429
574
|
break if File.exist?(file)
|
430
575
|
|
@@ -432,17 +577,89 @@ module PWN
|
|
432
577
|
puts restore_msg
|
433
578
|
end
|
434
579
|
|
435
|
-
rfid_data = JSON.parse(
|
436
|
-
|
437
|
-
|
580
|
+
rfid_data = JSON.parse(File.read(file), symbolize_names: true)
|
581
|
+
write_tag(
|
582
|
+
son_micro_rfid_obj: son_micro_rfid_obj,
|
583
|
+
rfid_data: rfid_data
|
438
584
|
)
|
585
|
+
rescue StandardError => e
|
586
|
+
logger.error("Error loading tag from file: #{e.message}")
|
587
|
+
puts "ERROR: Failed to load tag from file - #{e.message}"
|
588
|
+
raise e
|
589
|
+
end
|
439
590
|
|
440
|
-
|
441
|
-
|
591
|
+
# Supported Method Parameters::
|
592
|
+
# PWN::Plugins::SonMicroRFID.update_tag(
|
593
|
+
# son_micro_rfid_obj: 'required - son_micro_rfid_obj returned from #connect method'
|
594
|
+
# )
|
595
|
+
|
596
|
+
public_class_method def self.update_tag(opts = {})
|
597
|
+
son_micro_rfid_obj = opts[:son_micro_rfid_obj]
|
598
|
+
logger.info('Starting update_tag')
|
599
|
+
|
600
|
+
print 'This will modify the tag\'s data. Continue? [y/N]: '
|
601
|
+
unless gets.chomp.strip.upcase == 'Y'
|
602
|
+
logger.info('Update cancelled by user')
|
603
|
+
puts 'Update cancelled.'
|
604
|
+
return nil
|
605
|
+
end
|
606
|
+
|
607
|
+
rfid_data = read_tag(son_micro_rfid_obj: son_micro_rfid_obj)
|
608
|
+
unless rfid_data.is_a?(Hash) && rfid_data[:resp_code_desc] && rfid_data[:tag_id]
|
609
|
+
logger.error('Invalid rfid_data structure')
|
610
|
+
raise 'Invalid rfid_data structure'
|
611
|
+
end
|
612
|
+
|
613
|
+
# Update block data
|
614
|
+
block_data = rfid_data[:block_data] || ''
|
615
|
+
puts "\nCurrent Block Data: #{block_data}"
|
616
|
+
print 'Enter Updated Block Data (hex bytes, space-separated, press Enter to keep original): '
|
617
|
+
updated_value = gets.scrub.chomp.strip
|
618
|
+
|
619
|
+
if updated_value.empty?
|
620
|
+
puts "Keeping original value: #{block_data}"
|
621
|
+
logger.info("Keeping original block data: #{block_data}")
|
622
|
+
updated_value = block_data
|
623
|
+
else
|
624
|
+
# Validate hex bytes
|
625
|
+
unless updated_value.match?(/\A([\da-fA-F]{2}\s)*[\da-fA-F]{2}\z/)
|
626
|
+
logger.error('Invalid block data: must be hex bytes (e.g., FF 00)')
|
627
|
+
raise 'Invalid block data: must be hex bytes (e.g., FF 00)'
|
628
|
+
end
|
629
|
+
# Validate length based on tag type
|
630
|
+
data_bytes = updated_value.split.map { |b| b.to_i(16) }
|
631
|
+
max_bytes = rfid_data[:resp_code_desc] == :mifare_ultralight ? 4 : 16
|
632
|
+
unless data_bytes.length <= max_bytes
|
633
|
+
logger.error("Block data too long: max #{max_bytes} bytes")
|
634
|
+
raise "Block data too long: max #{max_bytes} bytes"
|
635
|
+
end
|
636
|
+
logger.info("Updated block data: #{updated_value}")
|
637
|
+
end
|
638
|
+
|
639
|
+
rfid_data[:block_data] = updated_value
|
640
|
+
|
641
|
+
# Confirm changes
|
642
|
+
puts "\nUpdated RFID Data:"
|
643
|
+
puts "Tag ID: #{rfid_data[:tag_id]}"
|
644
|
+
puts "Block Data: #{rfid_data[:block_data]}"
|
645
|
+
print 'Confirm writing these changes to the tag? [y/N]: '
|
646
|
+
unless gets.chomp.strip.upcase == 'Y'
|
647
|
+
logger.info('Update cancelled by user')
|
648
|
+
puts 'Update cancelled.'
|
649
|
+
return rfid_data
|
650
|
+
end
|
651
|
+
|
652
|
+
rfid_data = write_tag(
|
442
653
|
son_micro_rfid_obj: son_micro_rfid_obj,
|
443
654
|
rfid_data: rfid_data
|
444
655
|
)
|
656
|
+
|
657
|
+
logger.info("Update tag successful: #{rfid_data.inspect}")
|
658
|
+
puts 'tag updated successfully.'
|
659
|
+
rfid_data
|
445
660
|
rescue StandardError => e
|
661
|
+
logger.error("Error updating tag: #{e.message}")
|
662
|
+
puts "ERROR: Failed to update tag - #{e.message}"
|
446
663
|
raise e
|
447
664
|
end
|
448
665
|
|
@@ -452,19 +669,29 @@ module PWN
|
|
452
669
|
# )
|
453
670
|
|
454
671
|
public_class_method def self.disconnect(opts = {})
|
455
|
-
|
456
|
-
|
672
|
+
son_micro_rfid_obj = opts[:son_micro_rfid_obj]
|
673
|
+
|
674
|
+
logger.info('Disabling antenna power')
|
675
|
+
exec(
|
676
|
+
son_micro_rfid_obj: son_micro_rfid_obj,
|
677
|
+
cmd: :antenna_power,
|
678
|
+
params: :off
|
457
679
|
)
|
680
|
+
|
681
|
+
logger.info('Disconnecting from device')
|
682
|
+
|
683
|
+
PWN::Plugins::Serial.disconnect(serial_obj: son_micro_rfid_obj)
|
458
684
|
rescue StandardError => e
|
685
|
+
logger.error("Error disconnecting: #{e.message}")
|
459
686
|
raise e
|
460
687
|
end
|
461
688
|
|
462
689
|
# Author(s):: 0day Inc. <support@0dayinc.com>
|
463
690
|
|
464
691
|
public_class_method def self.authors
|
465
|
-
|
692
|
+
'AUTHOR(S):
|
466
693
|
0day Inc. <support@0dayinc.com>
|
467
|
-
|
694
|
+
'
|
468
695
|
end
|
469
696
|
|
470
697
|
# Display Usage for this Module
|
@@ -476,13 +703,14 @@ module PWN
|
|
476
703
|
baud: 'optional (defaults to 19_200)',
|
477
704
|
data_bits: 'optional (defaults to 8)',
|
478
705
|
stop_bits: 'optional (defaults to 1)',
|
479
|
-
parity: 'optional - :even|:mark|:odd|:space|:none (defaults to :
|
706
|
+
parity: 'optional - :even|:mark|:odd|:space|:none (defaults to :none)',
|
707
|
+
flow_control: 'optional - :none|:hard|:soft (defaults to :none)'
|
480
708
|
)
|
481
709
|
|
482
710
|
cmds = #{self}.list_cmds
|
483
711
|
|
484
712
|
params = #{self}.list_params(
|
485
|
-
cmd: 'required - cmd returned from #list_cmds method'
|
713
|
+
cmd: 'required - cmd returned from #list_cmds method'
|
486
714
|
)
|
487
715
|
|
488
716
|
parsed_cmd_resp_arr = #{self}.exec(
|
@@ -491,6 +719,31 @@ module PWN
|
|
491
719
|
params: 'optional - parameters for specific command returned from #list_params method'
|
492
720
|
)
|
493
721
|
|
722
|
+
rfid_data = #{self}.read_tag(
|
723
|
+
son_micro_rfid_obj: 'required son_micro_rfid_obj returned from #connect method'
|
724
|
+
)
|
725
|
+
|
726
|
+
rfid_data = #{self}.write_tag(
|
727
|
+
son_micro_rfid_obj: 'required son_micro_rfid_obj returned from #connect method',
|
728
|
+
rfid_data: 'required - RFID data to write'
|
729
|
+
)
|
730
|
+
|
731
|
+
rfid_data = #{self}.backup_tag(
|
732
|
+
son_micro_rfid_obj: 'required son_micro_rfid_obj returned from #connect method'
|
733
|
+
)
|
734
|
+
|
735
|
+
rfid_data = #{self}.clone_tag(
|
736
|
+
son_micro_rfid_obj: 'required son_micro_rfid_obj returned from #connect method'
|
737
|
+
)
|
738
|
+
|
739
|
+
rfid_data = #{self}.load_tag_from_file(
|
740
|
+
son_micro_rfid_obj: 'required son_micro_rfid_obj returned from #connect method'
|
741
|
+
)
|
742
|
+
|
743
|
+
rfid_data = #{self}.update_tag(
|
744
|
+
son_micro_rfid_obj: 'required son_micro_rfid_obj returned from #connect method'
|
745
|
+
)
|
746
|
+
|
494
747
|
#{self}.disconnect(
|
495
748
|
son_micro_rfid_obj: 'required son_micro_rfid_obj returned from #connect method'
|
496
749
|
)
|
data/lib/pwn/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pwn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.259
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- 0day Inc.
|
@@ -1952,7 +1952,6 @@ files:
|
|
1952
1952
|
- lib/pwn/www/uber.rb
|
1953
1953
|
- lib/pwn/www/upwork.rb
|
1954
1954
|
- lib/pwn/www/youtube.rb
|
1955
|
-
- msr206.log
|
1956
1955
|
- packer/daemons/msfrpcd.rb
|
1957
1956
|
- packer/daemons/openvas.rb
|
1958
1957
|
- packer/deploy_docker_containers.sh
|
data/msr206.log
DELETED
@@ -1,68 +0,0 @@
|
|
1
|
-
# Logfile created on 2025-04-22 11:39:09 -0600 by logger.rb/v1.7.0
|
2
|
-
I, [2025-04-22T11:39:09.967768 #2867164] INFO -- : Connecting to /dev/ttyUSB0 at baud 9600
|
3
|
-
I, [2025-04-22T11:39:09.991620 #2867164] INFO -- : Setting protocol to usi0
|
4
|
-
I, [2025-04-22T11:39:09.991792 #2867164] INFO -- : Executing command: proto_usi0 with params: nil
|
5
|
-
I, [2025-04-22T11:39:10.092182 #2867164] INFO -- : Response for proto_usi0: {cmd: :proto_usi0, cmd_bytes: ["0x55", "0x53", "0x49", "0x30"], msg: :response, hex: ["A1 AB A1"], binary: ["10100001", "10101011", "10100001"], decoded: "¿+¿"}
|
6
|
-
I, [2025-04-22T11:39:10.092353 #2867164] INFO -- : Executing command: simulate_power_cycle_warm_reset with params: nil
|
7
|
-
I, [2025-04-22T11:39:10.996840 #2867164] INFO -- : Response for simulate_power_cycle_warm_reset: {cmd: :simulate_power_cycle_warm_reset, cmd_bytes: ["0x7f"], msg: :power_on_report, hex: ["BA"], binary: ["10111010"], decoded: ":"}
|
8
|
-
I, [2025-04-22T11:39:10.996886 #2867164] INFO -- : Retrieving configuration
|
9
|
-
I, [2025-04-22T11:39:10.996905 #2867164] INFO -- : Executing command: configuration_request with params: nil
|
10
|
-
I, [2025-04-22T11:39:11.097145 #2867164] INFO -- : Response for configuration_request: {cmd: :configuration_request, cmd_bytes: ["0x23"], msg: :response, hex: ["F7"], binary: ["11110111"], decoded: "w"}
|
11
|
-
I, [2025-04-22T11:39:11.097302 #2867164] INFO -- : Configuration: {track1_read: true, track2_read: true, track3_read: true, track1_write: true, track2_write: true, track3_write: true, not_used: false, parity: true}
|
12
|
-
I, [2025-04-22T11:39:11.097349 #2867164] INFO -- : Executing command: version_report with params: nil
|
13
|
-
I, [2025-04-22T11:39:11.198353 #2867164] INFO -- : Response for version_report: {cmd: :version_report, cmd_bytes: ["0x39"], msg: :response, hex: ["32 B0 B6 C1 CD 31 37 31 20 31 32 AD 46 E5 62 AD 32 B0 B0 B9"], binary: ["00110010", "10110000", "10110110", "11000001", "11001101", "00110001", "00110111", "00110001", "00100000", "00110001", "00110010", "10101101", "01000110", "11100101", "01100010", "10101101", "00110010", "10110000", "10110000", "10111001"], decoded: "206AM171 12-Feb-2009"}
|
14
|
-
I, [2025-04-22T11:39:11.198500 #2867164] INFO -- : Executing command: green_flash with params: nil
|
15
|
-
I, [2025-04-22T11:39:11.298726 #2867164] INFO -- : Response for green_flash: {cmd: :green_flash, cmd_bytes: ["0x28"], msg: :ack_command_completed, hex: ["5E"], binary: ["01011110"], decoded: "^"}
|
16
|
-
I, [2025-04-22T11:39:19.913780 #2867164] INFO -- : Executing command: green_off with params: nil
|
17
|
-
I, [2025-04-22T11:39:20.014016 #2867164] INFO -- : Response for green_off: {cmd: :green_off, cmd_bytes: ["0x6c"], msg: :ack_command_completed, hex: ["5E"], binary: ["01011110"], decoded: "^"}
|
18
|
-
I, [2025-04-22T11:39:20.014120 #2867164] INFO -- : Executing command: yellow_off with params: nil
|
19
|
-
I, [2025-04-22T11:39:20.114315 #2867164] INFO -- : Response for yellow_off: {cmd: :yellow_off, cmd_bytes: ["0x6b"], msg: :ack_command_completed, hex: ["5E"], binary: ["01011110"], decoded: "^"}
|
20
|
-
I, [2025-04-22T11:39:20.114443 #2867164] INFO -- : Executing command: red_off with params: nil
|
21
|
-
I, [2025-04-22T11:39:20.214668 #2867164] INFO -- : Response for red_off: {cmd: :red_off, cmd_bytes: ["0x6d"], msg: :ack_command_completed, hex: ["5E"], binary: ["01011110"], decoded: "^"}
|
22
|
-
I, [2025-04-22T11:39:20.214799 #2867164] INFO -- : Disconnecting from device
|
23
|
-
I, [2025-04-22T11:41:46.363878 #2872588] INFO -- : Connecting to /dev/ttyUSB0 at baud 19200
|
24
|
-
I, [2025-04-22T11:41:46.379386 #2872588] INFO -- : Setting protocol to usi0
|
25
|
-
I, [2025-04-22T11:41:46.379521 #2872588] INFO -- : Executing command: proto_usi0 with params: nil
|
26
|
-
I, [2025-04-22T11:41:46.479918 #2872588] INFO -- : Response for proto_usi0: {cmd: :proto_usi0, cmd_bytes: ["0x55", "0x53", "0x49", "0x30"], msg: :response, hex: ["06 FE 06 FE"], binary: ["00000110", "11111110", "00000110", "11111110"], decoded: "¿~¿~"}
|
27
|
-
I, [2025-04-22T11:41:46.480081 #2872588] INFO -- : Executing command: simulate_power_cycle_warm_reset with params: nil
|
28
|
-
I, [2025-04-22T11:41:46.580309 #2872588] INFO -- : Response for simulate_power_cycle_warm_reset: {cmd: :simulate_power_cycle_warm_reset, cmd_bytes: ["0x7f"], msg: :response, hex: ["06 FE"], binary: ["00000110", "11111110"], decoded: "¿~"}
|
29
|
-
I, [2025-04-22T11:41:46.580431 #2872588] INFO -- : Retrieving configuration
|
30
|
-
I, [2025-04-22T11:41:46.580459 #2872588] INFO -- : Executing command: configuration_request with params: nil
|
31
|
-
I, [2025-04-22T11:41:46.680666 #2872588] INFO -- : Response for configuration_request: {cmd: :configuration_request, cmd_bytes: ["0x23"], msg: :response, hex: ["06 FE"], binary: ["00000110", "11111110"], decoded: "¿~"}
|
32
|
-
I, [2025-04-22T11:41:46.680809 #2872588] INFO -- : Configuration: {track1_read: false, track2_read: true, track3_read: true, track1_write: false, track2_write: false, track3_write: false, not_used: false, parity: false}
|
33
|
-
I, [2025-04-22T11:41:46.680848 #2872588] INFO -- : Executing command: version_report with params: nil
|
34
|
-
I, [2025-04-22T11:41:46.781057 #2872588] INFO -- : Response for version_report: {cmd: :version_report, cmd_bytes: ["0x39"], msg: :response, hex: ["06 FE"], binary: ["00000110", "11111110"], decoded: "¿~"}
|
35
|
-
I, [2025-04-22T11:41:46.781196 #2872588] INFO -- : Executing command: green_flash with params: nil
|
36
|
-
I, [2025-04-22T11:41:46.881415 #2872588] INFO -- : Response for green_flash: {cmd: :green_flash, cmd_bytes: ["0x28"], msg: :response, hex: ["06 FE"], binary: ["00000110", "11111110"], decoded: "¿~"}
|
37
|
-
I, [2025-04-22T11:41:50.780641 #2872588] INFO -- : Executing command: green_off with params: nil
|
38
|
-
I, [2025-04-22T11:41:50.880870 #2872588] INFO -- : Response for green_off: {cmd: :green_off, cmd_bytes: ["0x6c"], msg: :response, hex: ["06 FE"], binary: ["00000110", "11111110"], decoded: "¿~"}
|
39
|
-
I, [2025-04-22T11:41:50.880965 #2872588] INFO -- : Executing command: yellow_flash with params: nil
|
40
|
-
I, [2025-04-22T11:41:50.981179 #2872588] INFO -- : Response for yellow_flash: {cmd: :yellow_flash, cmd_bytes: ["0x7c"], msg: :response, hex: ["06 FE"], binary: ["00000110", "11111110"], decoded: "¿~"}
|
41
|
-
I, [2025-04-22T11:41:52.023768 #2872588] INFO -- : Executing command: green_off with params: nil
|
42
|
-
I, [2025-04-22T11:41:52.124015 #2872588] INFO -- : Response for green_off: {cmd: :green_off, cmd_bytes: ["0x6c"], msg: :response, hex: ["06 FE"], binary: ["00000110", "11111110"], decoded: "¿~"}
|
43
|
-
I, [2025-04-22T11:41:52.124151 #2872588] INFO -- : Executing command: yellow_off with params: nil
|
44
|
-
I, [2025-04-22T11:41:52.224358 #2872588] INFO -- : Response for yellow_off: {cmd: :yellow_off, cmd_bytes: ["0x6b"], msg: :response, hex: ["06 FE"], binary: ["00000110", "11111110"], decoded: "¿~"}
|
45
|
-
I, [2025-04-22T11:41:52.224491 #2872588] INFO -- : Executing command: red_off with params: nil
|
46
|
-
I, [2025-04-22T11:41:52.324786 #2872588] INFO -- : Response for red_off: {cmd: :red_off, cmd_bytes: ["0x6d"], msg: :response, hex: ["06 FE"], binary: ["00000110", "11111110"], decoded: "¿~"}
|
47
|
-
I, [2025-04-22T11:41:52.324969 #2872588] INFO -- : Disconnecting from device
|
48
|
-
I, [2025-04-22T11:41:56.503719 #2872594] INFO -- : Connecting to /dev/ttyUSB0 at baud 19200
|
49
|
-
I, [2025-04-22T11:41:56.518859 #2872594] INFO -- : Setting protocol to usi0
|
50
|
-
I, [2025-04-22T11:41:56.519014 #2872594] INFO -- : Executing command: proto_usi0 with params: nil
|
51
|
-
I, [2025-04-22T11:41:56.619439 #2872594] INFO -- : Response for proto_usi0: {cmd: :proto_usi0, cmd_bytes: ["0x55", "0x53", "0x49", "0x30"], msg: :response, hex: ["A1 AB A1"], binary: ["10100001", "10101011", "10100001"], decoded: "¿+¿"}
|
52
|
-
I, [2025-04-22T11:41:56.619599 #2872594] INFO -- : Executing command: simulate_power_cycle_warm_reset with params: nil
|
53
|
-
I, [2025-04-22T11:41:57.524457 #2872594] INFO -- : Response for simulate_power_cycle_warm_reset: {cmd: :simulate_power_cycle_warm_reset, cmd_bytes: ["0x7f"], msg: :power_on_report, hex: ["BA"], binary: ["10111010"], decoded: ":"}
|
54
|
-
I, [2025-04-22T11:41:57.524512 #2872594] INFO -- : Retrieving configuration
|
55
|
-
I, [2025-04-22T11:41:57.524530 #2872594] INFO -- : Executing command: configuration_request with params: nil
|
56
|
-
I, [2025-04-22T11:41:57.624761 #2872594] INFO -- : Response for configuration_request: {cmd: :configuration_request, cmd_bytes: ["0x23"], msg: :response, hex: ["F7"], binary: ["11110111"], decoded: "w"}
|
57
|
-
I, [2025-04-22T11:41:57.624863 #2872594] INFO -- : Configuration: {track1_read: true, track2_read: true, track3_read: true, track1_write: true, track2_write: true, track3_write: true, not_used: false, parity: true}
|
58
|
-
I, [2025-04-22T11:41:57.624906 #2872594] INFO -- : Executing command: version_report with params: nil
|
59
|
-
I, [2025-04-22T11:41:57.725212 #2872594] INFO -- : Response for version_report: {cmd: :version_report, cmd_bytes: ["0x39"], msg: :response, hex: ["32 B0 B6 C1 CD 31 37 31 20 31 32 AD 46 E5 62 AD 32 B0 B0 B9"], binary: ["00110010", "10110000", "10110110", "11000001", "11001101", "00110001", "00110111", "00110001", "00100000", "00110001", "00110010", "10101101", "01000110", "11100101", "01100010", "10101101", "00110010", "10110000", "10110000", "10111001"], decoded: "206AM171 12-Feb-2009"}
|
60
|
-
I, [2025-04-22T11:41:57.725298 #2872594] INFO -- : Executing command: green_flash with params: nil
|
61
|
-
I, [2025-04-22T11:41:57.825519 #2872594] INFO -- : Response for green_flash: {cmd: :green_flash, cmd_bytes: ["0x28"], msg: :ack_command_completed, hex: ["5E"], binary: ["01011110"], decoded: "^"}
|
62
|
-
I, [2025-04-22T11:42:03.647677 #2872594] INFO -- : Executing command: green_off with params: nil
|
63
|
-
I, [2025-04-22T11:42:03.747938 #2872594] INFO -- : Response for green_off: {cmd: :green_off, cmd_bytes: ["0x6c"], msg: :ack_command_completed, hex: ["5E"], binary: ["01011110"], decoded: "^"}
|
64
|
-
I, [2025-04-22T11:42:03.748010 #2872594] INFO -- : Executing command: yellow_off with params: nil
|
65
|
-
I, [2025-04-22T11:42:03.848227 #2872594] INFO -- : Response for yellow_off: {cmd: :yellow_off, cmd_bytes: ["0x6b"], msg: :ack_command_completed, hex: ["5E"], binary: ["01011110"], decoded: "^"}
|
66
|
-
I, [2025-04-22T11:42:03.848295 #2872594] INFO -- : Executing command: red_off with params: nil
|
67
|
-
I, [2025-04-22T11:42:03.948506 #2872594] INFO -- : Response for red_off: {cmd: :red_off, cmd_bytes: ["0x6d"], msg: :ack_command_completed, hex: ["5E"], binary: ["01011110"], decoded: "^"}
|
68
|
-
I, [2025-04-22T11:42:03.948574 #2872594] INFO -- : Disconnecting from device
|