안경잡이개발자

728x90
반응형

  Pwn Adventure 3게임 해킹(Game Hacking) 공부를 목표로 하여 만들어진 게임입니다. 일종의 MMORPG 게임인데, 이 게임에서는 모든 것을 해 볼 수 있습니다. 이 게임은 간단한 형태의 매우 많은 취약점을 내장하고 있다는 점에서 하늘 날기(Flying), 돈 버그(Endless Cash), 이외에도 클라이언트 데이터 변조 혹은 네트워크 해킹이 가능합니다.


  물론 이러한 게임 해킹 과정을 통해서 단순히 게임을 불법적으로 즐기는 것이 아니라, 취약점을 찾아서 게임을 개발한 사람에게 알려주겠다는 착한 마인드로 공부를 하셔야 됩니다. 이 게임은 개발자가 놓치기 쉬운 부분들을 누락시켜서, 고의적으로 문제가 있도록 개발이 되어있습니다. 그래서 엔진 자체를 해킹하려는 시도보다는 이 게임을 면밀히 분석해서 해킹하는게 좋습니다.


  ▶ 공식 웹 주소: http://www.pwnadventure.com



  사이트에 접속하면 바로 게임을 다운로드 해볼 수 있습니다.



  자신의 운영체제에 맞게 다운로드를 진행해주세요.



  압축 파일을 압축 해제 해보시면 위와 같이 설치 프로그램이 존재합니다. 이를 실행해서 설치를 진행해봅시다.



  설치를 위해서 외국 서버로부터 데이터를 받아오는데, 외국 서버가 생각보다 많이 느려서 기다리실 필요가 있습니다.



  설치가 완료되면 'Play' 버튼을 눌러서 게임을 시작할 수 있습니다.



  아직 우리는 서버를 설정하지 않았기 때문에 오프라인 플레이(Offline Play)를 눌러봅시다.



  그러면 위와 같이 캐릭터를 선택하여 생성할 수 있습니다.



  간단하게 게임을 실행해보면서 대략적인 게임 방법에 대해 알아보는 시간을 가지시면 됩니다.

728x90
반응형

728x90
반응형

pwnable.kr - lotto 문제풀이(Write Up)

문제 분류: 공격(Attack)


  이번 시간에 풀어 볼 문제는 pwnable.kr의 lotto입니다. 기존에 기초 프로그래밍 위주로 학습하고 보안 분야로 넘어오신 분들에게 적합한 문제라고 생각되어 이 문제 또한 앞 부분에서 다루게 되었습니다. 더불어 난이도 또한 낮은 기초 문제라서 기초 C언어 지식으로도 문제를 해결하실 수 있답니다.


  ▶ 문제풀이 사이트 주소: http://pwnable.kr/play.php



  이 문제는 SSH를 이용해 통신해야 하는 문제입니다. SSH는 원격지에 있는 서버에 접속하여 서버를 관리할 수 있도록 해주는 프로토콜입니다. 윈도우 10은 기본적으로 OpenSSH를 내장하고 있어 쉽게 SSH를 사용할 수 있지만 사용이 어려운 경우 Putty와 같은 별도의 소프트웨어가 필요할 수 있습니다. Putty는 https://www.putty.org에 접속하여 설치가 가능합니다.



  저는 위와 같이 윈도우에 내장된 OpenSSH를 이용해 서버에 접속해보았습니다.



  접속 이후에는 ls 명령어를 이용해 위와 같이 현재 루트 디렉토리에 어떠한 파일이 존재하는지 확인할 수 있습니다. lotto 실행 파일과 lotto.c 소스코드 파일이 존재합니다. 일반적으로 이러한 분석 및 공격 분류의 문제는 소스코드를 보면서 취약점을 파악해 실행 파일에 적용하여 Flag 값을 얻을 수 있는 방식입니다. 일단 간단히 ./lotto 명령어로 로또 프로그램을 테스트해보겠습니다.



  6자리의 로또 코드를 입력하라고 하는 군요. 다만, 제가 알기로 로또는 1부터 45까지의 숫자를 넣는 것인데 6자리를 문자열로 넣는 것이 조금 이상하다는 생각이 들었습니다. 일단 아래와 같이 cat lotto.c 명령어를 입력해 lotto.c 소스코드를 분석할 수 있습니다.



  소스코드를 확인한 결과 랜덤한 6개의 숫자가 lotto[] 배열에 저장되고, 숫자는 아스키 코드로 1부터 45까지의 랜덤한 숫자로 추출됩니다. 다만 아래쪽을 보면 이중 For문을 이용해 우리가 입력한 문자열과 배정된 당첨 lotto[] 번호가 일치하는지 확인하는 구문이 나옵니다. 저의 문자열 매칭 알고리즘 강의(https://blog.naver.com/ndb796/221240660061)를 들으신 분이라면 위 알고리즘이 잘못되었다는 것을 쉽게 파악할 수 있을 겁니다. 위 알고리즘은 단 하나의 로또 번호라도 일치한다면, match 변수의 값이 6이 됩니다. 즉, 하나만 번호가 일치해도 당첨이 되어버리는 잘못 작성된 소스코드라고 할 수 있습니다.


  우리는 이렇게 잘못 작성된 알고리즘을 이용하여 로또에 쉽게 당첨되는 공격(Attack) 시도를 할 것입니다.



  먼저 아스키 코드표를 봅시다. 이제 위에서 보이는 1부터 45까지의 아스키 코드 중에서 아무거나 6개를 넣으면 됩니다. 그러면 우연히 1개의 문자라도 로또 당첨 번호와 일치하는 경우 플래그(Flag) 값을 내뱉을 것입니다. 통계적으로 생각했을 때 대략 3~4번만 시도해도 답이 도출될 것이라 판단할 수 있습니다.



  위와 같이 문자열 "######"으로 몇 번 입력을 시도하니 플래그 값이 나왔습니다.

728x90
반응형

728x90
반응형

pwnable.kr - coin1 문제풀이(Write Up)

문제 분류: 코딩(Coding)


  이번 시간에 풀어 볼 문제는 대표적인 CTF 문제풀이 사이트인 pwnable.kr의 기초 문제 중 'coin1' 문제입니다. CTF 공부 카테고리에서 실질적으로 풀어보는 첫 번째 문제가 될 겁니다. pwnable.kr 공식 웹 사이트에서 coin1 문제를 확인하실 수 있습니다.


  ▶ 문제풀이 사이트 주소: http://pwnable.kr/play.php



  문제를 확인해보면 pwnable.kr에 9007번 포트로 접속해보라고 나오는 것을 알 수 있습니다.



  문제를 요약하면 다음과 같습니다.

 

- N은 코인의 개수, C는 시도 횟수

- 서버로 코인의 번호들을 보내면 서버는 해당 코인들의 무게 합을 반환합니다.

- 가짜 코인이 하나 숨어있는데, 가짜 코인의 무게는 9이고 정상 코인의 무게는 10입니다.

 

  따라서 이 문제를 해결하기 위해서는 이분 탐색을 수행하면 됩니다. 예를 들어 전체 코인이 4개가 있고, 각 코인의 무게가 다음과 같다고 해봅시다.

 

코인: 0 1 2 3

무게: 10 10 9 10

 

  이 때 맨 처음에 서버로 “0 1”을 보낼 수 있습니다. 그러면 서버에서는 두 코인의 무게 합인 20을 반환할 겁니다. 우리는 이 20이라는 결과를 통해서 , 01 중에는 가짜 코인이 없구나.’ 라는 것을 알 수 있습니다. 그러면 01은 더 이상 볼 필요 없이 23을 보면 됩니다.

 

  23 중에서 반드시 하나는 가짜 코인이 섞여있다는 것을 알고 있기 때문에 “2”만 보내면 됩니다. 만약에 서버로부터 돌아오는 결과가 9라면 2가 가짜 코인이고, 서버로부터 돌아오는 결과가 10이라면 3이 가짜 코인이 되는 것입니다.

 

  이와 같이 현재 가짜 코인이 섞여있는 코인의 집합 중에서 계속해서 절반(Half)만 확인하는 식으로 매 번 검사할 때마다 검사하는 집합의 크기를 1/2로 줄일 수 있습니다. 이것은 이분 탐색의 대표적인 예라고 할 수 있으며 통상적으로 코인의 개수가 N개일 때 O(logN)의 시간 복잡도를 가집니다.

 

  이제 문제를 푸는 방법을 알았으므로 Java를 이용해 서버 통신 모듈을 개발합니다.

 

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.OutputStream;

import java.io.OutputStreamWriter;

import java.net.Socket;


public class Main {


private static Socket sock = null;

private static OutputStream out = null;

private static InputStream in = null;

private static BufferedWriter bw = null;

private static BufferedReader br = null;


public static void init() {

try {

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

out = sock.getOutputStream();

in = sock.getInputStream();

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

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

} catch (Exception e) {

e.printStackTrace();

}

}


public static void close() {

try {

bw.close();

br.close();

sock.close();

} catch (IOException e) {

e.printStackTrace();

}

}


public static int findAnswer() {

    try {

    // 서버로부터 메시지를 전달 받습니다.

    String line = null;

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

        // 전달 받은 메시지를 출력합니다.

        System.out.println(line);

        // 첫 번째 문자가 'N'인 경우 문제 풀이가 시작된 것입니다.

        if(line.length() != 0 && line.charAt(0) == 'N') break;

        }

        // N과 C를 파싱하여 각각 숫자로 변환합니다.

        int N = Integer.parseInt(line.split("N=")[1].split(" C")[0]);

        int C = Integer.parseInt(line.split(" C=")[1]);

        System.out.println("N의 값은 " + N + ", C의 값은 " + C);

    } catch (Exception e) {

    e.printStackTrace();

    }

return -1;

    }


public static void main(String[] args) {

try {

init();

findAnswer();

close();

} catch (Exception e) {

System.out.println(e);

}

}

}

 

  전체 소스코드는 소켓 통신 관련 객체를 초기화하는 init() 함수, 소켓 통신 관련 객체를 파기하는 close() 함수, 서버와 직접 통신해 답을 찾아내는 findAnswer() 함수로 구성됩니다. 일단은 간단하게 findAnswer() 함수에서 서버로부터 메시지를 계속 전달 받되, 첫 번째 문자가 “N"인 라인을 만나면 NC의 값을 파싱하여 변수에 담는 것까지 작업해보았습니다.



  실행 결과는 위와 같습니다. 서버로부터 계속 데이터를 전달 받다가, “N=숫자 C=숫자의 형태를 만나면 이를 Javasplit() 함수를 이용해 숫자 정보만 파싱하는 것입니다. 이제 NC를 받아오는 모듈까지 작성했으므로 이를 확장시켜서 이분 탐색을 활용해 정답을 도출하도록 확장시키면 됩니다.


