<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>pin4ction 님의 블로그</title>
    <link>https://pin4ction.tistory.com/</link>
    <description>notion에 없는 다양한 보안 끄적끄적
contact : pin4ct@gmail.com</description>
    <language>ko</language>
    <pubDate>Mon, 6 Apr 2026 15:13:41 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>pin4ction</managingEditor>
    <item>
      <title>URL Globbing</title>
      <link>https://pin4ction.tistory.com/48</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. URL Globbing?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비슷한 형태의 여러 URL을 한 번에 표현하는 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*, ?, {}&lt;/b&gt; 같은 기호로 표현한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;https://example.com/page1 &lt;br /&gt;https://example.com/page2 &lt;br /&gt;https://example.com/page3&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 대신 아래와 같이 쓸 수 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;https://example.com/page[1-3]&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 왜&amp;nbsp; 필요한가?&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비슷한 구조의 여러 파일을 한 번에 요청하고 싶을 때&lt;/li&gt;
&lt;li&gt;연속된 번호의 API 엔드포인트나 페이지를 테스트할 때&lt;/li&gt;
&lt;li&gt;반복 작업을 줄이고 자동화할 때&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 패턴&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) 범위 지정&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;https://example.com/file[1-5].txt&lt;br /&gt;&amp;darr;&amp;nbsp; &amp;darr;&lt;br /&gt;https://example.com/file1.txt&lt;br /&gt;https://example.com/file2.txt &lt;br /&gt;https://example.com/file3.txt &lt;br /&gt;https://example.com/file4.txt&lt;br /&gt;https://example.com/file5.txt&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) 목록 지정&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;https://example.com/{a,b,c}&lt;br /&gt;&amp;darr;&amp;nbsp; &amp;darr;&lt;br /&gt;https://example.com/a&lt;br /&gt;https://example.com/b&lt;br /&gt;https://example.com/c&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) 조합 사용&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;https://example.com/{img,thumb}[1-3].jpg&lt;br /&gt;&amp;darr;&amp;nbsp; &amp;darr;&lt;br /&gt;https://example.com/img1.jpg&lt;br /&gt;https://example.com/img2.jpg&lt;br /&gt;https://example.com/img3.jpg&lt;br /&gt;https://example.com/thumb1.jpg&lt;br /&gt;https://example.com/thumb2.jpg&lt;br /&gt;https://example.com/thumb3.jpg&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 사용한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. 활용&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;curl https://example.com/{a,b,c}.json&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 curl에서 여러 리소스를 한 번에 가져오는 데 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(그러나 모든 프로그램이 URL Globbing을 지원하는 것을 아니다.)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보안 관점에서는 필터가 검사하는 문자열과 실제 처리된 문자열의 차이를 이용해서 필터링을 우회하는데 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 curl의 경우 아래와 같이 우회할 수 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;..&amp;nbsp; &amp;rarr; {.}.&lt;/b&gt;&lt;br /&gt;&lt;b&gt;flag&amp;nbsp;&amp;nbsp; &lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;&amp;rarr;&amp;nbsp; fla{g}&lt;/span&gt; &amp;nbsp;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션의 문자열 필터는 안전하다고 착각했지만, 실제 요청 해석은 curl이 수행하기 때문에 우회가 가능하다.&lt;/p&gt;</description>
      <category>Web</category>
      <category>cybersecurity</category>
      <category>It</category>
      <category>web</category>
      <category>webhacking</category>
      <author>pin4ction</author>
      <guid isPermaLink="true">https://pin4ction.tistory.com/48</guid>
      <comments>https://pin4ction.tistory.com/48#entry48comment</comments>
      <pubDate>Fri, 20 Mar 2026 16:13:27 +0900</pubDate>
    </item>
    <item>
      <title>DOM Clobbering</title>
      <link>https://pin4ction.tistory.com/46</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. DOM Clobbering?&lt;/h4&gt;
