달력

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
2017. 7. 9. 15:11

[문제풀이] pwnable.kr - leg Wargames/pwnable.kr2017. 7. 9. 15:11







※ 사전지식 


이 문제에서 필요한 사전지식은 파이프라인과 ARM 아키텍쳐의 두 종류의 모드에 대한 것이다. 


그럼 하나씩 살펴보도록 하겠다. 



파이프라인 


CPU는 클록 신호에 따라 명령을 처리하게 설계되어 있다. 하지만 이 파이프라인이라는 메커니즘을 적용하면 주어진 클록 속도보다 더 빠르게 처리할 수 있게 된다. 기본 명령어는 순차적으로 명령을 처리하기 전에 일련의 종속 단계로 니뉘어져 서로 다른 단계가 병렬로 실행될 수 있다. 


위 내용을 받아드리기 쉽게 좀 구체화시켜 정리해보도록 하겠다. 


보통 파이프라인에 대한 설명을 할 때 우리는 명령 처리 단계를 4단계(CPU 아키텍쳐에 따라 다양함)로 나누어 설명하곤 한다. 


1. Instruction Fetch     : 다음에 실행할 명령어를 읽는다.

2. Instruction Decode  : 명령어를 해석한다.

3. Execute                 : 명령어를 수행한다.

4. Write-Back             : 처리된 결과를 저장한다.


위 순서대로 잘 설명되어 있는 내용을 찾아서 이를 그림에 맞춰 순서대로 정리해보겠다. 





상단의 회색 박스는 실행되기를 기다리는 명령어의 리스트이고 아래의 회색 박스는 실행이 완료된 명령어의 리스트이다. 중간의 하얀 박스가 바로 파이프라인이다. 


명령어들이 어떻게 실행되는지 싸이클 몇 개를 통해 알아보도록 하겠다. 


§ 0 Cycle

 4개의 명령어가 실행되기를 기다린다.

§ 1 Cycle

 녹색 명령어는 메모리로부터 패치된다.

§ 2 Cycle

 녹색 명령어는 디코드된다.

 보라색 명령어는 메모리로부터 패치된다.

§ 3 Cycle

 녹색 명령어는 실행된다. (실제 명령이 실행된다)

 녹색 명령어는 디코드된다.

 파랑 명령어는 페치된다.

§ 4 Cycle

 녹색 명령어는 결과적으로 레지스터나 메모리에 쓰인다.

 녹색 명령어는 실행된다.

 파랑 명령어는 디코드된다.

 빨강 명령어는 패치된다.


이제 파이프라인이란 개념이 어떤건지 좀 명확해졌을거라 믿는다. 

즉, 하나의 명령어를 처리할 수 있는 여러 단계로 나누어 종속된 일련의 명령어들이 처리되는 것에 있어 서로에게 영향을 주지 않는 범위에서 동시에 다른 명령어를 처리할 수 있는 것이다.

예를 들면, ADD 명령어와 MOV 명령어가 존재할 경우 처음 ADD 명령어를 Fetch 한 뒤 ADD 명령어가 다 처리되기도 전에 다시 MOV 명령어가 다시 Fetch 단계로 진입되게 되는 것이다. 


따라서 PC(Program Counter)는 단순히 다음 명령어를 나타내기 보단 Fetch를 진행해야 하는 위치를 나타낸다고 하는게 더 옳은 표현이다(파이프라인 기술이 도입된 아키텍쳐의 경우).




ARM vs Thumb Mode 


이 문제풀이에서 가장 크게 눈여겨봐야 할 것은 아래 두줄로 설명 가능하다. 

ARM : 32bit RISC Machine 

Thumb : 16bit RISC Machine 


아래 레퍼런스에 추가해놓은 사이트(ref.2)에 따라 추가로 설명하자면,

처음 32 bit ARM 만들어 냈을  세상을 지배하던 Embedded system memory 16 bit data line 가진 Memory  시대의 주인공 이었슴다. 32 bit Core라고 해서  시대에 가장 흔히 구할  있고 많이 생산되던 16bit bus line 메모리를 무시할 없는 노릇이었지요.


해서 나타난 게 Thumb 모드라고 한다. 


사전지식 끝!!





※ 문제풀이 



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

이 문제는 위에 사전지식에서 보았듯이 파이프라인과 ARM, Thumb 모드에 관련된 지식, 그리고 약간의 ARM 어셈블러를 해석할 수 있으면 풀 수 있는 문제이다. 


우선 문제를 한번 보자. 



크기상 우선 메인함수만 캡쳐해왔다. 

key1 함수, key2 함수 그리고 key3 함수의 결과 값을 합쳐 내가 입력한 값과 비교하는 문제이다. 


그럼 key? 함수가 어떤 값을 반환하는 지 알아보도록 하자.


우선 key1 함수이다.



현재 pc 레지스터에 있는 값을 r3로 옮기고 난 뒤 반환한다. 

위에서 설명한 파이프라인을 보았으면 이제 pc가 가리키는 값이 0x0008cdc라고 생각하지 않을거라 믿는다. :)


