달력

5

« 2024/5 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

이번 문제는 랜섬웨어를 표방한 게임이었다.


문제의 난이도는 어렵지 않았지만 자칫 잘못된 상상을 하게 되면 헤맬수도 있을거 같다는 생각을 했다. 실제 잘못된 상상을 하고 몇번 실행에 옮겼지만 괜히 스스로가 오바하는 기분이 들어 멈췄다.


사실 이 문제보다 Twist1을 먼저 풀었는데 문제 배점 자체도 더 낮을 뿐더러 푼 사람도 훨씬 많아서 너무 어렵게 생각안해도 되겠지 싶어 잘못된 상상을 고쳐 먹었다.



패킹이 되어 있었는데 언패킹 과정은 어렵지 않으니 생략하고 바로 본론으로 넘어가겠다.

그럼 문제풀이를 시작해보겠다.




문제파일을 다운로드받고 해제했을 때 위와 같이 3개의 파일로 구성되어 있었다. 바로 readme.txt 파일을 확인해보았다. 



파일을 복호화하란 메시지였다. 저 괄호안에 있는게 나름 중요한 힌트였다. file 파일이 복호화가 되면 실행파일로 변환된다. 여기서 힌트를 흘려봤으면 복호화해도 또 엉뚱한 짓을 하느라 시간을 소비했을 수도 있다.  



파일을 실행시켜보았다. 위와 같은 메시지를 내보내고 키 값을 입력 받는다. 다행히 코드 배포자가 굉장히 나쁜사람이지만 약속은 지키는 사람이란다. 단, 여기서도 힌트가 존재하는데 잘못된 키를 넣었을 경우 파일이 더욱 훼손되는 것이다(내부 흐름을 보면 알겠지만 자신이 입력한 값이 무엇인지 순서대로 적어놓기만 하면 복호화하는덴 문제없다).



위에 캡쳐는 단순히 화면에 메시지를 출력하고 키 값을 입력받는데 사용된다. 이하 중요하지 않은 부분은 캡쳐를 포함하는 대신 간단히 말로 설명하겠다. 


이후에 내가 입력한 문자열 길이를 저장하고 파일의 내용을 가져오고 머 이런저런 작업을 한다. 뭐 복호화를 하기 위한 사전 작업이랄까나..



이게 핵심 로직이다. 복잡하지 않고 굉장히 심플하다. XOR 연산을 두번에 걸쳐 진행한다. 

내가 입력한 값과 파일의 값을 문자 단위로 XOR 연산하고, 0xFF로 다시 연산한다. 이게 끝이다. 


사실 처음에 딱 이것만 봤을 때 XOR 연산인데 내가 어떻게 원래 값을 확인할 수 있을까 싶었다. XOR 역연산을 하기 위해선 XOR연산에 사용한 값을 알아야 하기 때문에 ..!!  



파일의 특성(사실 특성이랄것도 없지만)과  XOR 연산의 특성을 인지하고 있다면 위의 캡쳐만 봐도 굉장히 쉽게 풀릴 것이다. 


간략히 해결방법을 나열하자면 이렇다. 

1. 파일은 0x00으로 채워진 공간이 존재한다.

2. XOR 연산은 같은 값으로 두번 연산할 경우 원래의 값으로 돌아간다. 


다들 감이 왔을거라 본다. 



위의 캡쳐는 암호화 된 파일의 최하단 부분이다. 딱 보면 일정한 길이로 반복되는 문자열이 존재한다. 이를 위의 XOR 연산을 대입하여 계산하면 어떤 문자가 나타난다. 

이를 이용하면 복호화가 진행되고 복호화가 진행된 후 파일의 확장자를 exe로 변경하고 실행시키면 해답이 나온다.




빠밤!

:
Posted by einai

이번 문제는 ARM 아키텍쳐 기반으로 구성된 문제다.

ARM 기반의 어셈블리어가 낯선 것을 제외하면 어려운 난이도는 아니었다.


그럼 문제를 푸는데 필요한 사전 지식을 최소한으로 설명하고 문제풀이를 진행하겠당.