import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.OutputStream;

import java.io.OutputStreamWriter;

import java.net.Socket;


public class Main {


private static Socket sock = null;

private static OutputStream out = null;

private static InputStream in = null;

private static BufferedWriter bw = null;

private static BufferedReader br = null;


public static void init() {

try {

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

out = sock.getOutputStream();

in = sock.getInputStream();

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

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

} catch (Exception e) {

e.printStackTrace();

}

}


public static void close() {

try {

bw.close();

br.close();

sock.close();

} catch (IOException e) {

e.printStackTrace();

}

}


public static int findAnswer() {

    try {

    // 서버로부터 메시지를 전달 받습니다.

    String line = null;

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

        // 전달 받은 메시지를 출력합니다.

        System.out.println(line);

        // 첫 번째 문자가 'N'인 경우 문제 풀이가 시작된 것입니다.

        if(line.length() != 0 && line.charAt(0) == 'N') break;

        }

        // N과 C를 파싱하여 각각 숫자로 변환합니다.

        int N = Integer.parseInt(line.split("N=")[1].split(" C")[0]);

        int C = Integer.parseInt(line.split(" C=")[1]);

        int up = N - 1;

        int down = 0;

        

        while(down <= up && C > 0) {

            int middle = (up + down) / 2;

            String message = "";

            for(int i = down; i <= middle; i++) {

            message += i + " ";

            }

            // 서버로 확인하고자 하는 코인들의 번호를 전달합니다.

            System.out.println("보낸 값: " + message);

            bw.write(message);

            bw.newLine();

            bw.flush();

            C--;

            // 서버로부터 결과 정보를 전달 받습니다.

            line = br.readLine();

            System.out.println("받은 값: " + line);

            int next = Integer.parseInt(line);

            // 10으로 나누어진다면 해당 범위에 가짜 코인이 없습니다.

            if(next % 10 == 0) {

            down = middle + 1;

            }

            // 그렇지 않다면 해당 범위에 가짜 코인이 있습니다.

            else {

            up = middle - 1;

            }

        }

        // 아직 확인할 수 있는 횟수가 더 남았다면 다 쓸 때까지 전송합니다.

        if(C > 0) {

            bw.write(down + "");

            bw.newLine();

            bw.flush();

        }

        // 결과적으로 찾은 가짜 코인의 번호는 down에 담겨있습니다.

        return down;

    } catch (Exception e) {

    e.printStackTrace();

    }

return -1;

    }


public static void main(String[] args) {

try {

init();

// 게임이 여러 차례 존재하므로 무한정 실행시킵니다.

while(true) {

int bottom = findAnswer();

String message = bottom + "";

System.out.println("가짜 코인 발견: " + message);

// 한 차시 게임에서 찾은 답을 전송합니다.

            bw.write(message);

            bw.newLine();

            bw.flush();

}

} catch (Exception e) {

System.out.println(e);

}

}

}



  결과적으로 총 100차례의 게임이 빠르게 수행되고 플래그 값으로 b1NaRy_S34rch1nG_1s_3asy_p3asy를 찾았습니다. 이를 입력하면 정답 처리를 받게 됩니다.

728x90
반응형

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
반응형

