Summary
In this challenge, you are given a file named calculator.ljbc. This is an accumulator-based calculator program, meaning it always starts from 0, and each new command immediately modifies the previous value. The input format consists of a combination of operators and operands; for example: +23.
The purpose of the challenge is to find the 6 correct mathematical commands to complete the internal checksum validation at each step without generating an error. After the 6 valid steps are inputted, the secret command “diag” will verify the application’s status and execute string decryption to display the flag.
Vulnerability Analysis
So, simply put, the calculation uses modulo 65521 to prevent the numbers from overflowing. When the program starts, the calculator display shows 0, the internal count starts at 4919, and each operator has its own numerical weight. The program only accepts inputs from 0 to 255, and division must result in an integer; division by 0 is not allowed.
slot0 = 65521
slot2 = "5765712076b155dcbe21fde9"
slot3 = "479d34633443c69c19b5002c1c2ecc66b858745aa2ab15051ae741cf5a5e0f07c10b23ccce6014fc6716c69268d74e"
slot4 = {
["*"] = 43,
["+"] = 17,
["-"] = 29,
["%"] = 79,
["/"] = 61
}
slot5 = 0
slot6 = 4919
The key is that this program decodes a 24-character hex string in little-endian format (read in 2-byte chunks) to produce 6 consecutive target numbers: [25943, 8305, 45430, 56405, 8638, 59901]. The results of steps 1 through 6 must match these target numbers exactly.
function slot10(slot0)
if (slot0 - 1) * 4 + 1 + 3 > #uv0 then
return nil
end
return tonumber(uv0:sub(slot1, slot1 + 1), 16) + tonumber(uv0:sub(slot1 + 2, slot1 + 3), 16) * 256
End
If tried using a brute-force attack, it would require tens of trillions of combinations of 5 operators and 256 possible numbers. This would clearly never be completed if attempted. However, the loophole lies in the program’s validation, which checks the checksum at every step, not just at the end. Therefore, we can use the backtracking + pruning technique. So, as soon as a number in any given step doesn’t match the target, that path is immediately cut off and discarded without needing to proceed to the next step. This method drastically reduces the search space, so the correct key sequence will be found in just a short amount of time.
import struct
MODULO = 65521
TARGET_HEX = "5765712076b155dcbe21fde9"
ENCRYPTED_FLAG = "479d34633443c69c19b5002c1c2ecc66b858745aa2ab15051ae741cf5a5e0f07c10b23ccce6014fc6716c69268d74e"
OPERATOR_WEIGHTS = {
"*": 43,
"+": 17,
"-": 29,
"%": 79,
"/": 61
}
OPERATORS = ['+', '-', '*', '/', '%']
def extract_target_checksums(hex_str):
"""Ekstrak 6 target checksum (16-bit little endian) dari string hex"""
targets = []
for i in range(0, len(hex_str), 4):
if i + 4 <= len(hex_str):
low = int(hex_str[i:i+2], 16)
high = int(hex_str[i+2:i+4], 16)
targets.append(low + high * 256)
return targets
def evaluate(a, b, op):
"""Evaluasi operasi, return None jika tidak valid (pembagian nol atau tidak bulat)"""
if op == '+':
return a + b
elif op == '-':
return a - b
elif op == '*':
return a * b
elif op == '/':
if b == 0:
return None
if a % b != 0: # harus habis dibagi (tanpa sisa)
return None
return a // b
elif op == '%':
if b == 0:
return None
return a % b
return None
def calculate_checksum(step, prev_ans, current_ans, operand, op_weight, state):
"""Hitung checksum (slot6) sesuai formula yang diberikan"""
return ((operand + op_weight * 257 + step * 911 + (prev_ans % MODULO) * 13) % MODULO
* 251 + (current_ans % MODULO) * 17 + state) % MODULO
def update_state(prev_state, slot6, op_weight, step):
"""Update state (uv4) dengan bobot operator"""
return (prev_state * 109 + slot6 * 97 + op_weight * 31 + step * 7) % MODULO
def solve():
targets = extract_target_checksums(TARGET_HEX)
print("Target checksums:", targets)
initial_ans = 0 # uv0
initial_state = 4919 # uv4 mulai dari 4919
solutions = []
def backtrack(step, current_ans, state, path):
# step: 1..6
if step > 6:
solutions.append(path.copy())
return True
# prev_ans untuk langkah ini adalah current_ans (nilai sebelum operasi)
prev_ans = current_ans
for op in OPERATORS:
for operand in range(256): # operand byte (0-255)
res = evaluate(current_ans, operand, op)
if res is None:
continue
op_weight = OPERATOR_WEIGHTS[op]
slot6 = calculate_checksum(step, prev_ans, res, operand, op_weight, state)
# Pruning: langsung bandingkan dengan target langkah ke-step
if slot6 == targets[step - 1]:
# Update state untuk langkah berikutnya
new_state = update_state(state, slot6, op_weight, step)
path.append(f"{op}{operand}") # format desimal, misal "+23"
found = backtrack(step + 1, res, new_state, path)
if found:
return True
path.pop()
return False
# Mulai pencarian
backtrack(1, initial_ans, initial_state, [])
if solutions:
print(f"\nDitemukan {len(solutions)} solusi:")
for sol in solutions:
print(" " + " ".join(sol))
return solutions[0]
else:
print("\nTidak ditemukan solusi.")
return None
def verify_solution(solution, targets):
"""Verifikasi solusi dengan mencetak setiap langkah"""
print("\n" + "=" * 60)
print("VERIFIKASI SOLUSI")
print("=" * 60)
ans = 0
prev_ans = 0
state = 4919
print(f"{'Step':<6} {'Cmd':<10} {'Operand':<8} {'Checksum':<12} {'Target':<12} {'Match':<6}")
print("-" * 70)
for step, cmd in enumerate(solution, 1):
op = cmd[0]
operand = int(cmd[1:]) # desimal
res = evaluate(ans, operand, op)
op_w = OPERATOR_WEIGHTS[op]
# Di sini prev_ans adalah ans (sebelum operasi)
slot6 = calculate_checksum(step, ans, res, operand, op_w, state)
new_state = update_state(state, slot6, op_w, step)
match = (slot6 == targets[step - 1])
print(f"{step:<6} {op:<4} {operand:<8} {slot6:<12} {targets[step-1]:<12} {match}")
prev_ans = ans
ans = res
state = new_state
print("=" * 60)
print(f"Urutan perintah: {' '.join(solution)}")
print("=" * 60)
if __name__ == "__main__":
targets = extract_target_checksums(TARGET_HEX)
solution = solve()
if solution:
verify_solution(solution, targets)

This script will display a sequence of commands. To obtain the flag, enter the commands in that order into the calculator program and type the secret command “diag”; the flag will then appear.

FLAG: JCC{51mpl3_lu4_rev32sin9_1n_c4lclu4tor_pr09ram}