def test_has_submissions_in_round(self):
        r0 = Round.create(num=0)
        r1 = Round.create(num=1)
        cs = ChallengeSet.create(name="foo")
        cbn = ChallengeBinaryNode.create(name="foo1", cs=cs, blob="aaa")
        our_team = Team.create(name=Team.OUR_NAME)
        other_team = Team.create(name="enemy")

        ChallengeSetFielding.create(cs=cs,
                                    cbns=[cbn],
                                    team=our_team,
                                    submission_round=r1)
        assert_false(cs.has_submissions_in_round(r0))
        assert_true(cs.has_submissions_in_round(r1))

        ChallengeSetFielding.create(cs=cs,
                                    cbns=[cbn],
                                    team=other_team,
                                    submission_round=r0)
        assert_false(cs.has_submissions_in_round(r0))

        ChallengeSetFielding.create(cs=cs,
                                    cbns=[cbn],
                                    team=our_team,
                                    submission_round=r0)
        assert_true(cs.has_submissions_in_round(r0))
    def test_is_multi_cbn(self):
        r0 = Round.create(num=0)
        our_team = Team.create(name=Team.OUR_NAME)
        # CS single binary
        cs = ChallengeSet.create(name="single")
        cs.rounds = [r0]
        cbn = ChallengeBinaryNode.create(name="foo", cs=cs, blob="aaa1")
        # CS multi binary
        cs_multi = ChallengeSet.create(name="multi")
        cs_multi.rounds = [r0]
        cbn1 = ChallengeBinaryNode.create(name="foo1",
                                          cs=cs_multi,
                                          blob="aaa2")
        cbn2 = ChallengeBinaryNode.create(name="foo2",
                                          cs=cs_multi,
                                          blob="aaa3")
        # create fielding entries
        ChallengeSetFielding.create(cs=cs,
                                    cbns=[cbn],
                                    team=our_team,
                                    available_round=r0)
        ChallengeSetFielding.create(cs=cs_multi,
                                    cbns=[cbn1, cbn2],
                                    team=our_team,
                                    available_round=r0)

        assert_false(cs.is_multi_cbn)
        assert_true(cs_multi.is_multi_cbn)
Example #3
0
    def _submit_ids_rule(self, cable):
        if cable.cbns and (cable.cbns[0].ids_rule is not None):
            ids_rule = cable.cbns[0].ids_rule
            result = self._cgc.uploadIDS(str(cable.cs.name),
                                         str(ids_rule.rules))

            submission_round, status = Round.get_or_create_latest(
                num=result['round'])

            if status == Round.FIRST_GAME:
                LOG.error(
                    "Submission in first round of first game (round #%d)",
                    submission_round.num)
            elif status == Round.NEW_GAME:
                LOG.info("Submission in first round of new game (round #%d)",
                         submission_round.num)
            elif status == Round.NEW_ROUND:
                LOG.info("Submission beginning of new round #%d",
                         submission_round.num)

            irf, _ = IDSRuleFielding.get_or_create(
                ids_rule=ids_rule,
                submission_round=submission_round,
                team=Team.get_our())
            return irf
    def test_submitted_and_unsubmitted_patches(self):
        r0 = Round.create(num=0)
        team = Team.create(name=Team.OUR_NAME)
        cs = ChallengeSet.create(name="foo")
        cs.rounds = [r0]
        cbn = ChallengeBinaryNode.create(name="cbn", cs=cs, blob="aaa1")
        patchtype1 = PatchType.create(name="PatchType1",
                                      functionality_risk=0,
                                      exploitability=0)
        patchtype2 = PatchType.create(name="PatchType2",
                                      functionality_risk=0,
                                      exploitability=0)

        patch1 = ChallengeBinaryNode.create(name="patch1",
                                            patch_type=patchtype1,
                                            cs=cs,
                                            root=cbn,
                                            blob="aaa2")
        patch2 = ChallengeBinaryNode.create(name="patch2",
                                            patch_type=patchtype2,
                                            cs=cs,
                                            root=cbn,
                                            blob="aaa3")

        assert_equals(len(cbn.unsubmitted_patches), 2)
        assert_in(patch1, cbn.unsubmitted_patches)
        assert_in(patch2, cbn.unsubmitted_patches)
        assert_equals(len(cbn.submitted_patches), 0)

        ChallengeSetFielding.create_or_update_submission(team=team,
                                                         cbns=[patch1, patch2],
                                                         round=r0)
        assert_equals(len(cbn.submitted_patches), 2)
        assert_equals(len(cbn.unsubmitted_patches), 0)
    def test_unsubmitted_exploits(self):
        r1 = Round.create(num=0)
        team = Team.create(name=Team.OUR_NAME)
        cs = ChallengeSet.create(name="foo")
        cs.rounds = [r1]
        job = RexJob.create(cs=cs)
        pov1 = Exploit.create(cs=cs,
                              job=job,
                              pov_type='type1',
                              exploitation_method='rop',
                              blob="exploit",
                              c_code="exploit it")
        pov2 = Exploit.create(cs=cs,
                              job=job,
                              pov_type='type2',
                              exploitation_method='rop',
                              blob="exploit",
                              c_code="exploit it")

        assert_equals(len(cs.unsubmitted_exploits), 2)
        assert_in(pov1, cs.unsubmitted_exploits)
        assert_in(pov2, cs.unsubmitted_exploits)

        pov1.submit_to(team, 10)
        assert_equals(len(cs.unsubmitted_exploits), 1)
        assert_not_in(pov1, cs.unsubmitted_exploits)
        assert_in(pov2, cs.unsubmitted_exploits)

        pov2.submit_to(team, 10)
        assert_equals(len(cs.unsubmitted_exploits), 0)
        assert_not_in(pov1, cs.unsubmitted_exploits)
        assert_not_in(pov2, cs.unsubmitted_exploits)