728x90
반응형

  네트워크 상에서 특정한 컴퓨터와 통신하기 위한 유틸리티(Utility)넷캣(Netcat)을 사용할 수 있습니다. TCP/UDP 프로토콜을 이용하는 환경에서는 범용적으로 적용이 가능하다는 점에서 간단한 네트워크 통신을 위한 목적으로 간단히 사용할 수 있습니다. 줄여서 NC(Network Connection)라고도 부르며 해킹(Hacking)에 있어서도 이용범위가 넓다는 특징이 있습니다. 리눅스 운영체제에서는 Netcat을 사용하기 어렵지 않지만 윈도우(Windows) 운영체제를 사용하는 사람들은 별도의 소프트웨어를 설치해서 사용할 수 있답니다.


  ▶ Netcat 다운로드 사이트: https://eternallybored.org/misc/netcat/



  사이트 접속 이후에는 위와 같이 netcat 1.12 버전을 다운로드하여 윈도우에서 사용할 수 있습니다.



  다운로드 이후에는 압축을 풀어줍니다. 저는 위와 같이 C 드라이브에 압축을 풀어주었습니다.



  이후에 제어판 -> 시스템 -> 고급 시스템 설정 -> '환경 변수'로 들어가서 우리가 방금 다운로드 해 준 Netcat 유틸리티를 커맨드 라인에서 사용할 수 있도록 변수 설정을 해주도록 하겠습니다.



  시스템 변수 -> 'Path'에서 사용할 유틸리티의 경로를 설정해 줄 수 있습니다. 여기에서 새롭게 자신이 압축을 푼 Netcat 폴더의 위치를 넣어주시면 됩니다. 이후에 명령 프롬프트(CMD)에서 Netcat 유틸리티를 사용하실 수 있습니다.


1. 서버 열기 및 접속하기


  서버를 열 때는 nc -l 명령어를 사용합니다. l(Listen)은 단순한 채팅 서버와 같은 역할을 수행합니다. 클라이언트에서 접속할 때는 호스트 주소와 포트 번호를 공백으로 구분하여 이어서 작성하면 됩니다.



  일반적으로 다음과 같이 해킹 문제풀이 서버에 접속하면 서버에서 미리 준비된 메시지를 출력하고, 사용자와 상호작용을 하는 식입니다.



  Netcat은 말 그대로 네트워크 통신 도구이므로 다음과 같이 웹 사이트에 접속할 수도 있습니다. 다음 사진은 제 개인 웹 사이트에 접속하여 요청(Request) 패킷을 Netcat 유틸리티 상에서 전송해 본 것입니다. 서버에서 성공적으로 응답(Response) 패킷이 날아온 것을 알 수 있습니다.



728x90
반응형

728x90
반응형

  해킹 방어 대회(CTF)에서는 다양한 문제들이 가리지 않고 출제됩니다. 이번 시간에는 해킹 방어 대회를 위해 사용할 수 있는 기본적인 소프트웨어 및 프로그래밍 언어에 대해 알아보겠습니다. 사실상 기본적인 도구가 없으면 해킹 자체를 할 수 없는 경우가 많기 때문에 아래에서 언급된 소프트웨어는 필수적으로 설치를 할 수 있으면 좋습니다. 또한 아래 언급되는 대다수의 소프트웨어가 기초적인 프로그래밍 능력이 없으면 활용하기 어렵습니다. 하지만 당장 잘 모르는 소프트웨어라고 하더라도, 필요할 때마다 설치하며 공부하시면 효율적인 학습이 가능합니다.


  어떠한 CTF라도 출제되는 문제 유형에서 요구하는 모든 도구(Tool)를 정확히 파악하기는 매우 어려우며 출제자의 의중을 파악하기도 어렵습니다. 특히 특정 분야에 대한 매우 전문적인 지식을 요구하는 고난이도의 문제가 자주 출제됩니다. 따라서 처음 CTF를 출전할 때 다양한 고충을 겪으시는 것은 당연하니 처음에 너무 모르는 도구가 많다고 하시더라도 겁먹지 말고, 천천히 하나씩 접해보시는 걸 추천합니다.


  ▶ 파이썬(Python) 및 IDE: 파이썬은 해킹을 위한 매우 강력한 기능을 제공합니다. 특히 pwntools와 같은 라이브러리를 활용할 수 있습니다. 프로그래밍 언어는 도구에 불과하다고는 하지만 사실상 오늘날의 CTF는 파이썬을 다루지 못하면 상당한 제약을 느낄 수 있습니다.


  ▶ C/C++/C# 및 Visual Studio: 비주얼 스튜디오 개발 환경에서 C언어 계열을 활용하는 문제는 매우 많이 출제되고 있습니다. 최근 F#까지 간혹 출제되는 추세입니다. 사실상 매우 기본적인 C언어 개발환경이므로 설치가 필수적입니다.


  ▶ 가상 머신(Virtual Machine): 상당수 문제는 리눅스(Linux) 환경이 아니면 접근조차 할 수 없는 경우가 많으므로 다른 운영체제 시스템 환경을 다루기 위해 가상 머신을 사용할 필요가 있습니다.


  ▶ SSH/Netcat: 원격지에 존재하는 서버(Server)에 접속하기 위한 목적으로 사용할 수 있는 유틸리티(Utility)입니다. 일반적으로 CTF 대회 문제 서버에 접속하기 위해 자주 사용됩니다. 또한 이러한 도구는 비단 해킹이 아니라 특정 서버를 관리하기 위한 목적으로 사용됩니다.


  ▶ IDA Debugger: 디버깅(Debugging) 도구 중에서 가장 강력한 소프트웨어 중 하나입니다. 다양한 플러그 인을 직접 개발하거나 사용할 수 있는데, 대표적인 플러그 인으로는 기존 기계어를 C언어 문법과 흡사하게 재구성해서 보여주는 기능을 가진 Hex-Rays가 있습니다.


  ▶ Cygwin/MinGW: 유닉스 계열의 명령어나 기능을 윈도우 운영체제에서 소스코드로부터 컴파일할 수 있도록 해주는 소프트웨어입니다. 물론 이러한 프로그램을 설치한다고 해서 리눅스 전용 바이너리 파일을 실행할 수 있는 것은 아니므로 가상 머신을 따로 설치하는 것이 좋습니다.


  ▶ 와이어샤크(Wireshark): 대표적인 네트워크 패킷(Packet) 분석 소프트웨어입니다. 사실 CTF 뿐만 아니라 네트워크를 통한 대부분의 소프트웨어를 분석하거나 개발할 때 사용할 수 있습니다.


  ▶ 칼리 리눅스(Kali Linux): 침투 테스트 목적으로 가장 인기있는 운영체제(OS)입니다. 기본적으로 해킹에 필요한 대부분의 기능 및 도구가 베이직하게 설치가 되어 있다는 점에서 매우 편리하게 사용 가능합니다. 보안을 시작하는 사람들이 가장 먼저 설치하는 것 중 하나입니다.


  ▶ 반디집: 윈도우 운영체제를 베이스로 사용하는 유저들이 리눅스나 맥(MAC) 개발 환경에서 압축된 다양한 파일을 쉽게 해제할 수 있도록 도와줍니다. 다양한 압축 기능을 사용하기 편리하게 해놓았다는 점에서 활용도가 높습니다.


  ▶ HxD: 바이너리 코드(2진수)보다 가독성이 높아 컴퓨터 분야에서 널리 쓰이는 16진수 형태의 데이터를 헥사 코드라고 말합니다. 특정한 파일이 있을 때 이를 16진수 코드로 분석하고자 할 때 사용할 수 있는 소프트웨어입니다. 이를 활용해 JPG, PNG 등의 이미지 파일 등을 16진수 데이터 형태로 분석할 수도 있으며 적절하게 변경하여 사용할 수 있습니다.


  ▶ Pwn Debugger: 리눅스 환경에서 손쉽게 사용할 수 있는 디버깅 도구입니다. 기본적인 gdb보다 더 가시적이며 동적인 환경에서 


  ▶ 버프 수트(Burp Suite): 웹 취약점 분석 도구 중에서 가장 유명한 도구 중 하나입니다. 자체적인 프록시(Proxy) 기능을 제공하며 다양한 파라미터 변조 및 반복적인 패킷 전송 공격 등 다양한 공격이 가능합니다.


  ▶ 크롬 & EditThisCookie: 크롬(Chrome) 개발자 도구만 잘 이용해도 다양한 웹 취약점 테스트를 별도의 프로그래밍 도구 없이 할 수 있는 시대가 왔습니다. 특히 EditThisCookie와 같은 별도의 확장 프로그램을 잘 활용하시면 매우 편리한 웹 취약점 분석이 가능합니다.


  ▶ 볼라빌리티(Volatility): 파이썬으로 개발된 메모리 분석 및 포렌식 전용 소프트웨어입니다. 기본적으로 칼리 리눅스 운영체제에 포함되어 있는 도구 중 하나입니다.


  ▶ FTK Imager: 포렌식 및 메모리 이미징을 위한 전문 소프트웨어입니다. 다양하고 강력한 부가적인 기능을 제공합니다.


  ▶ dex2jar: 대표적인 안드로이드 어플리케이션 디컴파일러입니다. 이를 활용하면 APK 파일을 뜯어 분석한 뒤에 smali 파일을 수정해 다시 패키징하고, 어플리케이션으로 제작하여 해적판까지 배포할 수 있습니다.


  ▶ jd-gui: 자바(Java)로 개발된 JAR 파일을 손 쉽게 분석할 수 있도록 도와주는 GUI 소프트웨어입니다.


  ▶ PHP/JSP 개발환경: 웹 해킹 문제로 가장 많이 출제되는 PHP 및 JSP 언어에 대한 개발환경을 구축해놓고, 기초적인 프로그래밍까지 할 수 있도록 공부하시면 많은 도움이 됩니다.

