level20이 마지막이다. 힌트를 확인해보도록 하자. fgets 함수를 사용하여 입력문자 제한을 두었다. 따라서 버퍼 오버플로우 공격은 힘들거라 예상할 수 있겠다. 하지만 printf 함수에서 서식문자를 사용하지 않고 바로 출력하였기 때문에 bleh 변수를 이용하여 포맷스트링 공격을 할 수 있을 것으로 예상이 된다. 서식문자를 사용하지 않고 직접 출력을 하게 된다면, 만약 bleh 변수에 서식문자를 입력하였을 경우 esp부터 요구되는 사이즈만큼 자동으로 참조를 하면서 메모리를 참조할 수 있게된다. %x는 4바이트씩 참조하기 때문에 4바이트 단위로 이동할 수 있는 수단이 된다. %n이라는 서식문자는 printf에서 출력된만큼 10진수로 저장하는 서식문자이다. 이 서식문자를 통해서 메모리에 RET주소를 쉘..
level19의 문제는 다음과 같았다. 해당 문제에 대해서 분석해보면 gets 함수를 사용하여 버퍼 오버플로우를 일으킬 수 있다. 해당 문제에서는 buf 변수의 사이즈가 작아서 다음을 고려하면 buf 변수에 쉘코드를 덮어씌우는 것은 무리일 것으로 예상된다. 따라서 우리가 해야할 공격 방법은 지난번 레벨15 에서 보였던 방법과 비슷하게 쉘코드를 환경변수로 저장하고 스택의 RET 메모리 주소를 해당 환경변수가 존재하는 주소로 바꿔주는 것을 목표로 하겠다. 우선 gdb로 디스어셈블을 수행한다. 스택의 사이즈가 40bytes이므로 dummy의 사이즈는 20bytes이다. 즉, buf(20bytes) + dummy(20bytes) + SFP + RET 의 구조를 지니고 있다. 우리는 RET에 쉘코드가 저장된 환경..
우선 level18의 힌트를 읽어보도록 하자. 문제의 최종 목적을 shellout() 함수를 동작하도록 하는 것이다. 그리기 위해서는 메모리 조작이 필요하고 메모리 구성을 확인하기 위해 gdb를 확인하였다. 여기서 buf 변수는 스택의 가장 최상위에 존재하므로 check에 대해 값을 바꾸기 위해서는 인덱스값이 음수가 되어 메모리를 수정해주면 된다. 우선 각 변수들에 대해서 정확한 메모리 구조를 알기 위해서 각각의 변수를 사용할때 어떤 위치에서 끌어다 쓰는지 확인할 필요가 있다. 우선 전체적인 사이즈로 0x100(256)bytes를 최초에 확보하였으므로 모든 지역변수의 사이즈 + dummy 의 값이 256bytes가 되는 것이다. 어셈블리의 코드를 분석해보면 각 변수들의 위치는 다음과 같다. fds(ebp..
level17의 힌트를 확인해보도록 하자. 이번에는 printit() 함수만 존재하고 shell함수가 별도로 존재하지 않는다. 스택에는 56바이트의 용량이 있는데 이때 call 포인터는 ebp에서 16바이트 떨어진 곳에 존재하기 때문에 buf에서 shellcode를 입력하여 call 포인터가 buf의 주소를 가리키도록 하면 된다. $(python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"A"*15+"[buf 메모리 주소]"';cat) | ./attackme 형식으로 입력하여 공격하면 된다.
level16의 힌트를 읽어보도록 하자. call 함수 포인터가 printit 함수를 가리키고 있기 때문에 Hello there 이라는 문자를 출력하는 프로그램이 되었다. 우리는 fgets 함수를 통하여 버퍼 오버플로우를 일으켜 call 함수 포인터가 가리키고 있는 주소를 shell() 함수의 주소값으로 변경하여야 한다. 여기서 스택의 용량이 56바이트로 구성되어있다는 것을 알 수 있고 함수 포인터인 call은 ebp로부터 16바이트 떨어진 곳에 있다는 것을 main+36을 통해 알 수 있다. 즉 buf의 시작부터 40바이트 떨어진 곳에 있으므로 해당 위치에 shell() 함수의 주소인 0x080484d0로 덮어 씌우면 완성이다. $(python -c 'print "A"*40+"\xd0\x84\x04\x..
level15의 힌트를 확인해보자. level14와 매우 유사한 코드를 가지고 있지만 한가지 차이점이 있다. 바로 check 변수가 포인터형이라는 것이다. 즉 check의 값이 0xdeadbeef가 되는 것이 아닌, check가 가리키는 값이 0xdeadbeef가 되도록 해주면 된다. 따라서 공격 방법으로 buf 변수에 0xdeadbeef를 입력해놓은 다음 check의 값을 buf 변수의 시작 주소값을 덮어씌워 주면 공격을 성공할 수 있다. gdb를 통하여 분석한 디스어셈블링을 통해 메모리의 배치가 level14와 마찬가지인 것을 확인할 수 있었다. $(python -c 'print "\xef\xbe\xad\xde"+"A"*36+"[buf시작주소]"'; cat) | ./attackme 라는 명령어로 공격..
level14에 들어와 힌트부터 확인을 하자. check 변수에 대해 직접 입력하는 구간이 없다. 따라서 우리는 버퍼 오버플로우를 이용해 check 값을 0xdeadbeef로 변경하여야 한다. 우선 디스어셈블을 수행하였다. main+29 를 통하여 check의 값은 ebp로부터 16만큼 떨어져 있는 것을 알 수 있었고 buf 변수는 ebp로부터 0x38(56) 만큼 떨어져 있는 것을 main+3을 통해 알 수 있다. 따라서 buf에서 40byte만큼 값을 입력한 후에 0xdeadbeef를 입력해주면 공격은 성공하게 된다. $(python -c 'print "A"*40+"\xef\xbe\xad\xde"'; cat) | ./attakme 라는 형식으로 공격할 수 있다.
level13으로 로그인을 하여 힌트를 우선 읽어보자. 본 문제는 스택가드에 관련된 문제이다. 스택가드는 버퍼 오버플로우를 방지하기 위한 방어 방법의 하나로, 레벨12의 문제를 예로 들어보자. buffer(256bytes) + dummy(8bytes) + SFP(4bytes) + RET(4bytes)를 덮어 씌워 버퍼 오버 플로우를 일으키는 공격이었다. 하지만 여기에 스택가드를 추가하여buffer(256bytes) + stackguard(4bytes) + dummy(8bytes) + SFP(4bytes) + RET(4bytes)로 구성하게 되었을 때 이미 저장되어있는 스택가드에 대하여 값이 변동이 있다면 버퍼 오버플로우가 발생했다는 것을 쉽게 감지할 수 있으므로 버퍼 오버플로우에 대해 방어를 할 수 있게..
이전에 획득한 비밀번호로 로그인을 하였다. 힌트의 내용을 보아 gets를 통해 버퍼 오버플로우를 일으킬 수 있다는 점을 발견하였다. 이번 문제도 지난 level11에서 해결한 것과 같은 방법으로 "A"*243+"shellcode(25bytes)"+"shellcode 시작주소" 를 입력하면 버퍼오버플로우가 일어나 쉘코드가 있는 주소로 리턴함으로 쉘을 취득할 수 있는 것이다. couldn't get registers: operation not permitted 라는 에러 메세지가 발생하면서 gdb에서 정상적인 디스어셈블이 불가능하게 되었다. 현재 서버가 닫혀있어 로컬 서버로 시도했지만, 로컬 서버에couldn't get registers: operation not permitted 라는 에러 메세지가 발생하..
level10을 통해 얻은 비밀번호로 level11에 접속하여 힌트를 읽어보자. 여태 공격성 문제에서는 system 함수를 공략하는 문제가 나왔다면 이제부터는 system 함수가 없어도 공격을 하는 방법에 대해서 찾아야 한다. 해당 문제에서는 printf를 보고 printf 와 관련된 취약점에 대해서 검색해 보았고 포맷 스트링 어택이라는 공격 기법을 사용하는 것을 깨달았다. attackme 프로그램에 대해서 분석해본 결과 우선 esp의 사이즈가 0x108(264)이라는 것을 알 수 있고 변수 선언을 256사이즈로 했다는 것을 감안하면 8바이트는 dummy로 추측이 된다. 또한 sfp와 ret의 8바이트를 추가하면 256(buffer),8(dummy),4(SFP),4(RET) 구조가 된다. 여기서 리턴하는..