(관심이 있으신 분들은 추가로 검색해보시는게 좋을거에요!!)




- ARM 설명 부분 -


Registers

R0 ~ R3 : 함수 호출 인자 전달

R0 ~ R12 : 범용 레지스터

R0 : 함수 리턴 값 저장

R13(Stack Pointer) : Stack Pointer

R14(Link Register) : Return address , 모드에 종속적임

R15(Porgram Counter) : Instruction Pointer

CPSR(Program Status Register) : 최근에 실행된 ALU 연산에 대한 정보를 관리하기 위함


Conditions


Instruction




- 문제풀이 부분 - 


항상 해왔던 것처럼 문제에 포함되어 있던 파일들을 확인해보자. 

"HateIntel"파일과 "ReadMe" 파일이 사이좋게 있는 것을 볼 수 있다. 



읽어달라는 파일을 한번 읽어보자. 

이젠 그렇게 큰 기대는 안한다. 나름 익숙해졌나보다. 캌ㅋ카카ㅏ



지령은 패스워드를 찾아라!! 


오케이 접수했다. 하지만 나는 인텔 아키텍처 기반 OS 밖에 가지고 있지 않는다.

이 문제 때문에 이미지를 구하기도 귀찮고 해서 이번판은 디스어셈블러만 확인하여 문제를 풀어보도록 하겠다. 고로, 동작한 캡쳐는 존재하지 않는다.


편리하게 접근하기 위해 문자열 검색부터 해보았다. 


직관적이고 흥미로운 문자열이었다. 흐흐




그 부분으로 들어가서 분석해보기로 하자. 



대충 보니 어떤식으로 화면에 구성될 지 딱 보이지 않는가 ? 간단하니까~ 음하하

Anyway, 간단히 설명을 하자면 


1. CLI 화면에 "Input Key : " 라는 문자열을 출력한다.

2. 사용자의 입력 값을 받는다. 

3. 함수를 호출한다. 


사실 이 이상 설명할 것도 없다.


이 문제에서 나름 핵심이라 할 수 있는 sub_232c 함수를 미리 설명해보자면,

사용자가 입력한 값을 왼쪽으로 쉬프트하고 그 값으로 원본 값을 덮어쓴다. 



위에서 설명한 sub_232c 함수 호출문 중에 나름 핵심 처리 부분이다. 

내가 입력한 문자열 중 한 문자씩 가지고 와 sub_2494 함수로 전달하면 sub_2494 함수는 이를 왼쪽으로 1씩 (<<1) 쉬프트 연산을 진행한다(흐름으로 본다면 Shift란 표현보단 Rotate가 적당하겠다). sub_2494 함수의 역할은 이게 전부니 더 이상의 설명은 안하겠다. 


이러한 쉬프트 연산을 문자열의 각 글자별로 진행하고 입력된 문자수만큼 진행한다. 


이와 같은 연산이 완료되면 함수는 종료되고 메인 구문으로 복귀한다. 



복귀하고 나면 연산을 거친 문자열과 data 세그먼트에 존재하는 문자열과 비교를 시작한다. 이후엔 머 조건을 만족시키면 미션 완료다. 그래서 난 data 세그먼트에 존재하는 문자열을 긁어와서 위에서 진행한 연산을 반대로 진행하는 코딩을 간단히 짜서 동작시켰다. 

(하나하나 해보려했는디 그게 더 시간이 많이 걸릴거 같아서리...)


어째든 미션 성공~!!









:
Posted by einai
2017. 7. 7. 10:25

[문제풀이] reversing.kr - Twist1 Wargames/reversing.kr2017. 7. 7. 10:25

이번엔 Twist1 문제에 대한 풀이를 진행해보겠다.

이 문제는 다행스럽게도 실행 파일과 텍스트 파일이 같이 존재하고 있었다.



어떤 힌트일까라는 부푼 마음으로 텍스트 파일을 열어보았다.



이 실행파일이 x86 윈도우에서 동작한다는 메시지를 주고 있었다.

너무 친절해서 잠시 당황했었다.

(초보자를 배려해줍시당 ㅠㅠ)


