Para resolver esse desafio primeiro a gente deve dar um jeito de entender o código mian.py, ele obviamente é quem deixa a flag igual à saída do output.txt, e minha abordagem para entender esse código foi renomear todas as variáveis.
main.py:
import random as rand
#Setando a seed.
base20 = int('1665663c', 20)
rand.seed(base20)
#Abrindo o arquivo .txt
arquivoBin = bytearray(open('flag.txt', 'rb').read())
R = '\r'r'\r''r''\\r'r'\\r\r'r'r''r''\\r'r'r\r'r'r\\r''r'r'r''r''\\r'r'\\r\r'r'r''r''\\r'r'rr\r''\r''r''r\\'r'\r''\r''r\\\r'r'r\r''\rr'
lista9 = [
b'arRRrrRRrRRrRRrRr',
b'aRrRrrRRrRr',
b'arRRrrRRrRRrRr',
b'arRRrRrRRrRr',
b'arRRrRRrRrrRRrRR'
b'arRRrrRRrRRRrRRrRr',
b'arRRrrRRrRRRrRr',
b'arRRrrRRrRRRrRr'
b'arRrRrRrRRRrrRrrrR',
]
func1L = lambda param: bytearray([pos + 1 for pos in param])
func2L = lambda param: bytearray([pos - 1 for pos in param])
def func(hex):
for id in range(0, len(hex) - 1, 2):
hex[id], hex[id + 1] = hex[id + 1], hex[id]
for list in range(1, len(hex) - 1, 2):
hex[list], hex[list + 1] = hex[list + 1], hex[list]
return hex
listaF = [func, func1L, func2L]
listaF = [rand.choice(listaF) for pos in range(128)]
def rand(arr, ar):
for r in ar:
arr = listaF[r](arr)
return arr
def funcModificada(arr, ar):
ar = int(ar.hex(),17)
for r in arr:
ar += int(r, 35)
return bytes.fromhex(hex(ar)[2:])
arrRRrrrrRRrRRRrRrRRRRr = rand(arquivoBin, R.encode())
arrRRrrrrRRrRRRrRrRRRRr = funcModificada(lista9, arrRRrrrrRRrRRRrRrRRRRr)
print(arrRRrrrrRRrRRRrRrRRRRr.hex())
Com as variáveis renomeadas fica bem mais fácil entender o que esse código faz, vale notar que o código reutiliza variáveis em certos momentos, mas isso não faz uma grande diferença para nós. Olhando o código podemos ver que o código pega a flag e faz uma série de operações em cima dela.
A função rand recebe como parâmetro a flag e uma string convertida pelo .encode(), essa função tem acesso à uma lista que contém 3 funções, em que 2 funções servem para aumentar ou diminuir 1 de cada valor da flag (func1L e func2L) e a outra troca as posições da flag. Note que quando eu me refiro à flag eu estou me referindo ao seu valor no bytearray gerado com a função open. Com acesso à essas 3 funções, a função rand usa um for para percorrer o segundo parâmetro, e com isso é usado a variável do for para escolher qual função da lista de função será usado na flag. Por fim é retornado a flag.
A função funcModificada recebe 2 parâmetros, o primeiro é uma lista com 9 strings de bytes, e o segundo é o bytearray da flag. A função começa convertendo o bytearray para um inteiro em base 17, e em seguida faz um for percorrendo o primeiro parâmetro e converte cada valor da lista para base 35 e soma com o inteiro gerado na base 17. Por fim retorna o resultado de todas as somas em bytes.
Resolução
Para resolver precisamos fazer todo o processo inverso. Primeiramente setamos a seed do random para ficar igual à seed no código main.py, porque com a mesma seed qualquer valor gerado aleatóriamente no nosso computador será igual aos valores gerados aleatorimente na geração do output.txt. Depois precisamos criar as variáveis que não são modificadas e que são usadas nas funções, elas são a string R (que é usada com o .encode()), a lista9 (que contém as strings de bytes) e abrimos a flag com a função open.
Após criarmos as variáveis, precisamos modificar as funções. A função func1L nós só preisamos modificar o + 1 para - 1, a função func2L segue a mesma lógica, só precisamos modificar o - 1 para + 1, e a função func só precisamos trocar a ordem dos for.
A função funModificada é a mais complicada, preisamos transformar nosso bytearray em inteiro (usando base 16 pelo output.txt estar em hexadecimal), após isso subtraímos o valor das strings de bytes convertidas em base 35 do nosso inteiro, e agora a função complica, precisamos fazer o processo inverso de converter para base 17 e para isso precisamos fazer diversas divisão por 17 e vamos salvando o resto até o valor ser menor do que 17, no fim verificamos se sobrou algum valor no inteiro e salvamos ele. O método escolhido para resolver isso foi usando uma string (por ser mais fácil de concatenar) e um while que ficará em loop até o inteiro ficar menor que 17. No while é verificado se o resto por 17 esta entre 10 e 16 para caso isso acontece nós colocamos o valor correspondente em hexadecimal e caso contrário é só colocar o resto, depois fazemos o inteiro ser ele mesmo dividido por 17. Após o while verificamos se sobrou algo no inteiro e no fim invertemos a string e retornamos ela convertida para bytes.
A função rand continua a mesma coisa, pois modificamos as funções que ela utiliza acima.
import random as r
#Converte o inteiro '1665663c' para um inteiro na base 20 (0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i,j)
base20 = int('1665663c', 20)
r.seed(base20)
R = '\r'r'\r''r''\\r'r'\\r\r'r'r''r''\\r'r'r\r'r'r\\r''r'r'r''r''\\r'r'\\r\r'r'r''r''\\r'r'rr\r''\r''r''r\\'r'\r''\r''r\\\r'r'r\r''\rr'
lista9 = [
b'arRRrrRRrRRrRRrRr',
b'aRrRrrRRrRr',
b'arRRrrRRrRRrRr',
b'arRRrRrRRrRr',
b'arRRrRRrRrrRRrRR'
b'arRRrrRRrRRRrRRrRr',
b'arRRrrRRrRRRrRr',
b'arRRrrRRrRRRrRr'
b'arRrRrRrRRRrrRrrrR',
]
flag = bytearray(open('output.txt', 'rb').read())
def revFuncModificada(arr, ar):
ar = int(ar,16)
for r in arr:
ar -= int(r, 35)
valor3 = ''
while ar >= 17:
if str(ar%17) == '16':
valor3 += '1f'
elif str(ar%17) == '15':
valor3 += 'f'
elif str(ar%17) == '14':
valor3 += 'e'
elif str(ar%17) == '13':
valor3 += 'd'
elif str(ar%17) == '12':
valor3 += 'c'
elif str(ar%17) == '11':
valor3 += 'b'
elif str(ar%17) == '10':
valor3 += 'a'
else:
valor3 += str(ar%17)
ar = ar//17
if str(ar) == '16':
valor3 += '1f'
elif str(ar) == '15':
valor3 += 'f'
elif str(ar) == '14':
valor3 += 'e'
elif str(ar) == '13':
valor3 += 'd'
elif str(ar) == '12':
valor3 += 'c'
elif str(ar) == '11':
valor3 += 'b'
elif str(ar) == '10':
valor3 += 'a'
else:
valor3 += str(ar)
return bytes.fromhex(valor3[::-1])
func1L = lambda param: bytearray([pos - 1 for pos in param])
func2L = lambda param: bytearray([pos + 1 for pos in param])
def func(hex):
for list in range(1, len(hex) - 1, 2):
hex[list], hex[list + 1] = hex[list + 1], hex[list]
for id in range(0, len(hex) - 1, 2):
hex[id], hex[id + 1] = hex[id + 1], hex[id]
return hex
listaF = [func, func1L, func2L]
listaF = [r.choice(listaF) for pos in range(128)]
def rand(arr, ar):
for r in ar:
arr = listaF[r](arr)
return arr
fg = revFuncModificada(lista9, flag)
fg = rand(bytearray(fg), R.encode())
print(fg)