LA CTF 2025

m0d0ri205·2025년 2월 8일
0

CTF

목록 보기
8/8
post-thumbnail

lucky-flag

JavaScript XOR 암호화 해제 - lactf 문제 풀이

이 문제는 JavaScript를 이용해 특정 .box 요소를 클릭하면 XOR 연산을 통해 플래그를 복호화하여 출력하는 방식입니다.

🔍 코드 분석

1. 랜덤 박스 선택

const boxes = document.querySelectorAll('.box');
let flagbox = boxes[Math.floor(Math.random() * boxes.length)];

boxes 배열에서 무작위로 하나를 선택해 flagbox로 지정합니다.

2. 클릭 이벤트 설정

for (const box of boxes) {
  if (box === flagbox) {
    box.onclick = () => {
      let enc = `"\\u000e\\u0003\\u0001\\u0016\\u0004\\u0019\\u0015V\\u0011=\\u000bU=\\u000e\\u0017\\u0001\\t=R\\u0010=\\u0011\\t\\u000bSS\\u001f"`;
      for (let i = 0; i < enc.length; ++i) {
        try {
          enc = JSON.parse(enc);
        } catch (e) { }
      }
      let rw = [];
      for (const e of enc) {
        rw ^ 0x62);
      }
      const x = rw['\x6dap'](x => String['\x66rom\x43har\x43ode'](x));
      alert(`Congrats ${x['\x6aoin']('')}`);
    };
    flagbox = null;
  } else {
    box.onclick = () => alert('no flag here');
  }
};

여기서 중요한 부분은 enc 문자열이 여러 번 JSON.parse를 통해 디코딩된다는 점입니다. 이후 XOR 연산을 통해 복호화가 진행됩니다.


🛠 XOR 복호화 과정

1. JSON 디코딩

let enc = `"\\u000e\\u0003\\u0001\\u0016\\u0004\\u0019\\u0015V\\u0011=\\u000bU=\\u000e\\u0017\\u0001\\t=R\\u0010=\\u0011\\t\\u000bSS\\u001f"`;

이 문자열은 UTF-16 이스케이프 형태로 저장된 문자열입니다. 여러 번 JSON.parse(enc)를 수행하면 원래 문자열로 변환됩니다.

2. XOR 복호화

rw.push(e.charCodeAt(0) ^ 0x62);

각 문자의 ASCII 코드에 0x62(98)와 XOR 연산을 수행하여 원래 값을 복원합니다.


✅ Python을 이용한 복호화

import json

# 원본 인코딩된 문자열
enc = "\u000e\u0003\u0001\u0016\u0004\u0019\u0015V\u0011=\u000bU=\u000e\u0017\u0001\t=R\u0010=\u0011\t\u000bSS\u001f"

# XOR 복호화
rw = [chr(ord(e) ^ 0x62) for e in enc]

# 결과 문자열
decoded_flag = "".join(rw)
print(decoded_flag)

출력 결과:

lactf{w4s_i7_luck_0r_ski11}

🎯 결론

이 문제는 JSON 디코딩 → XOR 연산을 통한 복호화 방식으로 이루어진 JavaScript 기반 CTF 문제였습니다. XOR 연산의 성질을 이용해 쉽게 플래그를 복원할 수 있었습니다. 🚀

I spy...

lactf{1_sp0773d_z_t0k3ns_4v3rywh3r3}

개발자 도구를 사용할 줄 아는지 물어보는 문제입니다.

javascryption

const msg = document.getElementById("msg");
const flagInp = document.getElementById("flag");
const checkBtn = document.getElementById("check");

function checkFlag(flag) {
    const step1 = btoa(flag);
    const step2 = step1.split("").reverse().join("");
    const step3 = step2.replaceAll("Z", "[OLD_DATA]");
    const step4 = encodeURIComponent(step3);
    const step5 = btoa(step4);
    return step5 === "JTNEJTNEUWZsSlglNUJPTERfREFUQSU1RG85MWNzeFdZMzlWZXNwbmVwSjMlNUJPTERfREFUQSU1RGY5bWI3JTVCT0xEX0RBVEElNURHZGpGR2I=";
}

checkBtn.addEventListener("click", () => {
    const flag = flagInp.value.toLowerCase();
    if (checkFlag(flag)) {
        flagInp.remove();
        checkBtn.remove();
        msg.innerText = flag;
        msg.classList.add("correct");
    } else {
        checkBtn.classList.remove("shake");
        checkBtn.offsetHeight;
        checkBtn.classList.add("shake");
    }
});

웹 사이트에 접속하는 정보를 제공한다.

해당 코드를 분석하면

  1. base64로 변환
  2. reverse
  3. 모든 'Z'를 "[OLD_DATA]" 로 대체
  4. 다시 Base64로 변환

http://gchq.github.io/CyberChef/#recipe=From_Base64('A-Za-z0-9%2B/%3D',true,false)URL_Decode()Find_/_Replace(%7B'option':'Simple%20string','string':'%5BOLD_DATA%5D'%7D,'Z',true,false,true,false)Reverse('Character')From_Base64('A-Za-z0-9%2B/%3D',true,false)&input=SlRORUpUTkVVV1pzU2xnbE5VSlBURVJmUkVGVVFTVTFSRzg1TVdOemVGZFpNemxXWlhOd2JtVndTak1sTlVKUFRFUmZSRUZVUVNVMVJHWTViV0kzSlRWQ1QweEVYMFJCVkVFbE5VUkhaR3BHUjJJPQ&oeol=FF

여기 나온대로 하면 플래그를 획득 할 수 있다.

lactf{no_grizzly_walls_here}

profile
말하는 감자중.....

0개의 댓글

관련 채용 정보