앱(또는 설치한 확장 기능)이 파일을 받는 모든 사람을 위한 글이다. 폼, 관리 화면, CMS 플러그인, API가 해당된다. 공격 방법은 다루지 않고, 공개된 사실을 바탕으로 자기 업로드 기능을 안전하게 만드는 방법만 다룬다. 관련 글: 의존성 결함을 확실히 고치는 CVE 대응 플레이북, 조직을 위한 보안 기본.
실제로 무슨 일이 일어나는가(쉬운 말로)
대부분의 앱에는 '이미지 올리기', '아이콘 바꾸기', '문서 첨부'처럼 파일을 받는 곳이 있다. 이곳의 방어가 약하면, 공격자는 이미지로 위장한 스크립트 파일을 보내 웹에 공개되는 폴더에 저장시킨다. 그다음 그 파일의 URL을 브라우저로 열기만 하면 된다. 서버가 내용을 프로그램으로 실행하면, 공격자는 원격으로 명령을 실행할 수 있다. 이것이 웹 셸(남겨 둔 작은 원격 조작 프로그램)이며, 여기서 사이트 변조, 데이터 탈취, 몰래 만든 관리자 계정, 다른 시스템으로의 확산이 이어진다.
문제는 파일을 받는 것이 아니라 위치와 실행이다
업로드는 정당한 기능이다. 위험한 것은 받은 것을 실행될 수 있는 곳에, 실행될 수 있는 형태로 두는 것이다. 반대로, 의심스러운 파일을 받더라도 절대 실행되지 않는 곳에 놓이고, 내용이 검사되고, 엔드포인트가 인증을 요구한다면 피해는 생기지 않는다. 생각을 '나쁜 파일을 막는다'에서 '저장 위치에서 절대 실행시키지 않는다'로 바꾼다.
2026년 실제 사례: 대규모로 악용된 Joomla 확장 기능(같은 패턴)
2026년, 여러 Joomla 확장 기능에서 완전히 같은 인증 없는 업로드 → RCE 패턴이 잇따라 공개되어 널리 악용됐다. '인증 확인 없음 + 파일 형식 검증 없음 + 웹 루트 아래 저장'이라는 전형적인 조합이었다고 한다. 페이지 빌더를 넘어 이벤트 캘린더 확장 기능까지 번졌고, CISA는 짧은 조치 기한을 정했다.
- SP Page Builder(CVE-2026-48908)
- JoomShaper 제품. 6.6.1 이하가 영향, 6.6.2에서 수정. 사용자 지정 아이콘 업로드에서 인증과 형식 검증이 이뤄지지 않았다고 한다. CVSS 10.0, 실제 악용 확인(CISA KEV 등재). 경보 해설: CVE-2026-48908.
- iCagenda(CVE-2026-48939)
- joomlic 제품, 이벤트 캘린더 확장 기능. 3.2.1–3.9.14 / 4.0.0–4.0.7이 영향, 3.9.15 / 4.0.8에서 수정. 공개 이벤트 신청 폼의 첨부 파일 처리에서 접근 제어가 화면 계층에서만 이뤄졌다고 한다. CVSS 10.0, 실제 악용 확인(CISA KEV 등재). 경보 해설: CVE-2026-48939.
- Page Builder CK(CVE-2026-56290)
- joomlack.fr 제품. 3.5.10 이하가 영향, 3.6.0에서 수정(이전 계열은 3.1.1 / 3.4.10으로 백포트). 같은 인증 없는 업로드가 RCE로 이어진다고 한다. CVSS 10.0.
- 공통점
- 로그인 없이 악용 가능 = 무차별 스캔의 표적. 공격은 접근 유지에 집중했다고 보고됐다. 숨은 관리자 계정을 만들고 웹 셸을 심어, 취약점이 패치된 뒤에도 공격자가 접근을 유지하는 것이다.
- 첫 번째 조치
- 해당 확장 기능을 수정 버전으로 업데이트한다(쓰지 않는 확장 기능은 점검해 제거). 여기에 아래의 설계와 설정을 겹친다.
교훈: 쓰지 않는 확장 기능이 가장 많이 악용되는 약점인 경우가 많다
이 사례들의 공통점은 잊힌 채 설치되어 있던 확장 기능이 침입에 쓰였다는 것이다. CMS 플러그인·확장 기능을 하나 추가할 때마다 공격 표면이 늘어난다. 쓰지 않는 것을 점검해 지우기만 해도 이런 대규모 악용이 노릴 대상이 줄어든다(자산 점검 방법).
공격의 각 단계와 막는 법
이 패턴은 모든 단계에 멈출 곳이 있다. 방법 설명이 아니라 어디서 멈출 수 있는지로 읽기 바란다.
1. 인증 없는 엔드포인트로 파일이 보내진다
누구나 업로드 처리에 도달해 스크립트를 보낼 수 있다.
대책: 인증 + 권한 확인 + CSRF 토큰
2. 형식 검증을 통과해 저장된다
확장자 / Content-Type을 위조해 '이미지'로 위장한다.
대책: 서버 측 허용 목록 + 내용(매직 바이트) 검사
3. 웹 루트 아래에 놓여 URL로 접근된다
추측 가능한 경로에 저장되어 브라우저로 바로 열린다.
대책: 웹 루트 밖에 저장 / 파일 이름 무작위화
4. 서버가 스크립트로 실행한다
저장 디렉터리에서 실행이 켜져 있음 = 웹 셸 → RCE.
대책: 업로드 영역에서 스크립트 실행 끄기
위험한 구성과 안전한 구성
뚫리는 구성
- 엔드포인트에 인증·권한 확인이 없다(누구나 도달한다)
- 확장자나 Content-Type만으로 판단한다(위조, 이중 확장자)
- 받은 파일을 웹 루트 바로 아래에 저장한다
- 저장 위치에서 여전히 스크립트가 실행될 수 있다
- 파일 이름이 사용자가 정한 것 / 추측 가능한 것이다
버티는 구성
- 엔드포인트에 인증 + 권한 + CSRF를 요구한다
- 형식을 허용 목록으로 정하고, 실제 바이트(매직 바이트)를 검사한다
- 웹 루트 밖에 저장한다(전용 처리기를 통해 제공)
- 업로드 영역은 스크립트 실행이 꺼져 있다
- 무작위 파일 이름으로 바꾸고, 사용자 경로는 절대 믿지 않는다
구현 방법(우선순위 순)
엔드포인트에 인증, 권한, CSRF를 요구한다
업로드를 처리하는 엔드포인트는 적절한 권한을 가진 로그인 사용자만 도달할 수 있어야 하고, CSRF 토큰을 검증해야 한다. 2026년 Joomla 사례에서 빠져 있던 것이 바로 이 인증·권한 확인이었다고 한다. 먼저 '누구나 호출할 수 있는' 상태를 없앤다.
서버 측에서 허용 목록으로 정하고 내용을 검사한다
클라이언트 측 검사나 브라우저가 보낸 Content-Type은 믿지 않는다. 서버에서 허용 목록으로 알려진 안전한 형식만 허용하고, 파일의 실제 바이트(매직 바이트)를 검사해 정말 그 형식인지 확인한다. 판단하기 전에 이중 확장자, 대소문자, 끝의 점을 정규화한다.
웹 루트 밖에 저장한다(또는 실행을 끈다)
받은 파일은 URL로 직접 열 수 없는 곳에 저장하고, 전용 컨트롤러를 통해(적절한 Content-Disposition과 함께) 제공한다. 그게 어렵다면 최소한 업로드 영역에서 스크립트 실행을 끈다(웹 서버 설정). 이것이 지켜지면 악성 파일이라도 실행되지 않는다. 다른 통제가 실패했을 때 당신을 지켜 준다.
파일 이름을 무작위로 바꾸고, 크기와 빈도를 제한한다
서버가 정한 무작위 이름으로 바꾸고, 사용자가 준 경로나 파일 이름은 믿지 않는다(경로 탐색 방지). 크기 제한과 요청 빈도 제한을 두고, 가능하면 악성코드 검사도 한다.
확장 기능과 CMS를 점검하고 패치한다
운영 중인 확장 기능·플러그인을 점검해 쓰지 않는 것은 지우고, 나머지는 최신으로 유지한다. 2026년 대규모 악용에서 공격자는 업데이트되지 않은 확장 기능으로 들어왔다. CVE 대응 플레이북에 따라 변경 감지를 더해, 다시 들어오면 잡히게 한다.
이 사이트의 구축 방식과 겹치는 부분
이 패턴의 핵심 문제는 믿을 수 없는 입력을 실행될 수 있는 곳에, 실행될 수 있는 형태로 두는 것이다. 이 사이트의 원칙은 그 반대다. 받은 것을 믿지 않고, 중요한 것은 격리하고, 여러 겹으로 막는다. 업로드에 한하지 않고 '입력은 서버에서 검증한다', '시크릿과 실행 영역을 격리한다'는 같은 방어다. 배치 실수는 공개 디렉터리에 시크릿을 두지 말 것도 참고하라.
다음에 읽을 글
- AI 에이전트 침입: Hugging Face 침입(2026): 자율형 AI 에이전트 공격
- Gyazo 유출(2026년 9월): 무엇이 유출됐고, 사용자가 오늘 할 일
- 결제 페이지 변조(2026년 9월): PhotoGoods(Daiko Printing) 결제 페이지의 카드 정보 탈취 프로그램(파일 업로드 기능 악용이 원인으로 지목된 사례)
- 용어: 안전하지 않은 역직렬화(외부 데이터가 타입을 정하는 경우) / RCE(원격 코드 실행)란 / 악성코드란(웹 셸도 그 한 종류)
- 경보: CVE-2026-48908(SP Page Builder) / CVE-2026-48939(iCagenda)(같은 인증 없는 업로드 → RCE 패턴)
- 실무: 조직을 위한 보안 기본 / CVE 대응 플레이북 / 공개 디렉터리에 시크릿을 두지 말 것
FAQ
Q파일 업로드 결함으로 왜 서버가 장악되나요?
서버가 실행할 파일(스크립트)을 공격자가 둘 수 있다면, 브라우저로 그 파일을 열기만 해도 서버에서 코드가 실행됩니다(웹 셸 → 원격 코드 실행, RCE). 그다음은 사이트 변조, 데이터 탈취, 몰래 만든 관리자 계정, 다른 시스템으로의 확산입니다. 핵심은 파일을 받았다는 것이 아니라, 놓인 곳에서 그 파일이 실행될 수 있다는 점입니다.
Q파일 확장자만 확인하면 충분한가요?
아닙니다. 확장자와 브라우저가 보내는 Content-Type은 쉽게 위조됩니다. 이중 확장자(picture.php.jpg), 대소문자 바꾸기, 끝의 점·널 바이트, 덜 알려진 실행 가능 확장자는 모두 단순한 검사를 통과합니다. 허용 목록(알려진 안전한 것만 허용), 파일의 실제 바이트 검사(매직 바이트), 그리고 무엇보다 저장 위치에서 아무것도 실행되지 않게 하는 것을 조합해 막으세요. 거부 목록에 기대지 마세요.
Q작은 사이트도 노려지나요?
그렇습니다. 이런 종류의 결함은 인증 없이 악용할 수 있어서, 공격자는 인터넷 전체를 스캔해 취약한 버전을 가리지 않고 공격합니다. 2026년 Joomla 페이지 빌더 확장 기능의 대규모 악용에서도 규모와 상관없이 해당 설치는 모두 표적이었습니다. '작아서 공격받지 않는다'는 통하지 않습니다.