본문으로 바로가기

해커스쿨 LOB darkknight 풀이, write-up

category Wargame/LOB 2018. 9. 14. 11:08

darkknight --- new attacker



우선 darkknight의 디렉터리를 확인한다.





bugbear라는 의심스러운 파일이 존재한다. bugbear는 bugbear의 권한을 가지고 있고, setuid가 걸려있는 파일이다.



bugbear.c를 가지고 bugbear elf 파일을 만들었을 가능성이 있기 때문에, bugbear.c 파일을 본 뒤 어떤 취약점을 가지고 있는지 확인해보자.





지역변수를 선언한다.



1
2
char buffer[40];                                                                    
int i;
cs



인자가 없으면 "argv error\n"를 출력하고 종료한다.



1
2
3
4
5
if(argc < 2)
{
    printf("argv error\n");                                                            
    exit(0);
}
cs



첫 번째 parameter의 48번째 문자가 '\xbf'이면 "stack betrayed you!!!"를 출력하고 종료한다.



1
2
3
4
5
if(argv[1][47== '\xbf')
{
    printf("stack betrayed you!!\n");                                                
    exit(0);
}
cs



첫 번째 parameter를 buffer에 복사하고 buffer를 출력한다.



1
2
strcpy(buffer, argv[1]);                                                             
printf("%s\n", buffer);    
cs



bugbear의 메모리 구조를 예상해보면 아래와 같이 그릴 수 있다.





실제 변수가 할당될 때 gcc가 최적화를 위해 자동적으로 dummy를 생성할 수 있다.


gdb를 이용하여, bugbear를 분석해보자. bugbear를 gdb로 실행하는 도중 permission denied가 발생하면 cp 명령을 이용해 파일을 복사하면 된다. 현재 user의 권한으로 똑같은 파일을 가질 수 있기 때문이다.





위와 같이 bugbearcp가 darkknight의 권한으로 복사된 것을 확인할 수 있다.



dummy가 생성되었는지 gdb를 통해 확인해보자.






dummy가 추가적으로 생성되지 않고 정확히 44(0x2C) byte가 생성된것을 확인할 수 있다.


bugbear.c를 보면 Return To Library(RTL)라는 힌트를 주었고, stack 영역을 사용할 수 없다.


RTL 기법에 대해 공부한 뒤 RTL을 통한 공격을 진행하면 될 것이다.


RTL 기법은 buffer overflow 공격이 stack 영역에서 실행되지 못하게 하는 non-executable stack 기법과 같은 보호 기법을 우회하기 위해서 나온 기법이다.


RTL 기법도 기존의 BOF와 같이 buffer를 넘치게 padding을 진행하여 EIP를 조작한다. 하지만 EIP를 stack 영역의 주소가 아닌, library의 영역으로 조작하는 것이다.


우리가 쉘을 실행하는 가장 기본적인 명령어는 system(/bin/bash)이다.

library에 system 함수가 있고, "/bin/bash"를  buffer or 환경 변수에 저장한 뒤 system 함수의 파라미터로 넘겨주면, 쉘이 실행될 것이다.

하지만, system 함수 내부에 execve 함수가 있고, execve 내부에 "/bin/sh" 문자열이 존재한다. 

우리는 system 함수 내부의 "/bin/sh"를 이용한다.


공유라이브러리의 system 함수의 주소는 gdb를 통해서 알 수 있다.




내부의 "/bin/sh"를 찾는 소스를 작성해보자.



1
2
3
4
5
6
7
8
9
// whereissh.c                                                                        
#include <stdio.h>
main()
{
        long shell = 0x40058ae0;
        while(memcmp((void*)shell, "/bin/sh"8))
                shell++;
        printf("%x\n", shell);
}
cs



shell에 system 함수의 시작주소를 넣고, system 함수의 시작부터 "/bin/sh"의 문자열을 만날 때 까지 주소를 1씩 증가시켜 "/bin/sh"의 문자열을 찾는 소스이다.



"/bin/sh"의 문자열은 0x400fbff9에 위치해 있다.


이제 system 함수의 주소와 "/bin/sh"의 주소를 알았으니 payload를 작성해 공격을 진행해보자.


Nop padding 44 byte + system 주소 + NOP padding 4byte + "/bin/sh" 문자열의 주소