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)
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)
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()
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])
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)
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)
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:]))
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)
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)
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))
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])
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)
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