zj3t

email: euntaejang@gmail.com

Latest Posts
이번 포스팅은 저번에 말한 것 처럼 serial을 생성하는 알고리즘을 분석해보도록 하겠습니다.



저번에 프로그램실행화면 기억하시나요?? 


이런화면 이였습니다. 이 위의 두 개의 사진은 각각 About과 Check를 눌렀을 때 호출되는 함수의 부분입니다.

우리는 About함수는 필요없으니 Check함수만 알면됩니다.

제가 어떻게 Check함수를 찾았냐 하면 우리가 name에 대한 serial을 인증하려면 반드시 Check를 눌러야합니다. 따라서 저번 포스팅에 했던, serial을 찾으려했던 모든 부분이 다 Check를 누르면 호출되는 함수의 내부에 있는 조금한 함수입니다. 

이 Check함수를 찾은 목적은 알고리즘을 어디서 생성하는지 알지못하기 때문에 Check의 시작부분부터 차근차근 리버싱해보기 위함입니다.


이런 부분을 찾았습니다. 입력한 name, abcd는 각각 아스키코드로 61,62,63,64가 됩니다.

그리고 밑에 vbaFreeStr함수와 vbaVarAdd함수가 보입니다. FreeStr함수는 별게 없었습니다. 핵심은 VarAdd함수였습니다. 한번 실습해보시는 것도 좋을 것같습니다.


Add함수 내부로 들어가니 또 이런 Add함수가 보였습니다. F7로 다시 내부로 들어가 보도록 하겠습니다.



이 부분이 내부로 들어간 부분입니다. 주석만 보면 이해가 되실 거에요 값을 구하는데 쓸데

없는 주석도 몇가지 보이는데 대충 저 정도만 보시면 될것같습니다. 이미 abcd에 해당하는

 serial이 C5C6C7C8이라는 것을 저번 포스팅에서 구해놨고 이번에 a의 ASCII코드 값 즉 61

을 64를 더한 값이 C5고 b,c,d의 아스키 코드는 각각 a의 ASCII코드 보다 1,2,3씩 많은 값이

기 때문에 64와 더해서 serial을 생성한 다는 것을 알 수 있었습니다.








오랫만에 리버싱 포스팅을 하게되었습니다. 두달도 지난거 같아요 앞으로 리버싱위주로 많이 포스팅하겠습니다.

너무 오랫동안 안했어서 그른지 쉬운 crackme 문제도 삽질하면서 풀었습니다.  
이 예제는 리버싱 핵심원리에 있던 파일인데 이번엔 혼자서 분석해 보았습니다.



예전 codeengn에서 많이 보던 문제 유형입니다. 아마 예상으로는 name의 입력값에서 어떤 연산을 거친후 serial을 생성하는 거 같아요. 한번 보겠습니다.


문자열 검색으로 실패시 띄어지는 Messagebox에서 나오는 문자열을 검색했더니 저 TEST 명령에서 분기하는 것을 알 수가있었습니다. 저 TEST 명령 실행 후 ZF 값을 바꾸어 주면 성공 메시지로 분기하는 것을 보실 수 있을 것입니다. 

그렇다는건 TEST위의 함수 호출에 따라서 분기가 결정된다는 것입니다.
그래서 안으로 들어가서 탐색해 보았습니다.

cmp 함수가 보이네요 비쥬얼베이직에서 문자열을 서로 비교할 때 많이 쓰던 API함수 입니다.


더 들어가 보았습니다. 또 cmp함수가 보이네요. 들어가 보도록하겠습니다.

들어가서 F8로 조금 더 디버깅해보니 저 두개의 문자열이 나란히 뜨네요 아마 경험상 저게 serial일 것 같습니다. (123456789는 제가 입력한 serial입니다.)


성공!!!


다음 포스팅은 이 문제가 어떻게 serial을 생성하는지 serial을 생성하는 알고리즘을 분석해보도록 하겠습니다. 




오랫만의 포스팅입니다. 몇일동안 학교 시스템해킹 과제를 하느랴 FTZ를 못풀었었습니다. FTZ를 끝낸후 과제푼 것을 포스팅 해보겠습니다.



#include <stdio.h>

void printit() {
  printf("Hello there!\n");
}

main()
{ int crap;
  void (*call)()=printit;
  char buf[20];
  fgets(buf,48,stdin);
  setreuid(3098,3098);
  call();
}

