Metagaming

Catégorie: Reverse Difficulté: hard Flag: HTB{m4n_1_l0v4_cXX_TeMpl4t35_9fb60c17b0}

Challenge

Description


Pas de description

Analyse

Le programme C++ fourni implémente un système d’instructions. On a donc une liste d’instructions qui sont passées au programme pour être exécutées

Puis une vérification sur l’état des registres final est faite pour savoir si nous avions le bon input

On va pas s’amuser à comprendre ce qui se passe en détail dans le programme mais à voir ce qu’il en ressort en fonction de notre input. Pour ce faire, vu que mon c++ est bancal je vais réimplémenter le code en python à l’aide de ChatGPT pour gagner du temps. On mettra tout dans le fichier chall.py

# La liste d'instructions
INSTRUCTIONS = [(12, 13, 10), (21, 0, 0), (0, 13, 13), (0, 14, 0), (15, 11, 12), (24, 14, 0), (5, 0, 14), (0, 14, 1), (7, 11, 11), (24, 14, 8), (5, 0, 14), (0, 14, 2), (2, 10, 11), (24, 14, 16), (18, 12, 11), (5, 0, 14), (0, 14, 3), (0, 11, 11), (24, 14, 24), (13, 10, 10), (5, 0, 14), (2, 11, 13), (21, 1, 0), (0, 14, 4), (24, 14, 0), (5, 1, 14), (6, 11, 12), (0, 14, 5), (8, 10, 10), (24, 14, 8), (11, 12, 11), (5, 1, 14), (0, 14, 6), (0, 12, 10), (24, 14, 16), (9, 10, 13), (5, 1, 14), (0, 14, 7), (13, 12, 12), (24, 14, 24), (15, 10, 12), (5, 1, 14), (21, 2, 0), (20, 13, 13), (0, 14, 8), (24, 14, 0), (19, 10, 11), (5, 2, 14), (6, 12, 10), (0, 14, 9), (8, 11, 11), (24, 14, 8), (5, 2, 14), (0, 14, 10), (4, 11, 12), (24, 14, 16), (5, 2, 14), (0, 14, 11), (24, 14, 24), (4, 13, 12), (5, 2, 14), (21, 3, 0), (14, 10, 12), (0, 14, 12), (13, 10, 11), (24, 14, 0), (16, 10, 10), (5, 3, 14), (5, 11, 12), (0, 14, 13), (12, 10, 13), (24, 14, 8), (2, 10, 13), (5, 3, 14), (20, 11, 11), (0, 14, 14), (24, 14, 16), (18, 13, 11), (5, 3, 14), (6, 11, 13), (0, 14, 15), (24, 14, 24), (4, 11, 10), (5, 3, 14), (21, 4, 0), (15, 13, 11), (0, 14, 16), (6, 10, 10), (24, 14, 0), (14, 10, 12), (5, 4, 14), (0, 14, 17), (12, 13, 13), (24, 14, 8), (19, 11, 10), (5, 4, 14), (0, 14, 18), (17, 13, 12), (24, 14, 16), (5, 4, 14), (0, 14, 19), (24, 14, 24), (21, 12, 10), (5, 4, 14), (13, 13, 10), (21, 5, 0), (0, 14, 20), (19, 10, 13), (24, 14, 0), (5, 5, 14), (0, 14, 21), (24, 14, 8), (8, 13, 13), (5, 5, 14), (0, 14, 22), (16, 13, 11), (24, 14, 16), (10, 10, 13), (5, 5, 14), (7, 10, 12), (0, 14, 23), (19, 13, 10), (24, 14, 24), (5, 5, 14), (17, 12, 10), (21, 6, 0), (16, 11, 10), (0, 14, 24), (24, 14, 0), (10, 11, 10), (5, 6, 14), (0, 14, 25), (24, 14, 8), (7, 10, 12), (5, 6, 14), (0, 14, 26), (16, 12, 11), (24, 14, 16), (3, 11, 10), (5, 6, 14), (15, 11, 13), (0, 14, 27), (4, 12, 13), (24, 14, 24), (5, 6, 14), (14, 11, 13), (21, 7, 0), (0, 14, 28), (21, 13, 11), (24, 14, 0), (7, 12, 11), (5, 7, 14), (17, 11, 10), (0, 14, 29), (24, 14, 8), (5, 7, 14), (0, 14, 30), (12, 10, 10), (24, 14, 16), (5, 7, 14), (0, 14, 31), (20, 10, 10), (24, 14, 24), (5, 7, 14), (21, 8, 0), (18, 10, 12), (0, 14, 32), (9, 11, 11), (24, 14, 0), (21, 12, 11), (5, 8, 14), (0, 14, 33), (24, 14, 8), (19, 10, 13), (5, 8, 14), (8, 12, 13), (0, 14, 34), (24, 14, 16), (5, 8, 14), (8, 10, 10), (0, 14, 35), (24, 14, 24), (21, 13, 10), (5, 8, 14), (0, 12, 10), (21, 9, 0), (0, 14, 36), (24, 14, 0), (5, 9, 14), (17, 11, 11), (0, 14, 37), (14, 10, 13), (24, 14, 8), (5, 9, 14), (4, 10, 11), (0, 14, 38), (13, 11, 13), (24, 14, 16), (5, 9, 14), (0, 14, 39), (10, 11, 10), (24, 14, 24), (20, 13, 13), (5, 9, 14), (6, 12, 11), (21, 14, 0), (8, 0, 2769503260), (10, 0, 997841014), (19, 12, 11), (2, 0, 4065997671), (5, 13, 11), (8, 0, 690011675), (15, 11, 11), (8, 0, 540576667), (2, 0, 1618285201), (8, 0, 1123989331), (8, 0, 1914950564), (8, 0, 4213669998), (21, 13, 11), (8, 0, 1529621790), (10, 0, 865446746), (2, 10, 11), (8, 0, 449019059), (16, 13, 11), (8, 0, 906976959), (6, 10, 10), (8, 0, 892028723), (10, 0, 1040131328), (2, 0, 3854135066), (2, 0, 4133925041), (2, 0, 1738396966), (2, 12, 12), (8, 0, 550277338), (10, 0, 1043160697), (2, 1, 1176768057), (10, 1, 2368952475), (8, 12, 11), (2, 1, 2826144967), (8, 1, 1275301297), (10, 1, 2955899422), (2, 1, 2241699318), (12, 11, 10), (8, 1, 537794314), (11, 13, 10), (8, 1, 473021534), (17, 12, 13), (8, 1, 2381227371), (10, 1, 3973380876), (10, 1, 1728990628), (6, 11, 13), (8, 1, 2974252696), (0, 11, 11), (8, 1, 1912236055), (2, 1, 3620744853), (3, 10, 13), (2, 1, 2628426447), (11, 13, 12), (10, 1, 486914414), (16, 11, 12), (10, 1, 1187047173), (14, 12, 11), (2, 2, 3103274804), (13, 10, 10), (8, 2, 3320200805), (8, 2, 3846589389), (1, 13, 13), (2, 2, 2724573159), (10, 2, 1483327425), (2, 2, 1957985324), (14, 13, 12), (10, 2, 1467602691), (8, 2, 3142557962), (2, 13, 12), (2, 2, 2525769395), (8, 2, 3681119483), (8, 12, 11), (10, 2, 1041439413), (10, 2, 1042206298), (2, 2, 527001246), (20, 10, 13), (10, 2, 855860613), (8, 10, 10), (8, 2, 1865979270), (1, 13, 10), (8, 2, 2752636085), (2, 2, 1389650363), (10, 2, 2721642985), (18, 10, 11), (8, 2, 3276518041), (15, 10, 10), (2, 2, 1965130376), (2, 3, 3557111558), (2, 3, 3031574352), (16, 12, 10), (10, 3, 4226755821), (8, 3, 2624879637), (8, 3, 1381275708), (2, 3, 3310620882), (2, 3, 2475591380), (8, 3, 405408383), (2, 3, 2291319543), (0, 12, 12), (8, 3, 4144538489), (2, 3, 3878256896), (6, 11, 10), (10, 3, 2243529248), (10, 3, 561931268), (11, 11, 12), (10, 3, 3076955709), (18, 12, 13), (8, 3, 2019584073), (10, 13, 12), (8, 3, 1712479912), (18, 11, 11), (2, 3, 2804447380), (17, 10, 10), (10, 3, 2957126100), (18, 13, 13), (8, 3, 1368187437), (17, 10, 12), (8, 3, 3586129298), (10, 4, 1229526732), (19, 11, 11), (10, 4, 2759768797), (1, 10, 13), (2, 4, 2112449396), (10, 4, 1212917601), (2, 4, 1524771736), (8, 4, 3146530277), (2, 4, 2997906889), (16, 12, 10), (8, 4, 4135691751), (8, 4, 1960868242), (6, 12, 12), (10, 4, 2775657353), (16, 10, 13), (8, 4, 1451259226), (8, 4, 607382171), (13, 13, 13), (10, 4, 357643050), (2, 4, 2020402776), (8, 5, 2408165152), (13, 12, 10), (2, 5, 806913563), (10, 5, 772591592), (20, 13, 11), (2, 5, 2211018781), (10, 5, 2523354879), (8, 5, 2549720391), (2, 5, 3908178996), (2, 5, 1299171929), (8, 5, 512513885), (10, 5, 2617924552), (1, 12, 13), (8, 5, 390960442), (12, 11, 13), (8, 5, 1248271133), (8, 5, 2114382155), (1, 10, 13), (10, 5, 2078863299), (20, 12, 12), (8, 5, 2857504053), (10, 5, 4271947727), (2, 6, 2238126367), (2, 6, 1544827193), (8, 6, 4094800187), (2, 6, 3461906189), (10, 6, 1812592759), (2, 6, 1506702473), (8, 6, 536175198), (2, 6, 1303821297), (8, 6, 715409343), (2, 6, 4094566992), (14, 10, 11), (2, 6, 1890141105), (0, 13, 13), (2, 6, 3143319360), (10, 7, 696930856), (2, 7, 926450200), (8, 7, 352056373), (20, 13, 11), (10, 7, 3857703071), (8, 7, 3212660135), (5, 12, 10), (10, 7, 3854876250), (21, 12, 11), (8, 7, 3648688720), (2, 7, 2732629817), (4, 10, 12), (10, 7, 2285138643), (18, 10, 13), (2, 7, 2255852466), (2, 7, 2537336944), (3, 10, 13), (2, 7, 4257606405), (10, 8, 3703184638), (7, 11, 10), (10, 8, 2165056562), (8, 8, 2217220568), (19, 10, 12), (8, 8, 2088084496), (15, 13, 10), (8, 8, 443074220), (16, 13, 12), (10, 8, 1298336973), (2, 13, 11), (8, 8, 822378456), (19, 11, 12), (8, 8, 2154711985), (0, 11, 12), (10, 8, 430757325), (2, 12, 10), (2, 8, 2521672196), (10, 9, 532704100), (10, 9, 2519542932), (2, 9, 2451309277), (2, 9, 3957445476), (5, 10, 10), (8, 9, 2583554449), (10, 9, 1149665327), (12, 13, 12), (8, 9, 3053959226), (0, 10, 10), (8, 9, 3693780276), (15, 11, 10), (2, 9, 609918789), (2, 9, 2778221635), (16, 13, 10), (8, 9, 3133754553), (8, 11, 13), (8, 9, 3961507338), (2, 9, 1829237263), (16, 11, 13), (2, 9, 2472519933), (6, 12, 12), (8, 9, 4061630846), (10, 9, 1181684786), (13, 10, 11), (10, 9, 390349075), (8, 9, 2883917626), (10, 9, 3733394420), (10, 12, 12), (2, 9, 3895283827), (20, 10, 11), (2, 9, 2257053750), (10, 9, 2770821931), (18, 10, 13), (2, 9, 477834410), (19, 13, 12), (3, 0, 1), (12, 12, 12), (3, 1, 2), (11, 13, 11), (3, 2, 3), (3, 3, 4), (3, 4, 5), (1, 13, 13), (3, 5, 6), (7, 11, 11), (3, 6, 7), (4, 10, 12), (3, 7, 8), (18, 12, 12), (3, 8, 9), (21, 12, 10), (3, 9, 10)]
# Les caractères autorisées par le programme
CHARSET = string.ascii_letters + string.digits + '_'
# L'état des registres final attendus à la fin
REGISTERS = [0x3ee88722, 0x0ecbdbe2, 0x60b843c4, 0x05da67c7, 0x171ef1e9, 0x52d5b3f7, 0x3ae718c0, 0x8b4aacc2, 0xe5cf78dd, 0x4a848edf, 0x0000008f, 0x04180000, 0x00000000, 0x0000000d, 0x00000000]
# Les deux fonctions de rotations de bits
def _rot_r(value, shift):
	return (value >> shift) | (value << (32 - shift))