그 다음은 Key2 함수이다. 

 


여기에서는 key+12 위치에 있는 add 명령어와 bx 명령어를 잘 확인해야 한다. bx는 분기명령어 중 하나인데 피연산자의 0번째 비트의 값을 확인하여 1일 경우 Thumb 모드로 진입하게 된다. 그렇게 되면 pc를 계산하는 값이 Thumb 모드에 맞춰 변경되게 될 것이다. 그럼 뭐 key2 함수에서 어떤 값을 반환할 지도 예측 가능하지 않은가?!


그리고 마지막 key3 함수는 



이와 같다. lr은 리턴 주소값을 가지고 있는 레지스터이다. 이것은 직관적이니까 넘어가도록 하겠다. 


그럼 이 값을 다 더한 값이 곧 정답이다.


문제풀이 끝!!!



사실 이 leg 문제까지는 문제를 직접 풀어보려하지 않고 인터넷을 먼저 검색해서 어떤 것이 문제의 핵심인지 파악하고 나서 접근했다. 다시 일을 시작하게 되니 이런 저런 고민하는 시간이 너무 아쉬워서 단순 학습의 개념으로만 만족했었다. 어째든 이 문제까지 풀어본 바(학습해본 바?^^) 여러가지 그러려니 했던 많은 내용들을 구체화시키고 포너블이라는 영역이 어떤것인지 대충 개념은 잡을 수 있었다(기초적인 거에도 쩔쩔매던 놈이-ㅅ-). 


앞으로는 시간있을 때마다 스스로 고민해서 풀어봐야겠다. 

화이팅~~!!




Reference 

[1] Instruction pipelining, https://en.wikipedia.org/wiki/Instruction_pipelining

[2] ARM mode와 THUMB mode, http://recipes.egloos.com/4985218

'Wargames > pwnable.kr' 카테고리의 다른 글

[문제풀이] pwnable.kr - unlink  (0) 2017.07.09
[문제풀이] pwnable.kr - uaf  (0) 2017.07.09
[문제풀이] pwnable.kr - mistake  (0) 2017.07.09
[문제풀이] pwnable.kr - input  (0) 2017.07.09
[문제풀이] pwnable.kr - passcode  (0) 2017.07.09
:
Posted by einai
2017. 7. 9. 15:10

[문제풀이] pwnable.kr - input Wargames/pwnable.kr2017. 7. 9. 15:10








이 문제는 문제풀이를 바로 들어가는 게 설명하기가 더 쉬울 것 같다. 


문제의 요지는 프로그램에 다양한 방법으로 입력 값을 전달하는 방법을 알고있는지에 대해 물어보는 것이다. 

하나씩 나열해보자면 아래와 같다. 

 

1. 메인함수 파라미터로 전달

2. 파일 디스크립터를 이용한 전달 

3. 환경변수를 통한 전달

4. 파일을 통한 전달

5. 네트워크 통신을 통한 전달 


부분적으로 하나씩 알아보자. 


[문제]

위는 메인함수의 파라미터로 전달된 파라미터 중 'A' 번째와 'B' 번째의 값을 비교하는 것이다. 

이는 아래와 같은 방법으로 우회할 수 있다. 


[해답]


위 코드는 파라미터에 요구된 값을 설정하는 부분이다. 

그 다음 문제를 확인해보자. 순착적으로 위에서 언급한 2번과 3번 문제에 해당한다. 


[문제]



여기에는 파이프 함수를 이용하여 파일 디스크립터 쌍을 생성하고 쓰기 파일디스크립터에 문제에서 제시한 값을 작성하고 읽기 파일디스크립터를 문제에서 제시한 0, 2 파일디스크립터로 각각 변경해주는 것이다. 

이는 아래와 같다. 


[해답]


그리고 환경 변수 값을 설정해준 뒤 부모 프로세스에서 문제의 프로그램을 execve 함수를 사용하여 호출한다.


이어서 파일에 값이 존재하는지 비교하는 함수가 존재한다.


[문제]


이는 간단히 파일 쓰기로 우회가 가능하다.

[해답]


그리고 마지막 문제는 소켓 통신 관련 문제이다. 

[문제]


이 문제는 소켓 프로그래밍을 이용하여 오픈된 포트로 접근한 뒤 요구하는 값을 전달해주면 된다. 단 여기서 포트로 사용되는 값은 최초 메인 함수에 전달된 값 중 'C' 번째에 전달된 값을 기반으로 생성된다. 


[해결]


흐름을 잘 조합하면 해당 문제가 클리어될 것이다. 


문제풀이 끝!!!



프로세스에 다양한 방법으로 입력 값을 전달하는 방법에 대해 알아볼 수 있었다.  :)





Reference

[1] Pwnable.kr - input, https://werewblog.wordpress.com/2016/01/11/pwnable-kr-input/

'Wargames > pwnable.kr' 카테고리의 다른 글