728x90
반응형

728x90
반응형

Facebook Hacker Cup 2018 Qualification Round

나동빈

 

  페이스북 해커컵(Facebook Hacker Cup)은 특이한 방법으로 진행됩니다. 프로그램을 만들 때의 논리력을 중요시하기 때문에 언어의 제약이 없습니다. 그래서 문제를 푼 뒤에 소스코드를 제출할 때는 페이스북에서 제공하는 입력 파일(Input)을 받아서, 그것을 프로그램에 넣고 나온 결과(Output)을 그대로 제출하면 됩니다. 소스코드도 별도로 제출하긴 하는데 부정행위 검사용에 불과한 것 같습니다.



  실제로 문제를 푼 뒤에 답안을 제출할 때는 6분의 시간을 줍니다. 입력 데이터에 대해 6분 안에 올바른 결과 값을 도출해서 제출하면 되는 방식입니다.



  출력 파일 및 소스코드를 제출하면 다음과 같이 제출이 이루어집니다. 결과는 대회가 끝나야 제대로 나오는 것으로 판단됩니다.



1. Tourist

 

문제 설명

(페이스북 해커컵의 문제는 영어로 제공됩니다. 제가 임의로 번역한 겁니다.)

 

- N개의 장소가 있고 장소의 이름은 문자열로 주어집니다.

- 1부터 N까지 인기가 많은 순서대로 주어집니다.

- 한 번 방문할 때 K개의 장소를 방문합니다.

- 구체적으로 어떤 장소를 방문할지 결정하기 위해서, 이미 몇 번 방문한 적이 있는지를 기준으로 N개의 장소를 오름차순 정렬합니다. 그리고 인기도가 많은 순으로 정렬하여 K개를 선택합니다.

- 즉 모든 장소에 대해서 방문한 횟수를 기준으로 먼저 선택하고, 방문한 횟수가 동일하다면 인기도가 높은 장소를 선택하면 됩니다.

- Alex는 이미 V-1번 방문한 적이 있습니다. 이제 V번째 방문을 하고자 합니다. AlexV번째 방문할 때 방문하게 될 K개의 장소를 출력하면 됩니다.

- T번의 테스트가 제공되고 매 테스트마다 N, K, V가 주어지고 N개의 장소명이 주어집니다.

- 1 <= T <= 80, 1 <= K <= N <= 50, 1 <= V 10^12


예제 입력

6

4 1 3

LikeSign

Arcade

SweetStop

SwagStore

4 4 100

FoxGazebo

MPK20Roof

WoodenSculpture

Biryani

4 3 1

LikeSign

Arcade

SweetStop

SwagStore

4 3 3

LikeSign

Arcade

SweetStop

SwagStore

4 3 10

LikeSign

Arcade

SweetStop

SwagStore

2 1 1000000000000

RainbowStairs

WallOfPhones

 

예제 출력

Case #1: SweetStop

Case #2: FoxGazebo MPK20Roof WoodenSculpture Biryani

Case #3: LikeSign Arcade SweetStop

Case #4: LikeSign SweetStop SwagStore

Case #5: LikeSign Arcade SwagStore

Case #6: WallOfPhones


문제 풀이

  문제의 조건을 보면 V가 최대 1,000,000,000,000까지 들어올 수 있습니다. 그래서 단순히 문제에서 요구하는 대로 매 번 정렬을 수행해서 최종적인 답을 도출하려고 하면 정해진 시간 안에 문제를 해결할 수 없을 겁니다. 그래서 최대 1,000,000,000,000 번을 실제로 다 방문하지 말고 어떠한 규칙을 발견할 수 있도록 애초에 문제에서 유도하고 있는 것입니다. 따라서 문제를 풀 때는 정확히 이러한 N, K, V의 범위. 즉 정의역에 대해서 가장 먼저 파악해야 합니다.

 

  만약에 장소의 개수가 5개라고 할 때, 차례대로 장소를 방문한다고 하면 i번째 장소를 방문하고자 할 때 인덱스는 어떻게 될까요?



  위와 같이 장소가 5개 있다고 해봅시다. 이 때 3번째 장소는 다음과 같이 인덱스 2에 해당합니다.



  그렇다면 9번째 장소는 어떻게 될까요? 다음과 같이 한 바퀴 돌아서 인덱스 3에 해당합니다.



  즉, i번째 장소의 인덱스를 구하려면 (i - 1) % N을 하면 됩니다. 이걸 왜 언급하는 걸까요? 그 이유는 이 문제는 슬라이딩 윈도우와 흡사한 알고리즘이 사용되기 때문입니다. 전체 배열의 크기가 N일 때 한 번 방문할 때 K개만큼 방문하면서 계속해서 원을 그리며 이동하면 됩니다.

 

  다만 방문 횟수가 동일한 경우에는 더 인기가 많은 장소부터 출력해야 하므로 슬라이딩 윈도우를 수행하며, 출력하기 전에 인덱스를 기준으로 장소의 이름에 대해 오름차순 정렬을 수행해주시면 됩니다.

 

  결과적으로 이미 V - 1번 방문을 했다고 가정하므로 V번 째 방문을 할 때는 (K * (V - 1)) % N + 1번째 장소부터 (K * (V - 1)) % N + K번째 장소까지 방문하여 출력하면 정답 처리를 받을 수 있습니다. (출력하기 직전에 인덱스를 기준으로 정렬을 해주시면 됩니다.)


