본문 바로가기

2. Reversing (리버싱)

[2023.09.23] 리버싱 1주차 팀활동

인프런 강의 <해킹 대회를 위한 시스템 해킹 프로토스타 완벽 풀이집>의 섹션 0, 1 강의를 듣고 칼리 리눅스 환경 구축과 스택에 관한 기본 리버싱 개념을 공부했다. 

 

stack0

문제해결

//문제 코드
#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");
  }
}

modified 값이 0이 아니게 만들어야 해결할 수 있는 것 같다.

 

//스택 구성

|      buffer[64]     |
|---------------------|
|      modified       |
|---------------------|
|       ebp           |
|---------------------|
|       ret           |
|---------------------|

일부러 취약하게 컴파일(요즘엔 알아서 고쳐주기 때문에)

바뀌는 모습

./stack0

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

gdb분석

set disassembly-flavor intel : intel 형식으로 바꿔주기

disas main :메인 함수를 디버깅

if문 이라 예상할 수 있는 곳이 test 부분 > breack point를 걸어주기

b *주소 : break point 설정

bp 걸린 모습

eax 값을 확인했을 때 0 으로 변조 안 된 상태 임을 확인 가능

info reg ($~) : 특정 레지스터 혹은 전체 레지스터 정보 확인

여기서 continue 하면 try again 이 뜨겠다..도 예측 가능

run 으로 처음부터 다시 시작해서 버퍼 이상으로 넣어주고

info reg $eax : eax 값을 확인해보면 채워진 게 확인됨

modified로 예상하고 있는 [rbp-0x4] 을 확인해보기 위해

info reg $rbp : rbp 레지스터의 정보 확인

0xfffffffdde0 , [rbp-0x4]는 0xfffffffdde0 - 0x4

스택 구조에서 살펴보면 0x61(=a)로 채워진 모습을 확인할 수 있음 > 변조됨

x/30gx $rsp : 메모리를 16 진수로 표시하고 스택 포인터($rsp)를 기준으로 주변 메모리 내용 출력

x : 메모리 검사, /30 : 출력할 메모리의 단위 수, g : 8바이트(64비트) 값, x : 16진수 형식, $rsp : 현재 스택의 상단 주소를 가리키며, 스택의 가장 최근에 추가된 데이터를 가리킴

 

stack1

 

1-1 다른 변수 덮어씌우기

buffer
modified
ebp
rep

 이런 식으로 쌓임

버퍼를 가득 채우면 밑의 데이터들이 변조가 될 수 있다.

 

스택 공격에 취약한 컴파일 명령어

gcc –z execstack –no–pie –w -o stack0 stack0.c : stack0.c라는 C언어 소스 코드 파일을 컴파일하여 ‘stack0’이라는 실행 가능한 바이너리 파일을 생성하며, 실행 스택 보호를 끄고, PIE를 사용하지 않으며, 경고 메시지를 비활성화함.

gcc : GNU Compiler Collection C컴파일러를 실행하는 명령어. C언어 소스 코드를 컴파일해 실행 가능한 프로그램을 생성함.

-z execstack : 실행 스택 보호(프로그램이 실행 중에 스택 메모리를 수정하는 것을 방지하는 보안 기능)를 끔. 스택을 실행할 수 있는 권한을 줌.

-nopie : Position Independent Executable(PIE) 형식(실행 파일을 메모리에 로드할 때 위치 독립적으로 로드하는 방식, 보안 향상에 사용)을 사용하지 않도록 함.

-w : 컴파일러의 경고 메시지를 비활성화.

-o stack0 : 출력 파일의 이름을 지정,  stack0이라고 저장.

stack0.c : 컴파일하려는 C언어 소스 코드 이름. 이 파일은 컴파일러에 의해 컴파일되어 실행 파일이 생성됨.

 

문제해결

//문제 코드
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

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

  if(argc == 1) {
      errx(1, "please specify an argument\n");
  }

  modified = 0;
  strcpy(buffer, argv[1]);

  if(modified == 0x61626364) {
      printf("you have correctly got the variable to the right value\n");
  } else {
      printf("Try again, you got 0x%08x\n", modified);
  }
}

modified 값이 0x61626364(=abcd) 여야 할 것 같다. > stack0 문제와 다르게 특정한 값 요구

https://devjh.tistory.com/22

버퍼를 넘치게 채워주고 리틀 엔디안 방식에 맞춰dcba로 넣어주면 된다

./stack1

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdcba

 

gdb분석

마찬가지로 컴파일 후 간단하게 실행해보기

gdb ./file~ - gdb 분석 시작

set disassembly-flavor intel : intel 형식으로 바꿔주기

disas main : 메인 함수를 디버깅

 

문제에 주어졌던 0x61626364 값을 비교하는 부분인 cmp eax, 0x61626364 를 찾을 수 있다

maiin 82에 break point를 걸어준다

b *주소 - break point 설정

info reg $eax : eax 값을 확인해보면 B로 차있는게 확인됨 > 제대로 덮어씌워지는걸 확인!

0x61626364 = abcd 를 넣어본다

결과 값이 0x64636261으로 거꾸로 들어간 걸 확인할 수 있다

리틀 엔디안 방식에 다시 맞춰 dcba로 바꿔 넣어주고 레지스터 값을 확인해보면 0x61626364로 알맞게 바뀐 걸 확인 가능