[문제풀이] pwnable.kr - unlink  (0) 2017.07.09
[문제풀이] pwnable.kr - uaf  (0) 2017.07.09
[문제풀이] pwnable.kr - mistake  (0) 2017.07.09
[문제풀이] pwnable.kr - leg  (0) 2017.07.09
[문제풀이] pwnable.kr - passcode  (0) 2017.07.09
:
Posted by einai
2017. 7. 9. 15:09

[문제풀이] pwnable.kr - passcode Wargames/pwnable.kr2017. 7. 9. 15:09






※ 사전지식 



PLT(Procedure Linkage Table)


외부 프로시저를 연결해주는 테이블이다. 이는 동적 링크 환경에서 함수를 호출할 때 중요한 역할을 하게 된다.



GOT(Global Offset Table)


이 테이블은 프로시져들의 주소를 가지고 있다. 이 테이블은 PLT가 참조하는 테이블이다. 프로그램에서 외부 프로시저를 호출할 때 이 GOT를 참조해서 해당 주소로 점프하게 된다. 해당 테이블은 함수가 처음으로 호출될 때와 그 외에 호출될 때에 다른 값을 가지고 있다. 즉 런타임시 변경되는 값이다. 




우선 해당 문제에 필요한 지식 정도만 공부해도록 하겠다. 

한번에 이런저런걸 너무 많이 검색해서 보니 정리가 잘 안되는 느낌이다. - ㅅ-/



함수를 호출할 때 흐름을 따라가면서 하나씩 살펴보도록 하겠다.



이는 간단히 printf 함수를 두번 호출한 테스트 프로그램이다. 이를 컴파일(not static way)하여 GDB로 분석해보겠따. 



위는 GDB로 메인 함수부분을 디스어셈블링한 내용이다. 빨간 박스로 쳐진 두개의 함수를 따라가면서 호출되는 방법이 어떻게 되는지 확인해보겠다. 



처음으로 함수가 호출될 경우

PLT영역에서 0x80496bc 주소에 있는 값을 참조하여 점프를 하나 이 값은 PLT+6으로 되돌아오게 된다. 그 뒤에 

reloc_offset으로 0x0을 푸쉬하고 0x80482b0으로 점프한다. 



점프한 뒤에 0x80496b4(link_map 구조체 포인터라고 함)를 푸쉬하고 다시 0x80496b8에 있는 값으로 점프를 한다. 여기서 점프하는 곳이 'dl_runtime_resolve' 함수인데 해당 함수에서 실제 puts 함수의 주소를 GOT 영역에 기록한다.


이 과정이 지나고 두번째 puts 함수를 호출하는 과정을 따라가보겠다. 


위에서는 PLT+6의 위치를 가르켰던 GOT가 다른 값을 가진 것을 확인할 수 있다. 이는 실제 puts 함수의 위치를 나타내는 것을 알 수 있다. 


위 과정을 간단히 말하면, 

최초 함수를 호출할 때 PLT가 가리키는 GOT는 다시 PLT+6를 가리켜 GOT가 함수의 주소를 동적으로 할당받을 수 있도록 해주고 동일한 함수를 두 번 이상 호출하게 될 경우 이와 같은 과정이 생략되며 직접적으로 호출이 가능하다. 


해당 과정을 보다 자세하고 심도있게 파헤친 사이트가 있어 아래에 적어놓았다. 관심있으신 분들은 보길 바란다(세상엔 대단한 사람들이 너무 많아). 



사전지식 끝!! 




※ 문제풀이


이제 본격 문제풀이를 들어가도록 하겠다. 





문제는 위와 같다. 여기서 주요하게 살펴볼 점은 login 함수가 되겠다. 



다들 눈치챘겠지만 scanf 함수의 인자로 int 형 변수가 전달되었는데 & 연산자가 누락되었다. & 연산자가 누락되면 변수의 값이 전달되어 그 값을 주소 삼아 쓰기가 가능하게 된다. 


이제 GDB를 통해 함수를 봐보도록 하자. 

소스코드에서 봐도 알겠지만 welcome() 다음에  login 함수가 시작된다. 


우선 welcome 함수를 봐보도록 하겠다. 



소스코드에서 보면 알겠지만 welcome 함수에서 우리가 입력할 수 있는 글자수는 100글자로 제한되어 있다. 즉 우리는 [ebp-0x70]부터 100글자를 입력할 수 있다. 


여기서 간단히 정리하자면 welcome 함수는 단순히 내가 입력한 값을 100글자 이내로 받고 이를 출력해주는 역할을 한다. 해당 함수가 종료되면 바로 login 함수로 진입하게 된다. 



login 함수에서는 [ebp-0x10]에 위치한 값을 scanf 함수의 두번째 인자로 받는다. 이 값은 입력한 값이 저장되는 곳이다. 일단 여기까지 확인하면 문제를 풀기 위해 살펴볼 것은 다 살펴본 것 같다. 


그럼 이제 동작을 시켜볼까나!?



우선 GDB를 통해 프로그램을 동작시키고 welcome함수에서 문자열을 입력받는 곳에 A*100을 입력하고 login함수에서 scanf의 두번째 인자가 위치한 [ebp-0x10]의 값을 확인하도록 하겠다.



짜잔~