Example #6
0
    def run(self):
        """A run() method. Happy now pylint?"""
        cgc_polls = self._get_feedback('poll')
        Feedback.update_or_create(self._round,
                                  polls=cgc_polls,
                                  povs=self._get_feedback('pov'),
                                  cbs=self._get_feedback('cb'))

        fielded = {
            c.name: c
            for c in ChallengeSet.fielded_in_round(self._round)
        }
        for c in cgc_polls:
            cs = fielded[c['csid']]

            fieldings = cs.fieldings.where(
                (ChallengeSetFielding.available_round == self._round)
                & (ChallengeSetFielding.team == Team.get_our()))
            if fieldings:
                fielding = fieldings.get()
                if fielding.poll_feedback is None:
                    fnct, perf = c['functionality'], c['performance']
                    pf = PollFeedback.create(
                        cs=cs,
                        round=self._round,
                        success=float(fnct['success']) / 100.0,
                        timeout=float(fnct['timeout']) / 100.0,
                        connect=float(fnct['connect']) / 100.0,
                        function=float(fnct['function']) / 100.0,
                        time_overhead=float(perf['time']) / 100.0 - 1,
                        memory_overhead=float(perf['memory']) / 100.0 - 1)
                    fielding.poll_feedback = pf
                    fielding.save()
