packetgen 2.1.2 → 2.1.3
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/.gitignore +1 -1
- data/README.md +10 -3
- data/bin/pgconsole +25 -28
- data/lib/packetgen/config.rb +47 -31
- data/lib/packetgen/header/arp.rb +1 -2
- data/lib/packetgen/header/asn1_base.rb +4 -0
- data/lib/packetgen/header/dns/question.rb +16 -30
- data/lib/packetgen/header/dot11.rb +73 -8
- data/lib/packetgen/header/dot11/control.rb +11 -1
- data/lib/packetgen/header/dot11/data.rb +14 -0
- data/lib/packetgen/header/dot11/element.rb +2 -0
- data/lib/packetgen/header/dot11/management.rb +43 -0
- data/lib/packetgen/header/dot11/sub_mngt.rb +84 -1
- data/lib/packetgen/header/dot1x.rb +8 -27
- data/lib/packetgen/header/ike.rb +10 -25
- data/lib/packetgen/header/ike/cert.rb +15 -31
- data/lib/packetgen/header/ike/notify.rb +35 -78
- data/lib/packetgen/header/ike/sa.rb +13 -25
- data/lib/packetgen/header/ike/ts.rb +4 -3
- data/lib/packetgen/inspect.rb +6 -4
- data/lib/packetgen/packet.rb +1 -1
- data/lib/packetgen/pcapng/epb.rb +1 -1
- data/lib/packetgen/pcapng/idb.rb +2 -2
- data/lib/packetgen/pcapng/shb.rb +1 -1
- data/lib/packetgen/pcapng/spb.rb +1 -1
- data/lib/packetgen/pcapng/unknown_block.rb +2 -2
- data/lib/packetgen/proto.rb +1 -1
- data/lib/packetgen/types.rb +1 -0
- data/lib/packetgen/types/enum.rb +165 -0
- data/lib/packetgen/types/fields.rb +29 -9
- data/lib/packetgen/types/int.rb +4 -0
- data/lib/packetgen/utils.rb +101 -0
- data/lib/packetgen/utils/arp_spoofer.rb +191 -0
- data/lib/packetgen/version.rb +1 -1
- data/packetgen.gemspec +1 -1
- metadata +7 -4
@@ -60,7 +60,8 @@ module PacketGen
|
|
60
60
|
# * +:builder+ to give a builder/constructor lambda to create field. The lambda
|
61
61
|
# takes one argument: {Fields} subclass object owning field,
|
62
62
|
# * +:optional+ to define this field as optional. This option takes a lambda
|
63
|
-
# parameter used to say if this field is present or not
|
63
|
+
# parameter used to say if this field is present or not,
|
64
|
+
# * +:enum+ to define Hash enumeration for an {Enum} type.
|
64
65
|
# For example:
|
65
66
|
# # 32-bit integer field defaulting to 1
|
66
67
|
# define_field :type, PacketGen::Types::Int32, default: 1
|
@@ -71,6 +72,8 @@ module PacketGen
|
|
71
72
|
# define_field :body_size, PacketGen::Type::Int16
|
72
73
|
# # String field which length is taken from body_size field
|
73
74
|
# define_field :body, PacketGen::Type::String, builder: ->(obj) { PacketGen::Type::String.new('', length_from: obj[:body_size]) }
|
75
|
+
# # 16-bit enumeration type. As :default not specified, default to first value of enum
|
76
|
+
# define_field :type_class, PacketGen::Type::Int16Enum, enum: { 'class1' => 1, 'class2' => 2}
|
74
77
|
#
|
75
78
|
# {.define_field_before} and {.define_field_after} are also defined to relatively
|
76
79
|
# create a field from anoher one (for example, when adding a field in a subclass).
|
@@ -133,16 +136,21 @@ module PacketGen
|
|
133
136
|
# @option options [Lambda] :optional define this field as optional. Given lambda
|
134
137
|
# is used to known if this field is present or not. Parameter to this lambda is
|
135
138
|
# the being defined Field object.
|
139
|
+
# @option options [Hash] :enum mandatory option for an {Enum} type.
|
140
|
+
# Define enumeration: hash's keys are +String+, and values are +Integer+.
|
136
141
|
# @return [void]
|
137
142
|
def self.define_field(name, type, options={})
|
138
143
|
define = []
|
139
|
-
if type < Types::
|
144
|
+
if type < Types::Enum
|
145
|
+
define << "def #{name}; self[:#{name}].to_i; end"
|
146
|
+
define << "def #{name}=(val) self[:#{name}].value = val; end"
|
147
|
+
elsif type < Types::Int
|
140
148
|
define << "def #{name}; self[:#{name}].to_i; end"
|
141
149
|
define << "def #{name}=(val) self[:#{name}].read val; end"
|
142
150
|
elsif type.instance_methods.include? :to_human and
|
143
|
-
|
144
|
-
|
145
|
-
|
151
|
+
type.instance_methods.include? :from_human
|
152
|
+
define << "def #{name}; self[:#{name}].to_human; end"
|
153
|
+
define << "def #{name}=(val) self[:#{name}].from_human val; end"
|
146
154
|
else
|
147
155
|
define << "def #{name}; self[:#{name}]; end\n"
|
148
156
|
define << "def #{name}=(val) self[:#{name}].read val; end"
|
@@ -151,8 +159,11 @@ module PacketGen
|
|
151
159
|
define.delete(1) if type.instance_methods.include? "#{name}=".to_sym
|
152
160
|
define.delete(0) if type.instance_methods.include? name
|
153
161
|
class_eval define.join("\n")
|
154
|
-
@field_defs[name] = [type, options.delete(:default),
|
155
|
-
options.delete(:
|
162
|
+
@field_defs[name] = [type, options.delete(:default),
|
163
|
+
options.delete(:builder),
|
164
|
+
options.delete(:optional),
|
165
|
+
options.delete(:enum),
|
166
|
+
options]
|
156
167
|
@ordered_fields << name
|
157
168
|
end
|
158
169
|
|
@@ -285,14 +296,23 @@ module PacketGen
|
|
285
296
|
default = ary[1].is_a?(Proc) ? ary[1].call : ary[1]
|
286
297
|
@fields[field] = if ary[2]
|
287
298
|
ary[2].call(self)
|
288
|
-
elsif
|
299
|
+
elsif ary[4]
|
289
300
|
ary[0].new(ary[4])
|
301
|
+
elsif !ary[5].empty?
|
302
|
+
ary[0].new(ary[5])
|
290
303
|
else
|
291
304
|
ary[0].new
|
292
305
|
end
|
293
306
|
|
294
307
|
value = options[field] || default
|
295
|
-
if ary[0] < Types::
|
308
|
+
if ary[0] < Types::Enum
|
309
|
+
case value
|
310
|
+
when ::String
|
311
|
+
@fields[field].value = value
|
312
|
+
else
|
313
|
+
@fields[field].read(value)
|
314
|
+
end
|
315
|
+
elsif ary[0] < Types::Int
|
296
316
|
@fields[field].read(value)
|
297
317
|
elsif ary[0] <= Types::String
|
298
318
|
@fields[field].read(value)
|
data/lib/packetgen/types/int.rb
CHANGED
@@ -0,0 +1,101 @@
|
|
1
|
+
# This file is part of PacketGen
|
2
|
+
# See https://github.com/sdaubert/packetgen for more informations
|
3
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
|
+
# This program is published under MIT license.
|
5
|
+
require_relative 'config'
|
6
|
+
require_relative 'utils/arp_spoofer'
|
7
|
+
|
8
|
+
module PacketGen
|
9
|
+
|
10
|
+
# Collection of some network utilities.
|
11
|
+
#
|
12
|
+
# This module is not enabled by default. You need to:
|
13
|
+
# require 'packetgen/utils'
|
14
|
+
# @author Sylvain Daubert
|
15
|
+
# @since 2.1.3
|
16
|
+
module Utils
|
17
|
+
|
18
|
+
# Get local ARP cache
|
19
|
+
# @return [Hash] key: IP address, value: array containing MAC address and
|
20
|
+
# interface name
|
21
|
+
def self.arp_cache
|
22
|
+
raw_cache = %x(/usr/sbin/arp -an)
|
23
|
+
|
24
|
+
cache = {}
|
25
|
+
raw_cache.split(/\n/).each do |line|
|
26
|
+
match = line.match(/\((\d+\.\d+\.\d+\.\d+)\) at (([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2})(?: \[ether\])? on (\w+)/)
|
27
|
+
if match
|
28
|
+
cache[match[1]] = [match[2], match[4]]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
cache
|
33
|
+
end
|
34
|
+
|
35
|
+
# Get MAC address from an IP address, or nil if this IP address is unknown
|
36
|
+
# on local network.
|
37
|
+
# @param [String] ipaddr dotted-octet IP address
|
38
|
+
# @param [Hash] options
|
39
|
+
# @option options [String] :iface interface name. Default to
|
40
|
+
# {PacketGen.default_iface}
|
41
|
+
# @option options [Boolean] :no_cache if +true+, do not query local ARP
|
42
|
+
# cache and always send an ARP request on wire. Default to +false+
|
43
|
+
# @option options [Integer] :timeout timeout in seconds before stopping
|
44
|
+
# request. Default to 2.
|
45
|
+
# @return [String,nil]
|
46
|
+
def self.arp(ipaddr, options={})
|
47
|
+
unless options[:no_cache]
|
48
|
+
local_cache = self.arp_cache
|
49
|
+
return local_cache[ipaddr].first if local_cache.has_key? ipaddr
|
50
|
+
end
|
51
|
+
|
52
|
+
iface = options[:iface] || PacketGen.default_iface
|
53
|
+
timeout = options[:timeout] || 1
|
54
|
+
my_hwaddr = Config.instance.hwaddr(iface)
|
55
|
+
arp_pkt = Packet.gen('Eth', dst: 'ff:ff:ff:ff:ff:ff', src: my_hwaddr)
|
56
|
+
arp_pkt.add('ARP', sha: @config.hwaddr, spa: @config.ipaddr, tpa: ipaddr)
|
57
|
+
|
58
|
+
capture = Capture.new(iface: iface, timeout: timeout, max: 1,
|
59
|
+
filter: "arp src #{ipaddr} and ether dst #{my_hwaddr}")
|
60
|
+
cap_thread = Thread.new do
|
61
|
+
capture.start
|
62
|
+
end
|
63
|
+
|
64
|
+
arp_pkt.to_w(iface)
|
65
|
+
cap_thread.join
|
66
|
+
|
67
|
+
if capture.packets.size > 0
|
68
|
+
capture.packets.each do |pkt|
|
69
|
+
if pkt.arp.spa.to_s == ipaddr
|
70
|
+
break pkt.arp.sha.to_s
|
71
|
+
end
|
72
|
+
end
|
73
|
+
else
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Do ARP spoofing on given IP address. Call to this method blocks.
|
79
|
+
# @note This method is provided for test purpose.
|
80
|
+
# For more control, see {ARPSpoofer} class.
|
81
|
+
# @param [String] target_ip target IP address
|
82
|
+
# @param [String] spoofed_ip IP address to spoofed_ip
|
83
|
+
# @param [Hash] options
|
84
|
+
# @option options [String] :mac MAC address used to poison target
|
85
|
+
# ARP cache. Default to local MAC address.
|
86
|
+
# @option options [Integer,nil] :for_seconds number of seconds to do ARP spoofing.
|
87
|
+
# If not defined, spoof forever.
|
88
|
+
# @option options [Float,Integer] :interval number of seconds between 2
|
89
|
+
# ARP packets (default: 1.0).
|
90
|
+
# @option options [String] :iface interface to use. Default to
|
91
|
+
# {PacketGen.default_iface}
|
92
|
+
# @return [void]
|
93
|
+
def self.arp_spoof(target_ip, spoofed_ip, options={})
|
94
|
+
interval = options[:interval] || 1.0
|
95
|
+
as = ARPSpoofer.new(for_seconds: options[:for_seconds], interval: interval,
|
96
|
+
iface: options[:iface])
|
97
|
+
as.start(target_ip, spoofed_ip, mac: options[:mac])
|
98
|
+
as.wait
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,191 @@
|
|
1
|
+
# This file is part of PacketGen
|
2
|
+
# See https://github.com/sdaubert/packetgen for more informations
|
3
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
|
+
# This program is published under MIT license.
|
5
|
+
require 'thread'
|
6
|
+
|
7
|
+
module PacketGen
|
8
|
+
module Utils
|
9
|
+
|
10
|
+
# @note This class is provided for test purpose.
|
11
|
+
# Utility class to make ARP spoofing.
|
12
|
+
# spoofer = PacketGen::Utils::ARPSpoofer.new
|
13
|
+
# # start an ARP spoof: send forged ARP packets to target to spoof spoofed_ip
|
14
|
+
# spoofer.start target_ip, spoofed_ip
|
15
|
+
# # start another ARP spoof. Say to target2 spoofed_ip has given MAC address
|
16
|
+
# spoofer.start target2_ip, spoofed_ip, mac: '00:00:00:00:00:01'
|
17
|
+
# # stop spoofing on target2
|
18
|
+
# spoofer.stop target2_ip
|
19
|
+
# # stop all spoofings
|
20
|
+
# spoofer.stop_all
|
21
|
+
# @author Sylvain Daubert
|
22
|
+
# @since 2.1.3
|
23
|
+
class ARPSpoofer
|
24
|
+
|
25
|
+
# @param [Integer,Float,nil] timeout spoof will happen for this amount
|
26
|
+
# of time
|
27
|
+
# @param [Integer,Float] interval time between 2 ARP packets
|
28
|
+
# @param [String,nil] iface network interface on which do spoofing.
|
29
|
+
# Defaults to {PacketGen.default_iface}
|
30
|
+
def initialize(timeout: nil, interval: 1.0, iface: nil)
|
31
|
+
@timeout = timeout
|
32
|
+
@timeout = @timeout.to_f if @timeout
|
33
|
+
@interval = interval
|
34
|
+
@iface = iface || PacketGen.default_iface
|
35
|
+
@targets = {}
|
36
|
+
@arp_packets = {}
|
37
|
+
@spoof_thread = nil
|
38
|
+
@queue = Queue.new
|
39
|
+
end
|
40
|
+
|
41
|
+
# Add a target to spoofer, without starting attack. Spoofing should
|
42
|
+
# be enabled with {#start_all}.
|
43
|
+
# @param [String] target_ip target IP address
|
44
|
+
# @param [String] spoofed_ip spoofed IP address
|
45
|
+
# @param [Hash] options
|
46
|
+
# @option options [String] :mac attacker's MAC address. Defaults to
|
47
|
+
# local MAC address.
|
48
|
+
# @option options [String] :target_mac target MAC address. If not given,
|
49
|
+
# an ARP request is made to get it.
|
50
|
+
# @return [void]
|
51
|
+
def add(target_ip, spoofed_ip, options={})
|
52
|
+
@targets[target_ip] = options.merge({spoofed_ip: spoofed_ip, active: false})
|
53
|
+
end
|
54
|
+
|
55
|
+
# Remove target from spoofer.
|
56
|
+
# @param [String] target_ip target IP address
|
57
|
+
# @return [void]
|
58
|
+
def remove(target_ip)
|
59
|
+
@targets.delete target_ip
|
60
|
+
@arp_packets.delete target_ip
|
61
|
+
end
|
62
|
+
|
63
|
+
# Get registered targets (all targets, registered with {#add} and {#start})
|
64
|
+
# @return [Array<String>] list of target IP addresses
|
65
|
+
def registered_targets
|
66
|
+
@targets.keys
|
67
|
+
end
|
68
|
+
|
69
|
+
# Get active targets (registered with {#start}, or all after using
|
70
|
+
# {#start_all})
|
71
|
+
# @return [Array<String>] list of target IP addresses
|
72
|
+
def active_targets
|
73
|
+
@arp_packets.keys
|
74
|
+
end
|
75
|
+
|
76
|
+
# Start spoofing on given target
|
77
|
+
# @param [String] target_ip target IP address
|
78
|
+
# @param [String] spoofed_ip spoofed IP address
|
79
|
+
# @param [Hash] options
|
80
|
+
# @option options [String] :mac attacker's MAC address. Defaults to
|
81
|
+
# local MAC address.
|
82
|
+
# @option options [String] :target_mac target MAC address. If not given,
|
83
|
+
# an ARP request is made to get it.
|
84
|
+
# @return [void]
|
85
|
+
def start(target_ip, spoofed_ip, options={})
|
86
|
+
add target_ip, spoofed_ip, options
|
87
|
+
activate target_ip
|
88
|
+
end
|
89
|
+
|
90
|
+
# Stop spoofing on given target
|
91
|
+
# @param [String] target_ip target IP address
|
92
|
+
# @return [void]
|
93
|
+
def stop(target_ip)
|
94
|
+
deactivate target_ip
|
95
|
+
remove target_ip
|
96
|
+
end
|
97
|
+
|
98
|
+
# Start spoofing on all targets added with {#add}.
|
99
|
+
# @return [void]
|
100
|
+
def start_all
|
101
|
+
@targets.each do |target_ip, _|
|
102
|
+
activate target_ip
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Stop spoofing on all targets.
|
107
|
+
# @return [void]
|
108
|
+
def stop_all
|
109
|
+
@targets.each do |target_ip, _|
|
110
|
+
deactivate target_ip
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Say if spoofing on given target is active or not
|
115
|
+
# @param [String] target_ip target IP address
|
116
|
+
# @return [Boolean,nil]
|
117
|
+
def active?(target_ip)
|
118
|
+
if @targets.has_key?(target_ip)
|
119
|
+
@targets[target_ip][:active]
|
120
|
+
else
|
121
|
+
nil
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Wait for spoofing to finish. Wait forever if no +timeout+ options
|
126
|
+
# was set on {#initialize}.
|
127
|
+
def wait
|
128
|
+
@spoof_thread.join
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
# Activate spoofing for given target
|
134
|
+
# @param [String] target_ip
|
135
|
+
# @return [void]
|
136
|
+
def activate(target_ip)
|
137
|
+
@arp_packets[target_ip] = make_arp_packet(target_ip)
|
138
|
+
@queue << @arp_packets.values
|
139
|
+
unless @spoof_thread
|
140
|
+
create_spoof_thread
|
141
|
+
end
|
142
|
+
@targets[target_ip][:active] = true
|
143
|
+
end
|
144
|
+
|
145
|
+
# Create spoof thread
|
146
|
+
def create_spoof_thread
|
147
|
+
@spoof_thread = Thread.new(@queue, @iface, @timeout, @interval) do |queue, iface, timeout, interval|
|
148
|
+
while timeout.nil? or timeout > 0.0 do
|
149
|
+
packets = queue.pop unless queue.empty?
|
150
|
+
send_packets_on_wire packets
|
151
|
+
timeout -= interval if timeout
|
152
|
+
sleep interval
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# send packets on wire
|
158
|
+
def send_packets_on_wire(packets)
|
159
|
+
packets.each { |pkt| pkt.to_w(iface) }
|
160
|
+
end
|
161
|
+
|
162
|
+
# Deactivate spoofing for given target
|
163
|
+
# @param [String] target_ip
|
164
|
+
# @return [void]
|
165
|
+
def deactivate(target_ip)
|
166
|
+
@arp_packets.delete target_ip
|
167
|
+
if @arp_packets.empty?
|
168
|
+
@spoof_thread.kill
|
169
|
+
@spoof_thread = nil
|
170
|
+
else
|
171
|
+
@queue << @arp_packets.values
|
172
|
+
end
|
173
|
+
@targets[target_ip][:active] = false
|
174
|
+
end
|
175
|
+
|
176
|
+
# Create ARP packet to spoof given target
|
177
|
+
# @param [String] target_ip
|
178
|
+
# @return [Packet]
|
179
|
+
def make_arp_packet(target_ip)
|
180
|
+
params = @targets[target_ip]
|
181
|
+
mac = params[:mac] || Config.instance.hwaddr(@iface)
|
182
|
+
|
183
|
+
target_mac = params[:target_mac] || Utils.arp(target_ip)
|
184
|
+
|
185
|
+
Packet.gen('Eth', dst: target_mac, src: mac).
|
186
|
+
add('ARP', op: 'reply', sha: mac, spa: params[:spoofed_ip],
|
187
|
+
tha: target_mac, tpa: target_ip)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
data/lib/packetgen/version.rb
CHANGED
data/packetgen.gemspec
CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.add_dependency 'rasn1', '~>0.3', '>= 0.3.1'
|
29
29
|
|
30
30
|
spec.add_development_dependency 'bundler', '~> 1.7'
|
31
|
-
spec.add_development_dependency 'rake', '~>
|
31
|
+
spec.add_development_dependency 'rake', '~> 12.0'
|
32
32
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
33
33
|
spec.add_development_dependency 'simplecov', '~> 0.12'
|
34
34
|
spec.add_development_dependency 'yard', '~> 0.9'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: packetgen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.
|
4
|
+
version: 2.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sylvain Daubert
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-11-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pcaprub
|
@@ -78,14 +78,14 @@ dependencies:
|
|
78
78
|
requirements:
|
79
79
|
- - "~>"
|
80
80
|
- !ruby/object:Gem::Version
|
81
|
-
version: '
|
81
|
+
version: '12.0'
|
82
82
|
type: :development
|
83
83
|
prerelease: false
|
84
84
|
version_requirements: !ruby/object:Gem::Requirement
|
85
85
|
requirements:
|
86
86
|
- - "~>"
|
87
87
|
- !ruby/object:Gem::Version
|
88
|
-
version: '
|
88
|
+
version: '12.0'
|
89
89
|
- !ruby/object:Gem::Dependency
|
90
90
|
name: rspec
|
91
91
|
requirement: !ruby/object:Gem::Requirement
|
@@ -206,12 +206,15 @@ files:
|
|
206
206
|
- lib/packetgen/proto.rb
|
207
207
|
- lib/packetgen/types.rb
|
208
208
|
- lib/packetgen/types/array.rb
|
209
|
+
- lib/packetgen/types/enum.rb
|
209
210
|
- lib/packetgen/types/fields.rb
|
210
211
|
- lib/packetgen/types/int.rb
|
211
212
|
- lib/packetgen/types/int_string.rb
|
212
213
|
- lib/packetgen/types/oui.rb
|
213
214
|
- lib/packetgen/types/string.rb
|
214
215
|
- lib/packetgen/types/tlv.rb
|
216
|
+
- lib/packetgen/utils.rb
|
217
|
+
- lib/packetgen/utils/arp_spoofer.rb
|
215
218
|
- lib/packetgen/version.rb
|
216
219
|
- packetgen.gemspec
|
217
220
|
homepage: https://github.com/sdaubert/packetgen
|