이런 코드 입니다. 공격 방법은 간단합니다. 저 printit함수의 시작주소를 저장하는 call변수에 쉘코드가 입력된 환경변수의 주소를 써주면 공격이 성공하게 됩니다.









dummy 부분을 찾아내는 건 저번 포스팅 level16에서 찾은 방법과 동일합니다. 너무 쉽기 때문에 여기까지 포스팅 하겠습니다. 아마 지금까지 문제 푸신분들은 그림만 봐도 아실것입니다.


level16은 코드만 보면 조금 어렵게 느낄 수 있겠지만 레벨 15보다도 훨훨훨씬 쉬었습니다.

풀이 하겠씁니다~



#include <stdio.h>
 
void shell() {
  setreuid(3097,3097);
  system("/bin/sh");
}
 
void printit() {
  printf("Hello there!\n");
}
 
main()
{ int crap;
  void (*call)()=printit;
  char buf[20];
  fgets(buf,48,stdin);
  call();
}   

이런 코드입니다. 많이 긴가민가 하셨을 부분이 아마도 void (*call)()=printit; 부분이라고 생각 됩니다.

void (*call)()=printit; 부분은 C언어에서 함수 포인터라고 합니다.

함수포인터란 말 그대로 함수를 가리키는 포인터 입니다. 함수도 다른 변수들처럼 메모리에 저장이 되기 때문에 시작주소가 존재하고 그럼으로써 시작주소를 가리킬 수 있게 되는 것 입니다.

원형으로는

리턴타입 *변수명(인자)=함수의시작주소

그렇다면 저 코드를 보자면 | buf |dummy| call |dummy| crap | 과 같은 구조로 스택이 되어있습니다.
지금까지 문제를 푸신분들은 감이 오셨을 거에요 buf에서 입력을 받아 buf[20]을 채우고 dummy까지를 채운뒤 call변수의 값으로 shell()함수의 주소를 넣어주면 됩니다.

그럼 어떻게 shell함수의 시작주소를 알 수가 있을까요??

이렇게 gdb를 이용해서 함수의 시작주소를 찾을 수 있습니다. 

리눅스에서는 objdump라는 명령이 존재합니다. 이 명령으로 시작 주소를 찾으신 분들도 계셨습니다.


시작 주소는 모두 찾았습니다. 이제 해야할 건 공격코드를 만드는 것입니다. 
그러기 위해서는 dummy의 크기를 알아야하는데 노가다를 하기 싫어 약간의 실험(?)을 해보았습니다.


리버싱을 해서 그런지 어셈블리어에서 함수가 호출될 때 인자가 어떤 방식으로 들어가는지 를 알아서 대충 그려봤습니다.

즉 ebp-56이 변수 buf이고 printit()이 call변수에 저장되는 곳이 ebp-16이였습니다. 따라서 이 거리는 40이라고 알 수 있었습니다. 
햇갈리시는 분들은 위의 hint에 있는 attackme.c코드와 스택구조를 같이보시면 이해가 쉬우실 겁니다.



끝났습니다.

레벨 15가 저한테는 굉장히 어려워서 그런지 이 문제는 굉장히 쉬웠었습니다.



 2015-10-26일

대한민국 국방부와 국가정보원이 주관하는 화이트햇 행사에 다녀왔습니다








행사장에 갔더니 많은 대학생들과 고등학생들이 참석해 있었습니다.

작년 POC에 갔을 때에는 아무 지식도 없이 수업뺴먹고 놀러가는 마음으로 가서 다른 잘하

시는 분들을 보고 자극을 받았었는데 이번에는 어느정도 공부를 한상태여서 그런지 재미있

게 구경하고 강연도 잘 듣고 온 것 같습니다.

행사가 있어도 어차피 가도 알아듣지도 못한다고 안가지말고 가서 자극을 받고 오는 것도 

좋다고 생각합니다.

일단 이 15번 문제는 가장 오랜 시간이 걸렸던거 같아요...

저번 포스팅 level15 틀 설명드린 것 중 두 가지 방법이 있었죠?? 첫번째와 두번째 먼저 두번째 방법을 포스팅 해보겠습니다. 첫번째 방법은 역시나 ASLR이 걸려있어 쉽지가 않네요.



일단 여기서는 환경변수를 선언해 줍니다.

 export POINTER=`python -c 'print "\xef\xbe\xad\xde"'`

그런데 가장 먼저 선언한 것은