#include <iostream>

#include <fstream>

#include <algorithm>

#include <vector>

 

using namespace std;

 

long long int n, k, v;

string a[50];

 

class Node {

  public:

    int rate;

    string name;

    Node(int rate, string name) {

      this->rate = rate;

      this->name = name;

    }

    bool operator <(Node other) {

      return this->rate < other.rate;

    }

};

 

int getIndex(int number) {

  return (number - 1) % n;

}

 

int main(void) {

  ifstream inFile("Tourist.txt");

  ofstream outFile("Tourist Answer.txt");

  int T;

  inFile >> T;

  for(int testCase = 1; testCase <= T; testCase++) {

    vector<Node> nodes;

    inFile >> n >> k >> v;

    for(int i = 0; i < n; i++) {

      inFile >> a[i];

    }

    for(int i = (k * (v - 1) % n + 1); i <= (k * (v - 1) % n + k); i++) {

      int index = getIndex(i);

      nodes.push_back(Node(index, a[index]));

    }

    sort(nodes.begin(), nodes.end());

    outFile << "Case #" << testCase << ": ";

    for(int i = 0; i < nodes.size(); i++) {

      outFile << nodes[i].name << ' ';

    }

    outFile << '\n';

  }

  return 0;

}


2. Interception

 

문제 설명

(페이스북 해커컵의 문제는 영어로 제공됩니다. 제가 임의로 번역한 겁니다.)

 

-

- 위와 같은 형태로 표현되는 다항식이 있습니다.

- 이러한 다항식을 실제로 계산할 때는 연산자 우선순위가 덧셈(+), 곱셈(*), 지수 승(^) 순서입니다.

- 예를 들어 는 로 계산됩니다.

- 음수(-) 부호는 우선순위가 제일 높습니다.

- 0^01입니다.

- T번의 다항식(Polynomial)이 주어집니다.

- 다항식마다 최고 차수 N이 주어지고, 그 이후에 차수 N부터 0까지 차례대로 계수가 주어집니다.

- 계산하기 위한 다항식을 f(x)라고 했을 때 f(x) = 0이 되는 X의 개수를 출력하고, 각 라인에서는 각 X의 값을 오름차순으로 출력합니다.


예제 입력

2

1

1

1

4

9

0

-6

2

-2

 

예제 출력

Case #1: 1

0.0

Case #2: 0

 

부가 설명

주어진 예제 입력을 설명해드리자면 다음과 같습니다.

 

2: 테스트 케이스가 2

1: 첫 번째 테스트 케이스는 최고 차수가 1

1: 차수 1의 계수

1: 차수 0의 계수

4: 두 번째 테스트 케이스는 최고 차수가 4

9: 차수 4의 계수

0: 차수 3의 계수

-6: 차수 2의 계수

2: 차수 1의 계수

-2: 차수 0의 계수

 

첫 번째 테스트 케이스에서 들어온 입력은 다음과 같은 식입니다.



이제 이걸 f(x)로 표현하면 다음과 같습니다.



  그러므로 X0일 때 f(x)0이 될 수 있는 것입니다.


문제 풀이

  일단 문제에서 요구하는 연산자의 우선순위를 따랐을 때 모든 다항식은 지수함수으로 표현된다는 것을 이해하셔야 합니다. 왜냐하면 지수 연산(^)의 우선순위가 제일 낮기 때문입니다. 어떠한 입력이 들어와도 결과적으로 f(x)는 지수함수 형태에요. 이 때 일반적인 지수함수는 절대로 f(x) = 0이 될 수 없다는 것을 생각해보세요. 지수함수는 다음과 같이 생겼습니다.



다만, 문제의 형태를 보면 항상 최종적으로는 X와 어떠한 식을 곱하도록 되어있습니다. 예를 들어 다음의 식을 고려해보세요 이 식은 다음과 같이 바뀝니다.



  즉 어떠한 다항식이 들어왔을 때 무조건 (어떠한 숫자 * X)의 지수 승 형태로 표현되는 것을 알 수 있습니다. 이게 힌트인데요. 일반적인 지수함수는 어떤 일이 있어도 그 결과 f(x) = 0이 될 수 없기 때문에 (어떠한 숫자 * X)를 이용하셔야 합니다. X = 0인 경우에는 f(x) = 0이 될 가능성이 존재하기 때문입니다. 다시 말해서 어떠한 입력 값이 들어오더라도 근이 한 개 존재하는 경우(X = 0), 근이 아예 존재하지 않는 경우 두 가지 경우 밖에 존재하지 않는다는 것입니다.

 

  이 때 실제로 특정한 f(x)에 대해 X = 0을 넣는 방식으로 답을 계산할 수도 있을 것입니다. 다만 저는 조금 더 문제를 분석해보았어요. 그랬더니 재미있는 규칙을 찾았습니다. 바로 항의 개수가 홀수일 때는 근이 없고, 항의 개수가 짝수일 때는 근이 있다는 겁니다. 종이로 그려보니까 다음과 같았어요.



  따라서 테스트 케이스마다 N을 입력 받아서 N이 홀수일 때와 짝수일 때를 구분해서 정답을 출력하면 문제를 쉽게 해결할 수 있습니다.


#include <iostream>

#include <fstream>

 

using namespace std;

 