이와 같은 현상은 최초에 welcome 함수에서 scanf 함수로 사용자의 입력 값을 입력받았을 때 사용하는 스택 영역과 login 함수에서 사용하는 스택 영역이 중첩되기 때문에 발생하게 된다. 



이대로 동작시킨 다음에 숫자를 입력할 경우는 값을 입력해보면 Segmentation Fault가 나는 것을 확인할 수 있다. 

(이유를 모르시겠다면 위를 다시 확인해주세용!)


그럼 이제 모든게 끝났다. 

어떤 함수의 GOT를 덮어쓸지 결정해서 그 주소를 지정해주고 실행하고자 하는 주소로 덮어쓰면 된다. 


위 내용을 조합해서 문제를 풀면 정답을 풀 수 있다. 




문제풀이 끝!!


포너블이라는 것 자체에 대한 경험이 없다보니 이리저리 참고하면서 풀었는데도 어렵네요.

문제 자체는 간단해보였는데 베이스가 되어야하는 지식이 여럿 필요한 문제였던 거 같습니다. 


우선 조급해하지 말고 공부한다 생각하고 천천히 접근해야할 것 같습니다. 





Reference

[1] PLT와 GOT 자세히 알기 1, https://bpsecblog.wordpress.com/2016/03/07/about_got_plt_1/

[2] PLT와 GOT 자세히 알기 2(with 'yocto'), https://bpsecblog.wordpress.com/2016/03/09/about_got_plt_2/

'Wargames > pwnable.kr' 카테고리의 다른 글

[문제풀이] pwnable.kr - unlink  (0) 2017.07.09
[문제풀이] pwnable.kr - uaf  (0) 2017.07.09
[문제풀이] pwnable.kr - mistake  (0) 2017.07.09
[문제풀이] pwnable.kr - leg  (0) 2017.07.09
[문제풀이] pwnable.kr - input  (0) 2017.07.09
:
Posted by einai
2017. 7. 7. 12:52

[문제풀이] reversing.kr - CRC1 Wargames/reversing.kr2017. 7. 7. 12:52

일단 문제풀이를 바로 시작해보겠다. 



이 문제는 보는 바와 같이 시작부터 사람을 도발한다.

영리하다고 생각하면 도전해보라는..!! 

(멋드러지게 문제를 격파하고 싶었지만 참 구질구질하게 풀어냈다ㅠㅠ)




해당 로직을 파악하는 건 그리 어렵지 않았다. 


흐름을 간단히 설명하자면, 

하나의 긴 문자열에서 순차적으로 문자를 추출해서 CRC 값의 최하위 바이트 값과 XOR 연산을 한 뒤 이를 인덱스로 하여 CRC 테이블의 값을 가져오고 이를 기존 CRC 값에 쉬프트 연산한 값으로 XOR 연산해준다.  

말이 좀 주저리 주저리하네.. ㅡㅡ ...


어째든 아래와 같은 코드가 될 수 있다.  


unsigned __int64 CRC()

{

byte index = 0;

unsigned __int64 crc = 0;

for (int i = 0; i <= strlen(Strings); i++)

{

index = (Strings[i] ^ (crc & 0xff)) & 0xff;

crc = ((unsigned __int64)crc >> 8ULL);

crc ^= CRCTable[index];

}

return crc;

}


여기에서 crc 변수는 생성되는 값이고, CRCTable 은 미리 생성된 int64 형 값이다. 

Strings은 CRC 알고리즘이 무결성을 확보하기 위한 주체라고 보면 된다. 

즉 Strings 변수에 포함된 문자열에 따라 CRC 값이 변경된다. 



이 문제는 최종 CRC 값과 문자열이 주어지며 이를 역연산해서 원래 삽입된 문자를 찾아내는 것이다. 

문제에서 내가 입력한 값이 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70 번째에 입력되며 변경된 문자열을 통해 CRC 값을 생성하고 해당 값을 비교하게 된다. 



처음에는 어떻게 역연산이 가능할 지 몰라서 고민했다. 

그러다 검색의 유혹을 뿌리치지 못하고 구글의 도움을 얻었다. 


그래서 역연산까지 방법을 얻었지만 브루트포씽의 범위가 굉장히 넓어 다시 한번 깊은 고민에 빠졌다. 

해서 이미 문제를 푸신 분께 약간의 자문을 얻어 실마리를 얻었다. 


그 때 당시에는 힌트를 들어도 아무것도 떠오르는 게 없었는데 시간이 지나니 뭔가 하나 떠오르기 시작했다.


참 희안하게도 시간이 지나면 뭔가 떠오른다. 

그리고 문제를 풀면 그렇게 애먹었는데도 아 이리 간단했구나 싶다.






이제 한문제 남았다 !!





참고하고 도움을 얻은 사이트는 아래에 별도로 표기해놓겠다. 



References

[1] crc 알고리즘과 취약점, http://anch0vy.tistory.com/60

[2] Reversing.kr CRC1, http://blog.naver.com/wlstngus0504/220606858247



:
Posted by einai

이 문제는 이전에 MetroApp 문제의 업그레이드 버전이라고 보면 될 것 같다. 


