안경잡이개발자

728x90
반응형

자바(Java)를 이용해 문제풀이 서버와 통신하기

나동빈

 

  일반적으로 시스템 해킹을 공부하기 위한 각종 포너블(Pwnable) 사이트나 실제 CTF 대회에서는 Netcat 모듈을 이용해 문제풀이 서버와 통신하는 경우가 많습니다. 또한 실시간으로 서버와 상호작용을 해야 하는 경우가 많기 때문에 실제로 문제를 풀 때는 파이썬(Python)을 이용해서 서버와 통신하는 모듈을 구현하곤 합니다. 하지만 저와 같이 국내 개발자 출신의 해커들은 자바(Java)가 더 익숙한 경우가 많기 때문에 자바를 이용해 문제를 푸는 방법에 대해 소개하고자 합니다.

 

  먼저 기본적인 Netcat(nc) 명령어를 이용해 서버와 통신하는 화면은 다음과 같습니다. 저는 윈도우 운영체제를 이용하고 있어서 별도의 Netcat 프로그램을 환경변수로 설정했습니다.



  pwnable.krcoin1 문제를 풀기 위해 접속한 모습은 위와 같습니다. 어차피 nc 모듈도 서버와 소켓 통신을 이용해 메시지를 주고받는 프로그램에 불과하기 때문에 어떠한 프로그래밍 언어를 이용하던지 간에 똑같은 기능을 구현할 수 있습니다.

 

import java.io.BufferedReader;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.OutputStream;

import java.io.OutputStreamWriter;

import java.io.PrintWriter;

import java.net.Socket;

 

public class Main {

 

public static void main(String[] args) {

    try {

      Socket sock = new Socket("pwnable.kr", 9007);

      InputStream in = sock.getInputStream();

      BufferedReader br = new BufferedReader(new InputStreamReader(in));

      String line = null;

      while((line = br.readLine()) != null){

        System.out.println(line);

      }

      br.close();

      sock.close();

    } catch (Exception e) {

    System.out.println(e);

    }

  }

}

 

  따라서 위와 같이 Java에서 Socket 통신 기본 라이브러리를 활용해서 동일한 기능을 구현할 수 있습니다. 프로그램의 실행 결과는 다음과 같습니다. 저는 이클립스(Eclipse) 개발환경에서 실행해보았습니다.



  요약하여 설명하자면 서버로부터 어떠한 명령어를 기다리고자 하는 경우에는 두 개의 라이브러리 InputStreamBufferedReader를 이용해 서버로부터 특정한 메시지를 전달받을 수 있습니다. 구체적 동작 과정을 살펴보면 InputStream을 이용해 서버로부터 전달 받은 메시지 스트림(Stream)을 일정 크기의 버퍼(Buffer)에 지속적으로 담아서 문자(Character) 형태로 읽어들여 String 객체에 문자열 데이터를 담은 것입니다. 이 때 이렇게 버퍼를 쓰는 이유는 매 번 CPU 자원을 활용하지 않고 일정 주기로 CPU 자원을 활용하도록 해서 프로그램의 효율성을 높이는 것입니다.

 

그렇다면 서버로 어떠한 데이터를 전달하고자 할 때는 어떻게 할 수 있을지 알아봅시다. 직관적으로 생각했을 때 InputStreamBufferedReader의 반대인 OutputStreamBufferedWriter를 쓰면 될 것 같다는 생각이 드실 겁니다. 결과적으로 다음과 같이 소스를 작성할 수 있습니다.


import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.OutputStream;

import java.io.OutputStreamWriter;

import java.net.Socket;


public class Main {


public static void main(String[] args) {

        try {

            Socket sock = new Socket(특정한 서버, 포트 번호);

            InputStream in = sock.getInputStream();

            BufferedReader br = new BufferedReader(new InputStreamReader(in));

            OutputStream out = sock.getOutputStream();

            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));

            String line = null;

            while((line = br.readLine()) != null){

            System.out.println(line);

            if(line.contains("Enter your name:")) break;

            }

            bw.write("Dongbin, Na");

            bw.newLine();

            bw.flush();

            bw.close();

            br.close();

            sock.close();

        } catch (Exception e) {

            System.out.println(e);

        }

}

}


  위 소스코드는 특정한 서버에 접속해서 메시지를 계속해서 전달 받다가 “Enter your name:"이 포함된 문장을 만나면 더 이상 서버로부터 데이터를 전달받지 않고 "Dongbin, Na"라는 메시지를 서버로 전송하는 것입니다. 실제로 이러한 방식으로 서버와 클라이언트 통신을 진행할 수 있습니다. 물론 일반적으로 서버로부터 들어오는 데이터가 정형화되어있지 않다면 split(), contains(), substring() 등의 함수를 이용해서 메시지에서 필요한 내용만 파싱하여 사용할 필요도 있습니다.


728x90
반응형