Exemple #1
0
def process(report: ReportWrapper) -> Optional[VulnTestInfo]:
    """ Process the given report into a VulnTestInfo named tuple """
    # If the user has not yet been prompted for automatic triaging
    if not report.botHasCommented():
        token = AutoTriageUtils.generateToken()
        return VulnTestInfo(reproduced=False,
                            message=constants.initialMessage(token, 'redirect to a domain', 'Open Redirect'),
                            type='Open Redirect',
                            info={})
    elif report.shouldBackoff():
        if not report.hasPostedBackoffComment():
            addFailureToDB(report.getReporterUsername(), report.getReportID())
            return VulnTestInfo(reproduced=False,
                                message=('Automatic verification of vulnerability has failed, Backing off! Falling '
                                         'back to human verification. '),
                                type='Open Redirect',
                                info={})
        else:
            return None
    elif report.isVerified():
        return None
    try:
        if isStructured(report.getLatestActivity()):
            return processStructured(report, token=report.getToken())
        else:
            return processUnstructured(report, token=report.getToken())
    except Exception as e:
        print("Caught exception: %s" % str(e))
        traceback.print_exc()
        print("+" * 80)
        return VulnTestInfo(reproduced=False,
                            message=('Internal error detected! Backing off...'),
                            type='Open Redirect',
                            info={})
Exemple #2
0
def test_ReportWrapperGetters():
    r = ReportWrapper(openRedirectReproJson)
    assert r.getReportID() == '239981'
    assert r.getLatestActivity() == ("blah open_redirect\n\n[some](http://example.com/redir.php?QUERY_STRING="
                                     "https://google.com)")
    assert r.getReportBody() == ("blah open_redirect\n\n[some](http://example.com/redir.php?QUERY_STRING="
                                 "https://google.com)")
    assert r.getReportWeakness() == "Open Redirect"
    assert r.getReportTitle() == "open redirect"
    assert r.getVulnDomains() == ['example.com']
    r = ReportWrapper(openRedirectUnreproJson)
    assert r.getReportID() == '240035'
    assert r.getLatestActivity() == ("this is detected as an open redirect but there is no markdown link to it\n\n"
                                     "https://example.com/redir.php?QUERY_STRING=https://google.com")
    assert r.getReportBody() == ("this is detected as an open redirect but there is no markdown link to it\n\n"
                                 "https://example.com/redir.php?QUERY_STRING=https://google.com")
    assert r.getReportWeakness() == "Open Redirect"
    assert r.getReportTitle() == "malformed open redirect"
    assert r.getVulnDomains() == ['example.com']
Exemple #3
0
def test_api():
    ids = json.loads(
        requests.post('http://api:8080/v1/getReportIDs',
                      json={
                          'time': '1970-01-01T00:00:00Z',
                          'openOnly': False
                      },
                      auth=HTTPBasicAuth('AutoTriageBot',
                                         secrets.apiBoxToken)).text)
    openIDs = json.loads(
        requests.post('http://api:8080/v1/getReportIDs',
                      json={
                          'time': '1970-01-01T00:00:00Z',
                          'openOnly': True
                      },
                      auth=HTTPBasicAuth('AutoTriageBot',
                                         secrets.apiBoxToken)).text)
    assert isinstance(ids, list)
    assert isinstance(openIDs, list)
    assert len(openIDs) <= len(
        ids
    )  # There should be an equal or lesser number of open bugs than all bugs
    assert all([(id in ids)
                for id in openIDs])  # All open ids should be in ids
    for id in ids:
        # They should be strings but they should be parseable into integers
        assert isinstance(id, str) and isinstance(int(id), int)
    # There should be no duplicate IDs
    assert len(set(ids)) == len(ids)

    for id in ids[:10]:
        ser = requests.post('http://api:8080/v1/getReport',
                            json={
                                'id': id
                            },
                            auth=HTTPBasicAuth('AutoTriageBot',
                                               secrets.apiBoxToken)).text
        try:
            r = ReportWrapper().deserialize(ser)
        except:
            assert False

    for serRep in json.loads(
            requests.post('http://api:8080/v1/getReports',
                          auth=HTTPBasicAuth('AutoTriageBot',
                                             secrets.apiBoxToken)).text)[:10]:
        try:
            r = ReportWrapper().deserialize(serRep)
        except:
            assert False
        assert r.getReportID() in ids
Exemple #4
0
def processReport(report: ReportWrapper, startTime: datetime) -> Optional[VulnTestInfo]:
    """ Attempt to verify a given report """
    if report.needsBotReply():
        if startTime > report.getReportedTime():
            return None
        if config.DEBUG:
            print("Processing %s" % report.getReportTitle())
        for module in modules:
            if module.match(report.getReportBody(), report.getReportWeakness()):  # type: ignore
                if config.DEBUG:
                    print(module.__file__.split('/')[-1] + " matched id=%s!" % report.getReportID())
                vti = module.process(report)  # type: ignore
                if config.DEBUGVERBOSE:
                    print(vti)
                if vti:
                    postComment(report.getReportID(), vti, addStopMessage=True)
                    if vti.reproduced and config.metadataLogging:
                        metadataVTI = generateMetadataVTI(report, vti)
                        postComment(report.getReportID(), metadataVTI, internal=True)
                return vti
        if config.DEBUG:
            print("No matches")
    return None