&lt;p data-end=&quot;218&quot; data-start=&quot;150&quot; data-ke-size=&quot;size16&quot;&gt;DOM Clobbering은 HTML 요소가 자바스크립트에서 사용하려던 변수나 객체 자리를 대신 차지하는 현상이다.&lt;/p&gt;
&lt;p data-end=&quot;370&quot; data-start=&quot;220&quot; data-ke-size=&quot;size16&quot;&gt;이 문장만 보면 조금 추상적으로 느껴질 수 있다. 쉽게 말하면, 개발자는 분명히 &amp;ldquo;이 이름은 내가 코드에서 만든 값&amp;rdquo;이라고 생각했는데, 실제로는 브라우저가 같은 이름을 가진 HTML 요소를 대신 보여줘서 자바스크립트가 엉뚱한 대상을 참조하게 되는 문제다.&lt;/p&gt;
&lt;p data-end=&quot;370&quot; data-start=&quot;220&quot; data-ke-size=&quot;size16&quot;&gt;이 공격은 자바스크립트를 직접 넣지 않아도, 단지 HTML 요소의 id나 name 같은 속성을 잘 이용하는 것만으로도 발생할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;370&quot; data-start=&quot;220&quot; data-ke-size=&quot;size16&quot;&gt;즉, DOM Clobbering은 &amp;ldquo;스크립트를 실행시키는 공격&amp;rdquo;이라기보다,&lt;br /&gt;브라우저가 HTML 요소를 다루는 방식과 자바스크립트가 값을 참조하는 방식 사이의 틈을 이용하는 공격이라고 보는 편이 이해하기 쉽다.&lt;/p&gt;
&lt;p data-end=&quot;370&quot; data-start=&quot;220&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 코드가 A를 쓸 줄 알았는데, 브라우저 때문에 B를 쓰게 되는 상황&lt;/p&gt;
&lt;p data-end=&quot;370&quot; data-start=&quot;220&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;370&quot; data-start=&quot;220&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;370&quot; data-start=&quot;220&quot; data-ke-size=&quot;size20&quot;&gt;2. 왜 발생하는가?&lt;/h4&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;- 브라우저가 일부 HTML 요소를 이름 기반으로 노출하는 레거시 동작을 가지고 있음&lt;/p&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;- 자바스크립트 코드가 그 이름을 안전한 값이라고 가정하고 사용&lt;/p&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;- 그 결과 같은 이름 사이의 충돌이 발생할 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저의 오래된 동작 방식과 개발자의 안전하지 않은 참조 방식이 겹치면서 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;3. Example&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 자바스크립트 코드가 있다고 하자.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&amp;lt;script&amp;gt; &lt;br /&gt;&amp;nbsp; &amp;nbsp; let url = window.redirectTo || &quot;/main&quot;;&lt;br /&gt;&amp;nbsp; &amp;nbsp; location.href = url; &lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자의 의도는 window.redirectTo에 값이 있으면 그 주소로 이동하고, 없으면 /main으로 이동시키려는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 공격자가 페이지에 이런&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt; HTML을 삽입한다면?&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&amp;lt;a&amp;nbsp;id=&quot;redirectTo&quot;&amp;nbsp;href=&quot;&lt;a href=&quot;https://attacker.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://attacker.com&lt;/a&gt;&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저는 redirectTo라는 이름을 가진 DOM 요소를 전역처럼 노출할 수 있다. 그러면 자바스크립트는 &amp;lt;a&amp;gt; 요소를 참조하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;redirectTo라는 DOM 요소가 등장하면서 자바스크립트가 그 요소를 참조하고, 원래 의도와 다른 값이 사용되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트를 직접 삽입한 것도 아니고 그냥 HTML만 삽입했는데 애플리케이션의 동작이 바뀌게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;같은 이름을 가진 HTML&quot;이 원래 값을 대신한다는게 핵심이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;4. Mitigation&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 제일 중요한 것은 어떤 값을 참조할 때 브라우저가 알아서 이름을 연결해줄 것이라 생각하지 말고, 코드에서 명확하게 어떤 대상을 가져오는지 직접 지정하는 방식으로 작성해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4-1. 전역 이름에 의존하지 않기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름 기반 접근이 항상 안전하다고 생각하면 안 된다. 특히 브라우저가 자동으로 노출할 수 있는 이름과 충돌할 가능성을 고려해야 한다. 본인이 만든 변수니까 괜찮을 것이라 생각하지 말고, 이 이름이 DOM 요소와 충돌할 수도 있다는 것을 고려해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4-2. DOM 요소 명시적으로 가져오기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DOM 요소를 사용할 때는 document.getElementById() 같은 명시적인 방법으로 가져오는 게 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4-3. 전역 변수 사용 줄이기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전역 공간에 값이 많을수록 충돌 가능성도 당연히 커진다. 따라서 가능한 한 let, const를 사용하고 필요한 범위 안에서만 변수를 관리하는 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;꼭 전역에 있어야 하는 거 아니면 차라리 지역 변수가 나아보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-size: 1.12em; letter-spacing: 0px;&quot;&gt;4-4. 사용자 입력으로 들어가는 HTML 제한&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 HTML을 삽입할 수 있을 때 발생하므로, 사용자 입력이 그대로 HTML로 들어가는 구조를 줄여야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;id, name 같은 속성을 포함한 태그를 허용할 경우에는 단순히 &amp;lt;script&amp;gt; 막는다고 충분하지 않을 수 있다.&lt;/p&gt;</description>
      <category>Web</category>
      <category>cybersecurity</category>
      <category>It</category>
      <category>web</category>
      <category>webhacking</category>
      <author>pin4ction</author>
      <guid isPermaLink="true">https://pin4ction.tistory.com/46</guid>
      <comments>https://pin4ction.tistory.com/46#entry46comment</comments>
      <pubDate>Fri, 13 Mar 2026 11:49:12 +0900</pubDate>
    </item>
    <item>
      <title>RPO(Relative Path Overwrite)</title>
      <link>https://pin4ction.tistory.com/44</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. RPO?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ralative Path Overwrite, 말 그대로 상대경로를 덮어쓰는 기법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 페이지가 CSS나 JS 같은 리소스를 상대경로로 불러올 때, 사용자가 접근한 URL 형태에 따라 브라우저가 그 상대경로를 원래 의도와 다르게 해석하게 만드는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 페이지에서 아래처럼 리소스를 불러온다고 하자.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&amp;lt;script src=&quot;config.js&quot;&amp;gt;&amp;lt;/script&amp;gt; &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&amp;gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자는 현재 문서 기준으로 config.js, style.css가 로드될 것 이라고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 사용자가 페이지를 여는 URL이 예상과 다르면, 브라우저는 이 상대경로를 다른 위치로 계산할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, RPO는 서버가 아니라 브라우저의 상대경로 해석 방식을 이용하는 기법이라고 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;2. 왜 발생하는가?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 문서가 리소스를 상대경로로 불러옴&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 서버가 비정상적인 경로도 같은 문서로 처리함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 브라우저는 현재 URL을 기준으로 상대경로를 다시 계산함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 /test.php로 접근한다고 했을 때, &amp;lt;script src=&quot;config.js&quot;&amp;gt;&amp;lt;/script&amp;gt; 는 보통 /config.js 또는 /test.php 기준의 같은 디렉터리 위치로 해석된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 /test.php/~~~ 처럼 접근 할 수 있으면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버가 이 주소들도 여전히 test.php가 처리하도록 받아준다면, 브라우저는 현재 문서를 디렉터리처럼 보고 상대경로 config.js를 /test.php/config.js 처럼 계산할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 개발자가 원래 의도한 위치가 아니다. 결국 config.js가 정상 로드되지 않거나, 심한 경우 다른 응답을 받게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;3. Example&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&amp;lt;html&amp;gt; &lt;br /&gt;&amp;lt;head&amp;gt; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;script src=&quot;config.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt; &lt;br /&gt;&amp;lt;body&amp;gt; &lt;br /&gt;&amp;nbsp; &amp;nbsp; Hello &lt;br /&gt;&amp;lt;/body&amp;gt; &lt;br /&gt;&amp;lt;/html&amp;gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 페이지가 있다고 하면, 개발자는 /page.php로 접근할 것만 생각했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 서버가 /page.php/~~~ 요청도 전부 page.php로 처리한다면, 브라우저는 현재 문서를 디렉터리처럼 보고 config.js를 /page.php/config.js 로 요청할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 의도는 /config.js 또는 /page_dir/config.js 였는데, 완전 다른 URL이 되어버린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 되면 필요한 JS가 로드되지 않고, CSS가 이상한 문서를 불러와 stylesheet처럼 해석될 수 있고, 이후 DOM 구조나 전역 변수에 의존하던 로직이 깨진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론은 RPO 단독으로 끝나기보다 보통 다른 취약점이랑 연계해서 같이 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;4. Extension&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4-1. 보호용 JS 로드를 깨뜨릴 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 페이지가 config.js, sanitize.js, security.js 같은 파일에 의존해서 방어 로직을 수행한다면, RPO로 해당 파일 로드를 망가뜨려 보호 로직 자체를 무력화할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4-2. DOM Clobberring과 결합&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래라면 JS가 window.CONFIG 같은 객체를 세팅해 주는데, 그 JS가 로드되지 않으면 공격자가 삽입한 DOM 요소가 그 자리를 대신 차지할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4-3. CSS 해석 문제로 이어질 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옛날 RPO 사례에서는 HTML 문서를 CSS처럼 해석하게 만들어서 정보 유출이나 스타일 기반 공격으로 이어지는 경우도 있었는데, 요즘은 브라우저/헤더 정책 때문에 자주 보이진 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;5. Mitigation&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;5-1. 상대경로 대신 절대경로 사용&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&amp;lt;script src=&quot;/js/config.js&quot;&amp;gt;&amp;lt;/script&amp;gt; &lt;br /&gt;&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;/css/style.css&quot;&amp;gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 하면 현재 URL이 어떻게 바뀌든 경로 해석이 흔들리지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;5-2. 비정상 경로 차단&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;/page.php/~~~ 같은 요청이 정상 경로가 아니면 404 반환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;5-3. 클라이언트 측 전역 객체에 과도하게 의존하지 않기&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;JS에서 window.CONFIG 같은 전역 객체를 너무 믿고 쓰는 구조는 DOM Clobbering과 결합될 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;더 명시적이고 안전한 초기화 방식이 좋다.&lt;/p&gt;</description>
      <category>Web</category>
      <category>cybersecurity</category>
      <category>It</category>
      <category>web</category>
      <category>webhacking</category>
      <author>pin4ction</author>
      <guid isPermaLink="true">https://pin4ction.tistory.com/44</guid>
      <comments>https://pin4ction.tistory.com/44#entry44comment</comments>
      <pubDate>Fri, 13 Mar 2026 10:49:17 +0900</pubDate>
    </item>
    <item>
      <title>백트래킹 알고리즘 (BackTracking)</title>
      <link>https://pin4ction.tistory.com/8</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;프로그래밍을 하다 보면 &quot;모든 경우의 수를 탐색해야 하는 문제&quot;를 자주 만나게 됩니다. 이럴 때 유용하게 쓰이는 기법 중 하나가 바로 백트래킹(Backtracking)입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-end=&quot;420&quot; data-start=&quot;313&quot; data-ke-size=&quot;size16&quot;&gt;백트래킹은 말 그대로 &quot;되돌아가기&quot;입니다. 어떤 문제를 풀기 위해 가능한 선택지를 따라가다가, 그 선택이 정답으로 이어지지 않으면 다시 돌아가 다른 선택지를 탐색하는 방식입니다.&lt;/p&gt;
