mirror of
				https://github.com/jtesta/ssh-audit.git
				synced 2025-10-31 05:25:28 +01:00 
			
		
		
		
	Fix banner protocol (1.99) recognition and clean banner comments. Add banner tests.
This commit is contained in:
		| @@ -655,8 +655,8 @@ class SSH(object): | |||||||
| 			return None | 			return None | ||||||
| 	 | 	 | ||||||
| 	class Banner(object): | 	class Banner(object): | ||||||
| 		_RXP, _RXR = r'SSH-\d\.\s*?\d+', r'(-([^\s]*)(?:\s+(.*))?)?' | 		_RXP, _RXR = r'SSH-\d\.\s*?\d+', r'(-\s*([^\s]*)(?:\s+(.*))?)?' | ||||||
| 		RX_PROTOCOL = re.compile(_RXP.replace('\d', '(\d)')) | 		RX_PROTOCOL = re.compile(re.sub(r'\\d(\+?)','(\\d\g<1>)', _RXP)) | ||||||
| 		RX_BANNER = re.compile(r'^({0}(?:(?:-{0})*)){1}$'.format(_RXP, _RXR)) | 		RX_BANNER = re.compile(r'^({0}(?:(?:-{0})*)){1}$'.format(_RXP, _RXR)) | ||||||
| 		 | 		 | ||||||
| 		def __init__(self, protocol, software, comments): | 		def __init__(self, protocol, software, comments): | ||||||
| @@ -704,6 +704,8 @@ class SSH(object): | |||||||
| 			if software is None and (mx.group(2) or '').startswith('-'): | 			if software is None and (mx.group(2) or '').startswith('-'): | ||||||
| 				software = '' | 				software = '' | ||||||
| 			comments = (mx.group(4) or '').strip() or None | 			comments = (mx.group(4) or '').strip() or None | ||||||
|  | 			if comments is not None: | ||||||
|  | 				comments = re.sub('\s+', ' ', comments) | ||||||
| 			return cls(protocol, software, comments) | 			return cls(protocol, software, comments) | ||||||
| 	 | 	 | ||||||
| 	class Fingerprint(object): | 	class Fingerprint(object): | ||||||
|   | |||||||
							
								
								
									
										68
									
								
								test/test_banner.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								test/test_banner.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | import pytest | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class TestBanner(object): | ||||||
