전체 글
![](http://i1.daumcdn.net/thumb/C400x400/?fname=https://blog.kakaocdn.net/dn/ELzLI/btqIghdW4hk/akkJYdFEwKzAshb6kqtJN0/img.png)
![](https://tistory1.daumcdn.net/tistory/3918100/skin/images/no-image.jpg)
인자 두 개 이상, 환경변수 초기화, 48번째 바이트 "\xbf", 48글자 초과 X, argv 배열 0으로 초기화, buffer 변수 초기화. 어우 많네요. 인자도 안되구 환경변수도 buffer 변수도 안되네요. 어떻게 해야할까요? 일단 gdb를 통해 디버깅해보겠습니다. 먼저 복사해야겠죠? aaaa라는 파일로 복사했습니다. 먼저 core 파일에 dump 후에 gdb를 통해 디버깅합니다. 쓸만한 정보가 메모리에 남아있는지 확인하는 겁니다. 이때는 프로그램 실행으로 할당된 메모리 +- 1000바이트씩 확인합니다. 이 값으로 시작해 천천히 살펴보겠습니다. 음... dump되었던 당시 인자로 주었던 A와 BBB\xbf가 SFP와 RET주소에만 남고 buffer는 모두 0으로 초기화되었네요. 여기에선 쓸만한게 ..
![](http://i1.daumcdn.net/thumb/C400x400/?fname=https://blog.kakaocdn.net/dn/d8JcAS/btqH3zmdgZk/MGkK9EyWnk7fUzosYxRPM1/img.png)
![](https://tistory1.daumcdn.net/tistory/3918100/skin/images/no-image.jpg)
오 이번엔 방해꾼이 별로 없네요. 인자 개수도 자유이고(두개이상), 48번째 == "\bf", 47번째 != "\xff" 밖에 없네요. 그러면 어떠한 인자의 주소가 0xbff(0~e)~~ 이여야 한다는 소리죠. 어떻게 해야할까요? 정답은 메모리 구조를 살펴보면 있습니다. 커널은 c0000000 ~ ffffffff까지 존재하죠. 전체의 1/4입니다. 커널의 메모리가 덮여지면 아주아주 큰일이 나겠죠? 아예 고장날겁니다. 그래서 메모리는 높은 주소에서 낮은 주소로 상승하게 되어있습니다. '커널 영역'에 메모리가 덮여지는 것을 방지하기 위해서 말이죠. 그렇다면, 우리가 main 함수의 인자에 무지막지한 길이의 문자열을 전달한다면 과연 높은 주소로 길어질까요, 낮은 주소로 길어질까요. 위의 내용을 이해했다면 당연..
![](http://i1.daumcdn.net/thumb/C400x400/?fname=https://blog.kakaocdn.net/dn/cByBoy/btqH3yHBtzi/VjzN1waVTExTNotUAwtI2K/img.png)
![](https://tistory1.daumcdn.net/tistory/3918100/skin/images/no-image.jpg)
이번에는 argv[1]까지 못쓰네요. argv[0]을 이용해 풀어야겠습니다. 이 문제는 두 가지 방법이 저는 떠올랐습니다. 하나는 심볼릭 링크를 통해 파일 이름에 쉘코드를 삽입시키는 것. 다른 하나는 execl 함수를 사용해 argv[0] 인자에 파일이름이 아닌 쉘코드를 삽입시키는 것. """ 심볼릭 링크를 이용하기 위해서는 쉘코드에 '\x2f'가 존재해서는 안되는데, 아직까지 깊게 생각하지 않아서인지 그 방법이 도무지 떠오르지 않는다. 또한 왜 하드 링크는 안되는지에 대한 궁금증이 생겼지만 이 역시 해결하려 노력하지 않아서인지 떠오르지 않는다. 이 두 가지 의문에 대해 답이 나온다면 추후에 수정하도록 하겠다. """ execl 함수가 있는 소스코드를 먼저 작성해보겠습니다. 저는 이렇게 작성했습니다. N..
![](http://i1.daumcdn.net/thumb/C400x400/?fname=https://blog.kakaocdn.net/dn/b8rhdt/btqHZjxp22c/E30l3hRHauxFnKCu8Ukol0/img.png)
![](https://tistory1.daumcdn.net/tistory/3918100/skin/images/no-image.jpg)
이번에는 argv[0]이 77글자가 되어야한다네요. '/'를 여러번 써주면 될 것 같습니다. argv[1]을 이용해 풀어보도록 하죠. RET 까지의 거리는 48이네요. argv[0]로 총 77글자가 들어갑니다. 하지만 지금 사진은 "./orge"까지만 들어간 것으로, 71글자가 더 들어가야합니다. 즉, 0xbffffc28 + 0x47을 해야한다는 것이죠. 0xbffffc6f이 나옵니다. payload를 작성해보겠습니다. `"." + "/"*72 + "orge"`, `"\x90"*19 + "~~"(ShellCode) + "\x6f\xfc\xff\xbf" 오류가 나서 core dump를 해보았습니다. 0xbffffb9c의 주소로 다시 해보겠습니다. 성공!
![](http://i1.daumcdn.net/thumb/C400x400/?fname=https://blog.kakaocdn.net/dn/bA6ukN/btqH2di6Cz0/CKTTxW1tZqNIazdQFyufNK/img.png)
![](https://tistory1.daumcdn.net/tistory/3918100/skin/images/no-image.jpg)
바로 전 문제에서 buffer 변수에 있는 메모리를 초기화시키는 부분이 추가되었네요. 어차피 main 함수의 인자를 이용해 똑같이 풀거기 때문에 상관없습니다. 바로 전 문제와 똑같이 해보겠습니다. 복사하고 컴파일하고 disas를 통해 먼저 거리를 계산합니다. 48이네요. A*44 + B*4 + C*100을 인자로 던져줘 얻은 결과입니다. RET 주소 다음의 위치는 0xbffffc10이네요. payload를 작성해보겠습니다. "A"*44 + "\x10\xfc\xff\xbf" + "'x90"*100 + "~~"(ShellCode) 성공!
![](http://i1.daumcdn.net/thumb/C400x400/?fname=https://blog.kakaocdn.net/dn/GA5dU/btqHTZNc002/trQLvYDcu1a4yKeW59NXr0/img.png)
![](https://tistory1.daumcdn.net/tistory/3918100/skin/images/no-image.jpg)
buffer의 크기가 40 즉, RET까지의 길이는 48, main 함수의 인자 개수 2개로 제한, 환경변수 초기화, 48번째 문자 '\xbf'. 이로써는 BOF 야기할 방법이 많습니다. argv[1]의 주소이용 또는 RET 다음의 주소이용 또는 execl 이용 또는 심볼릭 링크이용 등등... 여기서 RET 다음의 주소를 이용해보겠습니다. 먼저 orc.c 파일을 복사해줍니다. 이제 컴파일을 한 뒤 디버깅해보겠습니다. disas를 통해 buffer는 딱 크기만큼 $ebp보다 위에 있다는 것을 알아냈습니다. 그러면 RET까지의 거리는 48로 생각할 수 있겠네요. A*44 B*4 C*100을 인자로 던져 RET주소 다음의 위치를 알아내겠습니다. 0xbffffbf8이네요. payload를 작성해보겠습니다. "A..
![](http://i1.daumcdn.net/thumb/C400x400/?fname=https://blog.kakaocdn.net/dn/rRitJ/btqH0pb9NeY/JfS1IvBsBTAsMvxx4UjtEK/img.png)
![](https://tistory1.daumcdn.net/tistory/3918100/skin/images/no-image.jpg)
보통 C언어에서 인자를 받지 않겠다는 의미로 함수의 괄호 안에 void를 쓰게 되는데요, 이 부분을 확실하게 처리를 안해서 야기된 문제같습니다. (물론 제 생각..) 인자로 쉘코드를 던져준 다음 argv[1]의 주소를 알아내고, gets 함수를 통해 RET 주소를 argv[1]의 주소로 덮으면 문제는 해결될 것 같습니다. 먼저 현재 권한으로 디버깅을 하기 위해 goblin 파일을 복사해줍니다. 그리고 거리를 계산하기 위해 디스어셈블해줍니다. buffer~RET 까지 24바이트네요. 이제 argv[1]의 주소를 찾아보겠습니다. 찾았습니다. 주소는 0xbffffbf8이네요. payload를 작성해보겠습니다. (인자) "\x90"*100 + "~~"(ShellCode) (gets) "A"*20 + "\xf8\..
![](http://i1.daumcdn.net/thumb/C400x400/?fname=https://blog.kakaocdn.net/dn/bWQFjF/btqH0XfCyI1/RKmKkmd1eOc6cpsqVHF7xk/img.png)
![](https://tistory1.daumcdn.net/tistory/3918100/skin/images/no-image.jpg)
cobolt.c의 내용입니다. 16바이트의 아기자기한 데이터의 크기를 가지고 있는 buffer친구가 있네요. 먼저 저는 두 가지 방법이 떠올랐습니다. 첫째, argv[1]의 주소를 사용해 푼다. 둘째, argv[2]의 주소를 사용해 더욱 깔끔히 푼다. 결국 똑같은 소리입니다. main 함수의 인자를 이용하겠다는거죠. argv[1]을 이용해 먼저 풀어보겠습니다. 하기 전에 현재 권한으로 디버깅을 하기 위해 cobolt 실행파일을 원하는 이름으로 복사해놓읍시다. argv[1] 이용 "A" 문자열 100개를 argv[1] 인자로 던져줍니다. 이후에 디버깅을 통해 strcpy가 실행되기 전의 메모리 값들을 살펴보며 41 문자를 찾습니다. 그런데 이상한데에 낑겨있네요 ㅋㅋ 계산하기 싫을 때는 2바이트 앞당겨서 봅..