export P="0xdeadbeef" 였습니다. 굳이 리틀엔디안 방식으로 안해도 이 변수안에 값을 넣고 주소만 알면 이 값을 그대로 읽어 줄것 같았지만 역시나 이런 방식이 아닌 python으로 리틀엔디안을 넣어주었을 때만 성공하더라고요.... 이유는 학교에 잘하는 친구있는데 그 친구한테 물어보고 다시 올리겠습니다.


vi 에디터로 static_address.c 파일을 만들었습니다. 코드는 밑에


솔직히 말씀드리면 저도 시스템해킹을 공부한지 얼마안되고 이렇게 문제풀면서 하나하나 

익히고있습니다. C나 python은 어느정도 다루지만 저런 코드를 짤정도의 실력은 안됩니다.

 왜 저 코드를 써야하나는 지금은 설명드리지 못하고 이것도 제가 이해한 뒤 위에 궁금증과

같이 포스팅 하겠습니다.


어떻게 문제는 잘 푼거 같아요. 이렇게 오래걸릴지 몰랐는데... 처음 봤을 때는 굉장히 간단한 문제라고 생각했었습니다.

이제 level16이네요 level16포스팅은 일요일쯤 하겠습니다.


------------------------------------------------<핵심>-------------------------------------------




쉬운 문제일 줄 알았는데 아주 2일동안 못풀게한 문제입니다.

이 방법이 왜 틀린지만 하루종일 고민했던것 같습니다. 그러다가 생각난 이유가 그동안 왜

우리가 문제를 풀면서 NOP 썰매 즉, 'python -c 'print "\x90"*100+"\xff\xff\xff\xbf"'` 에

서 왜 앞에 NOP을 100개 넣어 주었나 하는 이유였습니다.  우리가 정의한 환경변수에는 우

리가 입력한 값말고 다른 값도 들어가있습니다. 또한 파일의 이름, 디렉토리의 위치에 따라

주소가 환경변수가 위치하는 주소가 다릅니다(그에 대한 설명이 위의 그림중 <핵심>이라

고 설명된 사진 두장입니다.)  즉 100개를 넣음으로써 대략적인 위치를 찾아 우리가 집어넣

은 데이터를 실행하도록 한 것이 NOP썰매 방법이였습니다.

따라서 이러한 이유로 저 윗방법은 틀린 것 입니다.

따라서 문제를 풀기 위해서는 두가지 크게 두가지 방법이 있는 것 같습니다.

1.변수 buf에 0xdeadbeef를 넣고 buf의 주소를 check 포인터 변수에 넣어주는 것
(이 방법은 ASLR이 적용되있다면 할 수 있을지 없을지 모르겠습니다.)

2./home/level15/attackme에서 0xdeadbeef가 들어있는 환경변수의 정확한 주소를 찾아 그 주소를 넣어 공격하는 방법

아직 못해봤지만 가능하다면 두 가지 모두 포스팅 해보겠습니다.






이번 문제는 level12와 거의 유사한 문제입니다.

#include <stdio.h>
#include <unistd.h>

main()
{ int crap;
  int check;
  char buf[20];
  fgets(buf,45,stdin);
  if (check==0xdeadbeef)
   {
     setreuid(3095,3095);
     system("/bin/sh");
   }
}  

fget()함수로 최대 입력횟수(NULL포함)을 지정해준 문제입니다. 따라서 최대 44개의 문자를 입력할 수 있습니다.

우리는 이 문제에서 crap 변수를 생각할 필요가 없습니다. 왜냐하면 밑에 그림을 보시면 됩니다.

따라서 스택의 구조상 우리는 buf[20] | dummy | check 이 부분만 살펴보면 됩니다.   
dummy의 크기를 알아보려고 또 노가다를 해야겠습니다. 
범위는 dummy가 없다고 가정한 20부터 40까지로 지정했습니다.
   
[level14@ftz level14]$ (python -c 'print "\x90"*20+"\xef\xbe\xad\xde"';cat)|./attackme
.
.
.
.
.
.
.
[level14@ftz level14]$ (python -c 'print "\x90"*40+"\xef\xbe\xad\xde"';cat)|./attackme




cat을 붙여주여야 하는 이유!!
=level12에서 이해하기 쉽게는 썼습니다. 여기서 간단히 적고 넘어가자면 cat없이 python만 쓴다면 python 명령이 실행되고 종료되어 파이프라인 오류, 즉 stdout의 역할을 하지 못하므로 cat을 너어주어 입력상태까지 함께 넣어주는 것이라고 생각하면 쉽습니다.