def _rot_l(value, shift):
	return (value << shift) | (value >> (32 - shift))
# Le programme en lui-même
class Program:
	def __init__(self, flag):
		self.registers = np.zeros(15, dtype=np.uint32)
		self.flag = flag

	def execute_one(self, instruction):
		opcode = instruction[0]
		op0 = instruction[1]
		op1 = instruction[2]

		if opcode == 0:
			self.registers[op0] = self.flag[op1]
		elif opcode == 1:
			self.registers[op0] = op1
		elif opcode == 2:
			self.registers[op0] ^= op1
		elif opcode == 3:
			self.registers[op0] ^= self.registers[op1]
		elif opcode == 4:
			self.registers[op0] |= op1
		elif opcode == 5:
			self.registers[op0] |= self.registers[op1]
		elif opcode == 6:
			self.registers[op0] &= op1
		elif opcode == 7:
			self.registers[op0] &= self.registers[op1]
		elif opcode == 8:
			self.registers[op0] += op1
		elif opcode == 9:
			self.registers[op0] += self.registers[op1]
		elif opcode == 10:
			self.registers[op0] -= op1
		elif opcode == 11:
			self.registers[op0] -= self.registers[op1]
		elif opcode == 12:
			self.registers[op0] *= op1
		elif opcode == 13:
			self.registers[op0] *= self.registers[op1]
		elif opcode == 14:
			pass
		elif opcode == 15:
			pass
		elif opcode == 16:
			self.registers[op0] = _rot_r(self.registers[op0], op1)
		elif opcode == 17:
			self.registers[op0] = _rot_r(self.registers[op0], self.registers[op1])
		elif opcode == 18:
			self.registers[op0] = _rot_l(self.registers[op0], op1)
		elif opcode == 19:
			self.registers[op0] = _rot_l(self.registers[op0], self.registers[op1])
		elif opcode == 20:
			self.registers[op0] = self.registers[op1]
		elif opcode == 21:
			self.registers[op0] = 0
		elif opcode == 22:
			self.registers[op0] >>= op1
		elif opcode == 23:
			self.registers[op0] >>= self.registers[op1]
		elif opcode == 24:
			self.registers[op0] <<= op1
		elif opcode == 25:
			self.registers[op0] <<= self.registers[op1]
		else:
			raise ValueError("Unknown opcode")

	def execute(self, instructions):
		for instruction in instructions:
			self.execute_one(instruction)

