今天跑去看CakeResume的Career Fair,決定目標是要進去Dcard了
今天的漏洞是跟JumpServer有關的,主要定位為堡壘機,其主要功用為做為公司外部的跳板機,讓使用者可以訪問內部資源(Windows/Linux主機、資料庫等)。類似的產品有Cyberark、CrazyEye(不支援Windows)。
堡壘機存在的目的為讓外部廠商、人員可以輕鬆存取公司內部資源,又能夠將其操作紀錄下來以供後續稽核用(Session Recording),IT也能控制每個帳號登入堡壘機之後的權限、能夠連線的Host、資源等,可以說是很方便。
另外,堡壘機跟跳板機的不同,在於堡壘機會儲存Host跟資源的登入資訊,所以在設置時需要格外注意。
這次漏洞主要是被發現在JumpServer的其中一隻獲取Session list的API /api/v1/terminal/sessions
可以被匿名訪問不需要驗證而且可以直接下載Session的錄影檔(如果有額外設定將錄影檔儲存在S3的話則不影響),前面的段落講過堡壘機的功能及其的重要性,在錄影檔裡可能會將機敏資料洩漏出去(例如廠商可能在部屬網站,然後在設定檔裡面放某個帳戶的資訊或者資料庫的資訊)
v3.0.0 - v3.6.3
v3.6.4, v3.5.5
class SessionViewSet(OrgBulkModelViewSet):
model = Session
serializer_classes = {
'default': serializers.SessionSerializer,
'display': serializers.SessionDisplaySerializer,
}
search_fields = [
"user", "asset", "account", "remote_addr",
"protocol", "is_finished", 'login_from',
]
filterset_class = SessionFilterSet
date_range_filter_fields = [
('date_start', ('date_from', 'date_to'))
]
extra_filter_backends = [DatetimeRangeFilter]
rbac_perms = {
'download': ['terminal.download_sessionreplay']
}
"""
Where it fucked up, either RBACPermission or IsSessionASsignee will be accepted
"""
permission_classes = [RBACPermission | IsSessionAssignee]
可以看到在IsSessionAssignee
裡並沒有處理has_permission
,他繼承了Django rest framework的BasePermission,而BasePermission預設是會直接回傳true
class IsSessionAssignee(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
try:
return obj.ticket_relation.first().ticket.has_all_assignee(request.user)
except:
return False
class BasePermission(metaclass=BasePermissionMetaclass):
"""
A base class from which all permission classes should inherit.
"""
def has_permission(self, request, view):
"""
Return `True` if permission is granted, `False` otherwise.
"""
return True
def has_object_permission(self, request, view, obj):
"""
Return `True` if permission is granted, `False` otherwise.
"""
return True
SessionViewSet
權限IsSessionAssignee
處理不當class IsSessionAssignee(permissions.BasePermission):
def has_permission(self, request, view):
"""
JumpServer changes here to return false to make sure RBACPermission must be valid to get session list
Ref: https://github.com/jumpserver/jumpserver/blob/v3.6.4/apps/terminal/permissions.py#L11
"""
return false
def has_object_permission(self, request, view, obj):
try:
return obj.ticket_relation.first().ticket.has_all_assignee(request.user)
except:
return False