
사이트에 접속하면 호박을 10000번 클릭하여 Flag를 획득하라고 되어있다.
호박을 클릭하는 부분을 요소 검사를 눌러보니
다음과 같이 id 가 jack-target인 요소임을 확인해볼 수 있었다.
<svg id="jack-target" viewBox="0 0 72 72" version="1.1" xmlns="http://www.w3.org/2000/svg">(생략)</svg>
다음은 script 부분 코드이다.
var pumpkin = [ 124, 112, 59, 73, 167, 100, 105, 75, 59, 23, 16, 181, 165, 104, 43, 49, 118, 71, 112, 169, 43, 53 ];
var counter = 0;
var pie = 1;
function make() {
if (0 < counter && counter <= 1000) {
$('#jack-nose').css('opacity', (counter) + '%');
}
else if (1000 < counter && counter <= 3000) {
$('#jack-left').css('opacity', (counter - 1000) / 2 + '%');
}
else if (3000 < counter && counter <= 5000) {
$('#jack-right').css('opacity', (counter - 3000) / 2 + '%');
}
else if (5000 < counter && counter <= 10000) {
$('#jack-mouth').css('opacity', (counter - 5000) / 5 + '%');
}
if (10000 < counter) {
$('#jack-target').addClass('tada');
var ctx = document.querySelector("canvas").getContext("2d"),
dashLen = 220, dashOffset = dashLen, speed = 20,
txt = pumpkin.map(x=>String.fromCharCode(x)).join(''), x = 30, i = 0;
ctx.font = "50px Comic Sans MS, cursive, TSCu_Comic, sans-serif";
ctx.lineWidth = 5; ctx.lineJoin = "round"; ctx.globalAlpha = 2/3;
ctx.strokeStyle = ctx.fillStyle = "#1f2f90";
(function loop() {
ctx.clearRect(x, 0, 60, 150);
ctx.setLineDash([dashLen - dashOffset, dashOffset - speed]); // create a long dash mask
dashOffset -= speed; // reduce dash length
ctx.strokeText(txt[i], x, 90); // stroke letter
if (dashOffset > 0) requestAnimationFrame(loop); // animate
else {
ctx.fillText(txt[i], x, 90); // fill final letter
dashOffset = dashLen; // prep next char
x += ctx.measureText(txt[i++]).width + ctx.lineWidth * Math.random();
ctx.setTransform(1, 0, 0, 1, 0, 3 * Math.random()); // random y-delta
ctx.rotate(Math.random() * 0.005); // random rotation
if (i < txt.length) requestAnimationFrame(loop);
}
})();
}
else {
$('#clicks').text(10000 - counter);
}
}
$(function() {
$('#jack-target').click(function () {
counter += 1;
if (counter <= 10000 && counter % 100 == 0) {
for (var i = 0; i < pumpkin.length; i++) {
pumpkin[i] ^= pie;
pie = ((pie ^ 0xff) + (i * 10)) & 0xff;
}
}
make();
});
});
함수 make() 를 통하여 호박모양을 만들고 있고 이건 별로 신경쓸건아니다.
전체적으로 counter 변수를 기준으로 동작하며 이 변수에 우리가
총 몇번 클릭하였는지 저장하는 것을 알 수 있다.
호박을 클릭하였을때 실행되는 이벤트 핸들러를 확인해보자
$(function() {
$('#jack-target').click(function () {
counter += 1;
if (counter <= 10000 && counter % 100 == 0) {
for (var i = 0; i < pumpkin.length; i++) {
pumpkin[i] ^= pie;
pie = ((pie ^ 0xff) + (i * 10)) & 0xff;
}
}
make();
});
});
한번 클릭할때마다 counter 변수를 1 증가시키고
이 변수가 10000 이하, 100의 배수일 때마다 pumpkin[i] 값을 pie 와 XOR 연산한다.
pie = ((pie ^ 0xff) + (i * 10)) & 0xff 부분은 pie를 255와 XOR 연산 후
현재 인덱스인 i 에 10을 곱한 후 더한값을 8비트로 제한시키는 식이다.
결과적으로 pumpkin 배열의 값이 갱신된다는 뜻이다.
가장 간단하게 생각했을 때는 console 창에서 counter 변수를 10000에 가깝게,
큰 수로 설정한 후 클릭을 하면 한번에 클릭이 된다고 생각했다.
하지만 10000번이 넘었을 때 단순히 문자열을 출력하는 형태가 아닌
pumpkin 배열의 값을 ASCII 문자로 변환한 후
이를 Canvas를 이용하여 그려 최종 Flag를 출력한다.
// pumpkin 데이터를 문자열로 변환
txt = pumpkin.map(x=>String.fromCharCode(x)).join(''),
따라서 counter 변수를 10000으로 하여 한번에 클릭을 해버리면 pumpkin 배열이
의도한대로 갱신이 안되므로 알수없는 형태의 글자가 출력된다.
기존에 설정한 대로 pumpkin 값이 올바르게 전부 갱신되어야
올바른 문자열의 flag를 그릴 수 있고
그 말은 곧 100의 배수인 값은 전부 클릭을 해야한다는 말이다.
마우스로 직접 클릭을 하지 않아도 '클릭 이벤트'를 발생시키는 법이 필요하다.
jQuery 로 id가 jack-target 은 요소를 찾고 click()를 통해 이벤트를 발생시킨다.
이제 이 과정을 10000번 반복하면 되므로 다음과 같은 코드를 작성하면 된다.
// id 가 jack-target 인 요소 10000번 클릭릭
for (var i =0; i < 10000; i++) {
$('#jack-target').click()
}
다음과 같이 올바르게 그려진 flag를 획득할 수 있다.