게임으로 동작되는 터라 낯선 부동소수점 연산을 눈에 익히는 과정과 객체를 분석하는 과정에 애를 먹었다. 

낯선 어셈블리 명령어를 보니 문제가 더욱 더 어려워보였다. 


하지만 막상 문제를 풀었을 때는 핵심을 놓치고 주변 것들에 너무 신경을 쓰고 있었구나 라는 느낌을 받았다. 


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

우선 ReadMe.txt 파일을 먼저 열어보았다.




해당 파일을 보았을 때 두개의 플래그가 존재하고 이를 결합한 뒤 md5 해시 함수를 적용하면 되겠구나 싶었다. 물론 정답은 소문자로 입력하고..!!




이후 애플리케이션을 동작시켜 보았다.




짠 ~ 저 네모난 주인공이 빨간 악마를 총으로 쏴 죽이는 게임이다. 


이를 보았을 때 뭐를 어떻게 해야 답을 맞출까 고민을 했다. 게임 난이도는 엄청나게 어렵다.

활성화되어 있는 악마만 죽일 수 있고 속도도 다양하고 움직이는 방향도 다르다. 




쩜쩜쩜.. 마음을 가다듬고 문제를 분석했다. 



저기에 보이는 빨간 박스에 존재하는 게 첫번째 조건이다. 0xDDB 수만큼 악마를 죽이면 된다. 그래도 이건 양호하다.

두번째 조건은 0x31159cd 마리를 잡아야 한다. - - ;


순간 별의별 생각을 다했다. 악마를 일렬로 내려오게 할까? 모든 악마를 활성화 시켜볼까? 등등..

결국 걍 알아서 죽이게끔 만들어서 동작시켰다. 



흠흠.. 게임할 땐 엄청 빨리 내려오던 악마들이 너무 천천히 내려왔다. 물론 속도는 동일하겠지만 스코어가 올라가는걸 보고 있자니 가슴이 답답했다. 약 1시간? 가량 돌리다보니 첫번째 플래그를 얻을 수 있었다. 


1초에 한마리씩이라고 가정했을 때의 속도랑 거의 유사했다. 

이후 고민을 했다. 


0x31159cd 마리는 약 51468749 초가 걸리고... 이는 857812분이 걸리고.. 이는 14296시간이 걸리고.. 이는 595일이 걸린다. 이 문제를 풀기 위해 약 2년이 안되는 시간을 컴퓨터만 켜놓고 요놈만 바라보고 있을 것인지.. 다른 해결책을 찾을 것인지..!!



결국 다른 해결책을 찾았다. !

걍 정답 로직을 구현해서 돌려버렸당. 그러니 뭐 금방 답이 나왔따 ! 냠냠

이제 CRC 문제들만 남았넹.. 아직 머릿속에 그림이 안그려지는디 어떻게 접근해야 할랑가~



:
Posted by einai

※ 사전지식 


AVR Registers 

총 32개로 구성되어 있으며 R0 ~ R31 로 표기한다. 



AVR 메모리 참조 방식 

AVR은 독특하게도 X, Y, Z 라는 명칭(?)으로 메모리를 참조하는데 이는 각 아래와 같이 레지스터에 의존한다.

X : R27:R26 

Y : R29:R28

Z : R31:R30 




따라서 이런 연산을 하는 어셈블러들을 리버싱하는 동안에 수도 없이 볼 것이다. 



AVR 어셈블리어 

AVR Studio로 디버깅을 하면 친절하게 어셈 명령어 옆에 해당 명령어가 무엇을 하는지 나타낸다. 


추가로 AVR 어셈블리어도 앞에 위치하는 피 연산자(R30, R31)에 연산된 결과가 적용된다. 

즉, ADD R30, R24 -> R30 += R24 와 동일하다.

 

자주 보여졌던 어셈블리어에 대해서만 나열하도록 하겠다. 


RCALL - Relative Call to Subroutine

CPC- Compare with Carry 

CPI- Compare with Immediate

LDI - Load Immediate

LSR – Logical Shift Right

ST - Store Indirect From Register to data space using Index X

ST (STD) - Store Indirect From Register to data space using Index Y

ST (STD) - Store Indirect From Register to data space using Index Z

BRNE - Branch if Not Equal

BREQ - Branch if Equal

BST – Bit Store from Bit in Register to T Flag in SREG

BRCC - Branch if Carry Cleard 

BRTC – Branch if the T Flag is Cleared


사전지식 끝!



그럼 이제 문제풀이를 시작하도록 하겠다. 


이 문제는 사전지식에서 알 수 있듯이 AVR(Atmel AVR) 아키텍쳐 기반 애플리케이션을 리버싱하는 문제이다.

AVR는 임베디드 전용 아키텍쳐라고 하는데 이번 기회에 처음 접해보았다.  


해당 애플리케이션은 AVR Studio와 hapsim 을 이용하여 동적 디버깅을 하면 된다. 


간단히 프로그램들을 설명하자면 AVR Studio는 AVR 디버거이고

