달력

2

« 2025/2 »

  • 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
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