&lt;p data-end=&quot;491&quot; data-start=&quot;422&quot; data-ke-size=&quot;size16&quot;&gt;즉, 가능한 모든 경우를 탐색하지만, 유망하지 않은 경로는 조기에 포기(가지치기)하면서 효율적으로 답을 찾아나갑니다.&lt;/p&gt;
&lt;p data-end=&quot;491&quot; data-start=&quot;422&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;완전탐색의 일종이지만, &lt;/span&gt;&lt;b&gt;불필요한 경우를 줄이는 전략&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;을 포함하고 있는 것이 차별점입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;491&quot; data-start=&quot;422&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;491&quot; data-start=&quot;422&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;Q. 언제 백트래킹을 사용하지?&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;491&quot; data-start=&quot;422&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;608&quot; data-start=&quot;576&quot;&gt;가능한 모든 조합, 순열, 부분집합 등을 구해야 할 때&lt;/li&gt;
&lt;li data-end=&quot;638&quot; data-start=&quot;609&quot;&gt;퍼즐, 미로 찾기, N-Queen, 스도쿠 등에서&lt;/li&gt;
&lt;li data-end=&quot;667&quot; data-start=&quot;639&quot;&gt;탐색 과정에서 제약 조건을 만족해야 하는 문제들&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기본 구조&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1752416916517&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def backtrack(상태):
    if 정답 조건 만족:
        정답 처리
        return
    
    for 선택 in 가능한 선택지:
        if 유망한 선택인지 확인:
            선택 수행
            backtrack(다음 상태)
            선택 되돌리기 (백트래킹)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;491&quot; data-start=&quot;422&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예제 : 1부터 N까지 수 중에서 M개를 고른 모든 조합 (순서 상관 X) &lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1752417023511&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def backtrack(start, path):
    if len(path) == M:
        print(path)
        return
    
    for i in range(start, N + 1):
        path.append(i)
        backtrack(i + 1, path)
        path.pop()  # 백트래킹