hapsim은 AVR 디버거로 분석하는 애플리케이션과 통신 할 수 있는 터미널 역할을 한다.  


AVR Studio를 이용하여 화면을 띄어보도록 하겠다. 




그리고 hapsim을 띄어보겠다. 



hapsim의 경우는 옵션에서 터미널 세팅의 시리얼 인터페이스를 USART1로 설정하면 알아서 통신한다. 

여기서 USART란 ATmel사에서 사용하는 직렬통신 방법이라고 한다. 


이 문제의 핵심(?)은 패스워드 처리 함수(비교함수 말고)에 대한 역연산으로 

이미 저장된 패스워드(비교대상)를 유추하는 것이다. 


이는 꼭 역연산을 하지 않고 브루트포싱을 해서 풀어도 시간이 오래 걸리지 않는다. 


나의 경우는 역함수를 구현하여 문제를 해결하였다. 

처음에 연산 순서를 역으로 배치하는 것 때문에 무지하게 애먹었다. 


논리상 문제가 없을 것이라고 판단했던 곳에서 문제가 발생하고 있었다. 

역시 내 머리는 너무 믿을게 못된다 -ㅅ-


anyway .. 


문제의 흐름을 간단히 살펴보도록 하겠다. 


이는 각 3단계의 반복문으로 구성되어 있으며 각 반복문에서 패스워드를 꼬아 다음 반복문에 전달하는 식으로 진행된다. 반복문에 전달하기 이전에 구성된 배열을 다시 재배치하는 작업도 진행한다. 


이는 아래와 같다(전체를 나타낸 것은 아님). 



위와 같은 재배치 과정이 끝나면 특정 연산과 함께 XOR를 진행하는데 XOR를 할 값을 구하기 위해 인덱스 값을 구하는 함수를 호출한다. 아래의 캡쳐에는 함수호출 부분이 빠져있다(일부로 뺀 것은 아님..)



패스워드를 변환하는 로직은 마지막 반복문을 빼고 이와 같은 순서를 가진다.

마지막 루프는 단순 ROTATE .. 



이를 쭈우욱 이해하고 역연산 함수를 짜면 패스워드가 나타난다 . 

이 패스워드를 이용해서 조금만 쉘을 가지고 놀면 답을 얻을 수 있다.

 

처음 작성했을 때 몇글자가 자꾸 깨져나와서 머리카락을 다 쥐어뽑을뻔 했는데 

결국 문제점을 찾아서 답을 얻을 수 있었다.


문제를 풀어서 마음이 한결 가벼워졌다. !!!!!ㅎ 


문제풀이 끝!




:
Posted by einai

이 문제는 윈도우 앱을 리버싱하는 문제이다. 


이 문제 하나로 윈도우 앱 분석을 어떻게 해야하는지 알겠다라고 깨닫긴 힘들었지만

그래도 접근은 어떻게 해야겠다 라는건 알았다. 


나중에 시간이 되면 더 깊게 공부해봐야겠다. 할때마다 느끼지만 참 공부란게 끝도 없다. 

그래서 이쪽 일이 재미있는 거지만 하루가 너무 짧다. 이것만 할수도 없고 ㅠㅠㅠ



푸념은 이정도로 하고 문제풀이 들어가보도록 하겠다. 

문제를 동적으로 풀기 위해서는 윈도우 8 이상 앱이 동작할 수 있는 환경을 깔아줘야 한다. 


일단 문제를 다운받으면 읽어달라는 놈을 읽어보자. 



이 시점에는 저게 먼 의미가 있을랑가 ~ 일단 음 저렇구나 하고 넘어가보자. 


환경이 구축되었으면 앱을 실행시켜보자. 




동작화면은 이렇다. 패스워드를 입력하고 "OK" 버튼을 누르면 뭐 옳다, 그르다 이런 팝업이 뜬다. 


사실 앱을 설치할 때 주의해야 할 사항이 있다. 

인증서가 만료되어 신뢰할 수 없기 때문에 파워쉘을 켜서 날짜를 조절해주고 설치를 시작한다.


또한, 신뢰되지 않은 사용자가 게시한 소프트웨어를 실행하기 위해서는 아래와 같이 설정해줘야한다.  

간단히 명령어만 나열하자면, 

 > Set-ExecutionPolicy -ExecutionPolicy Unrestricted 

 (캡쳐를 안찍었는데 다시 찍기는 귀찮다 ㅠㅠ)


이런 일련의 과정을 겪고 나면 위처럼 정상적으로 실행될 것이다. 



만약!!!!! 이 모든게 귀찮다. 

환경 구성도 귀찮고 다 싫다! 하시는 분은 appx 파일의 확장자를 zip으로 변경한 뒤 압축을 풀면 된다. 




그럼 뙇!! 하고 실행파일이 생기는데 이거를 머 IDA로 열어서 확인해보면 된다. 

얼떨결에 만지다보니 파일 시그니처가 압축 파일인 걸 알아서 풀어보니 걍 저렇게 있었다. 


어째든 실제 동작 로직을 찾아가기 위해서는 동적분석이랑 같이 해주는게 편하다(for me). 

