HTTP 파라미터 오염
HTTP 파라미터 오염은 웹 사이트가 HTTP 요청 중 전달받는 파라미터를 처리하는 방식을 조작하는 절차다.
공격자가 요청에 추가 파라미터를 삽입하고 대상 웹 사이트가 이를 신뢰해 예기치 않은 동작으로 이어질 때 취약점이 발생한다.
HPP 버그는 서버 측이나 클라이언트 측에서 발생할 수 있다.
일반적으로 브라우저에 해당하는 클라이언트 측에서 테스트 결과를 확인할 수 있다.
대부분 HPP 취약점은 공격자가 제어하는 파라미터로 전달된 값을 서버 측 코드에서 사용하는 방법에 따라 결정된다.
따라서 이 취약점을 찾으려면 다른 유형의 버그보다 더 많은 실험을 해야 할 수도 있다.
서버 측(Server-Side) HPP
서버 측 HPP는 서버 측 코드에서 예기치 않은 결과를 반환하도록 예상 밖의 정보를 전송한다.
웹 사이트에 요청을 보내면 사이트 서버에서 전달받은 요청을 처리하고 응답을 반환한다. 경우에 따라 서버는 웹 페이지를 반환할 뿐만 아니라 전송된 URL에서 수신한 정보를 기반으로 코드를 실행하기도 한다.
전송한 정보와 전달받은 결과를 볼 수 있지만 이 코드는 서버에서 실행되기 때문에 이들 사이에서 처리를 담당하는 코드를 확인할 수 없다. 따라서 작업에 대한 추론만 할 수 있다.
서버의 코드 작동 방식을 파악할 수 없기 때문에 서버 측 HPP는 취약할 가능성이 있는 파라미터를 식별하고 테스트하는 데 의존한다.
서버의 절차를 진행한 URL 파라미터를 승인해 은행에서 웹 사이트를 통해 이체를 시작하면 서버 측 HPP가 발생할 수 있다. 세 개의 URI, 파라미터 from, to, amout에 입력해 일정 금액을 이체할 수 있다고 가정해보자.
각 파라미터는 순서대로 출금 계좌번호, 입금 계좌번호, 이체 금액을 지정한다. 예를 들어 계좌번호 12345에서 계좌번호 67890으로 5,000달러를 이체하는 파라미터를 URL으로 나타내면 다음과 같다.
https://www.bank.com/transfer?from=12345&67890&amount=5000
은행은 각각 하나의 파라미터만 전달받을 것이라고 가정할 수 있다.
다음 URL과 같이 두 개의 파라미터를 전송해본다.
https://www.bank.com/transfer?from=12345&67890&amount=5000&from=ABCDEF
이 URL은 첫 번째 예제와 같은 방식으로 구성되지만 다른 이체 계정인 ABCDEF를 지정하는 from 파라미터를 하나 더 추가했다.
이는 공격자가 애플리케이션이 첫 번째 from 파라미터 값을 사용해 전송 유효성을 검사하지만 두 번째 파라미터 값으로 이체하기를 바라며 추가 파라미터를 전송한 상황이다.
따라서 은행이 마지막으로 전달받은 파라미터 값을 신뢰하면 공격자가 소유하지 않은 계좌에서 이체를 실행할 수 있다.
12345 계좌에서 67890 계좌로 5,000달러를 이체하는 대신 서버 측 코드는 두 번째 from 파라미터를 사용해 ABCDEF 계좌에서 67890 계좌로 송금할 것이다.
서버가 다수의 이름이 같은 파라미터를 수신하면 다양한 방식으로 응답할 수 있다.
예를 들어 PHP와 아파치(Apache)는 마지막 항목을 사용하고, 아파치 톰캣(Apache Tomcat)은 첫 번째 항목을 사용하며, ASP와 IIS는 모든 항목을 사용한다.
결과적으로 동일한 이름으로 다수의 파라미터가 제출됐을 때 처리하기 위한 확정된 단일 절차가 없으며, HPP 취약점을 찾으려면 테스트 중인 사이트의 작동 방식을 확인하기 위한 약간의 실험이 필요하다.
앞의 은행 예제에서는 확실한 파라미터를 사용했다. 그러나 때로는 직접 드러나지 않는 코드에 숨겨진 서버 측 동작으로 인해 HPP 취약점이 발생할 수도 있다.
예를 들어 은행에서 이체 처리 방법을 수정하고 URL에 from 파라미터를 포함하지 않도록 백엔드 코드를 변경한다고 가정해보자. 이번에는 해당 은행에서 두 가지 파라미터를 사용할 것인데, 하나는 입금 계좌번호이고 다른 하나는 이체 금액이다. 입금 계좌번호를 서버에서 설정하면 이용자는 해당 값을 직접 확인할 수 없다.
https://www.bank.com/transfer?to=67890&amount=5000
은행의 서버 측 Ruby 코드는 다음과 같다.
user.account = 12345
def prepare_transfer(①params)
② params << user.account
③ trnasfer_money(params) #user.account (12345) 은 params[2]가 된다.
end
def transfer_money(params)#h#
④ to = params[0]
⑤ amount = params[1]
⑥ from = params[2]
transfer(to,amount,from)
end
이 코드는 prepare_transfer와 transfer_money 두 가지 함수를 생성한다.
prepare_transfer 함수는 URL의 to와 amount 파라미터를 포함하는 params①라는 배열을 가져온다.
배열 값은 괄호로 묶고 각 값을 쉼표로 구분하면 배열은 [67890, 5000]이 된다.
함수의 첫 번째 줄②은 코드에서 이전에 정의된 사용자 계정 정보를 배열 끝에 추가한다.
params에서 배열 [67890, 5000, 12345]로 끝나고 param은 transfer_money③로 전달된다.
파라미터와 달리 배열은 값과 관련된 이름이 없기 때문에 코드는 순서에 따라 입금 계좌번호를 가장 먼저 저장하고 그다음으로 이체 금액, 출금 계좌번호 두 개의 값을 저장한다.
transfer_money 함수에서 각 배열 값을 변수에 할당함에 따라 순서가 명확해진다.
배열 위치는 0부터 번호를 매기기 때문에 param[0]은 배열의 첫 번째 위치의 값(예제를 기준으로 67890)에 접근해 이 값을 변수에 할당한다④. 다른 값은 ⑤와 ⑥줄의 변수에 할당된다.
그런 다음 변수 이름은 위의 코드에 보이지 않는 값을 가져온 후 이체를 하는 transfer 함수로 전달된다.
공격자는 다음 URL의 값을 파라미터로 전달해 로직의 결과를 바꿀 수 있다.
https://www.bank.com/transfer?to=67890&amount=5000&from=ABCDEF
이 경우 from 파라미터는 prepare_transfer 함수에 전달되는 params 배열에도 포함된다.
따라서 배열의 값은 [67890, 5000, ABCDEF]이며 ②에서 사용자 계정을 추가하면 값은 [67890, 5000, ABCDEF, 12345]가 된다.
결과적으로 prepare_transfer에서 호출된 transfer_money 함수에서 from 변수는 세 번째 파라미터 값으로 user.account의 12345를 예상하며 가져오지만 실제로 공격자가 전달한 ABCDEF④ 값을 참조한다.
클라이언트 측 HPP
클라이언트 측 HPP 취약점을 통해 공격자는 URL에 추가 파라미터를 삽입해 사용자에게 영향을 줄 수 있다.
URL http://host/page.php?par=123%26action=edit와 다음 서버 측 코드를 사용한 예제
① <? $val=htmlspecialchars($_GET['par'],ENT_QUOTES); ?>
② <a href="/page.php?action=view&par='.<?=$val>.'">View Me!</a>
이 코드는 사용자가 입력한 파라미터 par의 값을 기반으로 새로운 URL을 만들어낸다.
이 예제에서 공격자는 의도하지 않은 파라미터를 만들려고 par 파라미터에 123%26action=edit 값을 전달한다.
&에 대한 URL 인코딩 값은 %26이다.
즉, URL을 구문 분석할 때 %26은 &로 해석된다. 이 값은 URL에서 action 파라미터를 명시적으로 작성하지 않았지만 생성된 href에 별도의 파라미터를 추가한다.
파라미터 값으로 %26 대신 123&action=edit를 사용했다면 &는 두 개의 다른 파라미터를 분리하는 것으로 해석돼 par와 action 파라미터로 분리되지만 사이트의 코드에서 par 파라미터만 사용하기 때문에 action 파라미터는 사용되지 않는다. %26 값은 최초 시점에 action을 별도의 파라미터로 인식되지 않게 만들어주기 때문에 par 파라미터의 값은 12%26action=edit가 된다.
다음으로 par(&를 %26으로 인코딩해) 파라미터는 htmlspecialchars① 함수에 전달한다.
htmlspecialchars 함수는 %26과 같은 특수 문자를 &(HTML에서 &를 나타내는 HTML 엔터키)로 인코딩된 값으로 변환돼 특별한 의미를 갖는다. 변환된 값은 $val에 저장된다. 그런 다음 ②에서 href 값에 $val을 추가해 새로운 링크가 생성된다.
따라서 생성된 링크는 <a href="/page.php?action=view&par=123&action=edit">가 된다.
결과적으로 공격자는 href URL에 action=edit를 추가했고 몰래 추가된 action 파라미터를 애플리케이션에서 처리하는 방식에 따라 취약점을 만들어낼 수 있다.
해커원 소셜 공유 버튼
난이도: 낮음
URL: https://hackerone.com/blog/introducing-signal-and-impact/
출처: https://hackerone.com/reports/105953/
보고 날짜: 2015년 12월 18일
포상금: 500달러
HTTP 취약점을 찾는 한 가지 방법으로 다른 서비스와 연결하는 것으로 보이는 링크를 찾는 방법이 있다.
해커원 블로그 게시물은 트위터, 페이스북 등 인기 있는 소셜 미디어 사이트에서 콘텐츠를 공유할 수 있는 링크를 첨부했다. 해커원 링크를 클릭하면 사용자가 소셜 미디어에 게시할 콘텐츠를 생성한다. 게시된 콘텐츠에는 원본 블로그 게시물에 대한 URL 참조가 추가된다.
익명의 해커가 해커원 블로그 게시물의 URL에 파라미터를 사용자가 임의로 지정할 수 있는 취약점을 발견했다. 추가된 URL 파라미터는 공유용 소셜 미디어 링크에 반영돼 생성된 소셜 미디어 콘텐츠가 의도한 해커원 블로그 URL이 아닌 다른 곳으로 링크된다.
취약점 보고서에서 사용된 예제 URL에서는 https://hackerone.com/blog/introducing-signal을 방문하는 URL에 &u=https://vk.com/durov를 마지막에 추가한다. 해커원이 페이스북에서 공유하려는 링크를 블로그 페이지에서 렌더링 하면 다음과 같다.
https://www.facebook.com/sharer.php?u=https://hackerone.com/blog/introducing-signal?&u=https://vk.com/durov
해커원 방문자가 콘텐츠를 공유하려고 할 때 위와 같이 악의적으로 변경된 링크를 클릭했을 때 마지막 u파라미터가 첫 번째 u 파라미터보다 우선순위가 높다.
결과적으로 페이스북 게시물은 마지막 u 파라미터를 사용한다. 그런 다음 링크를 클릭한 페이스북 사용자는 해커원이 아닌 https://vk.com/durov로 연결된다.
또한 트위터에 게시할 때 해커원에는 게시물을 홍보하는 기본 트윗 텍스트가 추가된다.
공격자는 다음과 같이 URL에 &text=를 포함해 본문을 조작할 수 있다.
https://hackerone.com/blog/introducing-signal?&u=https://vk.com/durov&text=another_site:https://vk.com/durov
사용자가 이 링크를 클릭하면 해커원 블로그를 홍보하는 본문이 아닌 "another_site: https://vk.com/durov" 내용이 포함된 트윗 팝업이 나타난다.
웹 사이트가 콘텐츠를 허용하고 다른 웹 사이트(예, 소셜 미디어 사이트)에 접속하는 것으로 보이며, 현재 URL을 기반으로 공개 콘텐츠를 생성할 때 취약점이 발생할 수 있다.
이러한 상황에서 적절한 보안 점검을 거치지 않고 콘텐츠가 전달될 수 있으며 이로 인해 파라미터 오염 취약점이 발생할 수 있다.
트위터 구독 취소 알림
난이도: 낮음
URL: https://www.twitter.com/
출처: https://blog.mert.ninja/twitter-hpp-vulnerability/
보고 날짜: 2015년 8월 23일
포상금: 700달러
트위터 알림의 수신을 거부할 때의 URL
https://twitter.com/i/u?iid=F6542&uid=1134885524&nid=22+26&sig=647192e86e28fb6691db2502c5ef6cf3xxx
UID 파라미터를 주목해보자. 이 UID는 현재 로그인한 트위터 계정의 사용자 ID다.
UID를 다른 사용자의 UID로 변경했지만 아무런 일도 일어나지 않았으며, 트위터로부터 오류만을 전달받았다.
두 번째 UID 파라미터를 추가해 다음과 같은 URL을 확인해봤다.
https://twitter.com/i/u?iid=F6542&uid=2321301342&uid=1134885524&nid=22+26&sig=647192e86e28fb6691db2502c5ef6cf3xxx
이메일 알림으로 다른 사용자의 구독을 취소할 수 있었다.
트위터는 HPP 사용자 구독 취소에 취약했다. 이 취약점은 SIG 파라미터와 관련되어 있다.
결과적으로 트위터는 UID 값을 사용해 SIG 값을 생성한다. 사용자가 구독 취소 URL을 클릭하면 트위터는 SIG와 UID값을 확인해 URL이 변경되지 않았음을 확인한다.
따라서 최초의 테스트를 시도했을 때 서명이 트위터에서 예상한 서명 값과 일치하지 않아 UID를 변경해 다른 사용자의 구독을 취소하지 못했다.
그러나 두 번째 UID를 추가했고 트위터는 첫 번째 UID파라미터로 서명의 유효성을 검사하지만 구독 취소 시에는 두 번째 UID 파라미터를 사용했기 때문에 구독을 취소시키는 데 성공했다.
HTTP 요청에 포함된 UID와 같은 자동으로 증가하는 정수를 갖는 파라미터를 주시하자.
다수의 취약점에서 이러한 파라미터 값의 조작을 활용하고 있으며, 이러한 조작으로 웹 애플리케이션이 예상하지 못한 방식으로 동작하게 만들 수 있다.
트위터 웹 인텐트
난이도: 낮음
URL: https://twitter.com/
출처: https://ericrafaloff.com/parameter-tampering-attack-on-twitter-web-intents/
보고 날짜:2015년 11월
포상금: 비공개
트위터 웹 인텐트 기능은 트위터 사용자의 트윗, 댓글, 리트윗, 좋아요, 팔로우 작업을 위한 팝업 창을 트위터가 아닌 사이트에서 제공한다.
트위터 웹 인텐트를 사용하면 사용자가 페이지를 떠나지 않고 상호작용을 하려고 신규 앱의 승인을 받지 않아도 트위터 콘텐츠와 상호작용할 수 있다.
트위터에서는 다음과 같은 URL 파라미터를 사용하는 GET 요청을 통해 각각의 인텐트를 생성한다.
https://twitter.com/intent/intentType?parameter_name=parameterValue
이 URL에는 intentType과 하나 이상의 파라미터 이름/쌍(예, 트위터 사용자 이름과 트윗 ID)이 포함된다.
트위터는 이 파라미터를 사용해 사용자가 팔로우하거나 트윗할 수 있는 팝업 인텐트를 생성한다.
팔로우 인텐트용으로 예측되는 하나의 screen_name 대신 두 개의 screen_name 파라미처로 URL을 작성할 때 발생하는 문제점을 발견했다.
https://twitter.com/intent/follow?screen_name=twitter&screen_name=ericrtest3
트위터는 팔로우 버튼을 생성할 때 첫 번째 twitter 값 대신 두 번째 screen_name 파라미터 값인 ericrtest3을 먼저 처리한다. 따라서 트위터의 공식 계정을 팔로우하려던 사용자를 테스트 계정으로 팔로우하도록 속일 수 있다.
새로 생성한 URL에 방문하면 트위터의 백엔드 코드가 두 개의 screen_name 파라미터를 사용해 다음 HTML 양식을 생성한다.
①<form class="follow" id="follow_btn_form" action="/intent/follow?screen_name=erictest3" method="post">
<input type="hidden" name="authenticity_token" valule="...">
②<input type="hidden" name="screen_name" value="twitter">
③<input type="hidden" name="profile_id" value="783214">
<button class="button" type="submit">
<b></b><strong>Follow</strong>
</button>
</form>
트위터는 공식 트위터 계정과 연관된 첫 번째 screen_name 파라미터의 정보를 사용한다.
결과적으로 URL의 첫 번째 screen_name 파라미터의 값이 ②와 ③에서 코드에 사용되기 때문에 공격 대상은 올바른 프로필을 팔로우하는 것처럼 보인다.
그러나 form 태그의 작업은 URL로 전달된 두 번째 screen_name 파라미터 값 ①을 사용하기 때문에 버튼을 클릭한 후 공격 대상은 ericrtest3을 팔로우할 것이다.
마찬가지로 '좋아요'를 인텐트하려고 할 때 라파로프는 트윗에 '좋아요'를 하는 기능과 관련이 없는 screen_name 파라미터를 추가할 수 있는 것을 발견했다.
예를 들어 다음과 같은 URL을 만들 수 있다.
https://twitter.com/intent/like?tweet_i.d=6616252302978211845&screen_name=ericrtest3
일반적으로 '좋아요' 인텐트는 tweet_id 파라미터만 필요하지만 URL 마지막에 screen_name 파라미터를 추가했다.
이 트윗을 마음에 들어 하면 대상이 트윗을 좋아하는 올바른 소유자 프로필로 표시될 것이다.
그러나 정상적인 트윗과 트위터 프로필 옆에 있는 팔로우 버튼은 전혀 관련 없는 사용자인 ericrtest3을 팔로우할 것이다.
트위터 웹 인텐트 취약점은 이전의 UID 트위터 취약점과 유사하다. 사이트가 HPP와 같은 취약점에 취약하면 시스템 전반으로 문제가 있을 수 있다.
요약
- HPP의 위험은 사이트의 백엔드에서 수행하는 작업과 오염된 파라미터가 활용되는 위치에 따라 달라진다.
- 일반적으로 HTTP 요청을 전달받은 후 실행되는 코드 서버에 접근할 수 없기 때문에 HPP 취약점을 발견하려면 다른 취약점보다 철저한 테스트가 필요하다.
- 즉, 오직 사이트가 전달한 파라미터를 처리하는 방법을 유추할 수 밖에 없는 것을 의미한다.
- 시행착오를 통해서만 HPP 취약점이 발생하는 상황을 발견할 수 있다.
- 일반적으로 소셜 미디어 링크는 이러한 취약점 유형을 테스트하기에 좋은 위치지만 ID 값과 같은 파라미터의 대체 가능 여부를 테스트할 때는 HPP를 염두에 두고 지속적으로 확인해야 한다.
**피터 야로스키, Real-World Bug Hunting(실전 버그 바운티)를 참고하여 작성
'Webhacking > 버그바운티' 카테고리의 다른 글
CSRF(Cross-Site Request Forgery) 공격 (1) | 2022.04.13 |
---|---|
오픈 리디렉션(Open Redirect) 취약점 (0) | 2022.04.07 |
버그 바운티 기본 사항 (0) | 2022.04.04 |
댓글