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'