int main(void) {

  ifstream inFile("Interception.txt");

  ofstream outFile("Interception Answer.txt");

  int T;

  inFile >> T;

  for(int testCase = 1; testCase <= T; testCase++) {

    int n;

    inFile >> n;

    for(int i = 0; i <= n; i++) {

      int x;

      inFile >> x;

    }

    outFile << "Case #" << testCase << ": ";

    if(n % 2 == 1) {

      outFile << 1 << '\n';

      outFile << "0.0" << '\n';

    else {

      outFile << 0 << '\n';

    }

  }

  return 0;

}


3. Ethan Searches for a String

 

문제 설명

(페이스북 해커컵의 문제는 영어로 제공됩니다. 제가 임의로 번역한 겁니다.)

 

- 문자열 매칭 알고리즘이란 문자열 A가 문자열 B 안에 포함이 되어있는지를 판단하는 알고리즘입니다.

- 다음의 Ethan이 작성한 문자열 매칭 알고리즘이 있습니다. 이 알고리즘은 잘못된 알고리즘입니다.

 

(1) ij1로 설정합니다.

(2) i > |A|일 때, TRUE를 반환합니다.

(3) j > |B|일 때, FALSE를 반환합니다.

(4) Ai = Bj일 때, ij1 증가시키고 (2) 단계로 이동합니다.

(5) i = 1일 때, j1 증가시키고 (2) 단계로 이동합니다.

(6) i1로 설정하고 (2) 단계로 이동합니다.

 

- A라는 문자열이 주어졌을 때, 우리는 문자열 AB라는 문자열 안에 포함이 되는데도 불구하고 Ethan의 알고리즘이 FALSE를 뱉는 문자열 B’를 찾아내고자 합니다.

- 문자열 B를 찾을 수 없을 때는 'Impossible'을 출력합니다.

- 테스트 케이스 T100개까지 주어질 수 있습니다.

- 1 <= A의 길이 <= 2,000

- 1 <= B의 길이 <= 10,000

 

예제 입력

4

ABACUS

FACEBOOK

XYZXZYX

FBFBF

 

예제 출력

Case #1: ASUCABABACUSA

Case #2: Impossible

Case #3: XZYXYZXYZXZYXYZXYZYX

Case #4: Impossible

 

문제 풀이

 

  먼저 문제를 접하기 전에 KMP 알고리즘에 대한 제 강의 노트를 한 번 보시고 오시기 바랍니다.

 

  KMP 알고리즘: https://blog.naver.com/ndb796/221240660061

 

  일단 Ethan의 알고리즘을 직접 C++ 소스코드로 구현해보겠습니다.

 

#include <iostream>

 

using namespace std;

 

bool contains(string a, string b) {

  int i = 1, j = 1;

  while(1) {

    if(i > a.length()) return true;

    if(j > b.length()) return false;

    if(a[i - 1] == b[j - 1]) {

      i++;

      j++;

      continue;

    }

    if(i == 1) {

      j++;

      continue;

    }

    i = 1;

  }

}

 

int main(void) {

  string a = "ABACUS";

  string b = "ASUCABABACUSA";

  cout << contains(a, b) << '\n';

  int result = b.find(a);

  cout << result;

  return 0;

}


  위 소스코드를 보시면 “ABACUS”는 분명히 “ASUCABABACUSA”에 포함이 되는데도 불구하고 Ethan의 알고리즘은 FALSE(0)라는 값을 반환하는 것을 알 수 있습니다. find() 함수는 C++에서 기본적으로 제공하는 문자열 매칭 함수입니다. find() 함수는 "ABACUS"가 포함되는 시작 인덱스인 6이라는 값을 내뱉는 것을 알 수 있습니다. 그렇다면 이 문제를 풀기 위해서는 어떻게 해야 할까요? Ethan의 알고리즘을 직접 손으로 차근차근 해보면 쉽게 이해하실 수 있습니다. 문자열이 일치하는지 하나씩 검사하는 알고리즘인데요, 접미사와 동일한 접두사가 존재하는 경우를 캐치하지 못한답니다.

 

  따라서 하나씩 검사하다가 불일치 할 때 위치에서의 접미사와 동일한 접두사가 존재하는지 확인해야합니다. Ethan의 소스코드는 그러한 경우를 캐치하지 못하고 넘어가는 불완전한 소스코드니까요.

 

  예를 들어 FBFBFKEthan의 소스코드의 결함을 보여주는 예시입니다. FBFBFBFK와 비교했을 때 하나씩 검사하다가 FBFBFKFBFBFBFK가 불일치가 발생합니다. 이 때 접미사와 접두사는 FBFB로 동일하게 구성됩니다.

 

A: FBFBFK

B: FBFBFBFK

 

  이러한 경우 실제로는 문자열이 포함됨에도 불구하고 Ethan의 함수는 이를 감지할 수 없습니다. 따라서 Ethan 함수의 결함을 지적하기 위해서는 하나씩 검사하다가 불일치 할 때 위치에서의 접미사와 동일한 접두사가 존재하는 문자열 B를 만들면 됩니다.

 

  다만 불일치하기 직전까지는 일단 AB가 일치했다는 것을 이해하셔야 합니다.

 

A: FBFBFK

B: FBFBFBFK

 

  위 경우를 보시면 일단 FBFBF까지는 일치했습니다. 그 이후에 KB가 서로 다른 겁니다. 따라서 불일치 할 때 위치에서의 접두사와 접미사가 일치하려면, 불일치하기 직전까지 검사했던 일련의 문자열들도 당연히 접두사와 같아야 합니다. 예를 들어 FBFF 두 개가 존재할 겁니다.

 

  다시 말해서 하나씩 검사하다가 불일치 할 때 위치에서의 접미사와 동일한 접두사가 존재하는 문자열 B’를 만들기 위해서는 문자열 A에서 이미 접두사와 접미사가 일치하는 문자열 쌍이 존재해야만 합니다. 예를 들어 FACEBOOK은 접두사와 접미사가 일치하는 문자열 쌍이 하나도 존재하지 않습니다. 그렇기 때문에 Ethan의 함수에서의 결함을 찾을 수 없는 예시가 되는 겁니다.

 

  이제 문자열 ‘FBFBF’를 고려해봅시다. 이것도 Ethan의 함수의 결함을 찾을 수 없습니다.

 

A: FBFBF

B: FBFB?

 

  위 경우를 보시면 물음표 위치에 F를 넣는다고 하면 문자열 일치가 발생해버리고, K와 같이 다른 문자를 넣는다고 하면 불일치 할 때 위치에서의 접미사와 동일한 접두사가 존재할 수 없습니다. 모순이 발생하는 거죠. 분명히 접두사와 접미사가 일치하는 경우는 'F', 'FB', 'FBF' 세 개가 존재함에도 불구하고 이러한 문제가 발생했습니다. 여기에서 하나의 사실을 유추할 수 있습니다. 바로 접두사와 접미사가 일치하는 연속된 경우의 뒤에 하나 이상의 여분 문자가 필요하다는 것입니다.

 

  예를 들어 FBFBK'F', 'FB'라는 두 개의 접미사와 동일한 접두사가 존재할 수 있습니다. 이제 'F'‘FB'는 연속되어 있으므로 ’FB'만 고려하겠습니다. 이 때 잘 살펴보시면 'FB'의 뒤에 K라는 하나 이상의 여분 문자가 존재합니다. 그래서 이 KF로 바꾸어주고, 뒤에 BK를 붙여줌으로써 다음과 같은 문자열을 만들 수 있어요.

 

B: FBFBFBK


  이렇게 만들게 되면 Ethan의 함수에 존재하는 결함을 밝힐 수 있게 되는 것입니다. 따라서 문제를 해결하기 위한 방법은 다음과 같습니다.

 

< Ethan의 함수에 존재하는 결함을 밝히는 방법 >

 

1. 접두사 및 접미사 쌍 테이블을 만들기

2. 접두사와 접미사가 일치하는 연속된 경우의 뒤에 하나 이상의 여분 문자가 존재하는지 확인하기

 

  예를 들어 ‘XYZXZYX’의 접두사 및 접미사 쌍 테이블은 다음과 같습니다.



  보면 ‘XYZXZYX’는 인덱스 3의 값이 1이라서 접두사와 접미사가 일치하는 부분 문자열이 존재하는 겁니다. 이 때 인덱스 4가 여분 문자로 존재합니다. 따라서 다음과 같은 문자열을 만들 수 있어요.

 

XYZXYZXZYX

 

  다시 말해 XYZX에서 그 뒤로 YZXZYX를 넣어준 겁니다. 이것은 접두사와 접미사가 일치할 수 있는 부분이 인덱스 3‘X’이므로 그 뒤로 접미사를 제외한 YZXZYX를 넣어준 것이라고 할 수 있습니다. 이런식으로 만들게 되면 ‘XYZXYZXZYX' 안에 'XYZXZYX’가 포함되어 있음에도 불구하고 Ethan의 함수는 이를 찾아내지 못합니다. 이제 이 내용을 소스코드로 옮기면 됩니다.


#include <iostream>

#include <fstream>

#include <vector>

 

using namespace std;

 

vector<int> makeTable(string pattern) {

  int patternSize = pattern.size();

  vector<int> table(patternSize, 0);

  int j = 0;

  for(int i = 1; i < patternSize; i++) {

    while(j > 0 && pattern[i] != pattern[j]) {

      j = table[j - 1];

    }

    if(pattern[i] == pattern[j]) {

      table[i] = ++j;

    }

  }

  return table;

}

 

int main(void) {

  ifstream inFile("Ethan.txt");

  ofstream outFile("Ethan Answer.txt");

  int T;

  inFile >> T;

  for(int testCase = 1; testCase <= T; testCase++) {

    outFile << "Case #" << testCase << ": ";

    string pattern;

    inFile >> pattern;

    vector<int> table = makeTable(pattern);

    bool find = false;

    for(int i = 1; i < table.size(); i++) {

      // 접두사와 접미사가 일치하는 '연속된 경우'의 뒤에 '하나 이상의 여분 문자가 존재'하는지 확인

      if(table[i] <= table[i - 1] && table[i - 1] != 0) {

        // 찾았을 경우 문자열 생성

        find = true;

        // 앞 부분 출력

        for(int j = 0; j < i; j++) {

          outFile << pattern[j];

        }

        // 뒷 부분 출력

        for(int j = table[i - 1]; j < pattern.size(); j++) {

          outFile << pattern[j];

        }

        outFile << '\n';

        break;

      }

    }

    if(!find) {

      outFile << "Impossible\n";

    }

  }

  return 0;

}

728x90
반응형

728x90
반응형

사 혹은 미래교사의 인터넷 교육(방송) 수익 창출에 대해서

나동빈


  저는 최근에 유튜브(YouTube) 활동을 하면서 공무원이 유튜브 활동으로 광고 수익을 얻는다면 어떠한 문제가 있을 지에 대해서 고민해보았습니다. 기본적으로 교사와 같은 공무원은 겸업 금지 항목에 의해서 자신의 본업을 제외하고 추가적인 직업을 가질 수 없습니다. 특히나 개인사업자를 내고 다른 사업을 하는 경우에는 더욱 그러한 제약이 심합니다.


  Q. 그렇다면 현직 교사가 유튜브와 같은 플랫폼에서 개인 방송으로 수익을 창출하는 건 괜찮나요?


  ▶ 이와 관련해서는 현재 국립 교사로 활동하고 계신 제 지인 분들께 여쭈어보니, 가장 중요한 건 학교장의 승인이라고 하더군요. 교육지원청에 전화를 해서 물어보았을 때도 겸업 관련 권한은 담당 학교장이 크게 관여하는 것이라고 말씀해주셨습니다. 구체적으로 하려는 활동이 공무원의 본질을 흐트리지 않으면서 정당하게 수익을 창출할 수 있다는 것을 증명해야 하는 것 같아요. 또한 아직까지 유튜브와 같은 플랫폼에 대한 사례가 많지 않은 것 같아요. 대부분 잘 모르시는 것 같구요.


  조금 다른 이야기이지만 회사로 나가는 외부 강의(현장 강의)의 경우에는 강의 수당으로 학교장의 승인이 있으면 된다고 합니다. 사실 그래서 가장 중요한 거는 학교장에게 보고하고, 승인을 받는 과정이 중요한 것 같아요. 물론 이런 강의 활동이 아니라 뻔하게 다른 사업(음식점, PC방 등)을 한다거나 하는 것들은 당연히 안 되는 거구요.


  Q. 아직 교사가 되기 전에 찍어 놓은 동영상이 교사가 된 이후에 부가적인 수입을 내는 경우는 어떤가요?


  ▶ 만약에 임용고시를 준비하는 대학생이 본인의 재량껏 다양한 유료 인터넷 교육을 진행해보았다고 해봅시다. 본인의 이름으로 개인 사업자를 내고 활동할 수도 있겠지요. 당연히 교사가 되기 전이니까 어떠한 제약조건도 없을 겁니다. 그런데, 대학생 때 찍은 유료 강의들이 교사가 된 이후에도 수익을 창출한다면? 이것도 겸업으로 판단되어 제재를 받을 수 있을지 궁금합니다.


  이와 관련해서는 모 지역의 교육지원청에 제가 직접 전화를 해보았어요. 그 답변으로는 교사가 되기 전에 기존에 찍었던 인터넷 강의는 '지속적이고 일정한 수익 창출'도 아니며 교사로 일하기 전에 일을 한 것이기 때문에 교사가 된 이후에 계속해서 인터넷 강의를 찍는게 아니라면, 애초에 과거의 일이므로 문제가 없다고 합니다.


  그래서 교사로 붙은 뒤에는 혹시 사업자 등록을 한 상태라면 인터넷 강사로 활동하던 관련 사업자를 폐지하고, 그 때부터는 계약 내용을 바꾸어서 6.6%로 기타소득으로 세금을 떼고 받는 식으로 진행하면 큰 어려우이 없는 것 같습니다. 물론 이는 교사가 되기 전에 찍은 강의라서 가능한 거고, 교사가 된 이후에는 새로 전문 사기업에서 인터넷 강의를 찍는 것은 쉽지 않은 것 같습니다.

728x90
반응형

728x90
반응형

  이번 시간에는 사용하지 않는 큰 용량의 파일을 찾아 지우는 방법에 대해 소개하고자 합니다. 간혹 가다가 어떠한 작업을 하기 위해서 다양한 프로그램 설치 파일 등을 받아 놓고, 설치 이후에 까먹고 설치 프로그램을 지우지 않으신 적이 있으실 겁니다. 저 또한 프로그램을 설치한 뒤에는 설치 프로그램을 지워야 되는데 맨날 잊고 지우지 않곤 합니다.


  그럴 때는 트리 사이즈라는 무료 소프트웨어가 굉장히 유용하더라구요.


  ▶ 트리 사이즈(Tree Size) 공식 사이트: https://www.jam-software.com/treesize_free/



  사이트에 접속하시면 위와 같이 '다운로드(Download)' 버튼이 존재합니다.


 


  이후에 윈도우 전용 설치 프로그램을 받아주겠습니다. 기본 옵션이 이렇게 되어있더라구요.



  이후에 약관에 동의해주시고 설치를 진행하시면 됩니다.



  설치가 완료되면 '관리자 권한으로 실행(Launch TreeSize Free now as Administrator)' 해주세요.



  설치 이후에 실행해보시면 우리의 디스크 드라이브에 존재하는 모든 폴더 및 파일들이 트리(Tree) 구조로 나타납니다.



  이후에 특정한 파일이나 폴더를 선택해 속성을 확인할 수 있습니다.



  저는 바탕화면(Desktop)을 확인해봤는데, 바탕화면에만 114 기가 바이트(GB)의 파일들이 존재하는 것을 확인할 수 있었습니다.

728x90
반응형

728x90
반응형

※ 해킹 방어 대회란? ※


  해킹 방어 대회해킹(Hacking) 실력을 겨루는 대회를 의미합니다. 코드게이트, 데프콘, 시큐인사이드 CTF, 삼성전자 CTF 등 다양한 해킹 방어 대회가 존재하며 다양한 기업 및 기관에서 운영하고 있습니다. 일반적인 해킹 방어 대회 진행 방식은 CTF(Capture The Flag)입니다. 말 그대로 플래그(Flag) 값을 찾으라는 의미를 가지며 대회에 참가할 때는 일반적으로 팀(Team)을 구성하여 참가하는 방식이지만 삼성전자 CTF와 같이 개인전 중심의 CTF도 존재합니다.


  해킹 방어 대회는 기본적으로 특정 시스템에서 존재할 수 있는 취약점을 익스플로잇(Exploit)하거나, 이를 방어(Patch)하거나, 특정 시스템을 직접 타격하지 않고 우회적으로 피해를 입히는 방법에 대해서 물어봅니다. 그렇기 때문에 CTF 대회에서의 다양한 문제들은 특정한 상황이나 시스템에 국한될 수 있습니다. 예를 들어 문제로 PHP 소스코드를 분석해야 하거나, 난데없이 F# 소스코드나 RFID 관련 덤프 데이터가 등장할 수도 있고 솔리디티(Solidity) 등의 블록체인 관련 문제가 출제될 수도 있습니다.


  일반적으로 개발을 공부할 때는 A라는 언어가 별로라고 느껴지면 B라는 언어를 선택해서 개발을 진행할 수도 있고, 시스템 환경도 자신이 원하는 대로 구성할 수 있지만 CTF는 반대로 '한정된' 시스템에 통하는 취약점에 대한 문제를 자주 다룰 수 있기 때문에 CTF에 참여한다는 것은 어찌보면 새로운 시스템 환경에 대한 공부라고 이해할 수 있습니다.


  어떠한 CTF에 출전하든지 간에 매 번 새로운 내용을 공부하게 되고, 그것이 CTF의 매력이 아닐까 생각합니다. :)


  또한 CTF는 알고리즘 분야보다 더 진입장벽이 높은 대회 유형입니다. 처음 공부를 시작해서 어떤 해킹 방어 대회에 '본선'이라도 나가는 것은 매우 어렵습니다. 특히 대부분의 CTF 대회는 내/외국인의 구분이 없으며 나이 제한도 없기 때문에 기존의 고수 분들과 경쟁을 해야 합니다. 반면에 알고리즘 대회는 대학(원)생 한정 대회가 많아서 그나마 진입장벽이 낮습니다.