N = 4
M = 2
backtrack(1, [])&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-end=&quot;201&quot; data-start=&quot;45&quot; data-ke-size=&quot;size16&quot;&gt;백트래킹의 성능을 결정짓는 핵심은 &lt;b&gt;가지치기&lt;/b&gt;입니다. 탐색 도중 &quot;&lt;b&gt;이 경로는 정답이 될 수 없다&lt;/b&gt;&quot;는 판단이 서면, 더 깊은 탐색을 진행하지 않고 즉시 중단함으로써 불필요한 연산을 줄일 수 있습니다. 이를 통해 시간 복잡도를 크게 개선할 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;318&quot; data-start=&quot;203&quot; data-ke-size=&quot;size16&quot;&gt;또한 백트래킹은 단순한 완전탐색과는 다릅니다. 가능한 모든 경우를 확인하되, &lt;b&gt;조건을 활용해 비효율적인 경로는 과감히 생략&lt;/b&gt;함으로써, &lt;b&gt;정답을 보장하면서도 효율성을 확보&lt;/b&gt;할 수 있는 탐색 기법입니다.&lt;/p&gt;
&lt;h3 data-end=&quot;2587&quot; data-start=&quot;2465&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-end=&quot;2587&quot; data-start=&quot;2465&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2587&quot; data-start=&quot;2465&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘</category>
      <category>Algorithm</category>
      <category>cybersecurity</category>
      <category>It</category>
      <author>pin4ction</author>
      <guid isPermaLink="true">https://pin4ction.tistory.com/8</guid>
      <comments>https://pin4ction.tistory.com/8#entry8comment</comments>
      <pubDate>Sun, 13 Jul 2025 23:37:22 +0900</pubDate>
    </item>
    <item>
      <title>LSB(Least Significant Bit)</title>
      <link>https://pin4ction.tistory.com/2</link>
      <description>&lt;h3 data-end=&quot;110&quot; data-start=&quot;69&quot; data-ke-size=&quot;size23&quot;&gt;1. 기본 개념&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;235&quot; data-start=&quot;112&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;146&quot; data-start=&quot;112&quot;&gt;사진 파일은 수많은 &lt;u&gt;&lt;b&gt;픽셀(pixel)&lt;/b&gt;&lt;/u&gt;로 되어 있고,&lt;/li&gt;