아직 익숙하지 않아서 그냥 찾아가기가 복잡스러워보인다. 



분석해야 하는 함수에 맞딱뜨리면 저렇게 기이이인 뭔가가 보기만해도 짜증나게 나타난다.

근데 사실 분석해야 하는 부분은 극도의 일부이다. 저것까지 알려주면 보시는 분의 재미를 빼앗아가는 것 같아 하지 않겠다.


진행하다보면 눈에 보이는 트릭이 존재하는데 알아서 잘 판단하시길 바란다. 

너무 얽매이지 않기를!!






극도의 일부를 분석하고 나면 답을 구할 수 있다. 답을 구할 때 힌트가 유용할 것이다. :) 





드디어 100위권 진입





:
Posted by einai

이번 문제는 플래쉬에 있는 액션스크립트를 분석해서 문제를 푸는 것이다. 

바로 문제풀이로 들어가보자~!

플래쉬 로더를 이용하여 플래시 파일을 실행시켜보자. 




위에 캡쳐와 같이 그냥 회색 화면에 입력받는 곳이 딸랑 하나 존재한다. 


프레임은 총 7개가 존재했다. 

디컴파일러를 구동시켜 내부를 살펴보도록 하겠다. 

swf 파일 역시 디컴파일러가 존재하여 검색한 뒤 다운받아 실행시켜 보았다. 




대충 위와 같은 구성으로 되어있다. 


내부의 액션스크립트는 음 인터넷으로 검색해서 봤던 거와는 달랐다. 

감이 잘 안와서 아 또 처음부터 차근차근해야하나 싶은 마음이 들었다. 

물론 공부하면야 좋지만,,, 왠지 그닥 관심이 가지 않았다. ㅠㅠ


그래서 스크립트를 걍 훑어보던 중 





위와 같이 전역 함수 gotoAndPlay()를 보게되었다. 다른 조건문에는 포함되지 않았는데 유독 저기에만 있었다. 

그래서 혹시나 싶어 다른 버튼 이벤트도 확인해보았다. 



여기도 존재했다. 각 입력란에 조건에 맞는 값을 넣어주니 정답이 뙇 !!



음 먼가 얻어걸린 느낌이다. 나중에 시간되면 차근차근 공부해봐야지~~ 나ㅏㅏㅏㅏ중에 ..


나중에 검색해서 알아보니 해당 디컴파일러에 난독화 해제 기능도 존재했고 이를 해제하니 완전 간단한 소스가 나왔다. 쩜쩜쩜...


:
Posted by einai

이번 문제는 ELF 파일구조에 대한 문제였다. 


ELF 파일 리버싱은 익숙하지 않기도 하고, 도대체 익숙한건 뭔지- -,  말로만 듣던 난독화 기법 중 가상머신이 적용된 내용이라 사전학습이 좀 필요했다. 개념을 잡기에 괜찮은 사이트를 하나 발견했는데 아래에 주소를 적어놓았으니 관심있는 사람은 한번쯤 읽어볼만 하다. 


간단히 가상머신 기법에 대한 설명을 하자면,

실행 프로그램안에 별도의 OPCODE를 정의하고 해당 OPCODE가 동작할 수 있는 기반을 마련하여 개발자가 정의한 OPCODE로 프로그램을 동작하는 것이다. 그러기 위해선 일단 사용자가 정의한 OPCODE가 동작할 수 있는 메모리(스택, 레지스터 등)가 필요하고 정의한 OPCODE가 어떻게 동작하는 지에 대한 정의는 필수적이다. 



그럼 문제풀이를 시작하도록 하겠다. 


우선 문제를 동작시키면 아래와 같은 형태로 실행된다. 여러 다른 문제들과 같이 프로그램 내에 정의된 값을 맞추는 것이다. 



내부를 보기 위해 디스에셈블러를 이용하여 한번 열어보았다. 그러니 아래처럼 툴이 정상적으로 캐치를 하지 못한다. 





