At first I found that there's an error in password check logic: after each check the value of the right hash (which is read from file before the first check) is overwritten by it's xor with hash of the entered password. So:1) we can enter the same password two times in a row and get the value of the right hash: 0x785e64baad242) we can learn hash of any password we enter (by xor'ing the hashes returned before and after we send the password). I've made a little base of pairs hash: password this way.3) we need to find such set of passwords, that sum modulo 2 of their hashes would be equivalent to the right hash. We can write a system of linear equations modulo 2 to get the set. The i-th equation would get us the i-th bit of the sum:xor(aij and xj) = bi, whereaij - value of bit in i-th position of hash of j-th password, which we'd got on step 2xj - shows us if j-th hash is in the set (1 - it's in the set, 0 - it isn't)bi - value of bit in i-th position of right hashThere would be 48 equations (since there are 48 bit of the hash), so we need to know hashes of only 48 different passwords. If the system is inconsistent we should drop one of the hashes and add some new one (but I've got the solution from the first try)import socketdef get_bit(n, i):    return ((n >> i) & 1) == 1def add_lines(l1, l2):    if len(l1) != len(l2):        raise Exception for i in range(len(l1)):        l1[i] ^= l2[i]def solve(A):  # solves the system of linear equations Z/2Z     for i in range(48):        for k in range(i, 48):            if A[k][i]:                T = A.pop(k)                A.insert(i, T)                break        if not A[i][i]:            return None        for j in range(48):            if i == j:                continue            if A[j][i]:                add_lines(A[j], A[i])hash_base = {}right_hash = int('785e64baad24', 16)base_name = "hashbase" # there are pairs of hash(password):password, got from the server on previous stepfor l in open(base_name, 'rt'):    if len(l) < 14: continue    known_hash, pwd = l.split('\t')    hash_base[int(known_hash.strip(), 16)] = pwd.strip()using_hashes = list(hash_base.keys())[1:49]  # since there are 48 equations we need only 48 vectorsA = []for i in range(48):    A.append([])    for j in range(len(using_hashes)):        A[-1].append(get_bit(using_hashes[j], i))    A[-1].append(get_bit(right_hash, i))print(len(A))solve(A)for i in range(48):    print(bool(A[i][-1]))# now we send the solution to the server and get the flaghh = 0sock = socket.socket()sock.connect(("school.fluxfingers.net", 1513))for i in range(48):    if A[i][-1]:        pwd = hash_base[using_hashes[i]].encode()        sock.send(b'login ' + pwd + b'\n')        ans = sock.recv(4096)        if ans[-1] != '\n':            ans += sock.recv(4096)        print(ans)sock.send(b'getflag\n')print(sock.recv(4096))print(sock.recv(4096))print(sock.recv(4096))The answer from the server:    b'Login successful\n'    b'Okay, sure! Let me grab that flag for you.'    b'\nflag{more_MATH_than_crypto_but_thats_n0t_a_CATegory}\n'P.S. It's interesting, that the complexity of the solution is O(n^2) local CPU operations and O(n) requests to the server, where n - is the length of hash in bits. So even if the hash were 256 or 512 bits long it still would be easy to solve it.