[LOB] nightmare -> xavious

Posted by dw0rdptr
2015. 6. 27. 21:31 System/LOB
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
#include <stdio.h>
#include <stdlib.h>
#include <dumpcode.h>
 
main()
{
    char buffer[40];
    char *ret_addr;
 
    // overflow!
    fgets(buffer, 256, stdin);
    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


쓸수 있는게 별로없다.

스택사용불가, leave ret사용불가, 라이브러리사용불가, LD_PRELOAD 사용불가

뭘쓰라는거야



stdin 임시입력버퍼 찾으면됨


strace ./xavius로 찾아보면 mmap으로 메모리 공간 확보하고 read()로 입력받는다
-> fets()는 read()를 사용한다.
-> 확보된 메모리공간 찾아가보면 입력받은 string이 남아있을 것.



페이로드와 Password


'System > LOB' 카테고리의 다른 글

[LOB] succubus -> nightmare  (0) 2015.06.01
[LOB] zombie_assassin -> succubus  (0) 2015.04.30
[LOB] assassin -> zombie_assassin  (0) 2015.04.18
[LOB] giant -> assassin  (0) 2015.04.14
[LOB] bugbear -> giant  (2) 2015.04.14

[LOB] succubus -> nightmare

Posted by dw0rdptr
2015. 6. 1. 21:44 System/LOB
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
/*
        The Lord of the BOF : The Fellowship of the BOF
        - nightmare
        - PLT
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dumpcode.h>
 
main(int argc, char *argv[])
{
    char buffer[40];
    char *addr;
 
    if(argc < 2){
        printf("argv error\n");
        exit(0);
    }
 
    // check address
    addr = (char *)&strcpy;
    if(memcmp(argv[1]+44, &addr, 4!= 0){
           printf("You must fall in love with strcpy()\n");
           exit(0);
    }
 
    // overflow!
   strcpy(buffer, argv[1]);
    printf("%s\n", buffer);
   
 
    // dangerous waterfall
    memset(buffer+40+8'A'4);
}
cs

빨리 LOB끝내고 pwnable.kr를 풀어야하므로 간단하게 정리한다


ret주소엔 strcpy(*dst, *src)주소인지 확인한다. 그리고 아래 memset은 strcpy()의 ret를 AAAA로 초기화시킨다.

[buffer][sfp][ret(strcpy@plt)][AAAA(strcpy()의 ret)][dest][src]


페이로드는
argv[1] : [buffer][sfp][strcpy()][AAAA][&AAAA][argv[2]]
argv[2] : [system()][BBBB or exit()][/bin/sh]


strcpy()함수를 사용해 AAAA로 초기화되어있는 strcpy()의 ret주소에 argv[2], system()함수가 있는 두번째 인자값을 복사한다.

strcpy함수가 종료되면서 ret에 의해 argv[2]로 뛰면 성공


&AAAA(strcpy() ret)와 argv[2]의 주소를 구하면 끝. 주소는 소스코드를 수정해 구함


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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dumpcode.h>
 
main(int argc, char *argv[])
{
        char buffer[40];
        char *addr;
        printf("buffer:%p\n",buffer);
        printf("argv[2]:%p\n",argv[2]);
 
        if(argc < 2){
                printf("argv error\n");
                exit(0);
        }
 
        // check address
        addr = (char *)&strcpy;
        if(memcmp(argv[1]+44, &addr, 4!= 0){
                printf("You must fall in love with strcpy()\n");
                exit(0);
        }
 
        // overflow!
        strcpy(buffer, argv[1]);
        printf("%s\n", buffer);
 
        // dangerous waterfall
        memset(buffer+40+8'A'4);
}
 
 
cs

 - 수정된 코드



&AAAA : 0xbffffa60+44= 0xbffffa90

argv[2] : 0xbffffc22


페이로드와 Password



'System > LOB' 카테고리의 다른 글

[LOB] nightmare -> xavious  (1) 2015.06.27
[LOB] zombie_assassin -> succubus  (0) 2015.04.30
[LOB] assassin -> zombie_assassin  (0) 2015.04.18
[LOB] giant -> assassin  (0) 2015.04.14
[LOB] bugbear -> giant  (2) 2015.04.14

[LOB] zombie_assassin -> succubus

Posted by dw0rdptr
2015. 4. 30. 16:38 System/LOB
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/*
        The Lord of the BOF : The Fellowship of the BOF
        - succubus
        - calling functions continuously 
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <dumpcode.h>
 
// the inspector
int check = 0;
 
void MO(char *cmd)
{
        if(check != 4)
                exit(0);
 
        printf("welcome to the MO!\n");
 
    // olleh!
    system(cmd);
}
 
void YUT(void)
{
        if(check != 3)
                exit(0);
 
        printf("welcome to the YUT!\n");
        check = 4;
}
 
void GUL(void)
{
        if(check != 2)
                exit(0);
 
        printf("welcome to the GUL!\n");
        check = 3;
}
 
void GYE(void)
{
    if(check != 1)
        exit(0);
 
    printf("welcome to the GYE!\n");
    check = 2;
}
 
void DO(void)
{
    printf("welcome to the DO!\n");
    check = 1;
}
 
 
 
main(int argc, char *argv[])
{
    char buffer[40];
    char *addr;
 
    if(argc < 2){
        printf("argv error\n");
        exit(0);
    }
 
    // you cannot use library
    if(strchr(argv[1], '\x40')){
        printf("You cannot use library\n");
        exit(0);
    }
 
    // check address
    addr = (char *)&DO;
        if(memcmp(argv[1]+44, &addr, 4!= 0){
                printf("You must fall in love with DO\n");
                exit(0);
        }
 
    // overflow!
    strcpy(buffer, argv[1]);
    printf("%s\n", buffer);
 
    // stack destroyer
    // 100 : extra space for copied argv[1]
    memset(buffer, 044);
    memset(buffer+48+10000xbfffffff - (int)(buffer+48+100));
 
    // LD_* eraser
    // 40 : extra space for memset function
    memset(buffer-300003000-40);
}
cs

소스가 길어졌다... 힌트를 보면 calling functions continuously, 함수 연속호출을 뜻하는것 같다


전역변수로 check를 선언한다

공유라이브러리를 사용할 수 없고, ret가 함수 DO의 주소가아니면 종료해버린다.

DO,GYE,GUL,YUT,MO를 연속적으로 호출해 함수MO의 system함수로 쉘을 실행시키자


ret에 DO의 주소를 덮으면 DO가 호출된다. ret로 호출된 함수는 그 함수의 ret가 생성되지 않기 때문에 바로 다음함수인 GYE의 주소를 덮어쓴다. 이런식으로 먼저 MO까지 호출해보자


DO : 0x80487ec
GYE : 0x80487bc
GUL : 0x804878c
YUT : 0x804875c
MO : 0x8048724

-> gdb로 구한 함수의주소

[ buffer+sfp(44bytes) ][DO()][GYE()][GUL()][YUT()][MO()]


MO까지 성공적으로 호출했다. MO는 *cmd를 인자로 받는데 공유라이브러리를 쓰지 못하니 argv[1]에 /bin/sh를 쓰고 주소를 구해 전달하자

[ buffer+sfp(44bytes) ][DO()][GYE()][GUL()][YUT()][MO()][dummy(4bytes)][&/bin/sh][/bin/sh]


먼저 core를 떨어트려 주소를구하자

[ buffer+sfp(44bytes) ][DO()][GYE()][GUL()][YUT()][MO()][AAAA][BBBB][CCCC]

/bin/sh 가 들어갈 주소인 0xbffffa68이 $/bin/sh이다


페이로드와 Password



'System > LOB' 카테고리의 다른 글

[LOB] nightmare -> xavious  (1) 2015.06.27
[LOB] succubus -> nightmare  (0) 2015.06.01
[LOB] assassin -> zombie_assassin  (0) 2015.04.18
[LOB] giant -> assassin  (0) 2015.04.14
[LOB] bugbear -> giant  (2) 2015.04.14

[LOB] assassin -> zombie_assassin

Posted by dw0rdptr
2015. 4. 18. 03:01 System/LOB
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
/*
        The Lord of the BOF : The Fellowship of the BOF
        - zombie_assassin
        - FEBP
*/
 
#include <stdio.h>
#include <stdlib.h>
 
main(int argc, char *argv[])
{
    char buffer[40];
 
    if(argc < 2){
        printf("argv error\n");
        exit(0);
    }
 
    if(argv[1][47== '\xbf')
    {
        printf("stack retbayed you!\n");
        exit(0);
    }
 
        if(argv[1][47== '\x40')
        {
                printf("library retbayed you, too!!\n");
                exit(0);
        }
 
    // strncpy instead of strcpy!
    strncpy(buffer, argv[1], 48); 
    printf("%s\n", buffer);
}
cs


소스를보면 strncpy로 인자가 48바이트로 제한돼 ret까지밖에 덮지 못한다. 이렇게 스택과 라이브러리를 필터링하고 ret이후로 덮어쓸 수 없을 때 fake ebp 기법을 활용한다


fake ebp란 sfp에 buffer-4의 주소를 덮어 ebp를 버퍼주소로 옮기고 ret에 leave주소를 덮어 함수 에필로그 과정을 한번 더 수행해 sfp를 변조해 만든 가짜 ebp로 esp가 가게 만들어 우회하는 기법이다. buffer-4 인 이유는 leave를 한번 더 수행할 때 pop ebp 과정으로 인해 esp+4가 되기 때문에 버퍼의 시작주소에 맞추기 위함이다


[system()][dummy(or exit())]["/bin/sh"][28byte dummy][buffer-4][leave]

                                                                                 ↓         ↓

                                                                                sfp       ret


system()과 /bin/sh 주소구하는 방법 전레벨과 같으므로 생략

buffer-4와 leave의 주소를 구하자


leave : 0x80484df

buffer-4 : 0xbffffa60-4 = 0xbffffa5c

[0x40058ae0][AAAA][0x400fbff9][AAA...AA(28byte)][0xbffffa5c][0x80484df]


페이로드와 Password


'System > LOB' 카테고리의 다른 글

[LOB] succubus -> nightmare  (0) 2015.06.01
[LOB] zombie_assassin -> succubus  (0) 2015.04.30
[LOB] giant -> assassin  (0) 2015.04.14
[LOB] bugbear -> giant  (2) 2015.04.14
[LOB] darkknight -> bugbear  (0) 2015.04.12

[LOB] giant -> assassin

Posted by dw0rdptr
2015. 4. 14. 17:22 System/LOB

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
/*
        The Lord of the BOF : The Fellowship of the BOF
        - assassin
        - no stack, no RTL
*/
 
#include <stdio.h>
#include <stdlib.h>
 
main(int argc, char *argv[])
{
    char buffer[40];
 
    if(argc < 2){
        printf("argv error\n");
        exit(0);
    }
 
    if(argv[1][47== '\xbf')
    {
        printf("stack retbayed you!\n");
        exit(0);
    }
 
    if(argv[1][47== '\x40')
    {
        printf("library retbayed you, too!!\n");
        exit(0);
    }
 
    strcpy(buffer, argv[1]); 
    printf("%s\n", buffer);
 
    // buffer+sfp hunter
    memset(buffer, 044);
}
cs

no stack, no RTL로 ret에 스택과 공유라이브러리 주소를 쓰지 못하게 됐다


하지만 ret에 ret주소를 덮게되면 esp+4에 있는 주소를 실행해 우회할 수 있다.

[ret주소][system()주소][dummy]["/bin/sh"] 이렇게 페이로드를구성한다면


higher address

----------

   /bin/sh

----------

   dummy

----------

    system

------------

       ret

------------  <- esp

lower address

ret가 pop eip, jmp eip 명령을 수행한다는것은 알고 있을것이다.

pop eip를 할 때 eip에 ret주소가 들어가고 jmp eip를하면 ret로 돌아오지만 esp는 pop명령으로 인해 +4가 되어 있는 상태다


higher address

----------

   /bin/sh

----------

   dummy

----------

    system

------------ <- esp

       ret

------------  

lower address


현재 ret주소로 다시 돌아왔으니 ret명령이 또한번 수행된다

pop eip, jmp eip를 수행하면 eip에는 system함수의 주소가 들어가고, jmp로 system함수를 실행해 /bin/sh가 실행된다



gdb로 main함수에서 ret주소를 찾자

ret : 0x804851f

system() : 0x40058ae0

/bin/sh : 0x400fbff9

system함수와 /bin/sh를 구하는 방법은 전레벨에서 설명이 되어있으니 건너뛰겠다



페이로드와 Password


'System > LOB' 카테고리의 다른 글

[LOB] zombie_assassin -> succubus  (0) 2015.04.30
[LOB] assassin -> zombie_assassin  (0) 2015.04.18
[LOB] bugbear -> giant  (2) 2015.04.14
[LOB] darkknight -> bugbear  (0) 2015.04.12
[LOB] golem -> darkknight  (0) 2015.04.11

[LOB] bugbear -> giant

Posted by dw0rdptr
2015. 4. 14. 16:34 System/LOB
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
/*
        The Lord of the BOF : The Fellowship of the BOF
        - giant
        - RTL2
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
main(int argc, char *argv[])
{
    char buffer[40];
    FILE *fp;
    char *lib_addr, *execve_offset, *execve_addr;
    char *ret;
 
    if(argc < 2){
        printf("argv error\n");
        exit(0);
    }
 
    // gain address of execve
    fp = popen("/usr/bin/ldd /home/giant/assassin | /bin/grep libc | /bin/awk '{print $4}'""r");
    fgets(buffer, 255, fp);
    sscanf(buffer, "(%x)", &lib_addr);
    fclose(fp);
 
    fp = popen("/usr/bin/nm /lib/libc.so.6 | /bin/grep __execve | /bin/awk '{print $1}'""r");
    fgets(buffer, 255, fp);
    sscanf(buffer, "%x", &execve_offset);
    fclose(fp);
 
    execve_addr = lib_addr + (int)execve_offset;
    // end
 
    memcpy(&ret, &(argv[1][44]), 4);
    if(ret != execve_addr)
    {
        printf("You must use execve!\n");
        exit(0);
    }
 
    strcpy(buffer, argv[1]); 
    printf("%s\n", buffer);
}
cs

코드가 복잡해졌다. execve의 주소를 구하고 ret를 execve함수의 주소로 덮어쓰지 않으면 프로그램이 종료된다


execve는 호출한 프로세스를 새로운 프로세스로 변경한다. 이때 환경변수 정보를 추가 가능하다


프로토타입

execve (const char *filename, char *const argv[], char *const envp[])

첫번째 인자 : 실행시킬 파일명

두번째 인자 : 전달할 인자값 (포인터배열)

세번째 인자 : 환경변수 (NULL을 주면됨)


ret에 execve의 주소를 덮으면

(lower address) [execve()][execve의 ret][인자1][인자2][인자3] (higher addess)


[execve()][system()][exit()]["bin/sh"][NULL]

execve함수로 exit함수를 실행하면 바로 종료해버리면서 ret에있는 system함수를 실행하고 두번째 인자로 전달한 /bin/sh이 실행된다.


system() : 0x40058ae0

execve() : 0x400a9d48

exit() : 0x400391e0

NULL : 0xbffffffc (스택끝부분에 있는걸 씀)

/bin/sh : 0x400fbff9 ( darkknight에서 구한 주소)



페이로드와 Password


*exit주소를 쓰지 않고 dummy로 채워도 쉘을 딸 수 있지만 dummy로 채웠을 경우 쉘을 나가면 세폴 오류가 뜬다는 차이점이 있다

 


'System > LOB' 카테고리의 다른 글

[LOB] assassin -> zombie_assassin  (0) 2015.04.18
[LOB] giant -> assassin  (0) 2015.04.14
[LOB] darkknight -> bugbear  (0) 2015.04.12
[LOB] golem -> darkknight  (0) 2015.04.11
함수의 프롤로그(prologue) 및 에필로그(epilogue)  (0) 2015.04.10

[LOB] darkknight -> bugbear

Posted by dw0rdptr
2015. 4. 12. 15:30 System/LOB


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
/*
        The Lord of the BOF : The Fellowship of the BOF
        - bugbear
        - RTL1
*/
 
#include <stdio.h>
#include <stdlib.h>
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 betrayed you!!\n");        
        exit(0);    
    }    
    
    strcpy(buffer, argv[1]); 
    printf("%s\n", buffer);
 
}
cs


bugbear의 소스이다 . 힌트를 보면 알 수 있듯이 이번엔 RTL 기법을 사용해서 풀어야 한다. ret에 스택내의 주소를 덮으려하면 스택이 배신했다고 하면서 종료돼버린다.


RTL(Return To Libc) : 스택에서 어떤 코드도 실행되지 못하도록 하는 보호기법이 나온 이후 나온 기법. 프로그램이 실행될 때 프로그램이 사용한 함수를 포함한 내장라이브러리인 Libc가 Libc 영역에 적재된다. 이 라이브러리에는 system()함수도 포함되어있는데 프로그램이 이함수를 쓰지 않더라도 LIbc가 통째로 올라가기 때문에 메모리에 같이 적재된다

*system()함수 : 명령어를 실행하는 함수. 


이제 메모리 적재되어있는 Libc 영역에서 system() 함수의 주소를 찾고 인자로 "/bin/sh"를 주면 다음레벨의 쉘을 딸 수 있을것이다.


system()함수의 주소는0x40058ae0이다.


이제 "/bin/sh"문자열이 있는 주소를 전달하면 되는데 환경변수를 /bin/sh로 등록해도되지만 system() 함수 내에서도 /bin/sh라는 문자열이 존재한다.

1
2
3
4
5
6
7
8
9
10
int main(int argc, char * argv[])
{
    long shell;
    shell = 0x40058ae0//system 함수 주소
    while(memcmp((void *)shell, "/bin/sh"8)) //시스템 함수 내에서 /bin/sh문자열 비교 
    shell++;
    printf("/bin/sh = %p\n",shell); // /bin/sh문자열이 있는 
}
 
 
cs

 위 소스로 "/bin/sh" 문자열이 있는 주소를 찾을 수 있다.


주소는 0x400fbff9


프로그램의 ret주소를 system()함수의 주소로 채우고 뒤에 인자를 전달하는데, ret명령에 의해 호출된 system() 함수는 ret가 쌓이지 않기 때문에 비어있는 ret자리인 4byte를 더미로 채우고 인자(/bin/sh의 주소)를 전달한다



페이로드와 Password




'System > LOB' 카테고리의 다른 글

[LOB] giant -> assassin  (0) 2015.04.14
[LOB] bugbear -> giant  (2) 2015.04.14
[LOB] golem -> darkknight  (0) 2015.04.11
함수의 프롤로그(prologue) 및 에필로그(epilogue)  (0) 2015.04.10
[LOB] skeleton -> golem  (0) 2015.04.07

[LOB] golem -> darkknight

Posted by dw0rdptr
2015. 4. 11. 02:16 System/LOB
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
/*
        The Lord of the BOF : The Fellowship of the BOF
        - darkknight
        - FPO
*/
 
#include <stdio.h>
#include <stdlib.h>
 
void problem_child(char *src)
{
    char buffer[40];
    strncpy(buffer, src, 41);
    printf("%s\n", buffer);
}
 
main(int argc, char *argv[])
{
    if(argc<2){
        printf("argv error\n");
        exit(0);
    }
 
    problem_child(argv[1]);
}
cs


먼저 함수의 프롤로그와 에필로그 글을 보고 오자


darkknight 소스를 보면
주석에 FPO라고 쓰여져있는데 이는 Frame Pointer Overflow의 약자로 함수 에필로그 과정에서 함수를 종료하면서 ebp포인터를 복구시킬 때 공격자가 원하는곳으로 ebp를 이동시켜 공격코드를 실행시키는 기법이다.


strncpy함수를 쓰는데 41바이트제한으로 딱 1바이트 오버플로우를 시킬 수 있다. sfp(saved frame pointer) 영역의 마지막 1바이트를 변조시킬 수 있다. 겨우 1바이트로 뭘하지 할텐데

우선 sfp에 저장되어있는 값을 보자

버퍼크기만큼 채운 NOP바로 뒤 sfp에 0xbffffa00값이 들어있다.

버퍼의 시작주소가 담겨있는 주소 역시 0xbffffaa0로 앞의 3바이트가 같으므로 1바이트 변조로도 ebp를 버퍼로 이동시킬 수 있다.


? 세폴이 뜬다. core를 떨어트려 분석해보자


역시 주소가 바뀌어있다. 80으로 바꿔서 해보자


세폴이뜬다.

problem_child에서 sfp를 변조하면 ebp는 0xbffffa80으로 날아간다. 그리고 main으로 돌아가서 나머지들을 실행한 후

main의 leave 과정을 통해 mov esp, ebp 명령어를 실행 할 때 esp가 0xbffffa80으로 날아가게 된다

leave과정중 pop ebp를 하게 되면 esp값이 +4가 된다.

그상태에서 ret과정을 통해 pop eip와 jmp eip, 결과적으로 0xbffffa80(esp)+4의 주소에 있는 값이 eip에 들어가고 그 값으로 jmp(점프)하게 되어서 0x90909090 주소로 점프해버려 쉘코드 실행이 되지 않는것이다,


주소를 -4하면 해결된다

\x80->\x7c


페이로드와  Password







'System > LOB' 카테고리의 다른 글

[LOB] bugbear -> giant  (2) 2015.04.14
[LOB] darkknight -> bugbear  (0) 2015.04.12
함수의 프롤로그(prologue) 및 에필로그(epilogue)  (0) 2015.04.10
[LOB] skeleton -> golem  (0) 2015.04.07
[LOB] vampire -> skeleton  (0) 2015.04.01

함수의 프롤로그(prologue) 및 에필로그(epilogue)

Posted by dw0rdptr
2015. 4. 10. 03:51 System/LOB
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
/*
        The Lord of the BOF : The Fellowship of the BOF
        - darkknight
        - FPO
*/
 
#include <stdio.h>
#include <stdlib.h>
 
void problem_child(char *src)
{
    char buffer[40];
    strncpy(buffer, src, 41);
    printf("%s\n", buffer);
}
 
main(int argc, char *argv[])
{
    if(argc<2){
        printf("argv error\n");
        exit(0);
    }
 
    problem_child(argv[1]);
}
cs

r

LOB darkknight의 소스이다. strncpy함수를 호출하는데 딱 1바이트만 오버플로우를 일으킬 수 있다.

이문제는 FPO(Frame Pointer Overflow)기법으로 풀어야 하는데 그전에 함수 프롤로그와 에필로그를 먼저 이해해야 한다.



참고) mov %esp(source),%ebp(destination)   -> AT&T 문법

  mov ebp(destination), esp(source)        -> intel 문법       

둘은 같은 명령을 의미(표기방법의 차이. 자세한건 구글신)


main에서 p(problem_child)함수를 호출했다.

어셈블리에선 생략되어있지만 우선 ret이 생성된다.

higher address

------------

      ret

------------ <-esp

lower address



먼저 push %ebp를 한다. 현재 ebp에는 main함수의 frame pointer(base pointer라고도 함)값이 있는데 이를 push해서 저장한 공간을 sfp(saved frame pointer) 라고 한다. push하였기 때문에 esp가 움직인다.

higher address

------------

      ret

------------

sfp(main의 ebp)

------------ <- esp

lower address



그리고 mov %esp, %ebp로 현재의 esp값을 ebp에 넣는다.(ebp를 esp로 이동시킨다)

현재까지의 스택상황을 보면

higher address

------------

      ret

------------

sfp

------------ <- ebp,esp

lower address


지금 ebp의 위치가 p함수의 frame pointer가 되는것이다

여기까지가 함수 프롤로그.



이제 p함수내에서 버퍼를 선언하면

higher address

------------

      ret

------------

sfp

------------ <- ebp


  buffer[40]

------------ <- esp

lower address


이렇게 esp에서 할당할 만큼의 공간을 빼면서 진행한다




* 아무래도 intel문법이 편해서 지금부턴 intel문법을 쓰겠다.




함수에필로그 과정은  leave와 ret이 있다

각각의 부분에서 실행하는 명령어는 다음과 같다

leave

ret

mov esp, ebp

 pop eip

pop ebp

 jmp eip


먼저 leave에서 p함수는 mov esp, ebp로 그동안 함수내에서 진행한 esp를 ebp값으로 돌려놓는다, 즉 위에서 진행했던 p함수의 프롤로그가 진행된 직후 상태로 되돌린다.

higher address

------------

      ret

------------

sfp

------------ <- ebp,esp

lower address




그리고 pop ebp명령어를 통해 sfp에 들어있던 main의 frame pointer 값이 ebp로 들어가게 된다 (ebp는 이제 main의 frame pointer를 가리키게 됨) pop했으니 esp 4증가.

higher address

------------

      ret

------------ <- esp

lower address



마지막으로 pop eip를 하면 ret에 있는 주소가 eip에 들어가게되고 jmp eip로 점프해 main함수 안의 p함수를 호출한 직후로 가게된다.





darkknight의 풀이는 다음글에서 다룰것이다. 이 글을 이해했으면 굳이 다음 글을 읽지 않아도 해결할 수 있을 것이다.



'System > LOB' 카테고리의 다른 글

[LOB] darkknight -> bugbear  (0) 2015.04.12
[LOB] golem -> darkknight  (0) 2015.04.11
[LOB] skeleton -> golem  (0) 2015.04.07
[LOB] vampire -> skeleton  (0) 2015.04.01
[LOB] troll -> vampire  (0) 2015.04.01

[LOB] skeleton -> golem

Posted by dw0rdptr
2015. 4. 7. 16:19 System/LOB
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
/*
        The Lord of the BOF : The Fellowship of the BOF
        - golem
        - stack destroyer
*/
 
#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, 044);
    memset(buffer+4800xbfffffff - (int)(buffer+48));
}
cs

1) egghunter가 없다 -> 환경변수 사용가능