Example #7
0
def create_round(args):
    if not len(args.challenge_sets):
        fielded = [cs.name for cs in CS.fielded_in_round()]
    else:
        fielded = args.challenge_sets
    new_round = Round.create(
        num=args.number if args.number is not None else Round.current_round() +
        1)

    for f in fielded:
        cs = CS.select().where(CS.name == f).get()
        CSF.create(cs=cs, team=Team.get_our(), available_round=new_round)
    def test_cbns_original(self):
        r0 = Round.create(num=0)
        r1 = Round.create(num=1)
        our_team = Team.create(name=Team.OUR_NAME)
        other_team = Team.create(name="opponent")
        cs = ChallengeSet.create(name="foo")
        cs.rounds = [r0, r1]
        cbn = ChallengeBinaryNode.create(name="foo", cs=cs, blob="aaa1")
        cbn_patched = ChallengeBinaryNode.create(name="foo",
                                                 cs=cs,
                                                 patch_type=PatchType.create(
                                                     name="patch1",
                                                     functionality_risk=0,
                                                     exploitability=1,
                                                 ),
                                                 blob="aaa2")
        cbn_other_team = ChallengeBinaryNode.create(name="foo",
                                                    cs=cs,
                                                    blob="aaa3")
        ChallengeSetFielding.create(cs=cs,
                                    cbns=[cbn],
                                    team=our_team,
                                    available_round=r0)
        ChallengeSetFielding.create(cs=cs,
                                    cbns=[cbn_patched],
                                    team=our_team,
                                    submission_round=r0).save()
        ChallengeSetFielding.create(cs=cs,
                                    cbns=[cbn_other_team],
                                    team=other_team,
                                    available_round=r0).save()

        assert_equals(len(cs.cbns_original), 1)
        assert_in(cbn, cs.cbns_original)
        assert_not_in(cbn_patched, cs.cbns_original)
        assert_not_in(cbn_other_team, cs.cbns_original)
    def test_most_reliable_exploit(self):
        r1 = Round.create(num=0)
        team = Team.create(name=Team.OUR_NAME)
        cs = ChallengeSet.create(name="foo")
        cs.rounds = [r1]
        job1 = RexJob.create(cs=cs)
        job2 = RexJob.create(cs=cs)
        job3 = RexJob.create(cs=cs)
        job4 = RexJob.create(cs=cs)

        pov1 = Exploit.create(cs=cs,
                              job=job1,
                              pov_type='type1',
                              exploitation_method='rop',
                              blob="exploit1",
                              c_code="exploit it",
                              reliability=0.9)
        assert_equals(pov1, cs.most_reliable_exploit)

        pov2 = Exploit.create(cs=cs,
                              job=job2,
                              pov_type='type2',
                              exploitation_method='rop',
                              blob="exploit2",
                              c_code="exploit it",
                              reliability=0.5)
        assert_equals(pov1, cs.most_reliable_exploit)

        pov3 = Exploit.create(cs=cs,
                              job=job3,
                              pov_type='type2',
                              exploitation_method='rop',
                              blob="exploit3",
                              c_code="exploit it",
                              reliability=0.9)
        assert_equals(pov1, cs.most_reliable_exploit)

        pov4 = Exploit.create(cs=cs,
                              job=job4,
                              pov_type='type2',
                              exploitation_method='rop',
                              blob="exploit4",
                              c_code="exploit it",
                              reliability=1.0)
        assert_equals(pov4, cs.most_reliable_exploit)
    def test_most_recent(self):
        cs = ChallengeSet.create(name="foo")
        cs2 = ChallengeSet.create(name="bar")
        team = Team.create(name="opponent")
        exploit = Exploit.create(cs=cs,
                                 job=RexJob.create(),
                                 pov_type="type1",
                                 blob="abc",
                                 c_code="exploit it")
        exploit2 = Exploit.create(cs=cs2,
                                  job=RexJob.create(),
                                  pov_type="type1",
                                  blob="def",
                                  c_code="delfino")
        Round.create(num=0)

        cable = ExploitSubmissionCable.create(team=team,
                                              cs=cs,
                                              exploit=exploit,
                                              throws=10,
                                              round=Round.current_round())
        cable2 = ExploitSubmissionCable.create(team=team,
                                               cs=cs2,
                                               exploit=exploit2,
                                               throws=10,
                                               round=Round.current_round())
        assert_equals(len(ExploitSubmissionCable.most_recent()), 2)
        assert_items_equal(ExploitSubmissionCable.most_recent(),
                           [cable, cable2])

        # assert we get back only the most recent exploit
        r1 = Round.create(num=1)
        new_exploit = Exploit.create(cs=cs,
                                     job=RexJob.create(),
                                     pov_type="type2",
                                     blob="def",
                                     c_code="don't exploit it")
        new_cable = ExploitSubmissionCable.create(team=team,
                                                  cs=cs,
                                                  exploit=new_exploit,
                                                  throws=10,
                                                  round=r1)
        assert_equals(len(ExploitSubmissionCable.most_recent()), 2)
        assert_items_equal(ExploitSubmissionCable.most_recent(),
                           [new_cable, cable2])
Example #11
0
    def test_submit_to(self):
        r0 = Round.create(num=0)
        r1 = Round.create(num=1)
        cs = ChallengeSet.create(name="foo")
        cs.rounds = [r1.id]
        job = AFLJob.create(cs=cs)
        exploit = Exploit.create(job=job, cs=cs, pov_type="type1", blob=BLOB, c_code="exploit it")
        team = Team.create(name="opponent")

        assert_equals(len(exploit.fieldings), 0)

        ef = exploit.submit_to(team=team, throws=10)
        assert_equals(len(exploit.fieldings), 1)
        assert_equals(ef.submission_round, Round.current_round())

        ef = exploit.submit_to(team=team, throws=5, round=r0)
        assert_equals(len(exploit.fieldings), 2)
        assert_equals(ef.submission_round, r0)
    def test_has_type1(self):
        from farnsworth.models.pov_test_result import PovTestResult
        pov_type = 'type1'
        cs = ChallengeSet.create(name="foo")
        job = AFLJob.create(cs=cs)
        Exploit.create(cs=cs,
                       job=job,
                       pov_type=pov_type,
                       blob=BLOB,
                       c_code="code",
                       reliability=0)
        assert_false(cs.has_type1)

        Exploit.create(cs=cs,
                       job=job,
                       pov_type=pov_type,
                       blob=BLOB,
                       c_code="code",
                       reliability=1)
        assert_true(cs.has_type1)

        # if not first condition is not met
        r2 = Round.create(num=2)
        cs2 = ChallengeSet.create(name="bar")
        job2 = AFLJob.create(cs=cs2)
        cbn2 = ChallengeBinaryNode.create(name="bar", cs=cs2, blob="aaa")
        team2 = Team.create(name=Team.OUR_NAME)
        exploit2 = Exploit.create(cs=cs2,
                                  job=job2,
                                  pov_type=pov_type,
                                  blob=BLOB,
                                  c_code="code",
                                  reliability=0)
        csf2 = ChallengeSetFielding.create_or_update_available(team=team2,
                                                               cbn=cbn2,
                                                               round=r2)
        pov_result2 = PovTestResult.create(exploit=exploit2,
                                           cs_fielding=csf2,
                                           num_success=0)
        assert_false(cs2.has_type1)

        pov_result2.num_success = 10
        pov_result2.save()
        assert_true(cs2.has_type1)