On peut faire plusieurs essais en python et en c++ avec le même input pour voir que l’état final des registres est le même donc à priori pas d’erreur d’implémentation, merci ChatGPT

Etude des registres

Pour voir un peu le comportement des registres, j’ai fait une fonction discover qui permet de tester des flags différents avec la possibilité de définir un début commun entre les flags et d’afficher les différences entre l’état des registres avec la fonction highlight_diff

def highlight_diff(text1, text2):
    output = ""
    for i in range(len(text1)):
        if text1[i] == text2[i]:
            output += text2[i]
        else:
            output += Fore.RED + Style.DIM + text2[i] + Style.RESET_ALL
    return output

def discover(fixed):
    fixed_chard = '_'
    missing_n = 35 - len(fixed)
    flag = "HTB{" + fixed + (fixed_chard * missing_n) + "}"
    witness_register = submit_flag(flag.encode())
    print(parse_registers(witness_register) + f' # {flag}')
    for c in range(16):
        garbage = ''.join(random.choices(CHARSET, k=missing_n))
        flag = "HTB{" + fixed + garbage + "}"
        result_registers = submit_flag(flag.encode())
        print(highlight_diff(parse_registers(witness_register), parse_registers(result_registers)) + f' # {flag}')

En faisant ça, on peut soumettre des flags différents et voir si certaines parties des registres réagissent à des changements minimes, exemple avec des flags dont seul le premier caractère est commun :