어째든 위 메시지를 본 뒤 실행파일을 동작시켜 보았다.


커맨드 창에서 입력 값을 받아 이를 비교하는 프로그램 같았다.

디버거를 켜고 동작시켜 보았다.



음.. 정상적으로 동작하지 않는다.

그래서 실행 파일을 패킹 탐지 프로그램으로 확인해보았다.



음 뭐가 많이 나왔다. 사실 머가 먼지 정확히는 몰랐다. 걍 대충 어떻겠구나 감만 좀 왔다.

그래서 분석을 해보기로 마음 먹었다.


우선 이 프로그램에는 몇 개의 안티 디버깅 기법이 적용되어 있다.

힙 관련 정보를 이용한 안티 디버깅 기법과 ZwQueryInformationProcess 함수 이용 기법, 컨텍스트 정보를 이용한 Hwbp 확인 기법이다.


우선 흐름을 따라 진행을 해보면 힙 관련 정보를 이용한 안티 디버깅 기법이다.

유저모드에서 FS 레지스터는 TEB를 가리키고 있는데 아래 캡쳐에서 보이는 FS:[30]는 PEB 정보를 가리키는 값을 가지고 있다.



위 캡쳐에서는 PEB 정보를 가지고 와서 최종적으로 PEB+0x18 위치의 값을 가지고 오는데 이는 프로세스 힙 포인터이다. 프로세스 힙 정보를 가지고 함수를 호출하게 되는데 이 함수에서 디버거를 탐지한다.



위 캡쳐는 함수 내부인데 간단히 말하자면 Windows Vista 이전 버전과 이후 버전의 Flags 값을 확인하여 디버거가 프로세스에 붙어 있는지를 검증하는 것이다. 위와 같은 안티 디버깅 적용 방식 때문에 ReadMe.txt 파일에 그와 같은 메시지가 적혀 있었던 것 같다(64비트는 Flags 위치가 다름).



위 탐지 로직을 우회해 계속 진행하다보면 한번 더 힙을 이용한 디버깅 탐지 로직이 존재한다.



위 캡쳐에서 빨간색으로 네모로 표시한 부분이 그 검증 로직인데 프로세스에 디버거가 붙음으로 인해 HEAP_TAIL_CHECKING_ENABLED 플래그와 HEAP_FREE_CHECKING_ENABLED 플래그가 설정되어 생성되는 값을 확인하는 로직이다.


이 부분을 우회하면 그리고 그리던 OEP가 나타나게 된다. 짠!@



이 지점에서 덤프를 뜬 뒤 IAT를 수정해주면 앞으로 분석을 좀 더 수월하게 진행할 수 있다. 그 부분은 별도로 추가하지 않겠다.


쭉쭉 진행하다보면 ntdll.dll에서 ZwQueryInformationProcess 함수 주소를 얻어와 이를 이용해 디버거를 탐지하려 한다.



해당 함수의 두번째 인자로 다른 두 값을 준 뒤 응답 값을 비교하는 식으로 진행하게 된다.

인자로 전달되는 값은 ProcessDebugPort, ProcessDebugObjectHandle 값에 해당되고 이를 이용하여 프로세스 디버깅 포트와 디버깅 객체를 확인할 수 있다.


그리고 마지막 디버거 탐지 로직은 컨텍스트 정보를 얻어와 하드웨어 브레이크포인트 설정 여부를 확인하는 것이다.

이제 거의 막바지당 !!!



위는 GetThreadContext 함수를 이용하여 하드웨어 BP 정보를 얻어온다. 그 뒤 이를 확인하여 하드웨어 BP가 설정되어 있을 경우 예외를 발생시키도록 유도한다.


이를 우회하면 드디어 INPUT 값에 입력한 값을 검사하기 시작한다. 검사는 문자 단위로 이루어지며 쉬프트 연산과 XOR 연산을 이용해 진행한다. 이 과정은 생략하도록 하겠다.



이 문제는 그냥 눈으로만 훑어봤던 안티 디버깅 우회 기법과 언패킹을 시도해볼 수 있는 좋은 기회였다. 출제자님 감사합니당.