[ 해킹 방어 대회 종류 ]


  해킹 방어 대회로 가장 유명한 몇 가지만 소개하고자 합니다. 일반적으로 해킹 방어 대회는 보안 컨퍼런스(Conference)와 함께 진행되는 경우가 많습니다. 공부하는 학생으로서 매 대회마다 정말 많은 것을 배울 수 있습니다.


- 코드게이트(Codegate): 과학기술정보통신부 주관하는 해킹 방어 대회입니다.


- HdCon: 일명 흐드콘이라고 불리는 해킹 방어 대회로 KISA에서 주관하는 대회입니다.


- SECUINSIDE: 고려대학교 정보보호대학원 주관의 해킹 방어 대회입니다.


- WITHCON: 화이트햇 콘테스트라고 불리는 대회로 국방부가 주관하는 해킹 방어 대회입니다.


- DEFCON: 데프콘이라고 불리우는 대표적인 해킹 방어 국제 대회입니다. 라스 베거스에서 진행되며 세계 규모 중에서 가장 유명한 해킹 방어 대회 중 하나입니다.


- SCTF: 삼성전자가 주관하는 해킹 방어 대회로 거의 유일하게 개인전으로 운영되고 있습니다. 또한 단순 공격 위주의 문제가 아니라 방어 및 코딩(Coding)을 활용한 문제가 출제됩니다.