discover("_")

On voit que le byte 4 du premier registre, autrement dit c’est le premier byte si on lit le registre en little endian, est toujours le même avec la valeur bc,

En essayant avec des flag qui commencent par les 3 mêmes caractères :

discover("_AB")

On voit 2 choses intéressante :

  • Maintenant les 3 derniers bytes du registre n°1 sont fixes

  • Le byte de l’essai d’avant n’a pas changé, c’est toujours bc

On peut donc émettre l’hypothèse qu’en faisant un brute force caractère par caractère on peut vérifier l’état des registres final et en déduire d’abord le premier caractère, puis le second etc…


Script de résolution

chall.py
import string
import numpy as np
import warnings

warnings.filterwarnings('ignore') # Pour éliminer les warnings de numpy

INSTRUCTIONS = [(12, 13, 10), (21, 0, 0), (0, 13, 13), (0, 14, 0), (15, 11, 12), (24, 14, 0), (5, 0, 14), (0, 14, 1), (7, 11, 11), (24, 14, 8), (5, 0, 14), (0, 14, 2), (2, 10, 11), (24, 14, 16), (18, 12, 11), (5, 0, 14), (0, 14, 3), (0, 11, 11), (24, 14, 24), (13, 10, 10), (5, 0, 14), (2, 11, 13), (21, 1, 0), (0, 14, 4), (24, 14, 0), (5, 1, 14), (6, 11, 12), (0, 14, 5), (8, 10, 10), (24, 14, 8), (11, 12, 11), (5, 1, 14), (0, 14, 6), (0, 12, 10), (24, 14, 16), (9, 10, 13), (5, 1, 14), (0, 14, 7), (13, 12, 12), (24, 14, 24), (15, 10, 12), (5, 1, 14), (21, 2, 0), (20, 13, 13), (0, 14, 8), (24, 14, 0), (19, 10, 11), (5, 2, 14), (6, 12, 10), (0, 14, 9), (8, 11, 11), (24, 14, 8), (5, 2, 14), (0, 14, 10), (4, 11, 12), (24, 14, 16), (5, 2, 14), (0, 14, 11), (24, 14, 24), (4, 13, 12), (5, 2, 14), (21, 3, 0), (14, 10, 12), (0, 14, 12), (13, 10, 11), (24, 14, 0), (16, 10, 10), (5, 3, 14), (5, 11, 12), (0, 14, 13), (12, 10, 13), (24, 14, 8), (2, 10, 13), (5, 3, 14), (20, 11, 11), (0, 14, 14), (24, 14, 16), (18, 13, 11), (5, 3, 14), (6, 11, 13), (0, 14, 15), (24, 14, 24), (4, 11, 10), (5, 3, 14), (21, 4, 0), (15, 13, 11), (0, 14, 16), (6, 10, 10), (24, 14, 0), (14, 10, 12), (5, 4, 14), (0, 14, 17), (12, 13, 13), (24, 14, 8), (19, 11, 10), (5, 4, 14), (0, 14, 18), (17, 13, 12), (24, 14, 16), (5, 4, 14), (0, 14, 19), (24, 14, 24), (21, 12, 10), (5, 4, 14), (13, 13, 10), (21, 5, 0), (0, 14, 20), (19, 10, 13), (24, 14, 0), (5, 5, 14), (0, 14, 21), (24, 14, 8), (8, 13, 13), (5, 5, 14), (0, 14, 22), (16, 13, 11), (24, 14, 16), (10, 10, 13), (5, 5, 14), (7, 10, 12), (0, 14, 23), (19, 13, 10), (24, 14, 24), (5, 5, 14), (17, 12, 10), (21, 6, 0), (16, 11, 10), (0, 14, 24), (24, 14, 0), (10, 11, 10), (5, 6, 14), (0, 14, 25), (24, 14, 8), (7, 10, 12), (5, 6, 14), (0, 14, 26), (16, 12, 11), (24, 14, 16), (3, 11, 10), (5, 6, 14), (15, 11, 13), (0, 14, 27), (4, 12, 13), (24, 14, 24), (5, 6, 14), (14, 11, 13), (21, 7, 0), (0, 14, 28), (21, 13, 11), (24, 14, 0), (7, 12, 11), (5, 7, 14), (17, 11, 10), (0, 14, 29), (24, 14, 8), (5, 7, 14), (0, 14, 30), (12, 10, 10), (24, 14, 16), (5, 7, 14), (0, 14, 31), (20, 10, 10), (24, 14, 24), (5, 7, 14), (21, 8, 0), (18, 10, 12), (0, 14, 32), (9, 11, 11), (24, 14, 0), (21, 12, 11), (5, 8, 14), (0, 14, 33), (24, 14, 8), (19, 10, 13), (5, 8, 14), (8, 12, 13), (0, 14, 34), (24, 14, 16), (5, 8, 14), (8, 10, 10), (0, 14, 35), (24, 14, 24), (21, 13, 10), (5, 8, 14), (0, 12, 10), (21, 9, 0), (0, 14, 36), (24, 14, 0), (5, 9, 14), (17, 11, 11), (0, 14, 37), (14, 10, 13), (24, 14, 8), (5, 9, 14), (4, 10, 11), (0, 14, 38), (13, 11, 13), (24, 14, 16), (5, 9, 14), (0, 14, 39), (10, 11, 10), (24, 14, 24), (20, 13, 13), (5, 9, 14), (6, 12, 11), (21, 14, 0), (8, 0, 2769503260), (10, 0, 997841014), (19, 12, 11), (2, 0, 4065997671), (5, 13, 11), (8, 0, 690011675), (15, 11, 11), (8, 0, 540576667), (2, 0, 1618285201), (8, 0, 1123989331), (8, 0, 1914950564), (8, 0, 4213669998), (21, 13, 11), (8, 0, 1529621790), (10, 0, 865446746), (2, 10, 11), (8, 0, 449019059), (16, 13, 11), (8, 0, 906976959), (6, 10, 10), (8, 0, 892028723), (10, 0, 1040131328), (2, 0, 3854135066), (2, 0, 4133925041), (2, 0, 1738396966), (2, 12, 12), (8, 0, 550277338), (10, 0, 1043160697), (2, 1, 1176768057), (10, 1, 2368952475), (8, 12, 11), (2, 1, 2826144967), (8, 1, 1275301297), (10, 1, 2955899422), (2, 1, 2241699318), (12, 11, 10), (8, 1, 537794314), (11, 13, 10), (8, 1, 473021534), (17, 12, 13), (8, 1, 2381227371), (10, 1, 3973380876), (10, 1, 1728990628), (6, 11, 13), (8, 1, 2974252696), (0, 11, 11), (8, 1, 1912236055), (2, 1, 3620744853), (3, 10, 13), (2, 1, 2628426447), (11, 13, 12), (10, 1, 486914414), (16, 11, 12), (10, 1, 1187047173), (14, 12, 11), (2, 2, 3103274804), (13, 10, 10), (8, 2, 3320200805), (8, 2, 3846589389), (1, 13, 13), (2, 2, 2724573159), (10, 2, 1483327425), (2, 2, 1957985324), (14, 13, 12), (10, 2, 1467602691), (8, 2, 3142557962), (2, 13, 12), (2, 2, 2525769395), (8, 2, 3681119483), (8, 12, 11), (10, 2, 1041439413), (10, 2, 1042206298), (2, 2, 527001246), (20, 10, 13), (10, 2, 855860613), (8, 10, 10), (8, 2, 1865979270), (1, 13, 10), (8, 2, 2752636085), (2, 2, 1389650363), (10, 2, 2721642985), (18, 10, 11), (8, 2, 3276518041), (15, 10, 10), (2, 2, 1965130376), (2, 3, 3557111558), (2, 3, 3031574352), (16, 12, 10), (10, 3, 4226755821), (8, 3, 2624879637), (8, 3, 1381275708), (2, 3, 3310620882), (2, 3, 2475591380), (8, 3, 405408383), (2, 3, 2291319543), (0, 12, 12), (8, 3, 4144538489), (2, 3, 3878256896), (6, 11, 10), (10, 3, 2243529248), (10, 3, 561931268), (11, 11, 12), (10, 3, 3076955709), (18, 12, 13), (8, 3, 2019584073), (10, 13, 12), (8, 3, 1712479912), (18, 11, 11), (2, 3, 2804447380), (17, 10, 10), (10, 3, 2957126100), (18, 13, 13), (8, 3, 1368187437), (17, 10, 12), (8, 3, 3586129298), (10, 4, 1229526732), (19, 11, 11), (10, 4, 2759768797), (1, 10, 13), (2, 4, 2112449396), (10, 4, 1212917601), (2, 4, 1524771736), (8, 4, 3146530277), (2, 4, 2997906889), (16, 12, 10), (8, 4, 4135691751), (8, 4, 1960868242), (6, 12, 12), (10, 4, 2775657353), (16, 10, 13), (8, 4, 1451259226), (8, 4, 607382171), (13, 13, 13), (10, 4, 357643050), (2, 4, 2020402776), (8, 5, 2408165152), (13, 12, 10), (2, 5, 806913563), (10, 5, 772591592), (20, 13, 11), (2, 5, 2211018781), (10, 5, 2523354879), (8, 5, 2549720391), (2, 5, 3908178996), (2, 5, 1299171929), (8, 5, 512513885), (10, 5, 2617924552), (1, 12, 13), (8, 5, 390960442), (12, 11, 13), (8, 5, 1248271133), (8, 5, 2114382155), (1, 10, 13), (10, 5, 2078863299), (20, 12, 12), (8, 5, 2857504053), (10, 5, 4271947727), (2, 6, 2238126367), (2, 6, 1544827193), (8, 6, 4094800187), (2, 6, 3461906189), (10, 6, 1812592759), (2, 6, 1506702473), (8, 6, 536175198), (2, 6, 1303821297), (8, 6, 715409343), (2, 6, 4094566992), (14, 10, 11), (2, 6, 1890141105), (0, 13, 13), (2, 6, 3143319360), (10, 7, 696930856), (2, 7, 926450200), (8, 7, 352056373), (20, 13, 11), (10, 7, 3857703071), (8, 7, 3212660135), (5, 12, 10), (10, 7, 3854876250), (21, 12, 11), (8, 7, 3648688720), (2, 7, 2732629817), (4, 10, 12), (10, 7, 2285138643), (18, 10, 13), (2, 7, 2255852466), (2, 7, 2537336944), (3, 10, 13), (2, 7, 4257606405), (10, 8, 3703184638), (7, 11, 10), (10, 8, 2165056562), (8, 8, 2217220568), (19, 10, 12), (8, 8, 2088084496), (15, 13, 10), (8, 8, 443074220), (16, 13, 12), (10, 8, 1298336973), (2, 13, 11), (8, 8, 822378456), (19, 11, 12), (8, 8, 2154711985), (0, 11, 12), (10, 8, 430757325), (2, 12, 10), (2, 8, 2521672196), (10, 9, 532704100), (10, 9, 2519542932), (2, 9, 2451309277), (2, 9, 3957445476), (5, 10, 10), (8, 9, 2583554449), (10, 9, 1149665327), (12, 13, 12), (8, 9, 3053959226), (0, 10, 10), (8, 9, 3693780276), (15, 11, 10), (2, 9, 609918789), (2, 9, 2778221635), (16, 13, 10), (8, 9, 3133754553), (8, 11, 13), (8, 9, 3961507338), (2, 9, 1829237263), (16, 11, 13), (2, 9, 2472519933), (6, 12, 12), (8, 9, 4061630846), (10, 9, 1181684786), (13, 10, 11), (10, 9, 390349075), (8, 9, 2883917626), (10, 9, 3733394420), (10, 12, 12), (2, 9, 3895283827), (20, 10, 11), (2, 9, 2257053750), (10, 9, 2770821931), (18, 10, 13), (2, 9, 477834410), (19, 13, 12), (3, 0, 1), (12, 12, 12), (3, 1, 2), (11, 13, 11), (3, 2, 3), (3, 3, 4), (3, 4, 5), (1, 13, 13), (3, 5, 6), (7, 11, 11), (3, 6, 7), (4, 10, 12), (3, 7, 8), (18, 12, 12), (3, 8, 9), (21, 12, 10), (3, 9, 10)]
REGISTERS = [0x3ee88722, 0x0ecbdbe2, 0x60b843c4, 0x05da67c7, 0x171ef1e9, 0x52d5b3f7, 0x3ae718c0, 0x8b4aacc2, 0xe5cf78dd, 0x4a848edf, 0x0000008f, 0x04180000, 0x00000000, 0x0000000d, 0x00000000]
CHARSET = string.ascii_letters + string.digits + '_

