ctf-2011

old assets from capture-the-flag ictf 2011

git clone https://9o.is/git/ctf-2011.git

riskasses.py

(30687B)


      1 #!/usr/bin/env python
      2 import socket
      3 import threading
      4 import SocketServer
      5 from datetime import datetime
      6 import re
      7 import pickle
      8 import time
      9 import json
     10 from termcolor import colored, cprint
     11 from pprint import pprint as pp
     12 import ipaddr
     13 import threading
     14 import urllib2
     15 import sys
     16 
     17 class ictf:
     18     # Risk assesment and money laundering library based on 
     19     # http://ictf.cs.ucsb.edu/iCTF_2011_Description.txt
     20     #
     21     # Missing Information, that will be provided at beginning of iCTF2011:
     22     
     23     #  - Regular expression for flags
     24     #flag_re = r'[A-Fa-f0-9]{40}'
     25     # like: 00583d5e55f0f54a9510201de7bbe7c7ba07
     26     flag_re = r'flg[0-9a-f]{36}'
     27     
     28     #  - ID of this team
     29     my_id = "HakM@ri$t"
     30 
     31     #  - Overall risk function
     32     def risk_function(self, R, M, N, Q):
     33         ''' Calculates the risk, using the following input:
     34         R: Risk associated with service (float, probability, <= 1)
     35         M: Amount of money to launder
     36         N: Amount of money that has been laundered through that team by us
     37         Q: Amount of money that has been laundered through that svc by us
     38         
     39         Must return a probability (float smaller/equal 1.0)'''
     40         
     41         return ((R*(M/10.0))+0.5*((N-700.0)/(300.0+ abs(N-700.0) )+1) + 0.5*((Q-1500.0)/(300.0+ abs(Q-1500.0)) +1.0))/3.0
     42         
     43     
     44     # - Submit launder requests
     45     def _launder_request(self, amount, flag):
     46         '''Must return a tuple with the following format:
     47         (result, points_gained, msg, exploited_team, exploited_svc) with 
     48         state:         "SUCCESS", "BAD_FLAG", "OLD_FLAG", "BAD_LUCK" or 
     49                        "OTHER"
     50         points_gained: amount of points gained
     51         msg:           whatever flugsubmission returned
     52         exploited_team, exploited_svc: if msg contains that information, 
     53                                        include team/svc id, otherwise None'''
     54     
     55         u = urllib2.urlopen('http://bubbles.ictf2011.info:8082/launder?flag='+\
     56             flag+'&amount='+str(int(amount))+'&fc=5fe2f7cc3e920e546613687b238117e1')
     57         status_line = u.readlines()[-1].strip()
     58     
     59         if status_line == 'You submitted an old flag, be faster next time':
     60             return ("OLD_FLAG", 0.0, '', None, None)
     61         elif status_line == 'Flag already submitted':
     62             return ("OLD_FLAG", 0.0, 'Flag already submitted', None, None)
     63         elif 'You successfully laundered' in status_line:
     64             # <br>You have 224 CHFs left<br>Your overall risk O is 0.00 based on risk(service 4) R:0.20, amount M:0, overall amount N:0 global amount Q:0<br>Your conversion would be: M: 0 P: 0.18 D: 0.58<br/>Your random value of [0,1] is 0.73<br>You successfully laundered 0 CHFs into 0.04 points
     65             points_gained = float(status_line.split(' ')[-2])
     66             money_left = int(status_line.split(' ')[2])
     67             return ("SUCCESS", points_gained, status_line, None, None)
     68         elif status_line == 'Unknown error -4578':
     69             # Try again, but might backfire
     70             return self._launder_request(amount, flag)
     71         elif 'You got caught by the feds...' in status_line:
     72             return ("BAD_LUCK", 0.0, status_line, None, None)
     73         elif status_line in ['You submitted an invalid flag', 'invalid flag']:
     74             return ("BAD_FLAG", 0.0, '', None, None)
     75         else:
     76             print 'Got unknown flag response:','|'+status_line+'|'
     77             return ("OTHER", 0.0, status_line, None, None, money_left)
     78     
     79     # - Submit betrayal requests
     80     def _betrayal_request(self, flag):
     81         '''Must return a tuple with the following format:
     82         (result, msg, from_team, from_service) with state being:
     83         "SUCCESS", "OLD_FLAG", "BAD_FLAG" or "OTHER"
     84         and msg whatever flugsubmission returned
     85         from_team, from_service if msg contains that information, 
     86         include team/svc id, otherwise None'''
     87         
     88         u = urllib2.urlopen('http://bubbles.ictf2011.info:8082/launder?flag='+\
     89             flag+'&amount='+str(int(amount))+'&fc=5fe2f7cc3e920e546613687b238117e1')
     90         status_line = u.readlines()[-1].strip()
     91     
     92         if status_line == 'You submitted an old flag, be faster next time':
     93             return ("OLD_FLAG", '', None, None)
     94         elif status_line == 'Flag already submitted':
     95             return ("OLD_FLAG",  'Flag already submitted', None, None)
     96         else:
     97             print 'Got unknown flag response:','|'+status_line+'|'
     98             return ("OTHER", status_line, None, None)
     99     
    100     # THAT'S IT! NOTHING TO DONE BELOW
    101     
    102     #  - State Pusher receive port
    103     recv_port = 55555
    104     
    105     def __init__(self, my_id=my_id):
    106         self.teams = {}
    107         # Format: 
    108         # { "TEAM1_ID": {'money': 123, 
    109         #                'points': 123, 
    110         #                'svc_up': ["SVC1_ID",...], 
    111         #                'svc_comp': ["SVC99_ID",...],
    112         #                'N': {"TEAM2_ID": 4, ...},
    113         #                'Q': {"SVC1_ID": 6, ...}
    114         #                'D': 0.33, 
    115         #                'subnet': '1.2.3.0/24',
    116         #                'challenges_solved': [30, 5391, 305]}
    117         
    118         self.services = {}
    119         # Format: 
    120         # { "SVC1_ID": {'C': 0.33,    # cut in Percentage/100
    121         #               'P': 0.67, # profit in Percentage/100
    122         #               'R': 0.1}    # risk in Probability
    123         
    124         self.transactions = []
    125         # Format:
    126         # [{ 'time_used': datetime.now(), # Time of usage
    127         #    'flag': 'fooBAR',            # String associated with flag
    128         #    'time_stolen': ...,          # As found in unused_flags
    129         #    'from_team': 'TEAM1_ID',     # As found in unused_flags
    130         #    'from_service': 'SVC1_ID',   # As found in new_flag
    131         #    'action': 'laundering',      # "betrayal" or "laundering"
    132         #    'money_given': 12.3,         # if "laundering", otherwise 0.0
    133         #    'points_gained': 12.3,       # if "laundering" and successfull, 
    134         #                                 # otherwise 0.0 
    135         #    'result': "SUCCESS",         # "SUCCESS", "BAD_FLAG", "BAD_LUCK",
    136         #                                 # "OLD_FLAG" or "OTHER"
    137         #    'msg': 'Flag sub. suc.',     # Whatever flagsubmission returned
    138         #  },...]
    139         
    140         self.unused_flags = []
    141         # Format:
    142         # [{ 'flag': 'fooBAR',            # String associated with flag
    143         #    'time_received': ...,        # Time of reception
    144         #    'from_team': 'TEAM1_ID',     # Where did it come from?
    145         #                                 # if unknown, None
    146         #    'from_service': 'SVC1_ID',   # Where did it come from?
    147         #                                 # if unknown, None
    148         #  },...]
    149         
    150         self.all_flags = []
    151         # List of all flags ever put in unused_flags or transactions
    152         
    153         self.my_id = my_id
    154         self.recv_state_socket = None
    155         self.recv_state_thread = None
    156         self.recv_flag_server = None
    157         
    158         self.flag_dissipater_instance = None
    159         
    160         # Do you want every tick to produce a message?
    161         self.show_ticks = True
    162         self.tick_callback = self.print_scorboard
    163 
    164     def get_risks(self, amount, service=None, team=None):
    165         '''Compiles a list of tuples describing the risk associated in 
    166         laundering *amount* money through each team and service, except
    167         our self.
    168         
    169         Returned list of tuples has the following format:
    170         [(team_id, service_id, risk),...]
    171         
    172         If service and team are given, only one risk will be returned.'''
    173         
    174         current_risks = []
    175         
    176         if team and service:
    177             N = 0
    178             if team in self.my_state['N']:
    179                 # The next line may needs to be exchanged by the following
    180                 # t['N'][self.my_id]
    181                 N = self.my_state['N'][team]
    182 
    183             Q = 0
    184             if service in self.my_state['Q']:
    185                 Q = self.my_state['Q'][service]
    186             
    187             return self.risk_function(self.services[service]['R'], amount, N, Q)
    188         
    189         for t_id,t in self.teams.items():
    190             # Ignore myself
    191             if t_id == self.my_id:
    192                 continue
    193             
    194             N = 0
    195             if t_id in self.my_state['N']:
    196                 # The next line may needs to be exchanged by the following
    197                 # t['N'][self.my_id]
    198                 N = self.my_state['N'][t_id]
    199             
    200             for s_id,s in self.services.items():
    201                 Q = 0
    202                 if s_id in self.my_state['Q']:
    203                     Q = self.my_state['Q'][s_id]
    204                 
    205                 current_risks.append(
    206                     (t_id, s_id, self.risk_function(s['R'], amount, N, Q)))
    207         
    208         return current_risks
    209     
    210     def get_payoffs(self, amount, service=None):
    211         '''Gives a quantitative prediction on how good a service would payoff 
    212         using it to launder *amount* money.
    213         
    214         If *defense* is not set, the quotient will be assumed 1.0 (meaning no 
    215         defense penalty)
    216         
    217         Returned list of tuples has the following format:
    218         [(service_id, payoff_prediction),...]
    219         
    220         If service is given, only that payoff will be returned'''
    221         
    222         if service:
    223             s = self.services[service]
    224             after_cut = amount*(1.0-s['C']) # cut is given as percentage
    225             return after_cut*s['P']*self.my_state['D']
    226         
    227         payoffs = []
    228         
    229         for s_id,s in self.services.items():
    230             # Payoff fuction: (amount laundered - cut) * defense% * payoff%
    231             after_cut = amount*(1.0-s['C']) # cut is given as percentage
    232             payoffs.append((s_id, after_cut*s['P']*self.my_state['D']))
    233         
    234         return payoffs
    235     
    236     def parse_pushed_state(self, json_input):
    237         ''' Updates self.teams and self.services
    238         For format of members, see _init__()
    239         and for json see: http://ictf.cs.ucsb.edu/your_pusher.txt
    240 
    241         Be careful to create new teams and services as they appear!'''
    242         for json_line in json_input.split('\n'):
    243             try:
    244                 state = json.loads(json_line)
    245                 assert type(state) == dict, 'Has to be a dict'
    246             except Exception, err:
    247                 return
    248             
    249             if state['tick'] <= self.tick:
    250                 continue
    251             
    252             self.tick = state['tick']
    253 
    254             for s_id,s in state['services'].items():
    255                 # Parse
    256                 s['C'] = s['C']/100.0
    257                 s['P'] = s['P']/100.0
    258                 s['R'] = s['R']/100.0
    259 
    260                 # Create service if necessary
    261                 if s_id not in self.services:
    262                     self.services[s_id] = s
    263                 else:
    264                     # Or just update
    265                     self.services[s_id].update(s)
    266 
    267             for t_id,t in state['teams'].items():
    268                 # Parse
    269                 t['D'] = t['D']/100.0
    270                 
    271                 # Subnet to ipaddr.IPv4Network object
    272                 t['subnet'] = ipaddr.IPv4Network(t['subnet'])
    273                 
    274                 # N, Q, money, points and challenges_solved are fine like
    275                 # they are, nothing to do
    276 
    277                 # Rename services_compromised_last_tick -> svc_up
    278                 t['svc_up'] = t['services_compromised_last_tick']
    279                 del t['services_compromised_last_tick']
    280                 # and services_up_last_tick -> svc_comp
    281                 t['svc_comp'] = t['services_up_last_tick']
    282                 del t['services_up_last_tick']
    283                 
    284                 # Create team if necessary
    285                 if t_id not in self.teams:
    286                     self.teams[t_id] = t
    287                 else:
    288                     # Or just update
    289                     self.teams[t_id].update(t)
    290 
    291             if self.show_ticks:
    292                 print 'New tick:',self.tick
    293                 if self.tick_callback:
    294                     self.tick_callback()
    295     
    296     def get_flag(self, flag, remove=False):
    297         r = filter(lambda x: x['flag']==flag, self.unused_flags)
    298         
    299         if r:
    300             if remove:
    301                 self.unused_flags.remove(r[0])
    302             return r[0]
    303         else:
    304             return None
    305     
    306     def launder(self, amount, flag_data):
    307         '''Tries to launder *amount* money with flag contained in *flag_data*
    308         *flag_data* must have same format as in unused_flags, see __init__()
    309         and should have been poped (removed) from unused_flags.
    310         
    311         Returns (result, points_gained, msg)'''
    312         
    313         assert amount<=self.teams[self.my_id]['money'], 'Insufficient funds.'
    314         
    315         result, points_gained, msg, from_team, from_service = \
    316             self._launder_request(amount, flag_data['flag'])
    317         
    318         # If from_team or from_service were returned on request, use them,
    319         # they must be correct
    320         if from_team:
    321             flag_data['from_team'] = from_team
    322         if from_service:
    323             flag_data['from_service'] = from_service
    324         
    325         flag_data['time_used'] = datetime.now()
    326         flag_data['action'] = 'laundering'
    327         flag_data['money_given'] = amount
    328         flag_data['points_gained'] = points_gained
    329         flag_data['result'] = result
    330         flag_data['msg'] = msg
    331         
    332         # Reduce our left-over money
    333         if result in ["SUCCESS", "BAD_LUCK"]:
    334             self.teams[self.my_id]['money'] -= amount
    335         # Own points are not used for anything, thus need no update
    336         
    337         self.transactions.append(flag_data)
    338         
    339         return (result, points_gained, msg)
    340     
    341     def betray(self, flag_data):
    342         '''Tries to betray others with flag contained in *flag_data*
    343         *flag_data* must have same format as in unused_flags, see __init__()
    344         and should have been poped (removed) from unused_flags.
    345         
    346         Returns (result, msg)'''
    347         
    348         result, msg, from_team, from_service = \
    349             self._betrayal_request(flag_data['flag'])
    350         
    351         # If from_team or from_service were returned on request, use them, 
    352         # they must be correct
    353         if from_team:
    354             flag_data['from_team'] = from_team
    355         if from_service:
    356             flag_data['from_service'] = from_service
    357         
    358         flag_data['time_used'] = datetime.now()
    359         flag_data['action'] = 'betrayal'
    360         flag_data['money_given'] = 0.0
    361         flag_data['points_gained'] = 0.0
    362         flag_data['result'] = result
    363         flag_data['msg'] = msg
    364         
    365         self.transactions.append(flag_data)
    366         
    367         return (result, msg)
    368     
    369     def add_new_flag(self, flag, team, service):
    370         if flag in self.all_flags:
    371             return False
    372         self.all_flags.append(flag)
    373         
    374         flag_data = { 
    375             'flag': flag, 
    376             'time_received': datetime.now(),
    377             'from_team': team,
    378             'from_service': service,
    379         }
    380         
    381         self.unused_flags.append(flag_data)
    382         return True
    383 
    384     @property
    385     def my_state(self):
    386         return self.teams[self.my_id]
    387 
    388     def start_state_receiver(self, host="localhost", port=recv_port):
    389         assert not self.recv_state_socket, 'Server has already been started!'
    390         
    391         class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
    392             def handle(self_server):
    393                 try:
    394                     f = self_server.request.makefile("rb")
    395                     while True:
    396                         self.parse_pushed_state(f.readline())
    397                 except:
    398                     return
    399 
    400         class ThreadedTCPServer(SocketServer.ThreadingMixIn, \
    401             SocketServer.TCPServer):
    402             pass
    403         
    404         self.recv_state_socket = ThreadedTCPServer((host, port), \
    405             ThreadedTCPRequestHandler)
    406         ip, port = self.recv_state_socket.server_address
    407 
    408         # Start a thread with the server -- that thread will then start one
    409         # more thread for each request
    410         self.recv_state_thread = threading.Thread( \
    411             target=self.recv_state_socket.serve_forever)
    412         # Exit the server thread when the main thread terminates
    413         self.recv_state_thread.daemon = True
    414         self.recv_state_thread.start()
    415         
    416         return ip, port
    417 
    418     def stop_state_receiver(self):
    419         if self.recv_state_socket:
    420             self.recv_state_socket.shutdown()
    421             self.recv_state_socket = None
    422 
    423     def find_team(self, needle):
    424         if needle in self.teams.keys():
    425             return needle
    426         
    427         try:
    428             ip = ipaddr.IPv4Address(needle)
    429             teams = filter(lambda x: ip in x[1]['subnet'], self.teams.items())
    430             if teams:
    431                 return teams[0][0]
    432         except:
    433             pass
    434         
    435         team_ids = map(lambda x: (x[0], x[1]['subnet'].ip.exploded.split('.')[2]), \
    436             self.teams.items())
    437         teams = filter(lambda x: needle in x[1], team_ids)
    438         if teams:
    439             return teams[0][0]
    440         
    441         return None
    442         
    443     def start_flag_receiver(self, host="localhost", port=0):
    444         assert not self.recv_flag_server, 'Server has already been started!'
    445         self.recv_flag_server = {}
    446 
    447         class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
    448             def handle(self_server):
    449                 try:
    450                     f = self_server.request.makefile("rb")
    451                     
    452                     f.write("Which team? Number, IP or name\n")
    453                     team = self.find_team(f.readline().strip())
    454                     if team == None:
    455                         f.write('Unknown team!\n')
    456                         return
    457                     
    458                     f.write("Which service? Choices: "+ \
    459                         str(self.services.keys())+"\n")
    460                     service = f.readline().strip()
    461                     if service not in self.services.keys():
    462                         f.write('Unknown service!\n')
    463                         return
    464                     
    465                     while True:
    466                         recv = f.readline()
    467                         if not recv: break
    468                     
    469                         counter_new, counter_old = 0, 0
    470                         for m in re.finditer(self.flag_re, recv):
    471                             if self.add_new_flag(m.group(0), team, service):
    472                                 counter_new += 1
    473                             else:
    474                                 counter_old += 1
    475                         
    476                         if counter_new:
    477                             print counter_new," new flags received!"
    478                         if counter_new or counter_old:
    479                             self_server.request.send(str(counter_new)+ \
    480                             ' new and '+str(counter_old)+' old flags.\n')
    481                         else:
    482                             self_server.request.send('No flags :(\n')
    483                 except Exception, e:
    484                     # Client may have disconnected
    485                     return
    486                 
    487         class ThreadedTCPServer(SocketServer.ThreadingMixIn, \
    488             SocketServer.TCPServer):
    489             pass
    490 
    491         self.recv_flag_server['socket'] = ThreadedTCPServer((host, port), \
    492             ThreadedTCPRequestHandler)
    493         ip, port = self.recv_flag_server['socket'].server_address
    494         self.recv_flag_server['ip'] = ip
    495         self.recv_flag_server['port'] = port
    496 
    497         # Start a thread with the server -- that thread will then start one
    498         # more thread for each request
    499         self.recv_flag_server['thread'] = threading.Thread( \
    500             target=self.recv_flag_server['socket'].serve_forever)
    501         # Exit the server thread when the main thread terminates
    502         self.recv_flag_server['thread'].daemon = True
    503         self.recv_flag_server['thread'].start()
    504 
    505         return ip, port
    506 
    507     def stop_flag_receiver(self):
    508         if self.recv_flag_server:
    509             self.recv_flag_server['socket'].shutdown()
    510             del self.recv_flag_server
    511     
    512     def print_scorboard(self, sort_by='points', reverse=True):
    513         print
    514         print "Scorboard as of tick",str(self.tick)+':'
    515         
    516         teams = sorted(self.teams.items(), key=lambda x: x[1][sort_by], \
    517             reverse=reverse)
    518         cprint('% 25s % 8s % 8s % 7s' % \
    519             ('Team', 'Points', 'Money', 'Chal.'), attrs=['bold'])
    520         for t_id,t in teams:
    521             if t_id == self.my_id:
    522                 cprint('% 25s % 8i % 8i % 7i' % \
    523                     (t_id, t['points'], t['money'], len(t['challenges_solved'])), \
    524                     'blue', 'on_red')
    525             else:
    526                 print '% 25s % 8i % 8i % 7i' % \
    527                     (t_id, t['points'], t['money'], len(t['challenges_solved']))
    528     
    529     def print_risks(self, amount, reverse=False):
    530         print
    531         print "Risks for converion of",amount,"as of tick",str(self.tick)+':'
    532 
    533         risks = sorted(self.get_risks(amount), key=lambda x: x[2], \
    534             reverse=reverse)
    535         cprint('% 25s % 15s % 6s' % \
    536             ('Team', 'Service', 'Risk'), attrs=['bold'])
    537         for t_id,s_id,risk in risks:
    538             have_flags = False
    539             for f in self.unused_flags:
    540                 if f['from_team'] == t_id and f['from_service'] == s_id:
    541                     have_flags = True
    542                     break
    543             
    544             if have_flags:
    545                 cprint('% 25s % 15s % 6.2f' % \
    546                     (t_id, s_id, risk), 'blue', 'on_red')
    547             else:
    548                 print '% 25s % 15s % 6.2f' % (t_id, s_id, risk)
    549     
    550     def print_payoffs(self, amount, reverse=True):
    551         print
    552         print "Payoffs for conversion of",amount,"as of tick",str(self.tick)+':'
    553 
    554         payoffs = sorted(self.get_payoffs(amount), key=lambda x: x[1], \
    555             reverse=reverse)
    556         cprint('% 15s % 8s' % \
    557             ('Service', 'Payoff'), attrs=['bold'])
    558         for s_id,payoff in payoffs:
    559             have_flags = False
    560             for f in self.unused_flags:
    561                 if f['from_service'] == s_id:
    562                     have_flags = True
    563                     break
    564 
    565             if have_flags:
    566                 cprint('% 15s % 8.0f' % \
    567                     (s_id, payoff), 'blue', 'on_red')
    568             else:
    569                 print '% 15s % 8.0f' % (s_id, payoff)
    570     
    571     def print_expectancy(self, amount, cutoff=None):
    572         flags = []
    573         
    574         for f in self.unused_flags:
    575             r = self.get_risks(amount, service=f['from_service'], \
    576                 team=f['from_team'])
    577             p = self.get_payoffs(amount, service=f['from_service'])
    578             
    579             if not cutoff or amount*(1-r)*p > cutoff:
    580                 flags.append((f['flag'], (1-r)*p))
    581         
    582         flags = sorted(flags, key=lambda x: x[1], reverse=True)
    583         
    584         print 
    585         print 'Payoff expectancy for',amount,'as of tick',str(self.tick)+':'
    586         cprint('% 12s % 40s' % \
    587             ('Exp.Points', 'Flag'), attrs=['bold'])
    588         for flag,payoff in flags:
    589             print '% 12.0f % 40s' % (payoff,flag)
    590     
    591     def print_transactions(self, num=20):
    592         #    'time_used': datetime.now(), # Time of usage
    593         #    'flag': 'fooBAR',            # String associated with flag
    594         #    'time_stolen': ...,          # As found in unused_flags
    595         #    'from_team': 'TEAM1_ID',     # As found in unused_flags
    596         #    'from_service': 'SVC1_ID',   # As found in new_flag
    597         #    'action': 'laundering',      # "betrayal" or "laundering"
    598         #    'money_given': 12.3,         # if "laundering", otherwise 0.0
    599         #    'points_gained': 12.3,       # if "laundering" and successfull, 
    600         #                                 # otherwise 0.0 
    601         #    'result': "SUCCESS",         # "SUCCESS", "BAD_FLAG", "BAD_LUCK",
    602         #                                 # "OLD_FLAG" or "OTHER"
    603         #    'msg': 'Flag sub. suc.'
    604         print
    605         print 'Latest transactions:'
    606         print '% 7s % 20s % 10s % 10s % 8s % 20s' % \
    607             ('Time', 'Team', 'Service', 'Result', 'Points', 'Return Message')
    608         for t in self.transactions[num*-1:]:
    609             time = t['time_used'].time()
    610             print '% 7s % 20s % 10s % 10s % 8i % 20s' % \
    611             (str(time.hour)+':'+str(time.minute), \
    612             t['from_team'], t['from_service'], t['result'], \
    613             t['points_gained'], t['msg'])
    614 
    615     
    616     def __getstate__(self):
    617         '''Needed for pickleability... (sockets can not be pickled)'''
    618         new_dict = self.__dict__
    619         new_dict['recv_flag_server'] = None
    620         new_dict['recv_state_thread'] = None
    621         new_dict['recv_state_socket'] = None
    622         new_dict['tick_callback'] = None
    623         new_dict['flag_dissipater_instance'] = None
    624         
    625         return new_dict
    626     
    627     def backup(self, filename='ictf2011.backup'):
    628         pickle.dump(self, open(filename, 'w'))
    629     
    630     @staticmethod
    631     def load(filename='ictf2011.backup'):
    632         return pickle.load(open(filename))
    633     
    634     def stop_flag_dissipater(self):
    635         if self.flag_dissipater_instance:
    636             self.flag_dissipater_instance.stop = True
    637     
    638     def start_flag_dissipater(self):
    639         if not self.flag_dissipater_instance:
    640             return
    641         
    642         class flag_dissipater(threading.Thread):
    643             stop = False
    644             cutoff = 0.75
    645             
    646             def run(self):
    647                 '''Runs until stop is set to True
    648                 Will "sell" all flags with expectancy over cutoff and use 
    649                 all others to compromise other people services
    650                 TODO'''
    651                 while not stop:
    652                     time.sleep(30)
    653                     # TODO
    654                     print 'foo'
    655         
    656         self.flag_dissipater_instance = flag_dissipater()
    657         self.flag_dissipater_instance.start()
    658     
    659     def start(self):
    660         self.start_state_receiver('10.13.147.24',55555)
    661         self.start_flag_receiver('10.13.147.24',2323)
    662     
    663     def submit_flags(self, aimed_risk=0.2, min_payoff=0.70):
    664         while len(self.unused_flags):
    665             f = self.unused_flags.pop()
    666             # calc amount:
    667             amount = 2
    668             calc_risk = self.get_risks(amount, f['from_service'], f['from_team'])
    669             while calc_risk < aimed_risk and amount < self.my_state['money']:
    670                 amount += 1
    671                 calc_risk = self.get_risks(amount, f['from_service'], f['from_team'])
    672             
    673             payoff = self.services[f['from_service']]['P']
    674             if payoff < min_payoff:
    675                 print 'To small payoff',payoff,'using minimum amount'
    676                 amount = 2
    677             
    678             s = self.launder(amount-1, f)
    679             if s[0] == 'OTHER':
    680                 break
    681             if s[0] == 'SUCCESS':
    682                 print "Converted",amount,"CHFs to",s[1],"points. Predicted",self.get_payoffs(amount-1,f['from_service']),s[5],'CHFs left'
    683             if s[0] == 'BAD_LUCK':
    684                 print "Lost",amount,"CHFs, risk was",calc_risk
    685             
    686             if len(self.unused_flags) % 10 == 0:
    687                 print len(self.unused_flags),'to go'
    688     
    689 def client(ip, port, messages):
    690     '''Just for debugging and testing purposes'''
    691     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    692     sock.connect((ip, port))
    693     try:
    694         for message in messages:
    695             sock.send(message)
    696     finally:
    697         sock.close()
    698 
    699 if __name__ == '__main__':
    700     ctf = ictf()
    701     ip, port = ctf.start_state_receiver()
    702     
    703     # Run test data through here!
    704     client(ip, port, '{"services": {"S1": {"P": 58, "C": 3, "R": 10}, "foobar": {"P": 98, "C": 42, "R": 90}, "hogwarts": {"P": 60, "C": 10, "R": 5}}, "tick": 666, "teams": {"A-team": {"subnet": "127.0.0.0/24", "D": 70, "services_compromised_last_tick": ["foobar", "S1"], "money": 395, "N": { "Justice League" : 600 }, "Q": {"S1": 10, "foobar": 10000}, "points": 394, "services_up_last_tick": ["S1", "foobar", "hogwarts"], "challenges_solved": [10, 971, 424242]}, "Justice League": {"subnet": "10.230.230.0/24", "D": 30, "services_compromised_last_tick": ["hogwarts"], "money": 3859, "N": { "foobar" : 6093 }, "Q": {"hogwarts": 1093, "foobar": 10000}, "points": 10293, "services_up_last_tick": ["hogwarts"], "challenges_solved": [30, 5391, 305]}}}'+ \
    705         "\nIf you can read this on your console, that is good :) (test passed)")
    706         
    707     time.sleep(1)
    708     t = ctf.teams['Justice League']
    709     assert t['svc_comp'] == ['hogwarts'], 'Justice League.svc_comp not received'
    710     assert t['svc_up'] == ['hogwarts'], 'Justice League.svc_up not received'
    711     assert t['points'] == 10293, 'Justice League.points not received'
    712     assert t['money'] == 3859, 'Justice League.money not received'
    713     assert t['N']['foobar'] == 6093, 'Justice League.N not received'
    714     
    715     s = ctf.services['foobar']
    716     assert s['C'] == 42/100.0, 'foobar.C not received'
    717     assert s['P'] == 98/100.0, 'foobar.P not received'
    718     assert s['R'] == 90/100.0, 'foobar.R not received'
    719     
    720     ctf.start_flag_receiver()
    721     time.sleep(1)
    722     ip, port = ctf.recv_flag_server['ip'], \
    723         ctf.recv_flag_server['port']
    724     client(ip, port, ["Justice League\n","foobar\n","ABCDEFGHIJKLMNOPQRSTUVWXYZ!\n"])
    725     client(ip, port, ["230\n","S1\n","ABCDEFGHIJKLFOOPQRSTUVWXYZ!\n"])
    726     client(ip, port, ["10.230.230.3\n","hogwarts\n","FOOBARGHIJKLMNOPQRSTUVWXYZ!\n", \
    727         "!!BARFOOBAZ!!\n","BLUBBER!\n","BAR\n"])
    728     time.sleep(1)
    729     assert 'FOO' in ctf.all_flags, 'Flag FOO not recognized'
    730     assert 'BAR' in ctf.all_flags, 'Flag BAR not recognized'
    731     assert 'BAZ' in ctf.all_flags, 'Flag BAZ not recognized'
    732     assert len(ctf.unused_flags) == 3, 'Flags did not make it in unused_flags'
    733     
    734     ctf.stop_flag_receiver()
    735     ctf.stop_state_receiver()
    736     
    737     ctf.backup()
    738     new_ctf = ictf.load()
    739     
    740     assert new_ctf.get_risks(100) == ctf.get_risks(100), 'Dump and reload faulty'
    741     assert new_ctf.get_payoffs(100) == ctf.get_payoffs(100), 'Dump and reload faulty'
    742     del new_ctf
    743     
    744     ctf.print_scorboard()
    745     ctf.print_risks(1000)
    746     ctf.print_payoffs(1000)
    747     ctf.print_expectancy(1000)
    748     
    749     print ctf.launder(100, ctf.get_flag('FOO',remove=True))
    750     assert None == ctf.get_flag('FOO'), 'get_flag(f, remove=True) failed'
    751     assert 'FOO' == ctf.transactions[-1]['flag'], 'Transaction failed'
    752     print ctf.betray(ctf.get_flag('BAR',remove=True))
    753     assert 'BAR' == ctf.transactions[-1]['flag'], 'Transaction failed'
    754     
    755     ctf.print_transactions()
    756     
    757     print 'ok'