From 0e458d5e2c7bc41649a358a402f22fd540281b9c Mon Sep 17 00:00:00 2001 From: sethumadh Date: Wed, 20 May 2026 13:56:21 +1000 Subject: [PATCH] Fix UnknownAttributeError on NetworkHost/NetworkService.create --- core/main/handlers/browserdetails.rb | 2 +- .../router/asus_rt_n12e_get_info/module.rb | 8 ++-- modules/host/detect_airdroid/module.rb | 2 +- modules/host/detect_cups/module.rb | 2 +- .../cross_origin_scanner_cors/module.rb | 2 +- .../cross_origin_scanner_flash/module.rb | 2 +- modules/network/detect_burp/module.rb | 2 +- modules/network/get_http_servers/module.rb | 2 +- .../network/get_ntop_network_hosts/module.rb | 2 +- .../network/get_proxy_servers_wpad/module.rb | 2 +- .../internal_network_fingerprinting/module.rb | 2 +- modules/network/jslanscanner/module.rb | 4 +- .../core/main/models/network_host_spec.rb | 40 +++++++++++++++++ .../core/main/models/network_service_spec.rb | 44 +++++++++++++++++++ 14 files changed, 100 insertions(+), 16 deletions(-) create mode 100644 spec/beef/core/main/models/network_host_spec.rb create mode 100644 spec/beef/core/main/models/network_service_spec.rb diff --git a/core/main/handlers/browserdetails.rb b/core/main/handlers/browserdetails.rb index 8e28482a6..cd344d3b2 100644 --- a/core/main/handlers/browserdetails.rb +++ b/core/main/handlers/browserdetails.rb @@ -268,7 +268,7 @@ module BeEF proxy_log_string += " [server: #{proxy_server}]" if config.get('beef.extension.network.enable') == true && (proxy_server =~ /^([\d.]+):(\d+)$/) print_debug("Hooked browser [id:#{zombie.id}] is using a proxy [ip: #{Regexp.last_match(1)}]") - BeEF::Core::Models::NetworkHost.create(hooked_browser_id: session_id, ip: Regexp.last_match(1), type: 'Proxy') + BeEF::Core::Models::NetworkHost.create(hooked_browser_id: session_id, ip: Regexp.last_match(1), ntype: 'Proxy') end end BeEF::Core::Logger.instance.register('Zombie', proxy_log_string.to_s, zombie.id.to_s) diff --git a/modules/exploits/router/asus_rt_n12e_get_info/module.rb b/modules/exploits/router/asus_rt_n12e_get_info/module.rb index 4799b65ad..d61a205a5 100644 --- a/modules/exploits/router/asus_rt_n12e_get_info/module.rb +++ b/modules/exploits/router/asus_rt_n12e_get_info/module.rb @@ -29,8 +29,8 @@ class Asus_rt_n12e_get_info < BeEF::Core::Command if !ip.nil? && BeEF::Filters.is_valid_ip?(ip) print_debug("Hooked browser found Asus RT-N12E router [ip: #{ip}]") - BeEF::Core::Models::NetworkHost.create(hooked_browser_id: session_id, ip: ip, type: 'Asus RT-N12E Router') - BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: 'http', ip: ip, port: 80, type: 'HTTP Server') + BeEF::Core::Models::NetworkHost.create(hooked_browser_id: session_id, ip: ip, ntype: 'Asus RT-N12E Router') + BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: 'http', ip: ip, port: 80, ntype: 'HTTP Server') end clients.scan(/([\d.]+,[:\dA-F]{17})/).flatten.each do |client| @@ -47,14 +47,14 @@ class Asus_rt_n12e_get_info < BeEF::Core::Command if !gateway.nil? && BeEF::Filters.is_valid_ip?(gateway) print_debug("Hooked browser found WAN gateway server [ip: #{gateway}]") - BeEF::Core::Models::NetworkHost.create(hooked_browser_id: session_id, ip: gateway, type: 'WAN Gateway') + BeEF::Core::Models::NetworkHost.create(hooked_browser_id: session_id, ip: gateway, ntype: 'WAN Gateway') end if !dns_servers.nil? && dns_servers =~ /^([\d. ]+)$/ dns_servers.split(' ').uniq.each do |dns| if BeEF::Filters.is_valid_ip?(dns) print_debug("Hooked browser found DNS server [ip: #{dns}]") - BeEF::Core::Models::NetworkHost.create(hooked_browser_id: session_id, ip: dns, type: 'DNS Server') + BeEF::Core::Models::NetworkHost.create(hooked_browser_id: session_id, ip: dns, ntype: 'DNS Server') end end end diff --git a/modules/host/detect_airdroid/module.rb b/modules/host/detect_airdroid/module.rb index d6694efa9..6fc8edaa8 100644 --- a/modules/host/detect_airdroid/module.rb +++ b/modules/host/detect_airdroid/module.rb @@ -27,7 +27,7 @@ class Detect_airdroid < BeEF::Core::Command if BeEF::Filters.is_valid_ip?(ip) print_debug("Hooked browser found 'Airdroid' [proto: #{proto}, ip: #{ip}, port: #{port}]") - BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: proto, ip: ip, port: port, type: type) + BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: proto, ip: ip, port: port, ntype: type) end end end diff --git a/modules/host/detect_cups/module.rb b/modules/host/detect_cups/module.rb index e6d347aec..7e6b6c67d 100644 --- a/modules/host/detect_cups/module.rb +++ b/modules/host/detect_cups/module.rb @@ -26,7 +26,7 @@ class Detect_cups < BeEF::Core::Command type = 'CUPS' if BeEF::Filters.is_valid_ip?(ip) print_debug("Hooked browser found 'CUPS' [proto: #{proto}, ip: #{ip}, port: #{port}]") - BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: proto, ip: ip, port: port, type: type) + BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: proto, ip: ip, port: port, ntype: type) end end end diff --git a/modules/network/cross_origin_scanner_cors/module.rb b/modules/network/cross_origin_scanner_cors/module.rb index 9e514303e..8d5925311 100644 --- a/modules/network/cross_origin_scanner_cors/module.rb +++ b/modules/network/cross_origin_scanner_cors/module.rb @@ -21,7 +21,7 @@ class Cross_origin_scanner_cors < BeEF::Core::Command session_id = @datastore['beefhook'] if BeEF::Filters.is_valid_ip?(ip) print_debug("Hooked browser found HTTP server #{ip}:#{port}") - BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: proto, ip: ip, port: port, type: type) + BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: proto, ip: ip, port: port, ntype: type) end end diff --git a/modules/network/cross_origin_scanner_flash/module.rb b/modules/network/cross_origin_scanner_flash/module.rb index bb3c8c4cc..7bc3ae15a 100644 --- a/modules/network/cross_origin_scanner_flash/module.rb +++ b/modules/network/cross_origin_scanner_flash/module.rb @@ -35,7 +35,7 @@ class Cross_origin_scanner_flash < BeEF::Core::Command type = 'HTTP Server (Flash)' if BeEF::Filters.is_valid_ip?(ip) print_debug("Hooked browser found HTTP server #{ip}:#{port}") - BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: proto, ip: ip, port: port, type: type) + BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: proto, ip: ip, port: port, ntype: type) end end end diff --git a/modules/network/detect_burp/module.rb b/modules/network/detect_burp/module.rb index 28a6e9b5b..265dd0fb3 100644 --- a/modules/network/detect_burp/module.rb +++ b/modules/network/detect_burp/module.rb @@ -16,7 +16,7 @@ class Detect_burp < BeEF::Core::Command session_id = @datastore['beefhook'] if BeEF::Filters.is_valid_ip?(ip) print_debug("Hooked browser found network service [ip: #{ip}, port: #{port}]") - BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: 'http', ip: ip, port: port, type: 'Burp Proxy') + BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: 'http', ip: ip, port: port, ntype: 'Burp Proxy') end end end diff --git a/modules/network/get_http_servers/module.rb b/modules/network/get_http_servers/module.rb index de4fbbfdd..d2ea0402d 100644 --- a/modules/network/get_http_servers/module.rb +++ b/modules/network/get_http_servers/module.rb @@ -32,7 +32,7 @@ class Get_http_servers < BeEF::Core::Command session_id = @datastore['beefhook'] if !ip.nil? && BeEF::Filters.is_valid_ip?(ip) print_debug("Hooked browser found HTTP Server [proto: #{proto}, ip: #{ip}, port: #{port}]") - BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: proto, ip: ip, port: port, type: 'HTTP Server') + BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: proto, ip: ip, port: port, ntype: 'HTTP Server') end end end diff --git a/modules/network/get_ntop_network_hosts/module.rb b/modules/network/get_ntop_network_hosts/module.rb index 8376e8f9f..9165a5f82 100644 --- a/modules/network/get_ntop_network_hosts/module.rb +++ b/modules/network/get_ntop_network_hosts/module.rb @@ -26,7 +26,7 @@ class Get_ntop_network_hosts < BeEF::Core::Command type = 'ntop' if BeEF::Filters.is_valid_ip?(ip) print_debug("Hooked browser found 'ntop' [proto: #{proto}, ip: #{ip}, port: #{port}]") - BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: proto, ip: ip, port: port, type: type) + BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: proto, ip: ip, port: port, ntype: type) end data.to_s.scan(/"hostNumIpAddress":"([\d.]+)"/).flatten.each do |ip| if BeEF::Filters.is_valid_ip?(ip) diff --git a/modules/network/get_proxy_servers_wpad/module.rb b/modules/network/get_proxy_servers_wpad/module.rb index 458440d6b..3f8f555d2 100644 --- a/modules/network/get_proxy_servers_wpad/module.rb +++ b/modules/network/get_proxy_servers_wpad/module.rb @@ -23,7 +23,7 @@ class Get_proxy_servers_wpad < BeEF::Core::Command proto = 'SOCKS' if proxy_type =~ /SOCKS/ if BeEF::Filters.is_valid_ip?(ip) print_debug("Hooked browser found #{proto} proxy [ip: #{ip}, port: #{port}]") - BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: proto.downcase, ip: ip, port: port, type: "#{proto} Proxy") + BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: proto.downcase, ip: ip, port: port, ntype: "#{proto} Proxy") end end end diff --git a/modules/network/internal_network_fingerprinting/module.rb b/modules/network/internal_network_fingerprinting/module.rb index 6f7b2eb1e..6cc3597a3 100644 --- a/modules/network/internal_network_fingerprinting/module.rb +++ b/modules/network/internal_network_fingerprinting/module.rb @@ -33,7 +33,7 @@ class Internal_network_fingerprinting < BeEF::Core::Command session_id = @datastore['beefhook'] if BeEF::Filters.is_valid_ip?(ip) print_debug("Hooked browser found '#{discovered}' [ip: #{ip}]") - BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: proto, ip: ip, port: port, type: discovered) + BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: proto, ip: ip, port: port, ntype: discovered) end end end diff --git a/modules/network/jslanscanner/module.rb b/modules/network/jslanscanner/module.rb index 6e0403223..035496c93 100644 --- a/modules/network/jslanscanner/module.rb +++ b/modules/network/jslanscanner/module.rb @@ -26,7 +26,7 @@ class Fingerprint_routers < BeEF::Core::Command session_id = @datastore['beefhook'] if BeEF::Filters.is_valid_ip?(ip) print_debug("Hooked browser found network service #{service} [proto: #{proto}, ip: #{ip}, port: #{port}]") - BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: proto, ip: ip, port: port, type: service) + BeEF::Core::Models::NetworkService.create(hooked_browser_id: session_id, proto: proto, ip: ip, port: port, ntype: service) end when /^ip=(.+)&device=(.+)/ ip = Regexp.last_match(1) @@ -34,7 +34,7 @@ class Fingerprint_routers < BeEF::Core::Command session_id = @datastore['beefhook'] if BeEF::Filters.is_valid_ip?(ip) print_debug("Hooked browser found network device #{device} [ip: #{ip}]") - BeEF::Core::Models::NetworkHost.create(hooked_browser_id: session_id, ip: ip, type: device) + BeEF::Core::Models::NetworkHost.create(hooked_browser_id: session_id, ip: ip, ntype: device) end end end diff --git a/spec/beef/core/main/models/network_host_spec.rb b/spec/beef/core/main/models/network_host_spec.rb new file mode 100644 index 000000000..bec3c166d --- /dev/null +++ b/spec/beef/core/main/models/network_host_spec.rb @@ -0,0 +1,40 @@ +# +# Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - https://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +require 'extensions/network/models/network_host' + +RSpec.describe BeEF::Core::Models::NetworkHost do + describe 'associations' do + it 'belongs_to hooked_browser' do + expect(described_class.reflect_on_association(:hooked_browser)).not_to be_nil + expect(described_class.reflect_on_association(:hooked_browser).macro).to eq(:belongs_to) + end + end + + describe '.create' do + let(:hooked_browser) { BeEF::Core::Models::HookedBrowser.create!(session: 'test_session', ip: '127.0.0.1') } + + it 'accepts ntype as the host type attribute' do + host = described_class.create!( + hooked_browser_id: hooked_browser.id, + ip: '192.168.1.1', + ntype: 'Host' + ) + + expect(host).to be_persisted + expect(host.ntype).to eq('Host') + end + + it 'rejects type as an unknown attribute (regression guard for #3493 and #3498)' do + expect { + described_class.create!( + hooked_browser_id: hooked_browser.id, + ip: '192.168.1.1', + type: 'Host' + ) + }.to raise_error(ActiveModel::UnknownAttributeError, /unknown attribute 'type'/) + end + end +end diff --git a/spec/beef/core/main/models/network_service_spec.rb b/spec/beef/core/main/models/network_service_spec.rb new file mode 100644 index 000000000..dab9d7315 --- /dev/null +++ b/spec/beef/core/main/models/network_service_spec.rb @@ -0,0 +1,44 @@ +# +# Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - https://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +require 'extensions/network/models/network_service' + +RSpec.describe BeEF::Core::Models::NetworkService do + describe 'associations' do + it 'belongs_to hooked_browser' do + expect(described_class.reflect_on_association(:hooked_browser)).not_to be_nil + expect(described_class.reflect_on_association(:hooked_browser).macro).to eq(:belongs_to) + end + end + + describe '.create' do + let(:hooked_browser) { BeEF::Core::Models::HookedBrowser.create!(session: 'test_session', ip: '127.0.0.1') } + + it 'accepts ntype as the service type attribute' do + service = described_class.create!( + hooked_browser_id: hooked_browser.id, + proto: 'http', + ip: '192.168.1.1', + port: '80', + ntype: 'HTTP Server' + ) + + expect(service).to be_persisted + expect(service.ntype).to eq('HTTP Server') + end + + it 'rejects type as an unknown attribute (regression guard for #3493 and #3498)' do + expect { + described_class.create!( + hooked_browser_id: hooked_browser.id, + proto: 'http', + ip: '192.168.1.1', + port: '80', + type: 'HTTP Server' + ) + }.to raise_error(ActiveModel::UnknownAttributeError, /unknown attribute 'type'/) + end + end +end