System Hacking

[해커스쿨FTZ] Level18

BIGFROG 2020. 1. 6. 17:11

FTZ level18

 

main+96 : cmp DWORD PTR [ebp-124], 0xdeadbeef

 

ebp-124가 가리키는 값을 0xdeadbeef인지를 확인한다.

 

소스에 보면 FD_라는 부분이 많이 나오는데,

file descriptor에 대한 내용인 듯 하다.

 

FD_ZERO(&fds); : fds에 설정된 모든 fd를 지우고 초기화합니다.

 

 

FD_SET(STDIN_FILENO,&fds); : fd_set은 여러 개의 fd를 select함수에서 읽기/쓰기/오류에 대한 event 발생 여부 체크 목록을 관리하고 select 실행 후에 event가 발생한 fd인지 여부를 기록하는 구조체.

 

select(FD_SETSIZE, &fds, NULL ,NULL ,NULL) >=1

--다중 입출력 함수 select()

다중 입출력이란?

- 다중 입출력은 여러 fd를 동시에 차단하면서 fd중 하나가 차단 없이 읽고 쓸 준비가 될 때 알려주는 기능을 말한다.

다중 입출력을 위한 기본 방식은 다음과 같다.

1. fd 중 하나가 입출력이 준비될 때를 알려준다.

2. 하나 이상의 fd가 준비될 때가지 잠든다

3. 어떤 fd가 준비되었는지 확인 후 준비가 되면 깨어난다.

4. 차단 없이 모든 fd가 입출력을 준비하도록 관리한다.

5. 1단계로 돌아가서 다시 시작.

 

select함수 반환값-

- 성공 시 반환 값 : 준비된 fd 개수

- 시간 만료시 반환 값 : 0

- 오류 시 반환 값 : -1

 

FD_ISSET(fileno(stdin),&fds)

read(fileno(stdin),&x,1);

 

read함수에 대해서,

파일 지시자가 int fd인 저수준 파일 입출력의 주요 함수로 open,close,read,write 등이 있다.

(고수준 파일 입출력은 fopen,fclose 등)

저수준 파일 입출력의 특징은 

1.훨씬 빠르다.

2.바이트 단위로 읽고 쓴다.

3.특수 파일에 대한 접근이 가능하다.

 

 

main+96 : cmp DWORD PTR[ebp-124], 0xdeadbeef

를 보면, ebp-124 부분에 check변수가 있는 것을 알 수 있다.

 

소스를 보면 일단

[높은 메모리 주소]

RET

SFP

char string[]

int check (ebp-124)

int x (ebp-128)

int count (ebp-132)

[낮은 메모리 주소]

순서로 메모리가 생길 것이다.

 

main+285쯤부터 보면,

ebp-128이 가리키는 값을 eax에 담고,

그 값을 다시 ebp-276이 가리키는 곳에 담는다.

그리고 main+294에서 ebp-276이 가리키는 값과 0xa를 비교하고 je명령어,

main+312에서 ebp-276이 가리키는 값과 0x8을 비교하고 je명령어..

계속해서 0xd와도 비교한다.

 

이쯤이 스위치문인듯하다 0x8과 비교하는 것에서 확신을 얻을 수 있다.

그렇다면 결국 ebp-128이 가리키는 값이 변수x를 나타낸다.

 

main+384에서 ebp-120을 찾았는데,

위의 메모리 구조를 봤을 때 string[]부분의 주소가 왠지 ebp-120 이면 좋을 것 같다.

그래서 찾아봤다.

의심가는 main+384 부분을 언제 실행하는지,

jmp main+384부분을 찾았다.

 

main+321 과 main+332 부분에서 찾았는데,

둘 다 스위치문 내부였다.

연속으로 점프문이 있는데,

je -> case에 해당되면 case 부분을 실행해야 하므로 점프.

jmp -> case에 해당되지 않은 경우 default부분으로 넘어가므로 점프.

따라서 main+384부분은 스위치문의 default부분이다.

eax에 ebp-120의 주소를 저장하는데

이 부분이 string[count] = x; 부분임을 알 수 있다.

따라서 ebp-120은 string버퍼 부분이다!

 

우연히도 위의 메모리구조에서 check와 string버퍼가 4바이트 차이가 난다.

문자열은 높은 주소 쪽으로 쌓이므로,

버퍼 위치를 조정해줘서(case 0x08) 아래로 내린 뒤에 check를 0xdeadbeef로 덮으면 될 것 같다.

 

더미 없이 4바이트만 조정해주면 되니까,

페이로드는 다음과 같다.

(python -c 'print "\x08"*4+"\xef\xbe\xad\xde"';cat) | ./attackme

 

 

***string[-1]의 의미

: string[]는 string의 시작주소를 의미한다.

string[count]로 받아오고 count가 1 증가할수록 시작주소에서 1바이트씩 높은 주소에 x값을 저장한다. 그러나 \x08 을 입력하여 count를 줄여나가 count가 -1이 되는 시점부터는,

string의 시작주소에서 1바이트씩 '낮은'주소에 x값을 저장하게 된다.

c언어에서 string[-1]은 문법에 맞지 않지만,

어셈블리 관점으로 따져 봤을 때, count가 증가하면 높은 주소로 1바이트,

count가 감소하면 낮은 주소로 1바이트 "이동한다"고 보면 되겠다.

따라서 개념상으로 string[-1]로 이해하면,

string의 시작주소보다 낮은 주소로 접근(이동)하게 되는 것이다.

빽도를 던지는 개념임 버퍼오버플로우는 아니다.

 

추가설명:

main+355 lea eax,[ebp-132]

main+361 dec DWORD PTR [eax]

ebp-132(count)의 주소를 eax에 넣고,

eax가 가리키는 값(결국은 count)를 1byte decrease 한다.(1바이트 줄인다)

 

그리고 string[count]=x부분을 다시 보면,

main+384 : lea eax,[ebp-120] 에서 string주소를 eax값에넣고,

main+387 : mov edx,eax 그 주소값을 edx로 넘기고

main+389 : add edx,DWORD PTR [ebp-132]

!!!!여기서 string버퍼의 '주소'값에 ebp-132가 가리키는 값(count의 값)을 '더한다'

근데 count가 음수인 상태라면

주소값에 음수를 더하는 꼴이 된다. 

따라서 낮은 주소인 check에 접근할 수 있게 된다.

이것을 string[-1]처럼 표현할 수 있겠다.

 

레벨19 패스워드 : "swimming in pink"

 

 

 

 

 

 

 

 

 

 

 

 

 

'System Hacking' 카테고리의 다른 글

[해커스쿨FTZ] Level20  (0) 2020.01.06
[해커스쿨FTZ] Level19  (0) 2020.01.06
[해커스쿨FTZ] Level17  (0) 2020.01.06
[해커스쿨FTZ] Level16  (0) 2020.01.06
[해커스쿨FTZ] Level15  (0) 2020.01.06