Example #13
0
    def patch_decision(target_cs):
        """
        Determines the CBNs to submit. Returns None if no submission should be made.
        """
        fielding = ChallengeSetFielding.latest(target_cs, Team.get_our())
        fielded_patch_type = fielding.cbns[0].patch_type
        current_cbns = list(fielding.cbns)

        all_patches = target_cs.cbns_by_patch_type()
        allowed_patches = {
            k: v
            for k, v in all_patches.items() if not CBSubmitter.blacklisted(v)
        }

        if not allowed_patches:
            # All of the patches are blacklisted, or none exist -- submit the originals
            if not CBSubmitter.same_cbns(target_cs.cbns_original,
                                         current_cbns):
                return list(target_cs.cbns_original)
            else:
                return

        allowed_patch_type = fielded_patch_type in allowed_patches.keys()
        if allowed_patch_type:
            enough_data = len(allowed_patches[fielded_patch_type]
                              [0].fieldings) > MIN_ROUNDS_ONLINE
            if not enough_data:
                LOG.debug("Old patch (%s) too fresh on %s, leaving it in.",
                          fielded_patch_type.name, target_cs.name)
                return

        to_submit_patch_type, _ = sorted(
            allowed_patches.items(),
            key=lambda i: CBSubmitter.cb_score(i[1][0]),
            reverse=True)[0]

        if to_submit_patch_type is fielded_patch_type:
            return

        new_cbns = all_patches[to_submit_patch_type]
        if not CBSubmitter.same_cbns(new_cbns, current_cbns):
            return new_cbns
    def test_unsubmitted_ids_rules(self):
        r1 = Round.create(num=0)
        team = Team.create(name=Team.OUR_NAME)
        cs = ChallengeSet.create(name="foo")
        ids1 = IDSRule.create(cs=cs, rules="aaa")
        ids2 = IDSRule.create(cs=cs, rules="bbb")

        assert_equals(len(cs.unsubmitted_ids_rules), 2)
        assert_in(ids1, cs.unsubmitted_ids_rules)
        assert_in(ids2, cs.unsubmitted_ids_rules)

        IDSRuleFielding.create(ids_rule=ids1, team=team, submission_round=r1)
        assert_equals(len(cs.unsubmitted_ids_rules), 1)
        assert_not_in(ids1, cs.unsubmitted_ids_rules)
        assert_in(ids2, cs.unsubmitted_ids_rules)

        IDSRuleFielding.create(ids_rule=ids2, team=team, submission_round=r1)
        assert_equals(len(cs.unsubmitted_ids_rules), 0)
        assert_not_in(ids1, cs.unsubmitted_ids_rules)
        assert_not_in(ids2, cs.unsubmitted_ids_rules)
    def test_process_and_unprocessed(self):
        cs = ChallengeSet.create(name="foo")
        team = Team.create(name="opponent")
        exploit = Exploit.create(cs=cs,
                                 job=RexJob.create(),
                                 pov_type="type1",
                                 blob="abc",
                                 c_code="exploit it")
        Round.create(num=0)

        cable = ExploitSubmissionCable.create(team=team,
                                              cs=cs,
                                              exploit=exploit,
                                              throws=10,
                                              round=Round.current_round())

        assert_equals(len(ExploitSubmissionCable.unprocessed()), 1)

        cable.process()
        assert_equals(len(ExploitSubmissionCable.unprocessed()), 0)
Example #16
0
    def test_variable_submitter(self):
        t = Team.create(name=Team.OUR_NAME)
        r0 = Round.create(num=0)

        # set up several CSes
        cses = [CS.create(name='CS_%s' % i) for i in range(10)]

        # Set up the patches
        for cs in cses:
            for pt in PT.select():
                ids = IDSRule.create(cs=cs, rules="HAHAHA")
                cbn = CBN.create(cs=cs,
                                 name=cs.name + "_" + pt.name,
                                 blob="XXXX",
                                 patch_type=pt,
                                 ids_rule=ids)

        patch_names = scriba.submitters.cb.ORIG_PATCH_ORDER

        try:
            cur_cssc_id = CSSC.select().order_by(CSSC.id.desc()).get().id
        except CSSC.DoesNotExist:
            cur_cssc_id = 0

        # run the scheduler
        for _ in scriba.submitters.cb.ORIG_PATCH_ORDER:
            for c in cses:
                scriba.submitters.cb.CBSubmitter.rotator_submission(c)

        # make sure they got rotated correctly
        for n, cs in enumerate(cses):
            cables = list(
                CSSC.select().where((CSSC.cs == cs)
                                    & (CSSC.id > cur_cssc_id)).order_by(
                                        CSSC.id.asc()))
            assert len(cables) > 0
            assert all(c.cbns[0].patch_type.name == pn
                       for c, pn in zip(cables, (patch_names * 10)[n:]))
