VaccineWeb 문제 풀이 보면서 다시 풀어볼 수 있도록 개인 서버에 올렸습니다.
VaccineWeb 문제 사이트 오픈 기간: ~ 2020년 12월 31일까지
※ 서버에 문제 풀이 관련 이외 공격 금지합니다.
서버: http://34.228.254.139/vaccineweb/secretdata.php
Covid vaccine arrangement page
What you need to do How To Protect Yourself covid virus vaccine data arrangement page
34.228.254.139
목차
- 시나리오
- 정보 수집
- 코드 분석 및 풀이 stage1
- 코드 분석 및 풀이 stage2
[Web] VaccineWeb 시나리오
VaccineWeb
시나리오: COVID-19 치료제로 사용될 후보 백신 정보를 정리한 페이지 파일 내용 확인이 불가능한 상태다.
홈페이지에서 단서를 찾고 백신 정보를 찾아내자!
Scenario: It is impossible to check the contents of the page file containing information on candidate vaccines to be used as a treatment for COVID-19.
Find clues on the website and identify the vaccine information!
시나리오는 COVID-19 치료제로 사용될 후보 백신 정보를 정리한 페이지 파일 내용 확인이 불가능하다고 한다. 홈페이지에서 단서를 찾고 백신 정보를 찾아내자고 적혀 있는데 파일 내용을 확인할 수 있어야 한다는 것을 알 수 있다.
이 점을 기억하고 추가적인 정보를 수집하자.
정보 수집
[그림 1]에 있던 DATA INPUT 입력 폼에 임의 값 1234를 넣고 DATA INPUT 버튼을 누르면 [그림 2]와 같이 dataprocessing.php 페이지로 이동되고 data input success라는 문자열이 출력된다. 다른 값을 넣더라도 [그림 2]와 동일한 장면이 나오는 것을 확인할 수 있다.
[그림 1] 메인 페이지에서 밑으로 조금 내려가면 [그림 3]이 보이는데 flag is c0v1d_c1e4r 라고 되어 있고 오른쪽에는 you find! :)라고 되어있다. 해당 내용은 진짜 flag가 아니다.
prevention 탭을 누르면 prevention.php로 이동된다. 해당 탭 안에서는 시나리오에서 제시한 파일 내용 확인 관련 단서는 없는 것을 확인할 수 있다.
Login 탭을 누르자 로그인 페이지가 나왔고 로그인 관련 사항으로 "Are you confident in logging in?" 로그인에 자신있냐는 질문과 로그인에 실패시 바이러스라는 문자열이 포함되어 있다.
그 아래에 ID와 Password 입력 폼과 LOGIN ACCESS, LOGIN PROCESSING SOURCE CODE 버튼이 있다.
1234, 1234로 로그인을 시도하자.
LOGIN ACCESS 버튼을 클릭하면 login.php 페이지로 이동하고 alert 메시지 박스에 올바르지 않은 값이므로 바이러스 페이지로 이동한다는 내용이 출력된다.
virus.php 페이지로 이동되고 다른 영향은 없고 페이지만 바뀐 것을 확인할 수 있다.
다시 Login 페이지(secretaccount.php)로 돌아와서 로그인 과정을 확인하기 위해 LOGIN PROCESSING SOURCE CODE 버튼을 클릭하면 [그림 9]와 같이 백신 이미지가 있던 부분이 소스 코드 이미지로 변경되어 출력된다.
여기까지 정보 수집 결과로는 메인 페이지(secretdata.php)에 있던 data input 폼과 회원가입이 없이 로그인만 해야 하는 로그인 페이지(secretaccount.php) 이 두 부분이 해당 문제의 핵심이자 단서라고 볼 수 있다. 로그인을 해야 하는 것과 data input 폼에는 올바른 값을 넣어야 하는 것으로 보면 된다.
코드 분석 및 풀이 stage1
<?php
$fake = $_GET['id'];
$id = "virus";
extract($_GET);
$pw = $_GET['pass'];
if(preg_match('/medic1ne/', $id))
{
echo("<script> location.href = 'virus.php'; </script>");
}
if(stristr($id, "medic1ne") && strcmp($pwcheck, $pw) == 0)
{
echo("<script> alert('success \$flag = ?'); </script>");
}
else
{
echo("<script> alert('incorrect value so virus page!!!!!'); </script>");
echo("<script> location.href = 'virus.php'; </script>");
}
?>
Login 페이지에서 제공한 소스 코드를 분석하자
1. $fake 변수에 id 값을 받아온다.
2. $id 변수에는 virus 문자열이 지정되어 있다.
3. $fake, $id 이후 extract()함수가 진행된다.
4. $pw 변수에 pass 값을 받아온다.
5. if 문에서 preg_match를 통해 medic1ne이 $id 변수에 있을 경우 virus 페이지로 이동시킨다.
6. 두 번째 if문에서 medic1ne이 있는지 검사하는데 대소문자를 구분하지 않는다. 그리고 $pw와 $pwcheck 변수 값이 같은지 검사하고 있다. 여기 값이 true가 되면 flag 값을 확인할 수 있고 false인 경우 else문이 실행되어 [그림 7]에서 본 메시지 박스 출력과 함께 virus page로 이동하게 된다.
여기서 취약한 부분을 아래의 표와 같이 정리했다.
함수 | 이유 |
extract() | 변수 선언 전에 사용해야 하는데 선언 후에 했기 때문에 전에 변수 값을 클라이언트 측에서 마음대로 변경이 가능하다. 즉, GET 방식이므로 login.php?id=medic1ne으로 새롭게 지정이 가능하다. |
preg_match() | preg_match에서 /medic1ne/는 대소문자 구분 없이 패턴을 찾는게 아니라 구분을 한다. 즉, /medic1ne/i로 해야 MEDIC1NE, Medic1ne 이렇게 대소문자가 섞여 있는 것도 찾을 수 있다. 하지만 위와 같이 구분을 하기 때문에 meDic1ne 이렇게 대문자 하나를 포함시켜주면 우회할 수 있다. |
stristr() | 위 분석 6번에서 언급한 것과 같이 대소문자를 구분하지 않는 strstr() 함수로 볼 수 있다. medic1ne을 $id 값과 비교하는데 대소문자를 구분하지 않는다. 즉, meDic1ne을 입력하면 우회할 수 있다. preg_match와 stristr 둘 다 우회해야 하기 때문에 medic1ne을 그대로 입력하면 preg_match에 걸리는 대신 stristr은 우회된다. 하지만 virus.page로 이동된다. 그래서 둘 다 우회할 수 있는 meDic1ne 또는 MeDic1ne 등 대소문자를 섞거나 대문자로 넣어야 한다. |
strcmp() | strcmp 함수의 경우 비교할 시 ===로 엄격하게 하는 것이 아닌 ==로 하게 되면 배열로 입력을 변경시키면 True가 된다. |
정리하면 login.php?id=meDic1ne&pass[]= 이렇게 입력하면 stage1 코드 전부 우회하여 success로 접근할 수 있다.
위 입력 값 그대로 적용하면 success 문구와 함께 첫 번째 flag 값을 알려준다.
이후 확인을 누르면 [그림 11]과 같이 두 번째 flag 값이라고 출력되는데 base64로 보이는 코드가 나온다.
decode 사이트 또는 python 등을 이용하여 base64 디코딩을 진행하면
"Find and see vaccine.php" 라는 문자열로 변환된다.
vaccine.php 를 찾고 시나리오에 맞춰서 해당 파일 내용을 확인해야 한다는 의미다.
당연히 vaccine.php로 그냥 접근하면 아무것도 확인할 수 없다.
두 번째 플래그 메시지 박스 확인을 누르면 [그림 12]와 같이 새로운 소스 코드를 제공하는데 출력하는 echo 문자열들을 보면 [그림 2]에서 DATA INPUT 폼에 입력 후 이동되어 출력된 문자열과 같다는 것을 알 수 있다. "data input success"가 해당 문자열이다. [그림 12] 소스 코드를 분석하여 vaccine.php를 확인해야 한다.
코드 분석 및 풀이 stage2
<?php
class medicine {
public function __wakeup() {
return highlight_file($this->input);
}
}
class printstr {
public function __wakeup() {
return 'your input value: ' . $this->input;
}
}
if(isset($_POST['input'])) {
$data = ~~~~~~~~~~~~ $_POST['input']);
unserialize($data);
echo "<br><br> data input success";
}
else {
echo("<script> location.href = 'virus.php'; </script>");
}
?>
medicine이라는 클래스를 주목하자.
highlight_file($this->input)이 되어있는데 이 부분은 php코드를 그대로 노출 시켜주는 코드이다.
즉, 우리가 찾는 vaccine.php 내용을 노출 시켜서 확인할 수 있다는 것이다.
그리고 [그림 12]를 보면 '메인 페이지 이동' 이라고 친절하게 표시가 되어있다. 이 말은 메인 페이지에서 봤던 [그림 1]에서 접근한 DATA INPUT 폼 양식을 이용하라는 것이다. 해당 폼에 placeholder 값으로도 input vaccine data라고 되어있다.
highlight_file을 다루는 메서드와 your input value를 출력하는 메서드는 동일한 메서드로 __wakeup 메서드다.
이 메서드는 PHP 매직 함수, PHP 매직 메서드라고 불리는데 직렬화 또는 역직렬화에 반응하여 실행되는 특징을 가지고 있다. 바로 밑에 unserialize($data); 를 보면 역직렬화를 진행하고 있는 것을 볼 수 있다.
$data는 우리가 입력하려는 input 값을 POST 방식으로 받아서 $data 변수에 담고 해당 변수를 역직렬화를 수행하는 것이다. [그림 12]를 보면 이상한 점이 POST 앞 부분을 검정색 네모 박스로 조금 가려져 있는 것을 볼 수 있다. 무슨 이유일까? 하지만 오른쪽에 코드를 보면 ' ) ' 로 포함되어 있는 것으로 볼 때 다른 함수에 포함된 것으로 추측할 수 있다.
결론을 말하자면 검정색 가린 부분은 의미가 없다. why? 위 stage2는 PHP Object Injection 취약점이기 때문이다.
역직렬화를 입력 받는 부분에 Object Injection을 통해 원하는 값을 출력시킬 수 있다.
└▶ unserialize() 함수가 실행되면 __wakeup() 메서드 자동 실행
그렇기 때문에 제공한 소스 코드 dataprocessing.php 파일 내용도 직접 확인할 수 있고 vaccine.php, secretdata.php 등 어느 php 파일이던 다 확인할 수 있기 때문에 직접 가린 부분도 확인할 수 있다.
정리하면 다음과 같다.
1. PHP Object Injection 시도를 하다 보면 검정색 가린 부분이 어떤 함수인지 추측할 수 있다.
2. 확실하게 하고 싶으면 dataprocessing.php 를 Object Injection을 통해 확인하여 어떤 함수가 포함되어 있는 건지 확인 후 vaccine.php 파일을 확인하면 된다.
자 그럼 PHP Object Injection을 수행하여 해결하자.
~~~~~~> 여기서 잠깐! PHP Object Injection이란 무엇인가? 혹시 모른다면 아래 출제자 블로그에서 개념을 파악한 뒤 다시 여기 Demon 팀 블로그로 와서 풀이를 확인하자!
blog.naver.com/lstarrlodyl/222172446060
PHP Object Injection
장치나 인명의 안전을 위한 보안기(arrester)→ arrester 피뢰기에 감동? 받으며 IT보안 공부하는 김주원...
blog.naver.com
O:8:"medicine":1:{s:5:"input";s:11:"vaccine.php";}
vaccine.php를 찾기 위해 Object Injection 양식 기준에 맞춰서 입력한 결과 이전과 같은 data input success 문자열만 출력되고 있다. 위 O:8:~ 는 입력 폼이다. 제공한 소스 코드를 참고하여 작성한 Object Injection data 내용이다.
O:8:"medicine":1:{s:5:"input";s:14:"secretdata.php";}
vaccine.php 는 확인할 수 없었기 때문에 secretdata.php를 시도하면 [그림 14]와 같이 정상적으로 코드가 출력되는 것을 볼 수 있다.
O:8:"medicine":1:{s:5:"input";s:9:"login.php";}
login.php (stage1) first_flag를 찾았던 로그인 페이지를 확인하면 마찬가지로 [그림 15]를 보면 [그림 14]와 동일하게 코드가 정상적으로 출력된다. 여기까지 확인하면 위에서 말한 검정색 가린 부분이 어떤 함수인지 추측할 수 있다는 것이다.
물론 추측이기에 정확하게 알아내려면 dataprocessing.php를 Object Injection 입력 폼에 맞춰서 입력하여 확인하면 된다.
추측이 가능한 부분은 vaccine.php를 검색하였을 때 정상적으로 되지 않았기 때문에 vaccine 해당 문자열을 감지하여 무언가 다른 역할을 하도록 만들었다고 생각할 수 있다. 하나 떠오르는 것은 치환이다. 다른 문자열로 입력되도록 만들면 data input success만 출력되도록 할 수 있다.
정확한 확인을 위해 dataprocessing.php를 확인하자.
O:8:"medicine":1:{s:5:"input";s:18:"dataprocessing.php";}
dataprocessing.php를 확인하면 예상대로 치환을 해주고 있고, 이용한 함수는 str_replace이다. vaccine을 확인하면 ""으로 변환시켜서 입력된다.
그러면 어떻게 입력하면 될까? str_replace 취약점을 이용하면 된다.
vaccine이 사라지고도 vaccine이 맞춰지면 되기 때문에 vacvaccinecine 이렇게 입력하고 object injection 폼 기준은 그대로 사라지고 남을 string length로 맞춰준다. 즉, vaccine.php의 길이는 11이다. vacvaccinecine는 14인데 replace되기 때문에 그대로 11로 넣어야 한다.
O:8:"medicine":1:{s:5:"input";s:11:"vacvaccinecine.php";}
위 폼과 동일하게 넣으면 [그림 17]과 같이 second_flag를 확인할 수 있고, 전체 flag는 first_flag와 second_flag를 합친 값이라고 나와있다.
$flag = POX{v4cc1ne_d4t4_f1nd_chingchanhae}
'CTF' 카테고리의 다른 글
POX 2020 CTF - Kiban64 (0) | 2020.11.25 |
---|---|
POX 2020 CTF - Mobile Pentest Write Up (0) | 2020.11.23 |
Power of XX 2020 Write up (0) | 2020.11.21 |
DownUnderCTF - Is this pwn or web? write-up (0) | 2020.09.28 |