&lt;li data-end=&quot;198&quot; data-start=&quot;147&quot;&gt;픽셀 하나는 보통 &lt;b&gt;빨강(R), 초록(G), 파랑(B)&lt;/b&gt; 3개의 색깔 값으로 표현된다.&lt;/li&gt;
&lt;li data-end=&quot;235&quot; data-start=&quot;199&quot;&gt;각각 R, G, B는 0~255 범위 숫자. (8비트 숫자)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;292&quot; data-start=&quot;237&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 여기서 &lt;b&gt;가장 끝에 있는 비트(1비트)&lt;/b&gt;를 몰래 수정하면, &lt;b&gt;사람 눈에는 티 안 난다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-end=&quot;301&quot; data-start=&quot;294&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;301&quot; data-start=&quot;294&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예시 :&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;&lt;span data-state=&quot;closed&quot;&gt;&lt;/span&gt;
&lt;div&gt;R값 원래수정 후사람 눈에 보이는 차이
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;398&quot; data-start=&quot;303&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;398&quot; data-start=&quot;352&quot;&gt;
&lt;tr data-end=&quot;398&quot; data-start=&quot;352&quot;&gt;
&lt;td data-end=&quot;369&quot; data-start=&quot;352&quot;&gt;10101010 (170)&lt;/td&gt;
&lt;td data-end=&quot;386&quot; data-start=&quot;369&quot;&gt;10101011 (171)&lt;/td&gt;
&lt;td data-end=&quot;398&quot; data-start=&quot;386&quot;&gt;거의 차이 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;463&quot; data-start=&quot;400&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그래서&lt;/b&gt; 이 &quot;끝 비트(Least Significant Bit)&quot;를 이용해서,&lt;br /&gt;몰래 데이터를 숨긴 것이다.&lt;/p&gt;
&lt;div style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;hr data-start=&quot;870&quot; data-end=&quot;873&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;875&quot; data-end=&quot;900&quot; data-ke-size=&quot;size23&quot;&gt;2. 코드&lt;/h3&gt;
&lt;pre id=&quot;code_1745662983081&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from PIL import Image

img = Image.open(&quot;hm.png&quot;).convert(&quot;RGB&quot;)
pixels = list(img.getdata())

bits = []
for r, g, b in pixels:
    bits.extend([(r &amp;amp; 1), (g &amp;amp; 1), (b &amp;amp; 1)])