:
Posted by einai

이번 문제도 역시 아무런 힌트가 없었다.


문제를 실행시켜서 버튼을 눌러보니 아래와 같이 동작했따.



그래서 올리디버거를 켜서 분석을 진행했다.

가장 만만한 문자열 검색을 시작했고 어렵지 않게 발견할 수 있었다.

위 메시지 뿐만 아니라 조건문도 쉽게 발견할 수 있었다.



간단히 설명하면 비트맵의 래스터 데이터를 메모리로 불러와서 리소스 섹션에 있는 값이랑 비교하여 동일할 경우 승리하는 ... 뭐 그런 문제다.


이 문제 역시 처음엔 멍청한 짓을 하며 시간을 보냈다.

메모리로 복사해 온 데이터란 걸 인지하기 전에 조건문을 만족시키기 급급하여 인라인 패칭을 하여 리소스 섹션에 있는 값을 메모리로 다 복사했었다. 이렇게 하면 화면에 보이는 비트맵에 정답이 보일 줄 알았다.


이같은 짓을 몇 번이나 해본 뒤 내가 얼마나 바보같은 짓을 시도했는지 깨닫게 되었다.


그래서 변경한 방법은 리소스 섹션에 존재하는 내용을 복사하여 그림판으로 열어보는 것이었다. 그래서 API 정보를 확인하고 관련 정보를 수집했다.



GetDIBits 함수에서 사용하는 BITMAPINFOHEADER 구조체를 활용하여 관련 정보를 수집할 수 있다. 


출처 : https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx


이 문제에서 신경써야하는 변수명은 biWidth, biHeight, biBitCount, biSizeImage 정도이다.

이는 순서대로 넓이, 높이, 적용된 비트수, 이미지 크기를 나타낸다.




따라서 리소스 섹션의 래스터 데이터 영역을 바이너리로 복사한 뒤 그림판으로 위 구조체가 가리키는 정보대로 생성한 다음에 비트맵 데이터 영역에  덮어써주면 답이 나온다.



처음에 위와 같은 생각을 하고 그림판에 저장을 했는데 아래와 같은 그림이 나와서 내 접근법이 잘못된 줄 알았다(한 곳에 글자가 뭉쳐저서 이상한 그림처럼 나옴).




답을 알고보니 저렇게 뭉쳐서 나와도 답처럼 보이네.. 그래서 모자이크 ...ㅋ


어째든 시간만 엄청 잡아먹고 성취감도 떨어지는 문제였다.

그러나 뭐 누굴 탓하나.. 미숙한 내 잘못이지 제길!!ㅋ


:
Posted by einai

해당 문제는 간단한 게임으로 만들어진 리버싱 문제다.


나같은 초보자한텐 문제에 대한 힌트가 없는게 참 난감하다.

일단 게임을 동작시켜 보았다.




리버싱의 시작은 스트링 검색!! ㅋㅋ 일단 승리와 관련된 문자열을 검색해보았다.



게임을 깼을 때 화면에 나오는 텍스트 문자열을 얻으면 그게 답이겠거니 감이 왔다. 

현 시점에서 문자열은 의미없는 문자열이다.




다시 게임으로 돌아와 저 악당들을 모두 해치우면 게임이 끝나고 의미없는 문자열이 답으로 변경되겠지 싶었다. 근데 한놈당 8발씩이나 맞춰야 하고 접근하면 에너지가 달아죽었다. 


그래서 게임을 좀 편리하게 두가지 꼼수를 부렸다. 


첫번째 꼼수는 에너지 검증 로직 우회를 통해 죽지 않는 것..!!



아무리 맞아도 죽지 않게 변경하였다. 짠!



두번째 꼼수는 얘들이 너무 많아서 한마리만 탄생시키는 것이었다. 

혼란의 시작은 여기서부터였지...



일단 한마리만 나왔다. 그래서 요놈만 죽이면 끝날 줄 알았다.

하지만 이놈을 죽여도 끝나지 않았다. 이때부터 머리속이 헝클어지면서 착각했던 내용 떄문에 문제의 논질을 찾지 못하고 한참을 헤맸다.


