mirror of
				https://github.com/jtesta/ssh-audit.git
				synced 2025-10-30 21:15:27 +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 | ||||
| 	 | ||||
| 	class Banner(object): | ||||
| 		_RXP, _RXR = r'SSH-\d\.\s*?\d+', r'(-([^\s]*)(?:\s+(.*))?)?' | ||||
| 		RX_PROTOCOL = re.compile(_RXP.replace('\d', '(\d)')) | ||||
| 		_RXP, _RXR = r'SSH-\d\.\s*?\d+', r'(-\s*([^\s]*)(?:\s+(.*))?)?' | ||||
| 		RX_PROTOCOL = re.compile(re.sub(r'\\d(\+?)','(\\d\g<1>)', _RXP)) | ||||
| 		RX_BANNER = re.compile(r'^({0}(?:(?:-{0})*)){1}$'.format(_RXP, _RXR)) | ||||
| 		 | ||||
| 		def __init__(self, protocol, software, comments): | ||||
| @@ -704,6 +704,8 @@ class SSH(object): | ||||
| 			if software is None and (mx.group(2) or '').startswith('-'): | ||||
| 				software = '' | ||||
| 			comments = (mx.group(4) or '').strip() or None | ||||
| 			if comments is not None: | ||||
| 				comments = re.sub('\s+', ' ', comments) | ||||
| 			return cls(protocol, software, comments) | ||||
| 	 | ||||
| 	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