bytes_out = bytearray()
for i in range(0, len(bits), 8):
    byte = 0
    for j in range(8):
        if i + j &amp;lt; len(bits):
            byte = (byte &amp;lt;&amp;lt; 1) | bits[i + j]
    bytes_out.append(byte)

with open(&quot;hidden.png&quot;, &quot;wb&quot;) as f:
    f.write(bytes_out)&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-end=&quot;468&quot; data-start=&quot;465&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;488&quot; data-start=&quot;470&quot; data-ke-size=&quot;size23&quot;&gt;3. 코드가 한 일은?&lt;/h3&gt;
&lt;p data-end=&quot;499&quot; data-start=&quot;490&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;요약하면:&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;715&quot; data-start=&quot;501&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;534&quot; data-start=&quot;501&quot;&gt;hm.png 파일 열고, &lt;b&gt;모든 픽셀을 읽음&lt;/b&gt;.&lt;/li&gt;
&lt;li data-end=&quot;633&quot; data-start=&quot;535&quot;&gt;&lt;b&gt;각 픽셀의 R, G, B값 각각&lt;/b&gt;에서, &lt;b&gt;맨 마지막 비트(LSB)&lt;/b&gt;만 뽑음.
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;633&quot; data-start=&quot;589&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;633&quot; data-start=&quot;589&quot;&gt;(r &amp;amp; 1), (g &amp;amp; 1), (b &amp;amp; 1) 이게 그 작업이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;670&quot; data-start=&quot;634&quot;&gt;모은 비트들을 8개씩 묶어 &lt;b&gt;1바이트(1글자)&lt;/b&gt;로 변환.&lt;/li&gt;
&lt;li data-end=&quot;715&quot; data-start=&quot;671&quot;&gt;그렇게 나온 바이트들을 이어붙여서 hidden.png라는 파일로 저장.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-end=&quot;720&quot; data-start=&quot;717&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;743&quot; data-start=&quot;722&quot; data-ke-size=&quot;size23&quot;&gt;4. 코드 흐름을 정리하면&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;원본 이미지: (R, G, B) 픽셀들 &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;gt; 각각의 &lt;/span&gt;&lt;span&gt;&lt;span&gt;R&lt;/span&gt;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&lt;span&gt;G&lt;/span&gt;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&lt;span&gt;B&lt;/span&gt;&lt;/span&gt;&lt;span&gt; 값의 마지막 비트만 뽑아&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;gt; 비트들을 &lt;/span&gt;&lt;span&gt;&lt;span&gt;8&lt;/span&gt;&lt;/span&gt;&lt;span&gt;개씩 묶어서 &lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span&gt;바이트로 변환&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;gt; 바이트를 모아서 파일 생성 (hidden.png) &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-end=&quot;873&quot; data-start=&quot;870&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;900&quot; data-start=&quot;875&quot; data-ke-size=&quot;size23&quot;&gt;5. 그래서 진짜 숨겨진 건 뭐였을까?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1071&quot; data-start=&quot;902&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;965&quot; data-start=&quot;902&quot;&gt;hidden.png는 &lt;b&gt;숨겨진 파일&lt;/b&gt;(ex: 또 다른 이미지, 텍스트 파일, zip 등)일 수도 있다.&lt;/li&gt;
&lt;li data-end=&quot;991&quot; data-start=&quot;966&quot;&gt;지금은 확장자를 .png로 저장했는데, 사실은 열어보면서 &quot;이게 진짜 이미지야?&quot; 확인해야 된다.&lt;/li&gt;
&lt;li data-end=&quot;1071&quot; data-start=&quot;992&quot;&gt;안 되면 확장자를 .txt, .zip 같은 걸로 바꿔볼 수도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-start=&quot;870&quot; data-end=&quot;873&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;p.s. 2025 세종 핵테온때 스테가노그래피 문제를 접했는데, 다 뒤져봐도 안돼서 좀 헤매다가&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; 새로 알게된 개념이다. 담엔 가볍게 풀 것이다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Forensic</category>
      <category>CTF</category>
      <category>cybersecurity</category>
      <category>forensic</category>
      <author>pin4ction</author>
      <guid isPermaLink="true">https://pin4ction.tistory.com/2</guid>
      <comments>https://pin4ction.tistory.com/2#entry2comment</comments>
      <pubDate>Sat, 26 Apr 2025 19:29:55 +0900</pubDate>
    </item>
  </channel>
</rss>