결국 검색의 도움을 조금 받았다. ㅠㅠㅠㅠ

악당 한놈 죽일때마다 한글자씩 변경된다는 것!!

난 악당이 없을 때 이벤트가 발생하며 글자가 변경될 것이라 착각했다.

미숙한 분석 실력과 추측을 기반으로 하다보니 ㅠㅠㅠ 



진즉에 검증 로직은 확인했었는데 내가 악당을 한놈으로 만들어버리니 그 부분이 호출이 거의 안되 이해하는데 난항을 겪었다. 제길 ㅋㅋㅋ 꼼수가 오히려 분석을 어렵게 만든 꼴이 되었다.


위 사실을 확인하고 검증 로직으로 BP를 걸고 악당을 한마리씩 처치해보았다. 




악당 인스턴스의 특정 위치에 있는 값을 가지고 와서 승리시 발생하는 문자열과 XOR 연산을 진행한다. 악당 인스턴스의 특정 위치에 있는 값은 4의 배수이고 악당 인스턴스 순서에 따라 승리시 발생하는 문자열과 연산을 진행한다. 


그래서 승리시 발생하는 문자열을 4의 배수 값과 XOR 연산을 진행하면 정답이 나온다.

첫번째 글자 = (0*4) ^ 첫번째 글자

두번째 글자 = (1*4) ^ 두번째 글자 

....... 



:
Posted by einai


 문제를 풀기 전에 ReadMe.txt 파일을 보도록 하자 .




문제의 요지는 프로그램에서 시리얼 넘버가 76876-77776 과 같을 때의 이름을 찾아라.

위의 파일로 보아 끝자리는 p로 끝나며 총 4글자임을 짐작해볼 수 있겠다. 



일단 시리얼 넘버를 넣어놓고 분석을 진행해보자. 

우선 이름을 입력하는 곳에 이름을 입력할 경우 기본적인 검증을 진행한다. 



복잡하지 않으니 그냥 말로만 간단히 적도록 하겠다.

1. 문자열이 4개로 구성되어 있는가 ? 

2. 입력된 글자가 알파벳 소문자로 구성되어 있는가 ?

3. 입력된 문자열 중 중복된 문자가 존재하는가 ?


위 사항을 만족하면 입력된 이름을 기준으로 시리얼과 매칭 작업을 진행하게 된다. 


로직은 첫번째 글자와 세번째 글자가 동일하게 적용되고

두번째 글자와 네번째 글자가 동일하게 적용된다. 



이것이 첫번째/세번째 글자를 이용한 로직 


EBP-20 = (CL & 1) + 5;           - 1 

EBP-1D = ((BL >> 3) & 1) + 5  - 2

EBP-1F = ((CL >> 1) & 1) + 5  - 3

EBP-1E = ((DL >> 2) & 1) + 5  - 4

EBP-1C = ((AL >> 4) & 1) + 5  - 5




이것이 두번째/네번째 글자를 적용한 로직 


BL       = (((BL >> 2) & 1) +1)   - 1

EBP-25 = ((DL >> 3) & 1) + 1   - 2

EBP-24 = ((AL >> 4) & 1) + 1   - 3

EBP-28 = (CL & 1) + 1   - 4

EBP-27 = ((CL >> 1) & 1) + 1   - 5



위에 나온 순서대로 첫번째 글자와 두번째 글자, 세번째 글자와 네번째 글자를 통해 나온 값을 더해서 시리얼 넘버를 생성하고 입력된 시리얼 넘버와 비교한다.

단순 3글자라서 브루트포스도 가능할 거 같긴 한데 (최대 약 3^26승 , 동일 문자열 제외/맞나?- -) 그럼 의미가 없으니 이렇게 진행해보았다.

사실 애플리케이션에 브루트포싱을 자동화돌리는 건 나한텐 의미있을수도 있겠다. 

해본적이 없기 때문에 이 또한 도전이 되리..


위의 경우의 수를 직접 판단해서 답을 작성해도 되지만,

간단히 프로그램 하나짜면 금방 답을 얻을 수 있다.



:
Posted by einai