워게임/CTFlearn

[CTFlearn] Bite-code - 리버싱 / Python

SecurityMan 2023. 5. 10. 11:00

 

CTFlearn의 아흔한번째 문제

 

이번엔 Medium 난이도의 리버싱 문제이다.

 

뒤로갈수록 뭔가 앞쪽에 있던 문제들이랑 난이도 책정 기준이 다른것 같다.

 

반응형

 

문제 설명을 읽어보면

 

checkNum 이 true 를 리턴하게 하는 input 이 뭐냐고 물어본다.

 

public static boolean checkNum(int);
    descriptor: (I)Z
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=3, args_size=1
         0: iload_0
         1: iconst_3
         2: ishl
         3: istore_1
         4: iload_0
         5: ldc           #2                  // int 525024598
         7: ixor
         8: istore_2
         9: iload_1
        10: iload_2
        11: ixor
        12: ldc           #3                  // int -889275714
        14: if_icmpne     21
        17: iconst_1
        18: goto          22
        21: iconst_0
        22: ireturn
      LineNumberTable:
        line 3: 0
        line 4: 4
        line 5: 9
      StackMapTable: number_of_entries = 2
        frame_type = 253 /* append */
          offset_delta = 21
          locals = [ int, int ]
        frame_type = 64 /* same_locals_1_stack_item */
          stack = [ int ]

 

이게 문제에서 주어지는 checkNum 의 코든데

 

생전 처음보는 형태였다.

 

검색해보니 JAVA Bytecode 였고,

 

이걸 해석할 수 있는 가이드가 위키피디아에 있었다.

 

https://en.wikipedia.org/wiki/List_of_Java_bytecode_instructions

 

List of Java bytecode instructions - Wikipedia

From Wikipedia, the free encyclopedia This is a list of the instructions that make up the Java bytecode, an abstract machine language that is ultimately executed by the Java virtual machine.[1] The Java bytecode is generated from languages running on the J

en.wikipedia.org

 

위키피디아를 보면서 

 

이게 맞는건지 계속 스스로를 의심하는 상태로 문제 해결을 시도했는데

 

얻어걸린건지 플래그를 찾을 수 있었다.

 

크게 세 부분으로 볼 수 있는데

 

         0: iload_0
         1: iconst_3
         2: ishl
         3: istore_1

 

이부분은 input 값을 

 

input << 3 하는 부분이다.

 

         4: iload_0
         5: ldc           #2                  // int 525024598
         7: ixor
         8: istore_2

 

다음으로 이부분은

 

input 값을 525024598 과 xor 하는 부분이다.

 

         9: iload_1
        10: iload_2
        11: ixor
        12: ldc           #3                  // int -889275714
        14: if_icmpne     21

 

마지막으로 여기는

 

input << 3 과 input ^ 525024598 

 

두 값을 xor 해서 

 

그 값이 -889275714 인지 확인하는 부분이다.

 

저 숫자가 대체 뭐지 하고 계산기에 써봤는데

 

 

0xCAFEBABE 였다.

 

대충 코드 돌아가는걸 알았으니

 

파이썬으로 똑같이 구현해주면 된다.

 

그런데 input 에 들어갈 숫자범위가

 

32-bit signed integer

 

즉, -2,147,483,648부터 2,147,483,647까지기 때문에

 

경우의 수가 너무 많다.

 

이걸 그냥 for 문 하나로만 돌리면 시간이 엄청나게 오래걸릴것이다.

 

num = 0x1f4b3d56
flag = 0xcafebabe


for i in range(4294967296):
    tmp1 = i <<3
    tmp2 = num ^ i

    if tmp1 ^ tmp2 == flag:
        print(i)

 

일단 이렇게 의도하는 대로 코드를 대충 짜준 뒤에

 

 

ChatGPT 에게 멀티스레드 코드로 바꿔달라고 던져주면 된다.

 

워게임 풀면서 코드 작성을 고민하지 않으니 너무 편하다.

 

import threading

num = 0x1f4b3d56
flag = 0xcafebabe

result_lock = threading.Lock()
result_found = False
result_value = None

def search(start, end):
    global result_found, result_value
    for i in range(start, end):
        if result_found:
            return
        tmp1 = (i << 3) & 0xffffffff
        tmp2 = num ^ i
        if tmp1 ^ tmp2 == flag:
            with result_lock:
                result_found = True
                result_value = i
                return

# 스레드 개수
num_threads = 8

# 범위를 스레드 개수로 분할
step = 4294967296 // num_threads
ranges = [(i * step, (i+1) * step) for i in range(num_threads)]
ranges[-1] = (ranges[-1][0], 4294967296)

# 스레드 생성 및 실행
threads = []
for start, end in ranges:
    t = threading.Thread(target=search, args=(start, end))
    threads.append(t)
    t.start()

# 모든 스레드 종료 대기
for t in threads:
    t.join()

# 결과 출력
if result_found:
    print("Result: ", result_value)
else:
    print("Result not found.")

 

이렇게 친절하게 주석까지 달아서 코드를 작성해준다.

 

 

코드를 실행시키면 이렇게 숫자가 하나 나오는데

 

이걸 그대로 쓰면 안된다.

 

32-bit signed integer 범위인 -2,147,483,648부터 2,147,483,647를 넘어가기 때문이다.

 

이걸 해당 범위 내로 한정시킬려면

 

-4,294,967,296 를 해주면 된다.

 

해당 값이 문제의 플래그이다.

반응형