Dreamhack-rev-basic-3 문제 풀이

Posted by : at

Category : reversing



/assets/img/posts/2024-12-01-rev-basic-3/Untitled_5.png


64비트 PE

/assets/img/posts/2024-12-01-rev-basic-3/Untitled_6.png


실행시 사용자 입력값을 받고, 아무렇게나 입력하면 프로그램 종료

/assets/img/posts/2024-12-01-rev-basic-3/Untitled_7.png


IDA에 넣고 돌려보니 non-stripped

/assets/img/posts/2024-12-01-rev-basic-3/Untitled_8.png


Strings subview에서 Input:이 어디에서 나오는지 확인해 보니 아래와 같음

/assets/img/posts/2024-12-01-rev-basic-3/Untitled_9.png


핵심은 sub_140001000() 같으므로 확인

/assets/img/posts/2024-12-01-rev-basic-3/Untitled_10.png


사용자 입력값과 조건을 대조하는 함수

byte_140003000 배열에 대해 입력값 하나하나와 조건문을 통과하는데, 조건 통과하지 못할 경우 0 리턴, 조건을 모두 통과하면 1 리턴

배열의 원소 중 0번째 원소부터 0x18개 즉, 24개만 봄. 즉, 사용자 입력값도 24byte

byte_140003000 배열은 아래와 같음

49 60 67 74 63 67 42 66  80 78 69 69 7B 99 6D 8868 94 9F 8D 4D A5 9D 45


검증 루틴을 방정식 풀이처럼 풀면 아래와 같은 답이 나옴

    byte_140003000[i] - 2*i  == i^input[i]
    byte_140003000[i] - 2*i  == input[i]^i
    (byte_140003000[i] - 2*i) ^ i  == (input[i]^i)^i = input[i]


따라서 파이썬으로 input 배열, 즉 사용자의 입력값에는 무엇이 들어가야 하는지 계산하는 함수를 작성했음

byte_140003000= [73, 96, 103, 116, 99, 103, 66, 102, 128, 120, 105, 105, 123, 153, 109, 136, 104, 148, 159, 141, 77, 165, 157, 69]
input=[] #사용자 입력값# 검증 루틴 역연산for i in range(0,24):
    input.append((byte_140003000[i] - 2*i) ^ i)
print(input)


하지만 저걸로 나온 값을 다짜고짜 주면 문제가 생긴다. 콘솔을 통해 stdin으로부터 값을 받는 행위가 있기 때문에 여기에 단순히 키보드로 숫자를 입력하면 char로 인식되지 int로는 인식되지 않는 게 당연한데, 난 이걸로 삽질했음

주어진 프로그램 내부를 보면 sub_140001210 내부에 이런 부분이 보인다.

/assets/img/posts/2024-12-01-rev-basic-3/Untitled_11.png


_acrt_iob_func(0) 은 stdin 함수의 핵심이다.

정확히는, stdin 함수의 정의가 아래와 같다.

FILE* __cdecl __acrt_iob_func(unsinged);#define stdin(__acrt_iob_func(0))


__acrt_iob_func(0) 은 fd 0인 파일(stdin)의 FILE* 형식의 주소값을 리턴하는 기능을 한다.

이 점을 감안하고 다시 sub_140001210 를 살펴보면 다음과 같은 사실을 알 수 있다.

  1. 내부에서 리턴시 콜하는 sub_1400010D0 은 아래와 같다

    /assets/img/posts/2024-12-01-rev-basic-3/Untitled_12.png

  2. 즉, stdin의 입력값을 받아 내부 버퍼에 저장하는 과정이다
  3. 즉!!!! 내가 입력하는 값은 char로 처리되는 거지 int로 처리되는 게 아님

따라서 나는 역산으로 도출한 값을 char로 바꿔보든가, 안 바꿔지면 파이프를 통해 hex를 보내든가 해야 할 것 같음

그런데 이건 플래그 값 찾는 거니까 아마 웬만하면 문자열일 것

/assets/img/posts/2024-12-01-rev-basic-3/Untitled_13.png


정답이었다


따라서 플래그는 I_am_X0_xo_Xor_eXcit1ng 인데,

NULL 문자는 왜 필요한가?

왜냐하면 C 언어로 쓰인 프로그램에서 문자열 입력을 받으면, 문자열 맨 끝에 자동으로 NULL을 덧붙여 메모리에 저장함으로써 문자열의 끝을 표현하기 때문이다.

아무튼 문제 풀이 완료!

/assets/img/posts/2024-12-01-rev-basic-3/Untitled_14.png



About TouBVA
TouBVA

A Security Researcher, now concentrating on Security Consulting.

Email : touBVa@gmail.com

Website : https://toubva.github.io