Example #17
0
    def _submit_patches(self, cable):
        patches = [
            (str(cbn.root.name) if cbn.root is not None else str(cbn.name),
             str(cbn.blob)) for cbn in cable.cbns
        ]
        result = self._cgc.uploadRCB(str(cable.cs.name), *patches)
        LOG.debug("Submitted RB! Response: %s", result)

        submission_round, status = Round.get_or_create_latest(
            num=result['round'])

        if status == Round.FIRST_GAME:
            LOG.error("Submission in first round of first game (round #%d)",
                      submission_round.num)
        elif status == Round.NEW_GAME:
            LOG.info("Submission in first round of new game (round #%d)",
                     submission_round.num)
        elif status == Round.NEW_ROUND:
            LOG.info("Submission beginning of new round #%d",
                     submission_round.num)

        return ChallengeSetFielding.create_or_update_submission(
            cbns=cable.cbns, team=Team.get_our(), round=submission_round)
Example #18
0
def ensure_teams(args):  #pylint:disable=unused-argument
    try:
        Team.get_our()
    except Team.DoesNotExist:  #pylint:disable=no-member
        Team.create(name=Team.OUR_NAME)
Example #19
0
    def test_simple_selector(self):
        try:
            t = Team.get_our()
        except Team.DoesNotExist:
            t = Team.create(name=Team.OUR_NAME)
        cs = CS.create(name='x')

        # Set up a CBN for it, with some feedback
        cbn_orig = CBN.create(cs=cs, name="unpatched", blob="XXXX")

        # Field the default CBN
        r0 = Round.create(num=0)
        pf_r0 = PF.create(cs=cs,
                          round=r0,
                          success=1.0,
                          timeout=0,
                          connect=0,
                          function=0,
                          time_overhead=0.0,
                          memory_overhead=0.0)
        cs.seen_in_round(r0)
        CSF.create(cs=cs,
                   cbns=[cbn_orig],
                   team=t,
                   available_round=r0,
                   poll_feedback=pf_r0)

        # make sure we don't submit on round 0
        assert_is_none(
            scriba.submitters.cb.CBSubmitter.patch_decision_simple(cs, r0))

        # tick the round
        r1 = Round.create(num=1)
        pf_r1 = PF.create(cs=cs,
                          round=r1,
                          success=1.0,
                          timeout=0,
                          connect=0,
                          function=0,
                          time_overhead=0.0,
                          memory_overhead=0.0)
        cs.seen_in_round(r1)
        CSF.create(cs=cs,
                   cbns=[cbn_orig],
                   team=t,
                   available_round=r1,
                   poll_feedback=pf_r1)

        # make sure we don't submit on round 0
        assert_is_none(
            scriba.submitters.cb.CBSubmitter.patch_decision_simple(cs, r1))

        # tick the round
        r2 = Round.create(num=2)
        pf_r2 = PF.create(cs=cs,
                          round=r2,
                          success=1.0,
                          timeout=0,
                          connect=0,
                          function=0,
                          time_overhead=0.0,
                          memory_overhead=0.0)
        cs.seen_in_round(r2)
        CSF.create(cs=cs,
                   cbns=[cbn_orig],
                   team=t,
                   available_round=r2,
                   poll_feedback=pf_r2)

        # Make sure we properly handle the case when there are no patches
        assert_is_none(
            scriba.submitters.cb.CBSubmitter.patch_decision_simple(cs, r0))

        # And patch it, without feedback
        pt1 = PT.create(name="a_patch",
                        functionality_risk=0.,
                        exploitability=0.4)
        cbn_p1 = CBN.create(cs=cs, name="patch1", blob="XXXYZ", patch_type=pt1)
        pt2 = PT.create(name="b_patch",
                        functionality_risk=0.,
                        exploitability=0.3)
        cbn_p2 = CBN.create(cs=cs, name="patch2", blob="XXXZZ", patch_type=pt2)

        # Make sure we grab the "best" patch
        assert_items_equal(
            scriba.submitters.cb.CBSubmitter.patch_decision_simple(cs, r2),
            [cbn_p2])

        # emulate the ambassador submitting this f****r
        csf0s = CSF.create(cs=cs, cbns=[cbn_p2], team=t, submission_round=r2)

        # add a new, better patch
        pt3 = PT.create(name="c_patch",
                        functionality_risk=0.,
                        exploitability=0.2)
        cbn_p3 = CBN.create(cs=cs, name="patch3", blob="XXXXZ", patch_type=pt3)

        # make sure we select the new patch, because it's still the right round
        assert_items_equal(
            scriba.submitters.cb.CBSubmitter.patch_decision_simple(cs, r2),
            [cbn_p3])
        csf0s.cbns = [cbn_p3]
        csf0s.save()

        # make sure we are now happy
        assert_is_none(
            scriba.submitters.cb.CBSubmitter.patch_decision_simple(cs, r2))

        # down a round
        r3 = Round.create(num=3)
        pf_r3 = PF.create(cs=cs,
                          round=r3,
                          success=0,
                          timeout=0,
                          connect=0,
                          function=0,
                          time_overhead=0.0,
                          memory_overhead=0.0)
        cs.seen_in_round(r3)
        CSF.create(cs=cs,
                   cbns=[cbn_p3],
                   team=t,
                   available_round=r3,
                   poll_feedback=pf_r3)

        # tick the round
        r4 = Round.create(num=4)
        pf_r4 = PF.create(cs=cs,
                          round=r4,
                          success=1.0,
                          timeout=0,
                          connect=0,
                          function=0,
                          time_overhead=0.05,
                          memory_overhead=0.05)
        cs.seen_in_round(r4)
        CSF.create(cs=cs,
                   cbns=[cbn_p3],
                   team=t,
                   available_round=r4,
                   poll_feedback=pf_r4)

        # make sure we don't choose to change the selection
        assert_is_none(
            scriba.submitters.cb.CBSubmitter.patch_decision_simple(cs, r4))

        # now find a better patch
        pt4 = PT.create(name="d_patch",
                        functionality_risk=0.,
                        exploitability=0.1)
        cbn_p4 = CBN.create(cs=cs, name="patch4", blob="XXXYX", patch_type=pt4)

        # too late, man
        assert_is_none(
            scriba.submitters.cb.CBSubmitter.patch_decision_simple(cs, r4))

        # now we get the baaaad news
        r5 = Round.create(num=5)
        pf_r5 = PF.create(cs=cs,
                          round=r5,
                          success=0.8,
                          timeout=0,
                          connect=0,
                          function=0.2,
                          time_overhead=0.05,
                          memory_overhead=0.05)
        cs.seen_in_round(r5)
        CSF.create(cs=cs,
                   cbns=[cbn_p3],
                   team=t,
                   available_round=r5,
                   poll_feedback=pf_r5)

        # Make sure we properly roll back
        assert_items_equal(
            scriba.submitters.cb.CBSubmitter.patch_decision_simple(cs, r5),
            cs.cbns_original)
        CSF.create(cs=cs, cbns=cs.cbns_original, team=t, submission_round=r5)

        # down a round
        r6 = Round.create(num=6)
        pf_r6 = PF.create(cs=cs,
                          round=r4,
                          success=0,
                          timeout=0,
                          connect=0,
                          function=0,
                          time_overhead=0.0,
                          memory_overhead=0.0)
        cs.seen_in_round(r6)
        CSF.create(cs=cs,
                   cbns=[cbn_orig],
                   team=t,
                   available_round=r6,
                   poll_feedback=pf_r6)

        # that worked
        r7 = Round.create(num=7)
        pf_r7 = PF.create(cs=cs,
                          round=r7,
                          success=1.0,
                          timeout=0,
                          connect=0,
                          function=0,
                          time_overhead=0.0,
                          memory_overhead=0.0)
        cs.seen_in_round(r7)
        CSF.create(cs=cs,
                   cbns=[cbn_orig],
                   team=t,
                   available_round=r7,
                   poll_feedback=pf_r7)

        # make sure we're happy staying unpatched
        assert_is_none(
            scriba.submitters.cb.CBSubmitter.patch_decision_simple(cs, r7))