Exemple #5
0
def processReport(report: ReportWrapper) -> None:
    """ Process the given report and post a private comment with a suggested bounty """
    if config.payoutDB:
        bountyInfo = suggestPayout(report)
        if bountyInfo:
            postComment(report.getReportID(),
                        VulnTestInfo(
                            reproduced=False,
                            info={},
                            message='Suggested bounty: %.2f with a σ of %.2f' %
                            (bountyInfo.average, bountyInfo.std),
                            type=''),
                        internal=True)
    else:
        if config.DEBUGVERBOSE:
            print("Not suggesting a payout beause config.payoutDB is falsy")
Exemple #6
0
def generateMetadataVTI(report: ReportWrapper, vti: VulnTestInfo) -> VulnTestInfo:
    """ Given the results of a vulnerability test thar reproduced a vulnerability and a report, generate an internal
        VTI used to hold metadata about the vulnerability """
    internalMetadata = {'id': report.getReportID(),
                        'title': report.getReportTitle(),
                        'reportedTime': str(report.getReportedTime()),
                        'verifiedTime': str(datetime.now()),
                        'type': vti.type,
                        'exploitURL': vti.info['src'],
                        'method': vti.info['method']}
    if vti.type == 'XSS':
        internalMetadata['confirmedBrowsers'] = vti.info['confirmedBrowsers']
        internalMetadata['alertBrowsers'] = vti.info['alertBrowsers']
        internalMetadata['httpType'] = vti.info['httpType']
        internalMetadata['cookies'] = vti.info['cookies']
    elif vti.type == 'SQLi':
        internalMetadata['delay'] = vti.info['delay']
        internalMetadata['httpType'] = vti.info['httpType']
        internalMetadata['cookies'] = vti.info['cookies']
    elif vti.type == 'Open Redirect':
        internalMetadata['redirect'] = vti.info['redirect']
        internalMetadata['httpType'] = vti.info['httpType']
        internalMetadata['cookies'] = vti.info['cookies']
    message = '# Internal Metadata: \n\n```\n%s\n```\n' % json.dumps(internalMetadata,
                                                                     sort_keys=True,
                                                                     indent=4,
                                                                     separators=(',', ': '))

    if config.DEBUGVERBOSE:
        print(internalMetadata)

    internalVTI = VulnTestInfo(reproduced=False,
                               message=message,
                               info={},
                               type='')
    return internalVTI
Exemple #7
0
def processReport(report: ReportWrapper) -> bool:
    """ Process a report via searching for duplicates and posting comments based off of the confidence levels
          Returns whether or not the report was classified as a duplicate with a high confidence """
    if report.getState() == "new" and not report.hasDuplicateComment(
    ) and not report.isVerified():
        earlierReports = getAllOpenReports(
            report.getReportedTime())  # type: List[ReportWrapper]
        idConfTuples = []  # type: List[Tuple[str, int]]
        matches = []  # type: List[str]
        for earlierReport in earlierReports:
            for module in modules:
                if (module.match(report.getReportBody(),
                                 report.getReportWeakness())
                        and  # type: ignore
                        module.match(earlierReport.getReportBody(),
                                     earlierReport.getReportWeakness())
                    ):  # type: ignore
                    matches.append(earlierReport.getReportID())
            try:
                confidence = int(isDuplicate(earlierReport, report)[0])
            except TypeError:
                confidence = 0
            if confidence == 99:
                AutoTriageUtils.postComment(
                    report.getReportID(),
                    VulnTestInfo(
                        message='Found a duplicate with 99%% confidence: #%s' %
                        earlierReport.getReportID(),
                        info={},
                        reproduced=False,
                        type=''),
                    internal=True)
                if config.DEBUG:
                    print("Detected that %s (%s) is a duplicate of %s (%s)!" %
                          (report.getReportID(), report.getReportTitle(),
                           earlierReport.getReportID(),
                           earlierReport.getReportTitle()))
                return False  # Change to return True to make the bot stop interacting after finding a duplicate
            elif confidence > 50:
                idConfTuples.append((earlierReport.getReportID(), confidence))
        # If you update the phrases here, you must also update them in AutoTriageUtils.ReportWrapper.hasDuplicateComment
        if len(idConfTuples) > 0:

            def idConfToStr(tuple: Tuple) -> str:
                return (
                    'Detected a possible duplicate report with confidence of %s: #%s'
                    % (tuple[1], tuple[0]))

            AutoTriageUtils.postComment(report.getReportID(),
                                        VulnTestInfo(message='\n'.join([
                                            idConfToStr(t)
                                            for t in idConfTuples
                                        ]),
                                                     info={},
                                                     reproduced=False,
                                                     type=''),
                                        internal=True)
            if config.DEBUG:
                print('Found partial matches: %s' % str(idConfTuples))
        if len(matches) > 0 and len(matches) <= 5:
            AutoTriageUtils.postComment(
                report.getReportID(),
                VulnTestInfo(message=(
                    'There are currently %s open reports about this type of '
                    'vulnerability: %s' %
                    (str(len(matches)), ', '.join(['#' + id
                                                   for id in matches]))),
                             info={},
                             reproduced=False,
                             type=''),
                internal=True)
            if config.DEBUG:
                print(
                    'Found %s reports on the same type of vulnerability as %s: %s'
                    % (str(len(matches)), str(report.getReportID()), ', '.join(
                        ['#' + id for id in matches])))
    return False