Protostar-Stack0 (Buffer Over Flow 공격)

2023. 1. 21. 20:09Pwnable/프로토스타_시스템해킹

먼저 gdb를 통해 stack0 을 메인함수까지 디스어셈블을 해보았다.

 

다음과 같은 프로그램의 C 소스코드는 다음과 같다.

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

int main(int argc, char **argv)
{
  volatile int modified;
  char buffer[64];

  modified = 0;
  gets(buffer);

  if(modified != 0) {
      printf("you have changed the 'modified' variable\n");
  } else {
      printf("Try again?\n");
  }
}

위에 코드를 해석해보자면 

 

64바이트의 크기로 변수 buffer을 선언하고 4바이트 크기의 modified 변수 또한 선언한다.

 

if문을 통해 modified 변수가 0인지 아닌지 확인해 Success 혹은 Failed를 타나내게 출력한다.

 

어셈블리어 부분 또한 해석을 해보자.

   0x080483f4 <+0>:     push   ebp
   0x080483f5 <+1>:     mov    ebp,esp
   0x080483f7 <+3>:     and    esp,0xfffffff0
   0x080483fa <+6>:     sub    esp,0x60
   0x080483fd <+9>:     mov    DWORD PTR [esp+0x5c],0x0
   0x08048405 <+17>:    lea    eax,[esp+0x1c]
   0x08048409 <+21>:    mov    DWORD PTR [esp],eax
   0x0804840c <+24>:    call   0x804830c <gets@plt>
   0x08048411 <+29>:    mov    eax,DWORD PTR [esp+0x5c]
   0x08048415 <+33>:    test   eax,eax
   0x08048417 <+35>:    je     0x8048427 <main+51>
   0x08048419 <+37>:    mov    DWORD PTR [esp],0x8048500
   0x08048420 <+44>:    call   0x804832c <puts@plt>
   0x08048425 <+49>:    jmp    0x8048433 <main+63>
   0x08048427 <+51>:    mov    DWORD PTR [esp],0x8048529
   0x0804842e <+58>:    call   0x804832c <puts@plt>
   0x08048433 <+63>:    leave  
   0x08048434 <+64>:    ret

1행 ~ 3행 까지는 함수 프롤로그로 스택구조의 최하위를 가리키기 위해 존재하는 어셈블리어다.

 

Push ebp는 ebp를 스택에 저장하는 걸 뜻하며 mov ebp, esp 는 현재 esp 위치에 ebp를 끌어올리는 명령어다.

0x080483fa <+6>:     sub    esp,0x60

부분에서 esp 레지스터에 main 함수가 사용할 0x60 크기 만큼 공간을 할당한다.

 

0x080483fd <+9>:     mov    DWORD PTR [esp+0x5c],0x0

 

esp+0x5c에 주소를 0으로 지정한다.

 

변수에 0을 지정하는 것은 modified 변수 밖에 없으므로 esp+0x5c는 modified 변수의 주소인 것을 확인할 수 있다.

 

그 밖에 DWORD는 데이터의 크기를 나타내므로 4바이트를 의미한다. (( 그 외에는 WORD =2byte BYTE = 1byte 가 있다.

 

0x08048405 <+17>: lea eax,[esp+0x1c]
0x08048409 <+21>: mov DWORD PTR [esp],eax
0x0804840c <+24>: call 0x804830c <gets@plt>

eax에 레지스터에 esp+0x1c 를 저장하며

 

지정된 esp+0x1c가 담긴 eax 함수를 esp로 다시 저장한다.

 

call 0x804830c 를 통해 <gets@plt> 의 입력이 저장된다.

 

즉 esp+0x1c의 위치가 buffer 변수의 주소인 것을 알 수 있다.

 

0x08048411 <+29>: mov eax,DWORD PTR [esp+0x5c]
0x08048415 <+33>: test eax,eax
0x08048417 <+35>: je 0x8048427 <main+51>
0x08048419 <+37>: mov DWORD PTR [esp],0x8048500
0x08048420 <+44>: call 0x804832c <puts@plt>
0x08048425 <+49>: jmp 0x8048433 <main+63>

 

esp+0x5c 변수를 eas 레지스터에 저장한다.

 

test 어셈블리어를 통해 eax, eax를 비교하여 0인지 아닌지 판단한다.

 

만일 0이라면 <main+51> 함수로 이동하여 진행한다.

만일 0이 아니라면 0이 아니라면 그대로 진행한다.

 

그대로 진행하는 경우:

 

esp가 가리키는 주소에 0x8048500을 입력해 PUTS 함수로 출력한다.

 

modified 변수가 0인 경우 0x8048529를 puts 함수로 출력하고 프로그램을 종료하는 에필로그로 이동한다.

 

여기서 더 위로 올라가 보면

esp 0x8048500에서 저장되어 있는 값을 조회할 수 있다. gdb x/s 명령어를 통해 알 수 있다.

 

이로써 0x8048500이 문자열임을 알수 있고 puts로 출력되는 결과물 또한 문자열인것이 증명이 된다.

 

================================================================================

 

Stack0의 스택 구조

 

 

==================================================================================

 

 

Exploit

 

 

Buffer의 크기는 64바이트 이며 modified는 4바이트다.

 

buffer 변수의 크기를 가득 채우기 위해서는 문자열 64개를 통해 채울 수 있다.

 

64개의 문자열 B로 buffer 변수를 가득 채우고 modified 변수는 0이 아닌 값으로 채원주면 해결되는 문제이기에 modified 변수 또한 문자열 B로 덮어 씌우도록 하면 된다.

 

문자열 64개 ( 64 byte ) + 문자열 4개 ( 4 byte ) 를 통해 변수 buffer와 modified 변수들의 크기를 가득 채울 수 있다.

 

이를 통해 변수 modified의 크기가 0이 아니게 되므로 문제를 풀 수 있게 되는 것이다.

 

Python을 통해 문자 B를 68개 출력한다.

복사하고 프로그램을 실행시켜 해당 문자들을 넣어보자.

 

위와 같이 modified 변수의 크기를 변경한 것을 확인할 수 있다.

 

gdb를 실행시켜서 크기가 가득 채워졌는지 확인해보자.

 

 

해당부분이 0x424242**... 값으로 채워진 것을 확인할 수 있다.

 

0x42는 문자로 바꾸면 B를 나타낸다.

'Pwnable > 프로토스타_시스템해킹' 카테고리의 다른 글

Protostar -stack 4 -  (0) 2023.02.13
Protostar stack-3 |실행 흐름 변조|  (0) 2023.02.03
Protostar stack-2  (0) 2023.02.01
Protostar-Stack1 (Buffer Over flow)  (0) 2023.01.23
어셈블리어 기본 명령어  (0) 2023.01.05