3 DreamHack Logical Bugs

Logical Bugs

프로그램의 논리적 오류

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// gcc -o logical logical.c 
#include <stdio.h>
int withdraw(int balance, int money) {
    return balance - money;
}
int main() {
    int balance = 10000;
    int amount = 0;
    int result = 0;
    printf("Your balance: %d\n\n", balance);
    printf("Please enter the amount to withdraw: ");
    scanf("%d", &amount);
    result = withdraw(balance, amount);
    printf("Check your balance: %d", result);
    return 0;
}

해당 코드는 은행에서의 잔고 처리인데 음수에대한 처리가업다.

Command Injection

인젝션은 검증되지 않은 공격자의 입력을 셸 커맨드 또는 쿼리 일부로 처리해 정상적인 실행 흐름을 변경할 수 있는 취약점

  • $ 쉘 환경변수
  • && 이전 명령어 실행 후 다음 명령어 실행
  • ; 명령어 구분자
  • 명령어 파이핑
  • ‘*’ 와일드 카드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// gcc -o cmdi cmdi.c
#include <stdlib.h>
#include <stdio.h>
int main()
{
    char ip[36];
    char cmd[256] = "ping -c 2 "; 
	
    printf("Alive Checker\n");
    printf("IP: ");
    read(0, ip, sizeof(ip)-1);
    printf("IP Check: %s",ip);
    strcat(cmd, ip);
    system(cmd);
    return 0;
}

;를 통해 의도한 명령어보다 추가적인 명령어를 악의적으로 집어넣을수있다.

ping -c 2 127.0.0.1;/bin/sh

Race Condition

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// gcc -o race1 race1.c -pthread
#include <stdio.h>
#include <pthread.h>
#include <time.h>
int count = 0;
void* counting() {
    for(int i=0;i<10000000;i++) {
        count += i;
    }
}
int main(int argc, char* argv[]) {
  pthread_t thread_id[3] = {0,};
  pthread_create(&thread_id[0], NULL, counting, (void*)NULL);
  pthread_create(&thread_id[1], NULL, counting, (void*)NULL);
  pthread_create(&thread_id[2], NULL, counting, (void*)NULL);
  sleep(1);
  printf("%d\n", count);
  return 0;
}

매실행마다 값이다르다.

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
// gcc -o race2 race2.c -fno-stack-protector -lpthread -m32
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int len;
void giveshell() {
    system("/bin/sh");
}
void * t_function() {
    int i = 0;
    while (i < 10000000) {
        len++;
        i++;
        sleep(1);
    }
}
int main() {
    char buf[4];
    int gogo;
    int idx;
    pthread_t p_thread;
    setvbuf(stdin, 0, 2, 0);
    setvbuf(stdout, 0, 2, 0);
    while (1) {
        printf("1. thread create\n");
        printf("2. read buffer\n");
        printf("> ");
        scanf("%d", &idx);
        switch (idx) {
        case 1:
            pthread_create( &p_thread, NULL, t_function, (void * ) NULL);
            break;
        case 2:
            printf("len: ");
            scanf("%d", &len);
            if(len > sizeof(buf)) {
                exit(0);
            }
            sleep(4);
            printf("Data: ");
            read(0, buf, len);
            printf("Len: %d\n", len);
            printf("buf: %s\n", buf);
            break;
        case 3:
            if (gogo == 0x41414141) {
                giveshell();
            }
        }
    }
    return 0;
}

Path Traversal

프로그래머가 가정한 디렉토리를 벗어나 외부에 존재하는 파일에 접근할 수 있는 취약점

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
// gcc -o path_traversal path_traversal.c
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main()
{
	char path[256] = "/tmp/";
	char file_buf[10240];
	char filename[256] = {0,};
	char cmd[256] = {0,};
	
	int len;
	FILE *fp;
	printf("Filename: ");
	fflush(stdout);
	len = read(0, filename, sizeof(filename)-1);
	filename[len-1] = '\0';
	strncat(path, filename, sizeof(path)-1);
	fp = fopen(path, "r");
	if(!fp) {
		return -1;
	}
	fread(file_buf, 1, sizeof(file_buf), fp);
	printf("%s\n", file_buf);
	fclose(fp);
	return 0;
}

/ . 과 같은 상위 디렉토리로 이동하는 문자들에 대한 검증이 존재하지 않아 다른 파일을 읽을 수 있다.

Environment attack

1
2
3
4
5
6
7
8
9
10
11
// gcc -o environ1 environ1.c
#include <stdlib.h>
#include <unistd.h>
int main()
{
    printf("Screen Cleaner\n");
    system("clear");
         
    return 0;
}

system에서 clear명령어를 실행해준다. /bin/sh 파일을 심볼릭 링크를 사용하여 clear 이름으로 링킹 하면 어떻게 될지 생각해보자

1
2
3
4
5
// gcc -o libc.so libc.c -fPIC -shared
#include <stdlib.h>
void read() {
	execve("/bin/sh", 0, 0);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// gcc -o environ2 environ2.c 
#include <unistd.h>
#include <stdio.h>
int main()
{
	char buf[16];
	setvbuf(stdout, 0, 2, 0);
	setvbuf(stdin, 0, 2, 0);
	write(1, "Data:", 5);
	read(0, buf, sizeof(buf)-1);
	
	write(1, "GOOD", 4);
        return 0;
}

LD_PRELOAD로 직접 특정 공유라이브러리를 먼저들고와 링킹하는 방법이 있다 따라서 libc.so파일을 링킹해서 environ2.c파일의 read실행시에 직접만든 read를 실행시킬수있다.

Posted 2020-06-03