|  | 	@pytest.fixture(autouse=True) | ||||||
|  | 	def init(self, ssh_audit): | ||||||
|  | 		self.ssh = ssh_audit.SSH | ||||||
|  | 	 | ||||||
|  | 	def test_simple_banners(self): | ||||||
|  | 		banner = lambda x: self.ssh.Banner.parse(x) | ||||||
|  | 		b = banner('SSH-2.0-OpenSSH_7.3') | ||||||
|  | 		assert b.protocol == (2, 0) | ||||||
|  | 		assert b.software == 'OpenSSH_7.3' | ||||||
|  | 		assert b.comments is None | ||||||
|  | 		assert str(b) == 'SSH-2.0-OpenSSH_7.3' | ||||||
|  | 		b = banner('SSH-1.99-Sun_SSH_1.1.3') | ||||||
|  | 		assert b.protocol == (1, 99) | ||||||
|  | 		assert b.software == 'Sun_SSH_1.1.3' | ||||||
|  | 		assert b.comments is None | ||||||
|  | 		assert str(b) == 'SSH-1.99-Sun_SSH_1.1.3' | ||||||
|  | 		b = banner('SSH-1.5-Cisco-1.25') | ||||||
|  | 		assert b.protocol == (1, 5) | ||||||
|  | 		assert b.software == 'Cisco-1.25' | ||||||
|  | 		assert b.comments is None | ||||||
|  | 		assert str(b) == 'SSH-1.5-Cisco-1.25' | ||||||
|  | 	 | ||||||
|  | 	def test_invalid_banners(self): | ||||||
|  | 		b = lambda x: self.ssh.Banner.parse(x) | ||||||
|  | 		assert b('Something') is None | ||||||
|  | 		assert b('SSH-XXX-OpenSSH_7.3') is None | ||||||
|  | 	 | ||||||
|  | 	def test_banners_with_spaces(self): | ||||||
|  | 		b = lambda x: self.ssh.Banner.parse(x) | ||||||
|  | 		s = 'SSH-2.0-OpenSSH_4.3p2' | ||||||
|  | 		assert str(b('SSH-2.0-OpenSSH_4.3p2    ')) == s | ||||||
|  | 		assert str(b('SSH-2.0-    OpenSSH_4.3p2')) == s | ||||||
|  | 		assert str(b('SSH-2.0-  OpenSSH_4.3p2  ')) == s | ||||||
|  | 		s = 'SSH-2.0-OpenSSH_4.3p2 Debian-9etch3 on i686-pc-linux-gnu' | ||||||
|  | 		assert str(b('SSH-2.0-  OpenSSH_4.3p2 Debian-9etch3   on i686-pc-linux-gnu')) == s | ||||||
|  | 		assert str(b('SSH-2.0-OpenSSH_4.3p2 Debian-9etch3 on i686-pc-linux-gnu  ')) == s | ||||||
|  | 		assert str(b('SSH-2.0-  OpenSSH_4.3p2 Debian-9etch3   on   i686-pc-linux-gnu  ')) == s | ||||||
|  | 	 | ||||||
|  | 	def test_banners_without_software(self): | ||||||
|  | 		b = lambda x: self.ssh.Banner.parse(x) | ||||||
|  | 		assert b('SSH-2.0').protocol == (2, 0) | ||||||
|  | 		assert b('SSH-2.0').software is None | ||||||
|  | 		assert b('SSH-2.0').comments is None | ||||||
|  | 		assert str(b('SSH-2.0')) == 'SSH-2.0' | ||||||
|  | 		assert b('SSH-2.0-').protocol == (2, 0) | ||||||
|  | 		assert b('SSH-2.0-').software == '' | ||||||
|  | 		assert b('SSH-2.0-').comments is None | ||||||
|  | 		assert str(b('SSH-2.0-')) == 'SSH-2.0-' | ||||||
|  | 	 | ||||||
|  | 	def test_banners_with_comments(self): | ||||||
|  | 		b = lambda x: self.ssh.Banner.parse(x) | ||||||
|  | 		assert repr(b('SSH-2.0-OpenSSH_7.2p2 Ubuntu-1')) == '<Banner(protocol=2.0, software=OpenSSH_7.2p2, comments=Ubuntu-1)>' | ||||||
|  | 		assert repr(b('SSH-1.99-OpenSSH_3.4p1 Debian 1:3.4p1-1.woody.3')) == '<Banner(protocol=1.99, software=OpenSSH_3.4p1, comments=Debian 1:3.4p1-1.woody.3)>' | ||||||
|  | 		assert repr(b('SSH-1.5-1.3.7 F-SECURE SSH')) == '<Banner(protocol=1.5, software=1.3.7, comments=F-SECURE SSH)>' | ||||||
|  | 	 | ||||||
|  | 	def test_banners_with_multiple_protocols(self): | ||||||
|  | 		b = lambda x: self.ssh.Banner.parse(x) | ||||||
|  | 		assert str(b('SSH-1.99-SSH-1.99-OpenSSH_3.6.1p2')) == 'SSH-1.99-OpenSSH_3.6.1p2' | ||||||
|  | 		assert str(b('SSH-2.0-SSH-2.0-OpenSSH_4.3p2 Debian-9')) == 'SSH-2.0-OpenSSH_4.3p2 Debian-9' | ||||||
|  | 		assert str(b('SSH-1.99-SSH-2.0-dropbear_0.5')) == 'SSH-1.99-dropbear_0.5' | ||||||
|  | 		assert str(b('SSH-2.0-SSH-1.99-OpenSSH_4.2p1 SSH Secure Shell (non-commercial)')) == 'SSH-1.99-OpenSSH_4.2p1 SSH Secure Shell (non-commercial)' | ||||||
|  | 		assert str(b('SSH-1.99-SSH-1.99-SSH-1.99-OpenSSH_3.9p1')) == 'SSH-1.99-OpenSSH_3.9p1' | ||||||
		Reference in New Issue
	
	Block a user
	 Andris Raugulis
					Andris Raugulis