※ 해킹 방어 대회를 준비하는 방법 ※


  해킹 방어 대회 준비를 위해서는 기초적인 프로그래밍 능력을 갖추시는 것이 중요합니다. C, Java, Python 및 웹(Web)에 대한 공부를 하시는 것이 좋습니다. 특히 간단히 게시판 정도는 만들 정도까지 웹에 대해 공부하시고, C에 대해 공부하실 때에도 단순히 프로그래밍만 공부하시지 말고 보안과 관련한 내용을 편식하지 말고 먹는 것이 좋습니다.


  기본적인 프로그래밍 능력이 갖추어지셨다면 다양한 워게임(Wargame) 사이트에서 CTF 문제를 풀어보시는 것이 좋습니다. 프로그래밍 공부를 하다가 지겨울 때는 잠깐 CTF 문제를 풀러 왔다가 다시 프로그래밍 공부를 하러 가는 방식으로 서로 균형적으로 공부해나가시는 것도 좋은 방법입니다. 무엇보다 꾸준히 문제를 풀어보는게 정말 좋은 습관인 것 같습니다.


[ 다양한 문제풀이 사이트 ]


1. wechall.net: 세계적으로 다양한 해킹 실습환경을 모두 모아둔 웹 사이트입니다.


2. webhacking.kr: PHP 기반의 웹 해킹에 대한 내용을 중심으로 다루고 있는 웹 사이트입니다. 기초적인 웹 해킹 기술부터 네트워크 관련 지식까지 문제를 풀면서 얻을 수 있습니다.


3. pwnable.kr: 시스템 해킹(System Hacking)에 관한 내용을 중점적으로 다루는 웹 사이트입니다. 실제 최근 CTF에서 출제되는 문제들과 흡사한 부분이 많으며 문제의 퀄리티가 높다는 특징이 있습니다.


4. suninatas.com: 웹 해킹, 시스템 해킹 등 다양한 분야를 다루면서도 난이도를 쉽게 구성하여 초보자가 입문하기에 적합한 해킹 공부 사이트입니다.


5. pythonchallenge.com: 해킹 문제는 파이썬(Python)으로 풀게 되는 경우가 많아 파이썬 문법을 빠르게 익히기에 좋고, 문제를 풀어가며 재미있게 공부할 수 있는 웹 사이트입니다.


※ 기타 대외 활동 ※


1. 차세대 보안리더 양성 프로그램(Best of the Best): 과학기술정보통신부 주관으로 정부에서 주관하는 보안 인력 양성 프로젝트입니다. 매 년 100명 가량의 연수생을 뽑아서 교육시키며 150만 원 가량의 노트북을 지원해주고 매 달 수십만 원의 학습 지원금도 주는 좋은 교육 프로그램입니다. 저도 2017년에 BoB에서 많은 것을 배웠습니다.


2. 해킹 팀(Hacking Team) 구성하기: 본격적으로 해킹에 대해 공부하고 싶으시다면 기초적인 프로그래밍 언어 공부를 먼저 해보시고, 다양한 CTF 문제를 풀어보면서 실력을 키워나가신 뒤에 해킹 팀에 구성원으로 들어가거나 친구끼리 스터디를 구성하는 것을 추천합니다. 컴퓨터는 분야를 막론하고 선의의 경쟁자가 많을수록 실력 향상에 도움이 됩니다.

728x90
반응형