Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add telnet plugin and improvements #85

Merged
merged 2 commits into from
May 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# About pynipper

## Roadmap

Tool under construction!



## Core contributors

[syn-4ck](https://github.com/syn-4ck)

## Author

[syn-4ck](https://github.com/syn-4ck)
1 change: 0 additions & 1 deletion src/analyze/cisco/ios/analyze_cisco_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ def analyze_cisco_device(device, input_filename, output_filename, output_type, c
# Device data to generate report
data = {}
data['hostname'] = get_cisco_ios_hostname(input_filename)

data['device-type'] = [dev.value for dev in DeviceType if dev.name == device][0]

# Generate report
Expand Down
17 changes: 0 additions & 17 deletions src/analyze/cisco/ios/cisco_parser/parse_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,20 +110,3 @@ def get_cisco_ios_tcp_keep_alives_out(filename: str) -> bool:
return True
else:
return False

# Services configuration
# -----------------------
# TODO: Migrate to specific module

# If the device has telnet configured -> true


def get_cisco_ios_telnet(filename: str) -> bool:
parser = parse_cisco_ios_config_file(filename)
transport_disable = parser.find_objects("transport input none")
ssh_enable = parser.find_objects("transport input ssh")
telnet_disable = parser.find_objects("no transport input telnet")
if (len(transport_disable) > 0 or len(ssh_enable) > 0 or len(telnet_disable) > 0): # noqa: E501
return False
else:
return True
5 changes: 1 addition & 4 deletions src/analyze/cisco/ios/issue/cisco_ios_issue.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
class CiscoIOSIssue:

def __init__(self, title, observation, impact, ease, recommendation, line_number):
def __init__(self, title, observation, impact, ease, recommendation):
self.title = title
self.observation = observation
self.impact = impact
self.ease = ease
self.recommendation = recommendation
self.line_number = line_number

def __str__(self):
print("Issue " + self.title + ":")
Expand All @@ -15,7 +14,6 @@ def __str__(self):
print("Impact: " + self.impact)
print("Ease: " + self.ease)
print("Recommendation: " + self.recommendation)
print("Line number: " + self.line_number)
print("\n---------------------------------------------------------------------------------------------------") # noqa: E501

def __dict__(self):
Expand All @@ -25,5 +23,4 @@ def __dict__(self):
d['impact'] = self.impact
d['ease'] = self.ease
d['recommendation'] = self.recommendation
d['line_number'] = self.line_number
return d
4 changes: 1 addition & 3 deletions src/analyze/cisco/ios/plugins/dns_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,12 @@ def _has_no_domain_lookup(self, filename: str) -> bool:

def get_domain_name(self, filename: str):
if (not self._has_dns_enabled(filename) and not self._has_no_domain_lookup(filename)):
parser = self.parse_cisco_ios_config_file(filename)
return CiscoIOSIssue(
"Domain Lookups",
"Cisco IOS-based devices support name lookups using the DNS. However, if a DNS server has not been configured, then the DNS request is broadcast.It is determined that name lookups had not been disabled and no DNS servers had been configured.", # noqa: E501
"An attacker who was able to capture network traffic could monitor DNS queries from the device. Furthermore, Cisco devices can connect to Telnet servers by supplying only the hostname or IP address of the server. A mistyped Cisco command could be interpreted as an attempt to connect to a Telnet server and broadcast on the network.", # noqa: E501
"It would be trivial for an attacker to capture network traffic broadcast from a device. Furthermore, network traffic capture tools are widely available on the Internet.", # noqa: E501
"It is recommends that domain lookups be disabled. Domain lookups can be disabled with the following command: no ip domain-lookup. If domain lookups are required, It is recommends that DNS be configured. DNS can be configured with the following command: ip name-server <IP address>.", # noqa: E501
parser.find_objects("ip name-server ")[0].linenum if len(parser.find_objects("ip name-server ")) > 0 else 0
"It is recommends that domain lookups be disabled. Domain lookups can be disabled with the following command: no ip domain-lookup. If domain lookups are required, It is recommends that DNS be configured. DNS can be configured with the following command: ip name-server <IP address>." # noqa: E501
)

def analyze(self, config_file) -> None:
Expand Down
12 changes: 3 additions & 9 deletions src/analyze/cisco/ios/plugins/http_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,12 @@ def _has_http(self, filename: str) -> bool:

def get_cisco_ios_http(self, filename: str):
if (self._has_http(filename)):
parser = self.parse_cisco_ios_config_file(filename)
return CiscoIOSIssue(
"HyperText Transport Protocol Service",
"Recent Cisco IOS-based devices support web-based administration using the HTTP protocol. Cisco web-based administration facilities can sometimes be basic but they do provide a simple method of administering remote devices. However, HTTP is a clear-text protocol and is vulnerable to various packet-capture techniques.", # noqa: E501
"An attacker who was able to monitor network traffic could capture authentication credentials.", # noqa: E501
"Network packet and password sniffing tools are widely available on the Internet. Once authentication credentials have been captured it is trivial to use the credentials to log in using the captured credentials.", # noqa: E501
"It is recommended that, if not required, the HTTP service be disabled. If a remote method of access to the device is required, consider using HTTPS or SSH. The encrypted HTTPS and SSH services may require a firmware or hardware upgrade. The HTTP service can be disabled with the following IOS command: no ip http server. If it is not possible to upgrade the device to use the encrypted HTTPS or SSH services, additional security can be configured.", # noqa: E501
parser.find_objects("ip http server")[0].linenum if len(parser.find_objects("ip http server")) > 0 else 0
"It is recommended that, if not required, the HTTP service be disabled. If a remote method of access to the device is required, consider using HTTPS or SSH. The encrypted HTTPS and SSH services may require a firmware or hardware upgrade. The HTTP service can be disabled with the following IOS command: no ip http server. If it is not possible to upgrade the device to use the encrypted HTTPS or SSH services, additional security can be configured." # noqa: E501
)
return None

Expand All @@ -51,14 +49,12 @@ def _get_cisco_ios_http_access_list(self, filename: str):

def get_cisco_ios_http_access_list(self, filename: str):
if (self._get_cisco_ios_http_access_list(filename) is None):
parser = self.parse_cisco_ios_config_file(filename)
return CiscoIOSIssue(
"ACL restrict for HTTP service",
"The HTTP service was not configured with an access-list to restrict network access to the device.",
"An attacker who was able to monitor network traffic could capture authentication credentials. This issue is made more serious with the enable password being used for authentication as this would give the attacker full administrative access to the device with the captured credentials. This issue is mitigated slightly by employing an access list to restrict network access to the device.", # noqa: E501
"Network packet and password sniffing tools are widely available on the Internet. Once authentication credentials have been captured it is trivial to use the credentials to log in using the captured credentials. Furthermore, it may be possible for an attacker to masquerade as the administrators host in order to bypass configured network access restrictions.", # noqa: E501
"If you can't disable HTTP, an access list can be configured to restrict access to the device. An access list can be specified with the following command:ip http access-class <access-list-number>", # noqa: E501
parser.find_objects("ip http access-class")[0].linenum if len(parser.find_objects("ip http access-class")) > 0 else 0
"If you can't disable HTTP, an access list can be configured to restrict access to the device. An access list can be specified with the following command:ip http access-class <access-list-number>" # noqa: E501
)
return None

Expand All @@ -76,14 +72,12 @@ def _get_cisco_ios_http_auth(self, filename: str) -> str:

def get_cisco_ios_http_auth(self, filename: str):
if (self._get_cisco_ios_http_auth(filename) == ""):
parser = self.parse_cisco_ios_config_file(filename)
return CiscoIOSIssue(
"Authentication mode to HTTP service",
"The HTTP service was not configured with an access-list to restrict network access to the device.",
"An attacker who was able to monitor network traffic could capture authentication credentials. This issue is made more serious with the enable password being used for authentication as this would give the attacker full administrative access to the device with the captured credentials. This issue is mitigated slightly by employing an access list to restrict network access to the device.", # noqa: E501
"Network packet and password sniffing tools are widely available on the Internet. Once authentication credentials have been captured it is trivial to use the credentials to log in using the captured credentials. Furthermore, it may be possible for an attacker to masquerade as the administrators host in order to bypass configured network access restrictions.", # noqa: E501
"If you can't disable HTTP, the authentication method can be changed using the following command (where the authentication method is either local, enable, tacacs or aaa): ip http authentication <authentication-method>", # noqa: E501
parser.find_objects("ip http auth")[0].linenum if len(parser.find_objects("ip http auth")) > 0 else 0
"If you can't disable HTTP, the authentication method can be changed using the following command (where the authentication method is either local, enable, tacacs or aaa): ip http authentication <authentication-method>" # noqa: E501
)
return None

Expand Down
16 changes: 4 additions & 12 deletions src/analyze/cisco/ios/plugins/ssh_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,12 @@ def _get_cisco_ios_ssh_version(self, filename: str) -> str:

def get_cisco_ios_ssh(self, filename: str):
if (not self._has_cisco_ios_ssh(filename) or self._get_cisco_ios_ssh_version(filename) == "" or self._get_cisco_ios_ssh_version(filename) != "2"):
parser = self.parse_cisco_ios_config_file(filename)
return CiscoIOSIssue(
"SSH Protocol Version",
"The SSH service is commonly used for encrypted command-based remote device management. There are multiple SSH protocol versions and SSH servers will often support multiple versions to maintain backwards compatibility. Although flaws have been identified in implementations of version 2 of the SSH protocol, fundamental flaws exist in SSH protocol version 1.", # noqa: E501
"An attacker who was able to intercept SSH protocol version 1 traffic would be able to perform a man-in-the-middle style attack. The attacker could then capture network traffic and possibly authentication credentials.", # noqa: E501
"Although vulnerabilities are widely known, exploiting the vulnerabilities in the SSH protocol can be difficult.",
"When SSH protocol version 2 support is configured on Cisco IOS devices, support for version 1 will be disabled. This can be configured with the following command: ip ssh version 2", # noqa: E501
parser.find_objects("ip ssh version")[0].linenum if len(parser.find_objects("ip ssh version")) > 0 else 0
"When SSH protocol version 2 support is configured on Cisco IOS devices, support for version 1 will be disabled. This can be configured with the following command: ip ssh version 2" # noqa: E501
)
return None

Expand All @@ -63,14 +61,12 @@ def _get_cisco_ios_ssh_retries(self, filename: str) -> str:
def get_cisco_ios_ssh_reties(self, filename: str):
retries = self._get_cisco_ios_ssh_retries(filename)
if (retries == "" or retries > 5):
parser = self.parse_cisco_ios_config_file(filename)
return CiscoIOSIssue(
"SSH retries misconfiguration",
"The SSH service must have a defined number of retries, the recommended is between 0 and 5.",
"Set a retries number allows to reduce the bruteforce and dictionary attacks. If a retry number is defined, the attacker can not test with an user multiple passwords.", # noqa: E501
"This issue improve the hardening of passwords in the network device.",
"This can be configured with the following command: ip ssh authentication-retries <retry-number>.",
parser.find_objects("ip ssh authentication-retries")[0].linenum if len(parser.find_objects("ip ssh authentication-retries")) else 0
"This can be configured with the following command: ip ssh authentication-retries <retry-number>."
)
return None

Expand All @@ -89,14 +85,12 @@ def _get_cisco_ios_ssh_timeout(self, filename: str) -> int:
def get_cisco_ios_ssh_timeout(self, filename: str):
timeout = self._get_cisco_ios_ssh_timeout(filename)
if (timeout == 0 or timeout > 120):
parser = self.parse_cisco_ios_config_file(filename)
return CiscoIOSIssue(
"SSH timeout misconfiguration",
"The SSH service must have a defined timeout between 0 and 60 seconds.",
"Set a timeout allows disable not used or malicious sessions in background.",
"This issue only increase the device management security, it is not exploitable.",
"This can be configured with the following command: ip ssh time-out <timeout-in-seconds>.",
parser.find_objects("ip ssh time-out")[0].linenum if len(parser.find_objects("ip ssh time-out")) > 0 else 0
"This can be configured with the following command: ip ssh time-out <timeout-in-seconds>."
)
return None

Expand All @@ -114,14 +108,12 @@ def _get_cisco_ios_ssh_interface(self, filename: str) -> str:

def get_cisco_ios_ssh_interface(self, filename: str):
if (self._get_cisco_ios_ssh_interface(filename) == ""):
parser = self.parse_cisco_ios_config_file(filename)
return CiscoIOSIssue(
"SSH source-interface enabled",
"The SSH service must have a controlated set of source interfaces to manage the device",
"To reduce bruteforce attacks is usefull have a set of source interfaces, logged and filtered, to access to SSH device management.",
"This issue only increase the device management security, it is not exploitable, but it reduce bruteforce attacks.",
"This can be configured with the following command: ip ssh source-interface <interface> ",
parser.find_objects("ip ssh source-interface")[0].linenum if len(parser.find_objects("ip ssh source-interface")) > 0 else 0
"This can be configured with the following command: ip ssh source-interface <interface> "
)
return None

Expand Down
42 changes: 42 additions & 0 deletions src/analyze/cisco/ios/plugins/telnet_plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# flake8: noqa

from ..core.base_plugin import GenericPlugin
from ..issue.cisco_ios_issue import CiscoIOSIssue

class PluginTelnet(GenericPlugin):

def __init__(self):
super().__init__()

def name(self):
return "Telnet configuration"

def _get_cisco_ios_telnet(self, filename: str) -> bool:
parser = self.parse_cisco_ios_config_file(filename)
transport_disable = parser.find_objects("transport input none")
ssh_enable = parser.find_objects("transport input ssh")
telnet_disable = parser.find_objects("no transport input telnet")
if (len(transport_disable) > 0 or len(ssh_enable) > 0 or len(telnet_disable) > 0): # noqa: E501
return False
else:
return True

def get_telnet_configuration(self, filename: str):
if (self._get_cisco_ios_telnet(filename)):
return CiscoIOSIssue(
"Telnet",
"Telnet is widely used to provide remote command-based access to a variety of devices and is commonly used on network devices for remote administration. However, Telnet is a clear-text protocol and is vulnerable to various packet capture techniques.", # noqa: E501
"An attacker who was able to monitor network traffic could capture sensitive information or authentication credentials.", # noqa: E501
"Network packet and password sniffing tools are widely available on the Internet and some of the tools are specifically designed to capture clear-text protocol authentication credentials. However, in a switched environment an attacker may not be able to capture network traffic destined for other devices without employing an attack such as Address Resolution Protocol (ARP) spoofing.",
"Nipper recommends that, if possible, Telnet be disabled. If remote administrative access to the device is required, Nipper recommends that SSH be configured. The Telnet service can be disabled on individual lines with the following command: transport input none. The following Cisco IOS command can be used to disable Telnet on individual lines, but enable SSH: transport input ssh" # noqa: E501
)
return None

def analyze(self, config_file) -> None:
issues = []

issues.append(self.get_telnet_configuration(config_file))

for issue in issues:
if issue is not None:
self.add_issue(issue)
Loading