Example #20
0
    def test_patch_selection(self):
        t = Team.create(name=Team.OUR_NAME)
        r0 = Round.create(num=0)
        cs = CS.create(name='x')

        # Set up a CBN for it, with some feedback
        cbn_orig = CBN.create(cs=cs, name="unpatched", blob="XXXX")
        pf_orig = PF.create(cs=cs,
                            round=r0,
                            success=1.0,
                            timeout=0,
                            connect=0,
                            function=0,
                            time_overhead=0.0,
                            memory_overhead=0.0)

        # Field the default CBN
        CSF.create(cs=cs,
                   cbns=[cbn_orig],
                   team=t,
                   available_round=r0,
                   poll_feedback=pf_orig)

        # Make sure we properly handle the case when there are no patches
        assert_is_none(scriba.submitters.cb.CBSubmitter.patch_decision(cs))

        # And patch it
        pt = PT.create(name="a_patch",
                       functionality_risk=0.,
                       exploitability=0.)
        cbn_p1 = CBN.create(cs=cs, name="patch1", blob="XXXYZ", patch_type=pt)
        PS.create(cs=cs,
                  patch_type=pt,
                  num_polls=10,
                  has_failed_polls=False,
                  failed_polls=0,
                  round=r0,
                  perf_score={
                      'score': {
                          'ref': {
                              'task_clock': 1.0,
                              'rss': 1.0,
                              'flt': 1.0,
                              'file_size': 1.0
                          },
                          'rep': {
                              'task_clock': 1.1,
                              'file_size': 1.1,
                              'rss': 1.1,
                              'flt': 1.1,
                          }
                      }
                  })

        # Make sure we choose this patch
        assert_equals(scriba.submitters.cb.CBSubmitter.patch_decision(cs),
                      [cbn_p1])

        # Field the patch - we're down the first round
        r1 = Round.create(num=1)
        pf1 = PF.create(cs=cs,
                        round=r1,
                        success=0.0,
                        timeout=0,
                        connect=0,
                        function=0,
                        time_overhead=0.0,
                        memory_overhead=0.0)
        CSF.create(cs=cs,
                   cbns=[cbn_p1],
                   team=t,
                   available_round=r1,
                   poll_feedback=pf1)

        r2 = Round.create(num=2)
        pf2 = PF.create(cs=cs,
                        round=r1,
                        success=1.0,
                        timeout=0,
                        connect=0,
                        function=0,
                        time_overhead=1.3,
                        memory_overhead=1.3)
        CSF.create(cs=cs,
                   cbns=[cbn_p1],
                   team=t,
                   available_round=r2,
                   poll_feedback=pf2)

        # Make sure we revert
        assert_equals(scriba.submitters.cb.CBSubmitter.patch_decision(cs),
                      [cbn_orig])
