#!/usr/bin/env python # -*- coding: utf-8 -*- # # TODO: # - check if everything is filled in (computers, params, preparation) # - improve scoring # - test # - switch to a real SSH/SFTP client to properly handle filenames instructions = { 'si':""" Ustvari dva navidezna računalnika s slikama diskov - SimpleArbiter s sliko diska simpleArbiterDhcp in SmallStudent s sliko diska student-entrance2. Na SimpleArbiter se lahko prijaviš z uporabniškim imenom tester in geslom tester. Na SmallStudent se lahko prijaviš kot root z geslom kaboom. Poskrbi, da bo SmallStudent s SimpleArbiter dostopen na naslovu {testip}. Na SmallStudent ustvari uporabnika {testuser} z geslom {passwd}. Na SmallStudent je nekje v domačem imeniku uporabnika "bilbo" skrita datoteka, ki vsebuje niz {magicstr}. Skopiraj jo v domači imenik {testuser} in poimenuj {dstfile}. Poskrbi, da bo lastnik {testuser}, skupina pa naj ostane nespremenjena. Brati naj jo ima pravico samo lastnik, pisati lastnik in skupina, poganjati nihče. V {dstfile} zamenjaj vse vrstice oblike poXYZlz, kjer so XYZ poljubni znaki, tako, da bo namesto XYZ niz "kaka". Napiši program v poljubnem programskem jeziku, ki kot argument sprejme število B med 0 in 7. Program naj prebere znak s standardnega vhoda. Če je B-ti bit v znaku nastavljen na 1, naj izpiše "ta". Če je B-ti bit nastavljen na 0, naj program izpiše "ti". Program poimenuj {progname} in ga spravi v domači imenik {testuser}. """, 'en': ''' Create two virtual machines - SimpleArbiter using simpleArbiterDhcp as the disk image and SmallStudent using student-entrance2 as its disk. You can log in as tester on SimpleArbiter with the password tester. You can log in as root on SimpleStudent with the password kaboom. Make sure that SmallStudent is accessible from SimpleArbiter on IP {testip}. Create a user {testuser} with the password {passwd} on SmallStudent. There is a file containing {magicstr} hidden somewhere in the home directory of user "bilbo". Copy the into the home directory of user {testuser} and name it {dstfile}. Change the owner to {testuser} and leave the group unchanged. Make sure only the owner has the right to read it, only the owner and group members have the right to write to it and noone has the right to execute it. In {dstfile}, replace all lines of the form poXYZlz where XYZ are arbitrary characters so that XYZ is replaced by "kaka". Write a program in any programming language. The program should accept a single argument, B, which is a number between 0 and 7. It should read a character from standard input and output "ta" if B-th bit in this character is set to 1. If B-th bit is not set, the program should output "ti". Name the program {progname} and place it in the home directory of {testuser}. ''', } # instructions = {'si': 'Potrpite.', 'en': 'Have patience.'} computers = { 'SimpleArbiter': { 'disks': [ { 'name': 'simpleArbiterDhcpGW', }, ], 'network_interfaces': [ { 'network': 'net1', }, { 'network': 'net2', }, ], 'flavor': 'm1.tiny', 'config_drive': False, }, 'SmallStudent': { 'disks': [ { 'name': 'student-entrance2', }, ], 'network_interfaces': [ { 'network': 'net2', }, ], 'flavor': 'm1.tiny', 'config_drive': False, } } networks = { 'net1': { 'public': True, }, 'net2': { 'public': False, } } params_meta = { 'testip': { 'descriptions': { 'si': 'IP SmallStudent', 'en': 'IP SmallStudent', }, 'w': False, 'public': True, 'type': 'IP', 'generated': True, }, 'testuser': { 'descriptions': { 'si': 'Uporabnik na SmallStudent', 'en': 'Username on SmallStudent', }, 'w': False, 'public': True, 'type': 'username', 'generated': True, }, 'passwd': { 'descriptions': { 'si': 'Geslo na SmallStudent', 'en': 'Password on SmallStudent', }, 'w': False, 'public': True, 'type': None, 'generated': True, }, 'magicstr':{ 'descriptions': { 'si': 'Niz v iskani datoteki', 'en': 'String in the file you need to find', }, 'w': False, 'public': True, 'type': None, 'generated': True, }, 'dstfile':{ 'descriptions': { 'si': 'Ciljno ime datoteke', 'en': 'Destination filename', }, 'w': False, 'public': True, 'type': 'filename', 'generated': True, }, 'progname':{ 'descriptions': { 'si': 'Ime programa', 'en': 'Program filename', }, 'w': False, 'public': True, 'type': 'filename', 'generated': True, }, 'pubseed':{ 'descriptions': { 'si': 'Nekaj nepredvidenega', 'en': 'A random seed', }, 'w': False, 'public': True, 'type': None, 'generated': True, }, 'rndseed':{ 'descriptions': { 'si': 'random seed za skrito datoteko', 'en': 'random seed for hiding the file', }, 'w': False, 'public': False, 'type': None, 'generated': True, }, } def task(testip, testuser, passwd, magicstr, dstfile, progname, pubseed): from pexpect import pxssh import random N_TITA = 40 target = pxssh.pxssh() target.login(testip, testuser, passwd) target.sendline('ls -l ~/{}'.format(dstfile)) target.prompt() dst_ls = target.before target.sendline('cat ~/{}'.format(dstfile)) target.prompt() dst_file_contents = target.before target.sendline('ls ~/'.format(dstfile)) target.prompt() home_ls = target.before results = { 'dst_ls': dst_ls, 'dst_file_contents': dst_file_contents, 'home_ls': home_ls, } tita_return = "" r = random.Random(pubseed) for i in range(N_TITA): b = r.randint(0, 7) x = oct(r.randint(37, 127)).replace('o', '') target.sendline('echo -e "\\{}" | ~/{} {}'.format(x, progname, b)) target.prompt() tita_return += target.before results['tita_return'] = tita_return target.logout() return results def gen_params(user_id, params_meta): import random params = dict() r = random.Random(user_id) params['testip'] = kpov_util.IPv4_addr_gen(r, network = '10.94.80.0/19', n_generated=1)[0] params['testuser'] = kpov_util.default_generators['username'](r) params['passwd'] = kpov_util.alnum_gen(r, 8) params['magicstr'] = "".join([r.choice("qwerztlpoQWERTPOL") for i in range(10)]) params['dstfile'] = kpov_util.default_generators['filename'](r) params['progname'] = kpov_util.default_generators['filename'](r) while params['dstfile'] == params['progname']: params['progname'] = kpov_util.default_generators['filename'](r) params['pubseed'] = kpov_util.alnum_gen(r, 8) params['rndseed'] = kpov_util.alnum_gen(r, 8) return params def task_check(results, params): import os import re N_TITA = 40 hints = [] score = 0 hidden_contents = params['magicstr'] r = random.Random(params['rndseed']) for i in range(1000): start = "".join([r.choice(["po", "p0", "no", "ko", "fo", "qo"]) for i in range(20)]) mid = "".join([r.choice("uiasdfghjkyxcvbnm1234567890ASDFGHJKYZXCVBNM") for i in range(60)]) end = r.choice(["lz", "1z", "Iz", "iz", "l2", "I2", "12"]) if start[:2] == "po" and end == "lz": start = "po" mid = "kaka" x = start + mid + end hidden_contents += x + "\r\n" expected_contents = hidden_contents #expected_contents = re.sub(r"^po.*lz\r$", # r"pokakalz\r", # hidden_contents, # re.MULTILINE) expected_contents = "cat ~/{}\r\n".format(params['dstfile']) + expected_contents if results["dst_file_contents"] == expected_contents: score += 3 else: diff_pos = "" for i, c in enumerate(results["dst_file_contents"]): if len(expected_contents) < i or c != expected_contents[i]: start = max(0, i-10) end = min(len(expected_contents), len(results["dst_file_contents"]), i+20) diff_pos = (i, results["dst_file_contents"][start:end]) break hints += ["wrong file contents\n" + str(diff_pos[1])] #hints += ["wrong file contents"] expected_ls = "ls -l ~/{dstfile}\r\n-rw--w---- 1 {testuser} bilbo .*{dstfile}.*\r\n".format(**params) if re.match(expected_ls, results["dst_ls"]): score += 3 else: hints += ["missing file or wrong user/permissions\n" + results["dst_ls"]] if results["home_ls"].find(params['progname']) > -1: score += 2 else: hints += ["missing program"] expected_tita = "" r = random.Random(params['pubseed']) for i in range(N_TITA): b = r.randint(0, 7) x_i = r.randint(37, 127) x = oct(x_i).replace('o', '') expected_tita += 'echo -e "\\{}" | ~/{} {}\r\n'.format(x, params['progname'], b) if x_i & (1 << b): expected_tita += "ta\r\n" else: expected_tita += "ti\r\n" if results["tita_return"] == expected_tita: score += 2 else: #hints += [u"program output incorrect\n" + results["tita_return"] + expected_tita] hints += ["program output incorrect\n" + results["tita_return"]] return score, hints def prepare_disks(templates, task_params, global_params): import random import os #print "Haha!" #print params #print templates d = templates['student-entrance2'] # first create the file contents to make it easyer to check. hidden_contents = task_params['magicstr'] r = random.Random(task_params['rndseed']) for i in range(1000): x = "".join([r.choice(["po", "p0", "no", "ko", "fo", "qo"]) for i in range(20)]) x += "".join([r.choice("uiasdfghjkyxcvbnm1234567890ASDFGHJKYZXCVBNM") for i in range(60)]) x += r.choice(["lz", "1z", "Iz", "iz", "l2", "I2", "12"]) hidden_contents += x + "\n" # create hidden file dir_list = ['Qlipper', 'Thunar', 'blender', 'autostart', 'kazam', 'mc', 'netsurf', 'pulse', 'qupzilla', 'radare2', 'teamviewer', 'texstudio', 'vlc'] ending_list = ['rc', '.conf', ''] start_list = ['net', 'dev', 'doc', 'lib', 'time', 'conf'] r.shuffle(dir_list) file_letters = ["mod", "co"] for potential_dir in dir_list: try: potential_dir = os.path.join('/home/bilbo/.config', potential_dir) d.mkdir(potential_dir) d.chown(1001, 1001, potential_dir) except: pass for i in range(r.randint(2, 20)): rndstr2 = r.choice(start_list) + \ r.choice(file_letters) + r.choice(ending_list) hidden_file_name = os.path.join(potential_dir, rndstr2) d.write(hidden_file_name, hidden_contents) d.chown(1001, 1001, hidden_file_name) file_letters = ["stamp", "", "dev", "re"] hidden_contents = "".join([r.choice("asdfghjkyxcvbnm1234567890 \n") for j in range(10000)]) file_letters = file_letters + ["mod", "co"] # TODO create some additional files write_default_config(templates['simpleArbiterDhcpGW'], global_params) # finish here # rename