EASY7
Race Condition 경쟁조건 본문
Race Condition 경쟁조건
다중 프로세스 환경에서 두개 이상의 프로세스가 동시에 수행될 때 발생되는 비정상적인 상태를 의미한다.
임의의 공유자원을 여러개의 프로세스가 경쟁하기 때문에 발생한다.
일반계정의 프로세스와 관리자의 힘을 가진 프로세스가 경쟁해서 이기면 관리자 힘을 획득할 수 있는 현상.
대표적인 예로 심볼릭 링크를 이용하는 예이다.
1. fork 함수의 이해
(참고 : https://codetravel.tistory.com/23)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#include <stdio.h>
#include <unistd.h>
int main() {
int x;
x = 0;
fork();
x = 1;
printf("PID : %ld, x : %d\n",getpid(), x);
return 0;
}
|
cs |
fork는 자식 프로세스를 생성해주는 함수. unistd.h라이브러리에서 system call로 정의되어있다.
fork함수를 호출하는 프로세스가 부모 프로세스가 되고 새롭게 생성되는 프로세스가 자식 프로세스이다.
함수 실행하면 자식 프로세스의 PID가 반환된다.
자식 프로세스는 부모 프로세스의 메모리를 그대로 복사하여 가지고 fork함수 호출 후 각자의 메모리를 사용해서 실행된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#include <stdio.h>
#include <unistd.h>
int main() {
int x;
x = 0;
fork();
x = 1;
printf("PID : %ld, x : %d\n",getpid(), x);
return 0;
}
|
cs |
알 수 있는 것.
자식프로세스는 부모 프로세스의 메모리를 복사하기 때문에 x=1이라는 변수를 알고 있다.
두 프로세스가 각자 마이웨이로 실행된다.
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 <unistd.h>
#include <sys/types.h>
int main() {
pid_t pid;
int x;
x = 0;
pid = fork();
if(pid > 0) { // 부모 코드
x = 1;
printf("부모 PID : %ld, x : %d , pid : %d\n",(long)getpid(), x, pid);
}
else if(pid == 0){ // 자식 코드
x = 2;
printf("자식 PID : %ld, x : %d\n",(long)getpid(), x);
}
else { // fork 실패
printf("fork Fail! \n");
return -1;
}
return 0;
}
|
cs |
알 수 있는 것.
fork하면 자식 프로세스의 PID가 반환되는데. 그 반환되기 전에 자식프로세스가 메모리를 복사하기 때문에
자식프로세스의 변수 pid는 여전히 0이다.
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
|
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
void main(void)
{
int childpid;
int a,b;
if((childpid = fork()) >0) {
for(a = 0; a < 100; a++){
if(a % 2 == 0) printf("O");
}
exit(0);
}
else{
for(b = 0; b < 100; b++) {
if(b % 2 == 1) printf("X");
}
exit(0);
}
}
|
cs |
블로그 주인장님께 질문을 드렸는데! 친절하게 답변을 받았습니다~
100번 정도는 스케쥴 한사이클에 끝낼 수 있는 양이라고 합니다!
해결책 1.
반복문을 백만번으로 늘려보자!
그래서 백만번으로 반복문을 돌렸더니 이렇게 O와 X가 번갈아가면서 나옵니다. 그동안의 삽질ㅠㅠ (감격의 눈물)
해결책 2.
sleep(1)을 넣어보라고 하시네요! 프로세스가 1초 쉬는 동안 프로세스 정책에 따라 다른 프로세스가 CPU를 점유할 수 있다!
그런데.. 왜 출력물이 한꺼번에 나올까 해서 블로그 주인님께 여쭤봤는데!
stdout 버퍼에 쌓아놓고 flush로 한번에 출력하기 때문이라고 합니다! .. 그래서 개행문자(\n)을 추가했더니.. 100번을 돌렸는데 중간에 O사이에 X가 하나 나오네요????!!!!!! 비록 하나의 X지만.. 참 고맙네요 ㅠㅠㅠ 궁금증 해결!!
sleep(1)과 개행문자, 100번 반복! 으로 돌리니 이렇게 착하게 나옵니다!!
성공한 코드:
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
|
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
void main(void)
{
int childpid;
int a,b;
if((childpid = fork()) >0) {
for(a = 0; a < 100; a++){
if(a % 2 == 0) printf("O \n");
sleep(1);
}
exit(0);
}
else{
for(b = 0; b < 100; b++) {
if(b % 2 == 1) printf("X \n");
sleep(1);
}
exit(0);
}
}
|
cs |
3. 심볼릭 링크를 이용해서 경쟁조건 해보기
1) 백도어 만들기
UID, GID 모두 0(root계정)으로 설정하기
2) 임의의 사용자가 백도어 프로그램을 실행시킬 수 있도록 SETUID 설정하기
# chmod 4755 backdoor.c
3) 심볼릭 링크 생성
# ln -s backdoor.c racecondition.c
4) root 사용자가 백도어 파일을 삭제하여도 심볼릭 링크는 링크정보가 그대로 남아있다.
5) root 사용자가 backdoor.c라는 이름의 파일을 같은 디렉터리에 생성하면 다시 심볼릭 링크는 유효하게 된다.
6)하지만...!!! 심볼릭링크는 새로 생긴 파일의 권한을 따른다.
이럴꺼면 2번의 setUID는 왜 설정했는가! 그리고 이게 왜 경쟁조건일까?
참조 : https://blog.z3alous.xyz/73
레이스 컨디션의 공격의 기본
1. 취약 프로그램이 생성하는 임시 파일의 이름을 파악
2. 생성될 임시 파일과 같은 이름의 파일을 생성
3. 이에 대한 심볼릭 링크를 생성
4. 원본 파일을 지운 채 취약 프로그램이 심볼릭 링크를 건 파일과 가은 파일을 생성할 때를 기다린다.
5. 생성되었을 때, 심볼릭 링크를 이용해 파일 내용을 변경 -> 변경 안됨;;
6. 시스템은 변경된 파일을 자신이 생성한 임시 파일로 생각하고 프로세스를 진행시킬 것이고,
공격자는 관리자 권한으로 실행되는 프로그램에 끼어들어 무언가를 할 수있는 여지를 만든다.-> 이게 경쟁조건일까..
출처: https://blog.z3alous.xyz/73 [Lucete]
'보안 공부 > 취약점 실습' 카테고리의 다른 글
ghost(CVE-2015-0235) (0) | 2019.09.10 |
---|---|
Routing Table, ARP Table, MAC Table (0) | 2019.09.04 |
세션 하이재킹 hunt 실습 (0) | 2019.08.17 |
CVE-2019-0193 (0) | 2019.08.13 |
FTP 2.3.4 command execution (0) | 2019.08.10 |