Example #21
0
    def _jobs(self):
        for cs in self.challenge_sets():
            # Unlike Rex, there's only 1 kind of crash we can exploit
            # We do not schedule if we already have a type1 exploit
            if not cs.has_type1:
                ordered_crashes = cs.crashes.select(Crash.id) \
                                            .where(Crash.kind == Vulnerability.IP_OVERWRITE) \
                                            .order_by(fn.octet_length(Crash.blob).asc())

                sliced = islice(ordered_crashes, FEED_LIMIT)
                for priority, crash in self._normalize_sort(
                        BASE_PRIORITY, sliced):
                    job = PovFuzzer1Job(cs=cs,
                                        payload={
                                            'crash_id': crash.id,
                                            'target_cs_fld': None,
                                            'target_ids_fld': None
                                        },
                                        request_cpu=1,
                                        limit_memory=4096,
                                        limit_time=5 * 60)
                    LOG.debug(
                        "Yielding PovFuzzer1Job for %s with crash %s priority %d",
                        cs.name, crash.id, priority)
                    yield (job, priority)
            else:
                # Schedule pov_fuzzers against other teams
                # We will schedule at most 3 exploits
                longest = list(
                    cs.exploits.select(Exploit.crash).join(Crash).where(
                        Exploit.method == "fuzzer", Exploit.reliability > 0,
                        Exploit.pov_type == "type1").order_by(
                            fn.octet_length(Crash.blob).desc()).limit(3))

                for team in Team.opponents():
                    target_cs_fld = ChallengeSetFielding.latest(cs, team)

                    if target_cs_fld is not None:  # Are there any CS fielded?
                        target_ids_fld = IDSRuleFielding.latest(cs, team)

                        # See if there are successful PoVs for this
                        # fielded CS and IDS. If yes, no need to
                        # schedule Pov Testing Jobs
                        pov_test_results = PovTestResult.best(
                            target_cs_fld, target_ids_fld)

                        if pov_test_results is None or pov_test_results.num_success < 3:
                            # We do not have any strong PoVs for the
                            # current fielded CS. Schedule 3 pov_fuzzers
                            for exploit in longest:
                                if target_ids_fld is not None:
                                    target_ids_id = target_ids_fld.id
                                else:
                                    target_ids_id = None

                                payload = {
                                    'crash_id': exploit.crash.id,
                                    'target_cs_fld': target_cs_fld.id,
                                    'target_ids_fld': target_ids_id
                                }
                                job = PovFuzzer1Job(cs=cs,
                                                    payload=payload,
                                                    request_cpu=1,
                                                    limit_memory=2048,
                                                    limit_time=5 * 60)
                                priority = 80
                                LOG.debug(
                                    "Yielding targeted PovFuzzer1Job for %s "
                                    "with crash %s priority %d team %d",
                                    cs.name, exploit.crash.id, priority,
                                    team.id)
                                yield (job, priority)
