반응형
문제설명
Topic: Login
분야: Web
난이도: Medium
Login!, login!, and login!
문제 URL: https://alpacahack.com/daily/challenges/alert-my-flag
코드 분석
let users = {
admin: {
password: crypto.randomBytes(32).toString("base64"),
},
};
- users는 사용자 정보를 저장한 객체
현재 admin 한 명만 있음 - password는 랜덤한 비밀번호 생성
app.get("/", (req, res) => {
res.send(`
<h2>Login</h2>
<form method="POST">
<input name="username" placeholder="username" required />
<br />
<input name="password" type="password" placeholder="password" required />
<br />
<button>Login</button>
</form>
`);
});
- GET / 요청 시 로그인 폼 HTML을 보여줌
- 브라우저에서 /에 접속하면 아이디/비번 입력창이 나옴
app.post("/", (req, res) => {
const { username, password } = req.body;
const user = users[username];
if (!user || user.password !== password) {
return res.send("invalid credentials");
}
res.send(FLAG);
});
- 로그인 폼 제출되면 POST / 로 들어온다
- 사용자가 입력한 username, passowrd가 바디로 요청함
- user 변수엔 {password: "랜덤 비밀번호"} 가 들어있음
- !user : username의 계정이 없으면 실패 / 비밀번호 다르면 실패
취약점 분석
- 사용자가 넣은 문자열을 객체 키로 사용함
→ __proto__ 같은 특수 키를 이용하면 의도하지 않은 객체가 user에 들어감
익스플로잇
username="__proto__" 를 입력해주면

username에 __proto__를 넣으면
const user = users[username]; ===> const user = users["__proto__"];
객체의 프로토타입에 연결된 특수한 키 처럼 동작이 가능하다. 그래서 users["__proto__"]는 보통 Object.prototype 같은 값을 가져오게 된다
즉,
users["__proto__"] -> Object.prototype
따라서 user = Object.prototype이 되고 조건문을 살펴보면
if (!user || user.password !== password) {
return res.send("invalid credentials");
}
user은 truthy가 되고, !user는 false가 된다.
그리고 password를 아예 안 보내면 password === ubdefined가 된다.
또한 Object.prototype.password도 기본적으로 undefined라서
undefined !== undefined로 결과가 false가 된다.
즉
if(false || false)
가 되어 통과하고 FLAG가 나온다.
반응형
'Alpacahack' 카테고리의 다른 글
| Alert my Flag (0) | 2026.03.05 |
|---|---|
| Rock Paper Scissors Lizard Spock (0) | 2026.03.03 |
| Alpaca Rangers (0) | 2026.03.03 |
| omikuji (0) | 2026.02.23 |
| Emojify (0) | 2026.02.20 |