2) argv[1][47] 에 \xbf가 없으면 종료(ret 주소) -> 스택 내에 쉘코드를 써야한다는 것을 뜻합

3) stack destroyer ! -> 스택을 모조리 초기화시켜버림


ret에 스택내의 주소를 덮어야하는데 스택을 몽땅 초기화시켜버려 답이 없는듯 보이지만 환경변수를 못쓰는 제약을 풀어놓아서 LD_PRELOAD 라는 환경변수를 이용하면 된다

프로그램이 실행될 때 일반적으로 정의되어있는 공유라이브러리를 참조하는데 공유라이브러리 파일을 만들어LD_PRELOAD라는 환경변수에 정의하면 이를 먼저 참조한다. 이 과정에서 찌꺼기가 남게 되는데 이를 이용하면 쉘을 딸 수 있다


*공유라이브러리를 사용하는 이유? : 여러 함수가 내장되어있는 공유라이브러리를 메모리에 올려놓으면 여러 프로그램이 동시에 활용할 수 있기 때문에 디스크공간과 메모리공간을 절약할 수 있다

touch test.c로 파일생성뒤 gcc로 컴파일하는데 이름은 NOP+쉘코드로 한다

그리고 LD_PRELOAD 환경변수도 같은 이름으로 정의한다



이제 프로그램이 실행될 때 LD_PRELOAD 를 먼저 참조하고 stack destroyer 뒤에도 쉘코드가 스택에 존재하게 될 것이다

gdb로 분석해보자

? 없네.. 좀더 뒤에서 찾아봐야겠다



x50x $esp-4000으로 노가다뛰어서 찾으니 NOP이 나왔다 

0xbffff60c로 공격하자


페이로드와 Password



 





'System > LOB' 카테고리의 다른 글

[LOB] golem -> darkknight  (0) 2015.04.11
함수의 프롤로그(prologue) 및 에필로그(epilogue)  (0) 2015.04.10
[LOB] vampire -> skeleton  (0) 2015.04.01
[LOB] troll -> vampire  (0) 2015.04.01
[LOB] orge -> troll  (0) 2015.04.01