Example #22
0
    def patch_decision_simple(target_cs, round_):
        """
        Determines the CBNs to submit. Returns None if no submission should be made.
        We only submit 1 patch type per CS.
        """
        LOG.info("CB SUBMISSION START: %s (round %d)", target_cs.name,
                 round_.num)

        # make sure that this binary is not new this round
        if not (target_cs.id
                in [cs.id for cs in ChallengeSet.fielded_in_round(round_)]
                and Round.prev_round() is not None and target_cs.id in [
                    cs.id
                    for cs in ChallengeSet.fielded_in_round(Round.prev_round())
                ]):
            LOG.info("%s - not patching in the first round", target_cs.name)
            return

        current_fielding = ChallengeSetFielding.latest(cs=target_cs,
                                                       team=Team.get_our(),
                                                       round=round_)

        # Fielding should always be not None, or we are in a
        # race condition and do not want to do anything right
        # now, we will be run again, at which point fieldings
        # should be set.
        if current_fielding is None:
            LOG.warning(
                "%s - hit the race condition for latest fielding being None",
                target_cs.name)
            return

        LOG.info("%s - current patch type: %s", target_cs.name,
                 (current_fielding.cbns[0].patch_type.name if
                  current_fielding.cbns[0].patch_type is not None else "None"))

        # if we just submitted, wait a round before making any decisions
        if current_fielding.poll_feedback is not None and (
                current_fielding.poll_feedback.timeout +
                current_fielding.poll_feedback.success +
                current_fielding.poll_feedback.function +
                current_fielding.poll_feedback.connect == 0):
            LOG.warning("%s - skipping 'downed' round", target_cs.name)
            return

        # if we don't have any patches ready, let's wait
        all_patches = target_cs.cbns_by_patch_type()
        if len(all_patches) == 0:
            return

        best_patch_type = sorted(all_patches.keys(),
                                 key=lambda pt: pt.exploitability)[0]
        has_feedback = {
            k: v
            for k, v in all_patches.iteritems() if len(v[0].poll_feedbacks) > 0
        }
        pull_back = any(cbns[0].min_cb_score is not None
                        and cbns[0].min_cb_score < MIN_CB_SCORE
                        for cbns in all_patches.values())

        for k, v in has_feedback.items():
            LOG.info("%s - minimum score of patch %s is %s", target_cs.name,
                     k.name, v[0].min_cb_score)

        if pull_back:
            LOG.info("%s - pulling back the patch :-(", target_cs.name)
            new_cbns = target_cs.cbns_original
        else:
            # if we've already patched, and we're not pulling back, forget about it
            if best_patch_type.name != 'manual' and not CBSubmitter.same_cbns(
                    current_fielding.cbns, target_cs.cbns_original):
                LOG.info("%s - already patched -- aborting!", target_cs.name)
                return

            LOG.info("%s - chose %s patch type!", target_cs.name,
                     best_patch_type.name)
            new_cbns = all_patches[best_patch_type]

        # Check if we have submitted in this round?
        submitted_fielding = ChallengeSetFielding.submissions(
            cs=target_cs, team=Team.get_our(), round=round_)

        if submitted_fielding is not None:
            LOG.info("%s - we have an earlier submission this round...",
                     target_cs.name)
            prior_submission = list(submitted_fielding.cbns)
        else:
            LOG.info("%s - submitting for the first time this round...",
                     target_cs.name)
            prior_submission = list(current_fielding.cbns)

        # if we submitted an exploit for the first time this round, let's not patch
        if not pull_back and ExploitSubmissionCable.select(
        ).join(Exploit).where(
            (ExploitSubmissionCable.cs == target_cs)
                & (ExploitSubmissionCable.processed_at != None)
                & (ExploitSubmissionCable.processed_at >= round_.created_at)
                & (Exploit.method != "backdoor")).exists(
                ) and not ExploitSubmissionCable.select().join(Exploit).where(
                    (ExploitSubmissionCable.cs == target_cs)
                    & (ExploitSubmissionCable.processed_at != None)
                    & (ExploitSubmissionCable.processed_at < round_.created_at)
                    & (Exploit.method != "backdoor")).exists():
            LOG.info(
                "%s - not submitting because we first found an exploit last round",
                target_cs.name)
            new_cbns = list(current_fielding.cbns)

        if CBSubmitter.same_cbns(new_cbns, prior_submission):
            LOG.info("%s - nothing to do, this would be a resubmission",
                     target_cs.name)
            return
        else:
            LOG.info("%s - we have not yet submitted these CBNs this round!",
                     target_cs.name)

        return new_cbns