class Program:
	def __init__(self, flag):
		self.registers = np.zeros(15, dtype=np.uint32)
		self.flag = flag

	def execute_one(self, instruction):
		opcode = instruction[0]
		op0 = instruction[1]
		op1 = instruction[2]

		if opcode == 0:
			self.registers[op0] = self.flag[op1]
		elif opcode == 1:
			self.registers[op0] = op1
		elif opcode == 2:
			self.registers[op0] ^= op1
		elif opcode == 3:
			self.registers[op0] ^= self.registers[op1]
		elif opcode == 4:
			self.registers[op0] |= op1
		elif opcode == 5:
			self.registers[op0] |= self.registers[op1]
		elif opcode == 6:
			self.registers[op0] &= op1
		elif opcode == 7:
			self.registers[op0] &= self.registers[op1]
		elif opcode == 8:
			self.registers[op0] += op1
		elif opcode == 9:
			self.registers[op0] += self.registers[op1]
		elif opcode == 10:
			self.registers[op0] -= op1
		elif opcode == 11:
			self.registers[op0] -= self.registers[op1]
		elif opcode == 12:
			self.registers[op0] *= op1
		elif opcode == 13:
			self.registers[op0] *= self.registers[op1]
		elif opcode == 14:
			pass
		elif opcode == 15:
			pass
		elif opcode == 16:
			self.registers[op0] = _rot_r(self.registers[op0], op1)
		elif opcode == 17:
			self.registers[op0] = _rot_r(self.registers[op0], self.registers[op1])
		elif opcode == 18:
			self.registers[op0] = _rot_l(self.registers[op0], op1)
		elif opcode == 19:
			self.registers[op0] = _rot_l(self.registers[op0], self.registers[op1])
		elif opcode == 20:
			self.registers[op0] = self.registers[op1]
		elif opcode == 21:
			self.registers[op0] = 0
		elif opcode == 22:
			self.registers[op0] >>= op1
		elif opcode == 23:
			self.registers[op0] >>= self.registers[op1]
		elif opcode == 24:
			self.registers[op0] <<= op1
		elif opcode == 25:
			self.registers[op0] <<= self.registers[op1]
		else:
			raise ValueError("Unknown opcode")

	def execute(self, instructions):
		for instruction in instructions:
			self.execute_one(instruction)

def _rot_r(value, shift):
	return (value >> shift) | (value << (32 - shift))

def _rot_l(value, shift):
	return (value << shift) | (value >> (32 - shift))
solve.py
import random
from colorama import Fore, Style
from chall import Program, CHARSET, INSTRUCTIONS, REGISTERS

def solve():
    flag = ''
    expected_state = b''.join([register.to_bytes(4, byteorder='little') for register in REGISTERS])
    for i in range(35):
        missing_n = 35 - len(flag) - 1
        for c in CHARSET:
            attempt_flag = "HTB{" + flag + c + ('_' * missing_n) + "}"
            program = Program(attempt_flag.encode())
            program.execute(INSTRUCTIONS)
            current_state = b''.join([int(register).to_bytes(4, byteorder='little') for register in program.registers])
            if expected_state[:i+1] == current_state[:i+1]:
                flag += c
                break
    print(f"Flag: HTB{{{flag}}}")

if __name__ == '__main__':
    solve()

Dernière mise à jour

Cet article vous a-t-il été utile ?