Substraction

Posted on Mon 05 August 2024 in ctf

This is a writeup of the misc challenge Substraction in the n00bz CTF 2024.

ec65f6a9c5d04c29b206d4fa92d3fd29.png

The attached file server.py contained the following code:

import random

n = 696969

a = []
for i in range(n):
    a.append(random.randint(0, n))
    a[i] -= a[i] % 2

print(' '.join(list(map(str, a))))

for turns in range(20):
    c = int(input())
    for i in range(n):
        a[i] = abs(c - a[i])

    if len(set(a)) == 1:
        print(open('/flag.txt', 'r').read())
        break

The code generates 696969 random round integers and stores them in a list a. Then over 20 rounds we must enter integers c which are used to update a by calculating a[i] = abs(c - a[i]).

If we choose c every time so that it is the largest power of two that is smaller than the maximum in a then all values in a logarithmically approach 0. The following code will ensure that all values in a will be equal to 0 after 20 rounds. This way the check len(set(a)) == 1 will be equal to True and server.py will print the flag:

from pwn import *

def largest_power_of_two_less_than(n):
    if n <= 1:
        return 0
    power = n
    power |= power >> 1
    power |= power >> 2
    power |= power >> 4
    power |= power >> 8
    power |= power >> 16
    power |= power >> 32
    return (power + 1) >> 1

con  = remote('challs.n00bzunit3d.xyz', 10265, typ='tcp')
line = con.recvline()

a = [int(x) for x in line.split()]
c = largest_power_of_two_less_than(max(a))

for turn in range(20):
    print(f"[TURN {turn}]\tc: {c}\tmin: {min(a)}\tmax: {max(a)}\t#: {len(list(set(a)))}")
    con.sendline(str(c).encode('utf-8'))

    for i in range(len(a)):
        a[i] = abs(c - a[i])

    if len(set(a)) == 1:
        print("DONE")
        break

    c = largest_power_of_two_less_than(max(a))

    if c == 2:
        c = 1
    if c == max(a):
        c = largest_power_of_two_less_than(max(a) - 1)

line = con.recvline()
print(line)

0e60dbfe823946099602a56e547f8f41.png