처음부터 호락호락하지 않은 문제구나 싶었다. :( 

왜 그럴까 싶었는데 프로그램의 EP가 프로그램 헤더에서 정의한 영역을 벗어나서 그런거 같았다. 그래서 현재 EP에 있던 명령어를 실행한 뒤 상태로 만들어놓고 EP를 수정한 뒤 다시 로드하니 아래처럼 인식을 하게 되었다. 




근데 저 위에 로직은 문제 해결에 핵심적인 부분은 아니다. 이는 문제를 생성하기 위한 기반을 만드는 로직인 것 같다. 뭐 메모리를 할당하고 해당 메모리에 별도의 실행 로직을 만들고 파기했다가 어쩌구 저쩌구 한다. 이런저런 행위가 지나고 나면 프로세스는 0x8048000-0x804a000 범위로 IP를 옮기게 된다.  


위에서 언급한 메모리를 덤프떠서 디스어셈블러 툴에서 열어보면 흐름을 파악할 수가 있다. 


대충 핵심만 얘기해보자면 프로세스는 자식 프로세스를 생성하고 생성된 자식 프로세스에서 Input: 에 입력된 값과 OPCODE 셋을 부모 프로세스에게 전달해준다. 이를 전달받은 부모 프로세스는 OPCODE 셋에 특정 연산을 한 뒤 저장하고 이를 활용하여 자신만의 OPCODE를 실행하게 된다. 


아래는 OPCODE 셋이 저장되어 있는 메모리다. 아래의 캡쳐를 간단히 설명하자면 빨간색 박스에 위치한 값이 내가 입력한 값이고 노랑색 박스는 내가 입력한 문자와 추가로 연산이 될 값이 저장되는 위치, 초록색 박스는 실행될 OPCODE의 인덱스(EIP와 같이)가 저장되는 위치이다. 
초록색 박스 뒤에는 연산자와 피연산자가 쭈우우욱 이어져있다. 



아래의 캡쳐는 위의 OPCODE 셋에 정의된 명령어를 실행시키는 반복문이다. 




바로 위 두개의 캡쳐가 이번 문제를 풀기 위한 핵심이다. 위 부분을 잘 분석하면 답을 얻을 수 있다. 



짜잔 ~ 


가상머신 난독화 기법에 대한 개념을 잡아보기에 좋은 문제인 것 같다. 좋은 경험이었다 :)



Reference

[1] Reversing Engineering Virtual Machine Protected Binaries, 

    http://resources.infosecinstitute.com/reverse-engineering-virtual-machine-protected-binaries/

:
Posted by einai
2017. 7. 7. 12:47

[문제풀이] reversing.kr - CSHARP Wargames/reversing.kr2017. 7. 7. 12:47

이번 문제는 닷넷 리버싱 관련 문제이다. 이전에도 닷넷 문제가 있었으나 블로깅은 하지 않았다. 


보통 닷넷 문제는 디컴파일러를 이용해서 문제를 해결한다. 이번 문제도 물론 디컴파일러(JetBrains dotPeek)를 이용했다. 하지만 이번 문제는 디컴파일러로만 해결할 순 없었다. 이와 더불어 디어셈블러(ILDasm.exe), 헥스에디터(Hxd)도 활용했다. 


CSHARP은 여러가지 방법으로 접근해서 문제를 해결할 수 있었다. 


우선 문제가 어떤식으로 출제됬는지 확인한 뒤 다시 논하도록 하겠다. 



프로그램을 실행시키면 위와 같은 화면이 뜨고 문자열을 입력한 뒤 Check를 입력할 경우 "Correct!!" 또는 "Wrong" 팝업을 띄운다. 그럼 디컴파일러를 이용하여 로직을 살펴보도록 하자.


우선 생성자 부분을 확인해보도록 하겠다. 



생성자 부분에서는 "MetMett" 함수 바디에서 MSIL 바이트를 배열 단위로 가져온 뒤 byte[] 에 삽입한다. 그 뒤에 반복문과 특정 값 대입을 실행한 뒤 InitializeComponent 함수를 호출한다. 해당 함수는 화면 구성과 이벤트 핸들러 등록 등 그닥 살펴볼 부분이 없기 때문에 넘어가도록 하겠다. 


MetMett 함수의 몸체는 아래와 같이 디컴파일에 실패한다. 



그 뒤 "MetMetMet" 함수가 존재하는데 프로그램에서 "Check" 버튼을 눌렀을 때 발생하는 함수다. 여기서 어셈블리가 동적으로 생성된다. 닷넷 프로그램에서 사용되는 어셈블리라는 개념은 흔히 사용하는 어셈블리 언어와 개념은 다르나 여기서는 크게 유념치 않아도 될 것 같다. 여기서는 단순히 하나의 동적 함수를 생성한다 정도로만 받아드리면 될 듯 하다(정확한 의미는 아님).



바로 위의 캡쳐를 잘보면 Form1 클래스의 생성자에서 생성된 Form1.bb 배열을 이용하여 메소드를 생성한다. 여기까지만 보면 대충 느낌이 오지 않는가 ?! 


위에서 문제를 풀 수 있는 방법에 대해 언급하다만 내용을 다시 얘기해보겠다. 

크게 두가지 방법으로 접근해서 해당 문제를 해결할 수 있겠다. 


첫 번째, MetMett 함수의 hex 값을 가져와서 수동으로 변조한 뒤 바이너리 파일의 hex 값을 덮어쓰는 것 

두 번째, 디버거를 이용하여 동적 어셈블리가 생성되어 호출될 곳에 BP를 걸고 분석하는 것 


각 방법에 대한 자세한 방법은 따로 기재하지 않겠다. 


우선 첫 번째 방법을 이용하여 hex 값을 수정한 뒤 디스어셈블러를 이용해 불러보면 아래와 같이 나타난다. 



그리고 두번째 방법을 이용하여 접근했을 경우는 이렇다. 



문자열 비교 로직은 여지껏 진행해 온 문제들과 다르지 않다. 한가지 정도 다른데 다들 눈치챘을거라 생각하고 ~슥 





빠밤~~ 미션 컴플릿 !!

:
Posted by einai