[Pwnable] 20. Logical Bug: Command Injection

Wonder_Land🛕·2022년 11월 24일
0

[Pwnable]

목록 보기
20/21
post-thumbnail

[Reference] : 위 글은 다음 내용을 제가 공부한 후, 인용∙참고∙정리하여 만들어진 게시글입니다.


  1. 서론
  2. Command Injection
  3. Q&A
  4. 마치며

1. 서론

프로그램을 만들다보면 스스로 코드를 작성하기보다, 이미 설치된 소프트웨어를 사용하는 것이 필요한 경우가 있습니다.

C/C++으로 프로그래밍할 때는 system함수를 사용하기도 합니다.
이 함수는 함수에 전달된 인자를 셸 프로그램에 전달해 명령어를 실행시킵니다.
system("cat /etc/passwd")를 호출하면, 셸 프로그램으로 cat /etc/passwd를 실행한 것과 같습니다.

이러한 이점도 있지만, 그와 동시에 함수의 인자를 셸 명령어로 전달한다는 점에서 치명적인 취약점으로 이어지기도 합니다.


2. Command Injection

  • 인젝션(Injection)
    : 악의적인 데이터를 프로그램에 입력하여, 이를 시스템 명령어, 코드, 데이터베이스 쿼리 등으로 실행되게 하는 기법
    : 이 중, 사용자의 입력을 시스템 명령어로 실행하게 하는 것을 'Command Injection'이라고 함

Command Injection은 명령어를 실행하는 함수에 사용자가 임의의 인자를 전달할 수 있을 때 발생합니다.
사용자가 입력한 임의 IP에 ping을 전송하고 싶다면 system("ping [user-input]"),
임의 파일을 읽고 싶다면 system("cat [user-input]")등의 형태로 system함수를 사용할 수 있습니다.

하지만, 이러한 호출 과정에서 사용자의 입력을 제대로 검사하지 않으면 임의 명령어가 실행될 수도 있습니다.
이는 리눅스 셸 프로그램이 지원하는 여러 메타 문자 때문입니다.

system함수는 셸 프로그램에 명령어를 전달하여 실행합니다.
셸 프로그램은 다양한 메타 문자를 지원하기도 하죠.

Meta 문자설명Example
$셸 환경변수$ echo $PWD
/homeTheori
&&이전 명령어 실행 후
다음 명령어 실행
$ echo hello && echo theori
hello
theori
;명령어 구분자$ echo hello ; echo theori
hello
theori
|명령어 파이핑$ echo id | /bin/sh
uid=1001(theori) ...
*와일드 카드$ echo .*
...
`명령어 치환$ echo `echo hello theori`
hellotheori

아래의 예제에서는, 사용자가 입력한 IP를 ping의 인자로 전달합니다.
(ping은 특정 IP의 서버가 작동하는지 확인하려고 자주 사용합니다.)

// Name: cmdi.c
// Compile: gcc -o cmdi cmdi.c

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

const int kMaxIpLen = 36;
const int kMaxCmdLen = 256;

int main() {
  char ip[kMaxIpLen];
  char cmd[kMaxCmdLen];
  
  // Initialize local vars
  memset(ip, '\0', kMaxIpLen);
  memset(cmd, '\0', kMaxCmdLen);
  strcpy(cmd, "ping -c 2 ");
  
  // Input IP
  printf("Health Check\n");
  printf("IP: ");
  fgets(ip, kMaxIpLen, stdin);
  
  // Construct command
  strncat(cmd, ip, kMaxCmdLen);
  printf("Execute: %s\n",cmd);
  
  // Do health-check
  system(cmd);
  return 0;
}

IP로 127.0.0.1을 입력하면 다음과 같이 작동합니다.

$ ./cmdi
Health Check
IP: 127.0.0.1
Execute: ping -c 2 127.0.0.1

PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.019 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.032 ms

--- 127.0.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1065ms
rtt min/avg/max/mdev = 0.019/0.025/0.032/0.008 ms

만약, 악의적인 사용자라고 하면, 코드 상에서 아무런 검사가 없다는 점을 파악해 Command Injection을 시도할 수 있습니다.

다음은 ;를 메타문자로 사용하여 셸을 실행시키는 예제입니다.
ping이 정상적으로 실행된 후, /bin/sh가 이어서 실행됩니다.

$ ./cmdi
Health Check
IP: 127.0.0.1; /bin/sh
Execute: ping -c 2 127.0.0.1; /bin/sh

PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.020 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.046 ms

--- 127.0.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1059ms
rtt min/avg/max/mdev = 0.020/0.033/0.046/0.013 ms

$ id
uid=1000(dreamhack) gid=1000(dreamhack) groups=1000(dreamhack)

따라서 개발자는 이러한 취약점을 막기 위해,
입력값에 대해 메타 문자의 유무를 철저히 검사해야합니다.
또한, 꼭 필요한 상황이 아니면 system과 같은 함수의 사용을 자제해야 합니다.
이러한 함수는 memory corruption과 관련된 익스플로잇에도 사용될 수 있기 때문입니다.


3. Q&A

-


4. 마치며

-

[Reference] : 위 글은 다음 내용을 제가 공부한 후, 인용∙참고∙정리하여 만들어진 게시글입니다.

profile
아무것도 모르는 컴공 학생의 Wonder_Land

0개의 댓글