์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿ” ํฌํŠธ ์Šค์บ๋„ˆ์™€ ๋„คํŠธ์›Œํฌ ๋ณด์•ˆ ์ ๊ฒ€ ์†Œ์Šค์ฝ”๋“œ

๐Ÿ” ํฌํŠธ ์Šค์บ๋„ˆ์™€ ๋„คํŠธ์›Œํฌ ๋ณด์•ˆ ์ ๊ฒ€ ์†Œ์Šค์ฝ”๋“œ

๋„คํŠธ์›Œํฌ ๋ณด์•ˆ์˜ ์ฒซ๊ฑธ์Œ, ํฌํŠธ ์Šค์บ๋‹๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด๋ณด์ž! ๐Ÿš€

Server Port Scanner Network Scan Request Response

์•ˆ๋…•! ์˜ค๋Š˜์€ ๋„คํŠธ์›Œํฌ ๋ณด์•ˆ์˜ ๊ธฐ์ดˆ ์ค‘์˜ ๊ธฐ์ดˆ, ํฌํŠธ ์Šค์บ๋„ˆ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•ด๋ณผ๊นŒ ํ•ด. ๐ŸŽฏ ํ˜น์‹œ ๋„ˆ์˜ ์ปดํ“จํ„ฐ๋‚˜ ์„œ๋ฒ„์— ์–ด๋–ค ํฌํŠธ๊ฐ€ ์—ด๋ ค์žˆ๋Š”์ง€ ๊ถ๊ธˆํ–ˆ๋˜ ์  ์žˆ์–ด? ์•„๋‹ˆ๋ฉด ํ•ด์ปค๋“ค์ด ์–ด๋–ป๊ฒŒ ์‹œ์Šคํ…œ์˜ ์ทจ์•ฝ์ ์„ ์ฐพ์•„๋‚ด๋Š”์ง€ ๊ถ๊ธˆํ–ˆ๋˜ ์ ์€? ๋ฐ”๋กœ ํฌํŠธ ์Šค์บ๋‹์ด ๊ทธ ์‹œ์ž‘์ ์ด์•ผ!

ํฌํŠธ ์Šค์บ๋„ˆ๋Š” ๋‹จ์ˆœํžˆ ํ•ดํ‚น ๋„๊ตฌ๊ฐ€ ์•„๋‹ˆ๋ผ, ์‹œ์Šคํ…œ ๊ด€๋ฆฌ์ž์™€ ๋ณด์•ˆ ์ „๋ฌธ๊ฐ€๋“ค์ด ์ž์‹ ์˜ ๋„คํŠธ์›Œํฌ๋ฅผ ์ ๊ฒ€ํ•˜๊ณ  ๋ณดํ˜ธํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ํ•„์ˆ˜ ๋„๊ตฌ์•ผ. ๋งˆ์น˜ ์ง‘์˜ ๋ชจ๋“  ๋ฌธ๊ณผ ์ฐฝ๋ฌธ์„ ์ ๊ฒ€ํ•ด์„œ ์ œ๋Œ€๋กœ ์ž ๊ฒจ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ง€! ๐Ÿ ๐Ÿ”

์ด ๊ธ€์—์„œ๋Š” ํฌํŠธ ์Šค์บ๋„ˆ์˜ ์›๋ฆฌ๋ถ€ํ„ฐ ์‹ค์ œ ๊ตฌํ˜„ ์†Œ์Šค์ฝ”๋“œ, ๊ทธ๋ฆฌ๊ณ  ๋„คํŠธ์›Œํฌ ๋ณด์•ˆ ์ ๊ฒ€ ๋ฐฉ๋ฒ•๊นŒ์ง€ ์นœ๊ตฌ์—๊ฒŒ ์„ค๋ช…ํ•˜๋“ฏ ์‰ฝ๊ณ  ์žฌ๋ฏธ์žˆ๊ฒŒ ์•Œ๋ ค์ค„๊ฒŒ. ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ๊ด€์‹ฌ ์žˆ๋‹ค๋ฉด ์žฌ๋Šฅ๋„ท์—์„œ ๊ด€๋ จ ์ „๋ฌธ๊ฐ€๋“ค๊ณผ ์ง€์‹์„ ๋‚˜๋ˆ„๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋‹ˆ ์ฐธ๊ณ ํ•ด๋ด!

๐ŸŽฏ ํฌํŠธ ์Šค์บ๋‹์ด๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

ํฌํŠธ ์Šค์บ๋‹(Port Scanning)์€ ๋„คํŠธ์›Œํฌ ์ƒ์˜ ํ˜ธ์ŠคํŠธ์—์„œ ์–ด๋–ค ํฌํŠธ๊ฐ€ ์—ด๋ ค์žˆ๊ณ  ์–ด๋–ค ์„œ๋น„์Šค๊ฐ€ ์‹คํ–‰ ์ค‘์ธ์ง€ ํ™•์ธํ•˜๋Š” ๊ธฐ์ˆ ์ด์•ผ. ์ปดํ“จํ„ฐ๋Š” 0๋ฒˆ๋ถ€ํ„ฐ 65535๋ฒˆ๊นŒ์ง€ ์ด 65,536๊ฐœ์˜ ํฌํŠธ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด. ์ด ์ค‘์—์„œ ํŠน์ • ํฌํŠธ๋“ค์€ ํŠน์ • ์„œ๋น„์Šค๋ฅผ ์œ„ํ•ด ์˜ˆ์•ฝ๋˜์–ด ์žˆ์ง€.

๐Ÿ”ข ์ฃผ์š” ํฌํŠธ ๋ฒˆํ˜ธ์™€ ์„œ๋น„์Šค

โ€ข ํฌํŠธ 20/21: FTP (ํŒŒ์ผ ์ „์†ก ํ”„๋กœํ† ์ฝœ)
โ€ข ํฌํŠธ 22: SSH (๋ณด์•ˆ ์…ธ)
โ€ข ํฌํŠธ 23: Telnet
โ€ข ํฌํŠธ 25: SMTP (์ด๋ฉ”์ผ ์ „์†ก)
โ€ข ํฌํŠธ 53: DNS (๋„๋ฉ”์ธ ๋„ค์ž„ ์‹œ์Šคํ…œ)
โ€ข ํฌํŠธ 80: HTTP (์›น ์„œ๋น„์Šค)
โ€ข ํฌํŠธ 443: HTTPS (๋ณด์•ˆ ์›น ์„œ๋น„์Šค)
โ€ข ํฌํŠธ 3306: MySQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค
โ€ข ํฌํŠธ 3389: RDP (์›๊ฒฉ ๋ฐ์Šคํฌํ†ฑ)
โ€ข ํฌํŠธ 8080: ๋Œ€์ฒด HTTP ํฌํŠธ

ํฌํŠธ ์Šค์บ๋‹์˜ ๋ชฉ์ ์€ ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€์•ผ. ์ฒซ์งธ๋Š” ์ •๋‹นํ•œ ๋ณด์•ˆ ์ ๊ฒ€์ด๊ณ , ๋‘˜์งธ๋Š” ๊ณต๊ฒฉ ์ „ ์ •์ฐฐ์ด์ง€. ์šฐ๋ฆฌ๋Š” ๋‹น์—ฐํžˆ ์ฒซ ๋ฒˆ์งธ ๋ชฉ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ๊ฑฐ์•ผ! ๐Ÿ˜Š

๐Ÿ› ๏ธ ํฌํŠธ ์Šค์บ๋‹์˜ ์ฃผ์š” ๊ธฐ๋ฒ•๋“ค

ํฌํŠธ ์Šค์บ๋‹์—๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๊ธฐ๋ฒ•์ด ์žˆ์–ด. ๊ฐ๊ฐ์˜ ๊ธฐ๋ฒ•์€ ์žฅ๋‹จ์ ์ด ์žˆ๊ณ , ์ƒํ™ฉ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ๋ฐฉ๋ฒ•์„ ์„ ํƒํ•ด์•ผ ํ•ด. ์ฃผ์š” ๊ธฐ๋ฒ•๋“ค์„ ์‚ดํŽด๋ณด์ž! ๐Ÿ”

1๏ธโƒฃ TCP Connect ์Šค์บ”

๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ด๊ณ  ์ •ํ™•ํ•œ ๋ฐฉ๋ฒ•์ด์•ผ. TCP 3-way handshake๋ฅผ ์™„์ „ํžˆ ์ˆ˜ํ–‰ํ•ด์„œ ํฌํŠธ๊ฐ€ ์—ด๋ ค์žˆ๋Š”์ง€ ํ™•์ธํ•ด. SYN โ†’ SYN-ACK โ†’ ACK ๊ณผ์ •์„ ๊ฑฐ์น˜์ง€. ์ •ํ™•ํ•˜์ง€๋งŒ ๋กœ๊ทธ์— ๋‚จ๊ธฐ ๋•Œ๋ฌธ์— ์‰ฝ๊ฒŒ ํƒ์ง€๋  ์ˆ˜ ์žˆ์–ด.

2๏ธโƒฃ SYN ์Šค์บ” (Half-Open ์Šค์บ”)

"์Šคํ…”์Šค ์Šค์บ”"์ด๋ผ๊ณ ๋„ ๋ถˆ๋Ÿฌ. SYN ํŒจํ‚ท๋งŒ ๋ณด๋‚ด๊ณ  SYN-ACK๋ฅผ ๋ฐ›์œผ๋ฉด ๋ฐ”๋กœ RST๋ฅผ ๋ณด๋‚ด์„œ ์—ฐ๊ฒฐ์„ ๋Š์–ด๋ฒ„๋ ค. 3-way handshake๋ฅผ ์™„์„ฑํ•˜์ง€ ์•Š์•„์„œ ๋กœ๊ทธ์— ๋œ ๋‚จ์ง€๋งŒ, root ๊ถŒํ•œ์ด ํ•„์š”ํ•ด.

3๏ธโƒฃ UDP ์Šค์บ”

UDP๋Š” ์—ฐ๊ฒฐ ์ง€ํ–ฅ ํ”„๋กœํ† ์ฝœ์ด ์•„๋‹ˆ๋ผ์„œ ์Šค์บ”์ด ๋” ๊นŒ๋‹ค๋กœ์›Œ. UDP ํŒจํ‚ท์„ ๋ณด๋‚ด๊ณ  ICMP "port unreachable" ๋ฉ”์‹œ์ง€๊ฐ€ ์˜ค์ง€ ์•Š์œผ๋ฉด ํฌํŠธ๊ฐ€ ์—ด๋ ค์žˆ๋‹ค๊ณ  ํŒ๋‹จํ•ด. ๋А๋ฆฌ์ง€๋งŒ UDP ์„œ๋น„์Šค ํ™•์ธ์— ํ•„์ˆ˜์ ์ด์•ผ.

4๏ธโƒฃ FIN, NULL, Xmas ์Šค์บ”

๋น„์ •์ƒ์ ์ธ ํ”Œ๋ž˜๊ทธ ์กฐํ•ฉ์„ ์‚ฌ์šฉํ•ด์„œ ๋ฐฉํ™”๋ฒฝ์„ ์šฐํšŒํ•˜๋ ค๋Š” ๊ธฐ๋ฒ•๋“ค์ด์•ผ. FIN ์Šค์บ”์€ FIN ํ”Œ๋ž˜๊ทธ๋งŒ, NULL ์Šค์บ”์€ ํ”Œ๋ž˜๊ทธ ์—†์ด, Xmas ์Šค์บ”์€ FIN, PSH, URG ํ”Œ๋ž˜๊ทธ๋ฅผ ๋ชจ๋‘ ์ผœ์„œ ๋ณด๋‚ด.

๐Ÿ’ก ์•Œ์•„๋‘๋ฉด ์ข‹์€ ํŒ!

์‹ค์ œ ๋ณด์•ˆ ์ ๊ฒ€์—์„œ๋Š” ์—ฌ๋Ÿฌ ์Šค์บ” ๊ธฐ๋ฒ•์„ ์กฐํ•ฉํ•ด์„œ ์‚ฌ์šฉํ•ด. ํ•˜๋‚˜์˜ ๋ฐฉ๋ฒ•๋งŒ์œผ๋กœ๋Š” ๋ฐฉํ™”๋ฒฝ์ด๋‚˜ IDS(์นจ์ž… ํƒ์ง€ ์‹œ์Šคํ…œ)์— ์˜ํ•ด ์ฐจ๋‹จ๋˜๊ฑฐ๋‚˜ ์ž˜๋ชป๋œ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๊ฑฐ๋“ !

๐Ÿ’ป Python์œผ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๊ธฐ๋ณธ ํฌํŠธ ์Šค์บ๋„ˆ

์ž, ์ด์ œ ์‹ค์ œ๋กœ ํฌํŠธ ์Šค์บ๋„ˆ๋ฅผ ๋งŒ๋“ค์–ด๋ณผ๊นŒ? Python์˜ socket ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ƒ๊ฐ๋ณด๋‹ค ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์–ด. ๋จผ์ € ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ TCP Connect ์Šค์บ”๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด๋ณด์ž! ๐Ÿ

๐Ÿ“ ๊ธฐ๋ณธ ๋‹จ์ผ ํฌํŠธ ์Šค์บ๋„ˆ

import socket
import sys

def scan_port(target_host, target_port):
    """
    ๋‹จ์ผ ํฌํŠธ๋ฅผ ์Šค์บ”ํ•˜๋Š” ํ•จ์ˆ˜
    
    Args:
        target_host: ์Šค์บ”ํ•  ํ˜ธ์ŠคํŠธ IP ๋˜๋Š” ๋„๋ฉ”์ธ
        target_port: ์Šค์บ”ํ•  ํฌํŠธ ๋ฒˆํ˜ธ
    
    Returns:
        ํฌํŠธ๊ฐ€ ์—ด๋ ค์žˆ์œผ๋ฉด True, ๋‹ซํ˜€์žˆ์œผ๋ฉด False
    """
    try:
        # ์†Œ์ผ“ ์ƒ์„ฑ (IPv4, TCP)
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        
        # ํƒ€์ž„์•„์›ƒ ์„ค์ • (1์ดˆ)
        sock.settimeout(1)
        
        # ์—ฐ๊ฒฐ ์‹œ๋„
        result = sock.connect_ex((target_host, target_port))
        
        # ์†Œ์ผ“ ๋‹ซ๊ธฐ
        sock.close()
        
        # result๊ฐ€ 0์ด๋ฉด ํฌํŠธ๊ฐ€ ์—ด๋ ค์žˆ์Œ
        if result == 0:
            return True
        else:
            return False
            
    except socket.gaierror:
        print(f"ํ˜ธ์ŠคํŠธ ์ด๋ฆ„์„ ํ™•์ธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {target_host}")
        return False
    except socket.error:
        print(f"์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {target_host}")
        return False

# ์‚ฌ์šฉ ์˜ˆ์‹œ
if __name__ == "__main__":
    host = "127.0.0.1"  # ๋กœ์ปฌํ˜ธ์ŠคํŠธ
    port = 80
    
    print(f"[*] {host}์˜ ํฌํŠธ {port} ์Šค์บ” ์ค‘...")
    
    if scan_port(host, port):
        print(f"[+] ํฌํŠธ {port}์ด(๊ฐ€) ์—ด๋ ค์žˆ์Šต๋‹ˆ๋‹ค! โœ…")
    else:
        print(f"[-] ํฌํŠธ {port}์ด(๊ฐ€) ๋‹ซํ˜€์žˆ์Šต๋‹ˆ๋‹ค. โŒ")

์œ„ ์ฝ”๋“œ๋Š” ์ •๋ง ๊ธฐ๋ณธ์ ์ธ ํฌํŠธ ์Šค์บ๋„ˆ์•ผ. socket.connect_ex() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํŠน์ • ํฌํŠธ์— ์—ฐ๊ฒฐ์„ ์‹œ๋„ํ•˜๊ณ , ์„ฑ๊ณตํ•˜๋ฉด 0์„ ๋ฐ˜ํ™˜ํ•ด. ๊ฐ„๋‹จํ•˜์ง€? ๐Ÿ˜Š

๐Ÿš€ ๋‹ค์ค‘ ํฌํŠธ ์Šค์บ๋„ˆ (๋ฒ”์œ„ ์Šค์บ”)

์ด์ œ ์—ฌ๋Ÿฌ ํฌํŠธ๋ฅผ ํ•œ ๋ฒˆ์— ์Šค์บ”ํ•˜๋Š” ๋ฒ„์ „์œผ๋กœ ์—…๊ทธ๋ ˆ์ด๋“œํ•ด๋ณด์ž! ์‹ค์ œ๋กœ๋Š” ์ด๋Ÿฐ ๋ฐฉ์‹์ด ํ›จ์”ฌ ์œ ์šฉํ•˜๊ฑฐ๋“ .

import socket
import sys
from datetime import datetime

def scan_port_range(target_host, start_port, end_port):
    """
    ํฌํŠธ ๋ฒ”์œ„๋ฅผ ์Šค์บ”ํ•˜๋Š” ํ•จ์ˆ˜
    
    Args:
        target_host: ์Šค์บ”ํ•  ํ˜ธ์ŠคํŠธ
        start_port: ์‹œ์ž‘ ํฌํŠธ ๋ฒˆํ˜ธ
        end_port: ์ข…๋ฃŒ ํฌํŠธ ๋ฒˆํ˜ธ
    """
    print("-" * 60)
    print(f"์Šค์บ” ๋Œ€์ƒ: {target_host}")
    print(f"ํฌํŠธ ๋ฒ”์œ„: {start_port} - {end_port}")
    print(f"์Šค์บ” ์‹œ์ž‘ ์‹œ๊ฐ„: {datetime.now()}")
    print("-" * 60)
    
    open_ports = []
    
    try:
        # ํ˜ธ์ŠคํŠธ ์ด๋ฆ„์„ IP๋กœ ๋ณ€ํ™˜
        target_ip = socket.gethostbyname(target_host)
        print(f"[*] IP ์ฃผ์†Œ: {target_ip}\n")
        
    except socket.gaierror:
        print(f"[!] ํ˜ธ์ŠคํŠธ ์ด๋ฆ„์„ ํ™•์ธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {target_host}")
        sys.exit()
    
    # ํฌํŠธ ๋ฒ”์œ„ ์Šค์บ”
    for port in range(start_port, end_port + 1):
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(0.5)  # ๋น ๋ฅธ ์Šค์บ”์„ ์œ„ํ•ด ํƒ€์ž„์•„์›ƒ ๋‹จ์ถ•
            
            result = sock.connect_ex((target_ip, port))
            
            if result == 0:
                # ์„œ๋น„์Šค ์ด๋ฆ„ ๊ฐ€์ ธ์˜ค๊ธฐ ์‹œ๋„
                try:
                    service = socket.getservbyport(port)
                except:
                    service = "Unknown"
                
                print(f"[+] ํฌํŠธ {port:5d} : OPEN  ({service})")
                open_ports.append(port)
            
            sock.close()
            
        except KeyboardInterrupt:
            print("\n[!] ์‚ฌ์šฉ์ž์— ์˜ํ•ด ์Šค์บ”์ด ์ค‘๋‹จ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
            sys.exit()
        except socket.error:
            pass
    
    # ๊ฒฐ๊ณผ ์š”์•ฝ
    print("\n" + "=" * 60)
    print(f"์Šค์บ” ์™„๋ฃŒ ์‹œ๊ฐ„: {datetime.now()}")
    print(f"์—ด๋ฆฐ ํฌํŠธ ๊ฐœ์ˆ˜: {len(open_ports)}")
    if open_ports:
        print(f"์—ด๋ฆฐ ํฌํŠธ ๋ชฉ๋ก: {open_ports}")
    print("=" * 60)

# ์‚ฌ์šฉ ์˜ˆ์‹œ
if __name__ == "__main__":
    target = "127.0.0.1"
    start = 1
    end = 1024  # Well-known ports
    
    scan_port_range(target, start, end)
๐ŸŽ“ ์ฝ”๋“œ ์„ค๋ช…

1. socket.gethostbyname(): ๋„๋ฉ”์ธ ์ด๋ฆ„์„ IP ์ฃผ์†Œ๋กœ ๋ณ€ํ™˜ํ•ด์ค˜
2. socket.getservbyport(): ํฌํŠธ ๋ฒˆํ˜ธ์— ํ•ด๋‹นํ•˜๋Š” ์„œ๋น„์Šค ์ด๋ฆ„์„ ๊ฐ€์ ธ์™€
3. settimeout(0.5): ํƒ€์ž„์•„์›ƒ์„ ์งง๊ฒŒ ์„ค์ •ํ•ด์„œ ์Šค์บ” ์†๋„๋ฅผ ๋†’์—ฌ
4. KeyboardInterrupt: Ctrl+C๋กœ ์Šค์บ”์„ ์ค‘๋‹จํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜

โšก ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ์œผ๋กœ ์„ฑ๋Šฅ ํ–ฅ์ƒํ•˜๊ธฐ

์œ„์˜ ์ฝ”๋“œ๋Š” ํฌํŠธ๋ฅผ ํ•˜๋‚˜์”ฉ ์ˆœ์ฐจ์ ์œผ๋กœ ์Šค์บ”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋А๋ ค. 1000๊ฐœ ํฌํŠธ๋ฅผ ์Šค์บ”ํ•˜๋ ค๋ฉด ๋ช‡ ๋ถ„์ด ๊ฑธ๋ฆด ์ˆ˜๋„ ์žˆ์ง€. ์ด๊ฑธ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ์œผ๋กœ ๊ฐœ์„ ํ•˜๋ฉด ์—„์ฒญ๋‚˜๊ฒŒ ๋นจ๋ผ์ ธ! ๐Ÿš€

import socket
import threading
from queue import Queue
from datetime import datetime

# ์ „์—ญ ๋ณ€์ˆ˜
print_lock = threading.Lock()
open_ports = []

def port_scanner(target_ip, port):
    """
    ๊ฐœ๋ณ„ ํฌํŠธ๋ฅผ ์Šค์บ”ํ•˜๋Š” ํ•จ์ˆ˜ (์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰)
    """
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(1)
        
        result = sock.connect_ex((target_ip, port))
        
        if result == 0:
            with print_lock:
                try:
                    service = socket.getservbyport(port)
                except:
                    service = "Unknown"
                
                print(f"[+] ํฌํŠธ {port:5d} : OPEN  ({service})")
                open_ports.append(port)
        
        sock.close()
        
    except:
        pass

def threader(target_ip, port_queue):
    """
    ํ์—์„œ ํฌํŠธ๋ฅผ ๊ฐ€์ ธ์™€์„œ ์Šค์บ”ํ•˜๋Š” ์›Œ์ปค ํ•จ์ˆ˜
    """
    while True:
        port = port_queue.get()
        if port is None:
            break
        port_scanner(target_ip, port)
        port_queue.task_done()

def scan_ports_threaded(target_host, start_port, end_port, num_threads=100):
    """
    ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ ํฌํŠธ ์Šค์บ”
    
    Args:
        target_host: ์Šค์บ”ํ•  ํ˜ธ์ŠคํŠธ
        start_port: ์‹œ์ž‘ ํฌํŠธ
        end_port: ์ข…๋ฃŒ ํฌํŠธ
        num_threads: ์‚ฌ์šฉํ•  ์Šค๋ ˆ๋“œ ๊ฐœ์ˆ˜ (๊ธฐ๋ณธ 100)
    """
    print("=" * 70)
    print(f"๐Ÿ” ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํฌํŠธ ์Šค์บ๋„ˆ")
    print("=" * 70)
    print(f"๋Œ€์ƒ ํ˜ธ์ŠคํŠธ: {target_host}")
    print(f"ํฌํŠธ ๋ฒ”์œ„: {start_port} - {end_port}")
    print(f"์Šค๋ ˆ๋“œ ๊ฐœ์ˆ˜: {num_threads}")
    print(f"์‹œ์ž‘ ์‹œ๊ฐ„: {datetime.now()}")
    print("=" * 70 + "\n")
    
    try:
        target_ip = socket.gethostbyname(target_host)
        print(f"[*] IP ์ฃผ์†Œ: {target_ip}\n")
    except socket.gaierror:
        print(f"[!] ํ˜ธ์ŠคํŠธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {target_host}")
        return
    
    # ํ ์ƒ์„ฑ ๋ฐ ํฌํŠธ ์ถ”๊ฐ€
    port_queue = Queue()
    for port in range(start_port, end_port + 1):
        port_queue.put(port)
    
    # ์Šค๋ ˆ๋“œ ์ƒ์„ฑ ๋ฐ ์‹œ์ž‘
    threads = []
    for _ in range(num_threads):
        thread = threading.Thread(target=threader, args=(target_ip, port_queue))
        thread.daemon = True
        thread.start()
        threads.append(thread)
    
    # ๋ชจ๋“  ์ž‘์—…์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
    port_queue.join()
    
    # ์Šค๋ ˆ๋“œ ์ข…๋ฃŒ
    for _ in range(num_threads):
        port_queue.put(None)
    for thread in threads:
        thread.join()
    
    # ๊ฒฐ๊ณผ ์ถœ๋ ฅ
    print("\n" + "=" * 70)
    print(f"โœ… ์Šค์บ” ์™„๋ฃŒ!")
    print(f"์ข…๋ฃŒ ์‹œ๊ฐ„: {datetime.now()}")
    print(f"์—ด๋ฆฐ ํฌํŠธ ๊ฐœ์ˆ˜: {len(open_ports)}")
    if open_ports:
        open_ports.sort()
        print(f"์—ด๋ฆฐ ํฌํŠธ: {open_ports}")
    print("=" * 70)

# ์‚ฌ์šฉ ์˜ˆ์‹œ
if __name__ == "__main__":
    target = "scanme.nmap.org"  # ํ…Œ์ŠคํŠธ์šฉ ๊ณต๊ฐœ ์„œ๋ฒ„
    scan_ports_threaded(target, 1, 1000, num_threads=200)

๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ ๋ฒ„์ „์€ ์—ฌ๋Ÿฌ ํฌํŠธ๋ฅผ ๋™์‹œ์— ์Šค์บ”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์†๋„๊ฐ€ 10๋ฐฐ ์ด์ƒ ๋นจ๋ผ์ ธ! 100๊ฐœ์˜ ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด 1000๊ฐœ ํฌํŠธ๋ฅผ ๋ช‡ ์ดˆ ๋งŒ์— ์Šค์บ”ํ•  ์ˆ˜ ์žˆ์–ด. ๐ŸŽฏ

โš ๏ธ ์ฃผ์˜์‚ฌํ•ญ

์Šค๋ ˆ๋“œ ๊ฐœ์ˆ˜๋ฅผ ๋„ˆ๋ฌด ๋งŽ์ด ์„ค์ •ํ•˜๋ฉด ์‹œ์Šคํ…œ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ณผ๋„ํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜, ๋Œ€์ƒ ์„œ๋ฒ„์— ๋ถ€๋‹ด์„ ์ค„ ์ˆ˜ ์žˆ์–ด. ๋˜ํ•œ ์ผ๋ถ€ ๋ฐฉํ™”๋ฒฝ์ด๋‚˜ IDS๋Š” ๋™์‹œ ๋‹ค๋ฐœ์ ์ธ ์—ฐ๊ฒฐ ์‹œ๋„๋ฅผ ๊ณต๊ฒฉ์œผ๋กœ ๊ฐ„์ฃผํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ ์กฐ์‹ฌํ•ด์•ผ ํ•ด!

๐Ÿ”ฌ ๊ณ ๊ธ‰ ํฌํŠธ ์Šค์บ๋„ˆ: SYN ์Šค์บ” ๊ตฌํ˜„

์ด์ œ ์ข€ ๋” ๊ณ ๊ธ‰ ๊ธฐ๋ฒ•์ธ SYN ์Šค์บ”์„ ๊ตฌํ˜„ํ•ด๋ณผ๊นŒ? ์ด๊ฑด raw socket์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ด€๋ฆฌ์ž ๊ถŒํ•œ์ด ํ•„์š”ํ•ด. Python์˜ scapy ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์–ด! ๐ŸŽ“

๐Ÿ’ก Scapy ์„ค์น˜ํ•˜๊ธฐ

pip install scapy

Windows์—์„œ๋Š” Npcap๋„ ์„ค์น˜ํ•ด์•ผ ํ•ด: https://npcap.com/
from scapy.all import *
import sys

def syn_scan(target_ip, port_range):
    """
    SYN ์Šค์บ” (Half-Open Scan) ๊ตฌํ˜„
    
    Args:
        target_ip: ๋Œ€์ƒ IP ์ฃผ์†Œ
        port_range: ์Šค์บ”ํ•  ํฌํŠธ ๋ฆฌ์ŠคํŠธ
    """
    print("=" * 70)
    print("๐ŸŽฏ SYN ์Šค์บ” (Stealth Scan)")
    print("=" * 70)
    print(f"๋Œ€์ƒ: {target_ip}")
    print(f"ํฌํŠธ ๊ฐœ์ˆ˜: {len(port_range)}")
    print("=" * 70 + "\n")
    
    open_ports = []
    closed_ports = []
    filtered_ports = []
    
    for port in port_range:
        # SYN ํŒจํ‚ท ์ƒ์„ฑ
        src_port = RandShort()  # ๋žœ๋ค ์†Œ์Šค ํฌํŠธ
        
        # IP ๋ ˆ์ด์–ด + TCP ๋ ˆ์ด์–ด (SYN ํ”Œ๋ž˜๊ทธ)
        packet = IP(dst=target_ip) / TCP(sport=src_port, dport=port, flags="S")
        
        # ํŒจํ‚ท ์ „์†ก ๋ฐ ์‘๋‹ต ๋Œ€๊ธฐ
        response = sr1(packet, timeout=1, verbose=0)
        
        if response is None:
            # ์‘๋‹ต ์—†์Œ = ํ•„ํ„ฐ๋ง๋จ
            filtered_ports.append(port)
            print(f"[?] ํฌํŠธ {port:5d} : FILTERED")
            
        elif response.haslayer(TCP):
            if response[TCP].flags == 0x12:  # SYN-ACK
                # ํฌํŠธ ์—ด๋ฆผ
                open_ports.append(port)
                print(f"[+] ํฌํŠธ {port:5d} : OPEN โœ…")
                
                # RST ํŒจํ‚ท ์ „์†กํ•˜์—ฌ ์—ฐ๊ฒฐ ์ข…๋ฃŒ
                rst_packet = IP(dst=target_ip) / TCP(sport=src_port, dport=port, flags="R")
                send(rst_packet, verbose=0)
                
            elif response[TCP].flags == 0x14:  # RST-ACK
                # ํฌํŠธ ๋‹ซํž˜
                closed_ports.append(port)
                print(f"[-] ํฌํŠธ {port:5d} : CLOSED")
        
        elif response.haslayer(ICMP):
            # ICMP ์—๋Ÿฌ = ํ•„ํ„ฐ๋ง๋จ
            filtered_ports.append(port)
            print(f"[?] ํฌํŠธ {port:5d} : FILTERED (ICMP)")
    
    # ๊ฒฐ๊ณผ ์š”์•ฝ
    print("\n" + "=" * 70)
    print("๐Ÿ“Š ์Šค์บ” ๊ฒฐ๊ณผ ์š”์•ฝ")
    print("=" * 70)
    print(f"์—ด๋ฆฐ ํฌํŠธ: {len(open_ports)} ๊ฐœ")
    if open_ports:
        print(f"  โ†’ {open_ports}")
    print(f"๋‹ซํžŒ ํฌํŠธ: {len(closed_ports)} ๊ฐœ")
    print(f"ํ•„ํ„ฐ๋ง๋œ ํฌํŠธ: {len(filtered_ports)} ๊ฐœ")
    print("=" * 70)

# ์‚ฌ์šฉ ์˜ˆ์‹œ
if __name__ == "__main__":
    # ๊ด€๋ฆฌ์ž ๊ถŒํ•œ ํ™•์ธ
    if os.geteuid() != 0:
        print("[!] ์ด ์Šคํฌ๋ฆฝํŠธ๋Š” root ๊ถŒํ•œ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค!")
        print("    sudo python3 syn_scanner.py")
        sys.exit(1)
    
    target = "192.168.1.1"
    ports = [20, 21, 22, 23, 25, 80, 443, 3306, 8080]
    
    syn_scan(target, ports)

SYN ์Šค์บ”์˜ ์žฅ์ ์€ 3-way handshake๋ฅผ ์™„์„ฑํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋งŽ์€ ๋กœ๊ทธ ์‹œ์Šคํ…œ์—์„œ ํƒ์ง€๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฑฐ์•ผ. ํ•˜์ง€๋งŒ ์ตœ์‹  IDS/IPS๋Š” ์ด๋Ÿฐ ํŒจํ„ด๋„ ํƒ์ง€ํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ ์™„์ „ํžˆ ์Šคํ…”์Šค๋Š” ์•„๋‹ˆ์•ผ! ๐Ÿ˜‰

๐Ÿ” TCP ํ”Œ๋ž˜๊ทธ ์„ค๋ช…

โ€ข SYN (0x02): ์—ฐ๊ฒฐ ์‹œ์ž‘
โ€ข ACK (0x10): ํ™•์ธ ์‘๋‹ต
โ€ข RST (0x04): ์—ฐ๊ฒฐ ์žฌ์„ค์ •
โ€ข FIN (0x01): ์—ฐ๊ฒฐ ์ข…๋ฃŒ
โ€ข SYN-ACK (0x12): SYN + ACK (ํฌํŠธ ์—ด๋ฆผ)
โ€ข RST-ACK (0x14): RST + ACK (ํฌํŠธ ๋‹ซํž˜)

๐Ÿ›ก๏ธ ์„œ๋น„์Šค ๋ฒ„์ „ ํƒ์ง€ ๊ธฐ๋Šฅ ์ถ”๊ฐ€

ํฌํŠธ๊ฐ€ ์—ด๋ ค์žˆ๋‹ค๋Š” ๊ฒƒ๋งŒ ์•„๋Š” ๊ฒƒ๋ณด๋‹ค, ์–ด๋–ค ์„œ๋น„์Šค๊ฐ€ ์–ด๋–ค ๋ฒ„์ „์œผ๋กœ ์‹คํ–‰๋˜๊ณ  ์žˆ๋Š”์ง€ ์•„๋Š” ๊ฒŒ ํ›จ์”ฌ ์œ ์šฉํ•ด! ์ด๊ฑธ Service Version Detection์ด๋ผ๊ณ  ํ•ด. ๋ฐฐ๋„ˆ ๊ทธ๋ž˜๋น™(Banner Grabbing) ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์–ด. ๐ŸŽฏ

import socket
import re

def grab_banner(ip, port, timeout=2):
    """
    ๋ฐฐ๋„ˆ ๊ทธ๋ž˜๋น™์„ ํ†ตํ•œ ์„œ๋น„์Šค ์ •๋ณด ์ˆ˜์ง‘
    
    Args:
        ip: ๋Œ€์ƒ IP
        port: ๋Œ€์ƒ ํฌํŠธ
        timeout: ํƒ€์ž„์•„์›ƒ (์ดˆ)
    
    Returns:
        ์„œ๋น„์Šค ๋ฐฐ๋„ˆ ๋ฌธ์ž์—ด ๋˜๋Š” None
    """
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(timeout)
        sock.connect((ip, port))
        
        # HTTP ์š”์ฒญ ์ „์†ก (์›น ์„œ๋ฒ„์ธ ๊ฒฝ์šฐ)
        if port in [80, 443, 8080, 8443]:
            request = b"GET / HTTP/1.1\r\nHost: " + ip.encode() + b"\r\n\r\n"
            sock.send(request)
        else:
            # ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ ๋นˆ ๋ฐ์ดํ„ฐ ์ „์†ก
            sock.send(b"\r\n")
        
        # ์‘๋‹ต ์ˆ˜์‹ 
        banner = sock.recv(1024).decode('utf-8', errors='ignore').strip()
        sock.close()
        
        return banner
        
    except:
        return None

def detect_service_version(ip, port):
    """
    ์„œ๋น„์Šค ๋ฒ„์ „ ํƒ์ง€
    """
    banner = grab_banner(ip, port)
    
    if not banner:
        return "Unknown", "Unknown"
    
    # ์„œ๋น„์Šค ํƒ€์ž… ๋ฐ ๋ฒ„์ „ ํŒŒ์‹ฑ
    service_patterns = {
        'SSH': r'SSH-[\d\.]+-(\S+)',
        'FTP': r'220.*?(\S+)\s+FTP',
        'HTTP': r'Server:\s*(\S+)',
        'MySQL': r'(\d+\.\d+\.\d+)-MySQL',
        'Apache': r'Apache/([\d\.]+)',
        'nginx': r'nginx/([\d\.]+)',
        'Microsoft-IIS': r'Microsoft-IIS/([\d\.]+)',
    }
    
    service_name = "Unknown"
    version = "Unknown"
    
    for service, pattern in service_patterns.items():
        match = re.search(pattern, banner, re.IGNORECASE)
        if match:
            service_name = service
            version = match.group(1)
            break
    
    return service_name, version, banner[:100]

def advanced_port_scan(target_ip, ports):
    """
    ์„œ๋น„์Šค ๋ฒ„์ „ ํƒ์ง€ ๊ธฐ๋Šฅ์ด ํฌํ•จ๋œ ํฌํŠธ ์Šค์บ”
    """
    print("=" * 80)
    print("๐Ÿ” ๊ณ ๊ธ‰ ํฌํŠธ ์Šค์บ๋„ˆ (์„œ๋น„์Šค ๋ฒ„์ „ ํƒ์ง€)")
    print("=" * 80)
    print(f"๋Œ€์ƒ: {target_ip}")
    print("=" * 80 + "\n")
    
    results = []
    
    for port in ports:
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(1)
            
            result = sock.connect_ex((target_ip, port))
            
            if result == 0:
                # ํฌํŠธ๊ฐ€ ์—ด๋ ค์žˆ์œผ๋ฉด ์„œ๋น„์Šค ์ •๋ณด ์ˆ˜์ง‘
                service_name, version, banner = detect_service_version(target_ip, port)
                
                results.append({
                    'port': port,
                    'service': service_name,
                    'version': version,
                    'banner': banner
                })
                
                print(f"[+] ํฌํŠธ {port:5d} : OPEN")
                print(f"    ์„œ๋น„์Šค: {service_name}")
                print(f"    ๋ฒ„์ „: {version}")
                if banner and banner != "Unknown":
                    print(f"    ๋ฐฐ๋„ˆ: {banner[:80]}...")
                print()
            
            sock.close()
            
        except Exception as e:
            pass
    
    # ๊ฒฐ๊ณผ ํ…Œ์ด๋ธ” ์ถœ๋ ฅ
    if results:
        print("\n" + "=" * 80)
        print("๐Ÿ“Š ํƒ์ง€๋œ ์„œ๋น„์Šค ์š”์•ฝ")
        print("=" * 80)
        print(f"{'ํฌํŠธ':<10} {'์„œ๋น„์Šค':<20} {'๋ฒ„์ „':<30}")
        print("-" * 80)
        for r in results:
            print(f"{r['port']:<10} {r['service']:<20} {r['version']:<30}")
        print("=" * 80)
    
    return results

# ์‚ฌ์šฉ ์˜ˆ์‹œ
if __name__ == "__main__":
    target = "scanme.nmap.org"
    common_ports = [21, 22, 23, 25, 80, 110, 143, 443, 3306, 3389, 8080]
    
    advanced_port_scan(target, common_ports)

๋ฐฐ๋„ˆ ๊ทธ๋ž˜๋น™์€ ์„œ๋ฒ„๊ฐ€ ์—ฐ๊ฒฐ ์‹œ ๋ณด๋‚ด๋Š” ์ดˆ๊ธฐ ๋ฉ”์‹œ์ง€๋ฅผ ์ฝ์–ด์„œ ์„œ๋น„์Šค ์ •๋ณด๋ฅผ ํŒŒ์•…ํ•˜๋Š” ๊ฑฐ์•ผ. ์˜ˆ๋ฅผ ๋“ค์–ด SSH ์„œ๋ฒ„๋Š” SSH-2.0-OpenSSH_7.4 ๊ฐ™์€ ๋ฐฐ๋„ˆ๋ฅผ ๋ณด๋‚ด์ฃผ์ง€. ์ด ์ •๋ณด๋กœ ์ทจ์•ฝ์ ์„ ์ฐพ์„ ์ˆ˜ ์žˆ์–ด! ๐Ÿ”

๐ŸŒ ์‹ค์ „ ๋„คํŠธ์›Œํฌ ๋ณด์•ˆ ์ ๊ฒ€ ์Šคํฌ๋ฆฝํŠธ

์ด์ œ ์ง€๊ธˆ๊นŒ์ง€ ๋ฐฐ์šด ๋‚ด์šฉ์„ ์ข…ํ•ฉํ•ด์„œ ์‹ค์ „์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์™„์ „ํ•œ ๋„คํŠธ์›Œํฌ ๋ณด์•ˆ ์ ๊ฒ€ ๋„๊ตฌ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž! ์ด ์Šคํฌ๋ฆฝํŠธ๋Š” ํฌํŠธ ์Šค์บ”, ์„œ๋น„์Šค ํƒ์ง€, ์ทจ์•ฝ์  ์ฒดํฌ, ๋ณด๊ณ ์„œ ์ƒ์„ฑ๊นŒ์ง€ ๋ชจ๋‘ ํฌํ•จํ•ด. ๐Ÿ’ช

import socket
import threading
from queue import Queue
from datetime import datetime
import json
import argparse

class NetworkSecurityScanner:
    """
    ์ข…ํ•ฉ ๋„คํŠธ์›Œํฌ ๋ณด์•ˆ ์Šค์บ๋„ˆ ํด๋ž˜์Šค
    """
    
    def __init__(self, target, ports=None, threads=100):
        self.target = target
        self.target_ip = None
        self.ports = ports if ports else range(1, 1025)
        self.threads = threads
        self.open_ports = []
        self.services = {}
        self.vulnerabilities = []
        self.print_lock = threading.Lock()
        
        # ์•Œ๋ ค์ง„ ์ทจ์•ฝํ•œ ์„œ๋น„์Šค/๋ฒ„์ „
        self.vulnerable_services = {
            'OpenSSH': ['7.2', '7.3', '7.4'],
            'Apache': ['2.4.49', '2.4.50'],
            'nginx': ['1.6.2', '1.6.3'],
            'vsftpd': ['2.3.4'],
        }
    
    def resolve_target(self):
        """๋Œ€์ƒ ํ˜ธ์ŠคํŠธ๋ฅผ IP๋กœ ๋ณ€ํ™˜"""
        try:
            self.target_ip = socket.gethostbyname(self.target)
            return True
        except socket.gaierror:
            print(f"[!] ํ˜ธ์ŠคํŠธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {self.target}")
            return False
    
    def scan_port(self, port):
        """๊ฐœ๋ณ„ ํฌํŠธ ์Šค์บ”"""
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(1)
            
            result = sock.connect_ex((self.target_ip, port))
            
            if result == 0:
                with self.print_lock:
                    self.open_ports.append(port)
                    print(f"[+] ํฌํŠธ {port} ์—ด๋ฆผ")
            
            sock.close()
            
        except:
            pass
    
    def worker(self, queue):
        """์Šค๋ ˆ๋“œ ์›Œ์ปค"""
        while True:
            port = queue.get()
            if port is None:
                break
            self.scan_port(port)
            queue.task_done()
    
    def run_port_scan(self):
        """๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํฌํŠธ ์Šค์บ” ์‹คํ–‰"""
        print("\n" + "=" * 70)
        print("๐Ÿ” 1๋‹จ๊ณ„: ํฌํŠธ ์Šค์บ”")
        print("=" * 70)
        
        queue = Queue()
        for port in self.ports:
            queue.put(port)
        
        threads = []
        for _ in range(self.threads):
            thread = threading.Thread(target=self.worker, args=(queue,))
            thread.daemon = True
            thread.start()
            threads.append(thread)
        
        queue.join()
        
        for _ in range(self.threads):
            queue.put(None)
        for thread in threads:
            thread.join()
        
        self.open_ports.sort()
        print(f"\nโœ… ์—ด๋ฆฐ ํฌํŠธ {len(self.open_ports)}๊ฐœ ๋ฐœ๊ฒฌ")
    
    def detect_services(self):
        """์„œ๋น„์Šค ํƒ์ง€"""
        print("\n" + "=" * 70)
        print("๐Ÿ” 2๋‹จ๊ณ„: ์„œ๋น„์Šค ํƒ์ง€")
        print("=" * 70)
        
        for port in self.open_ports:
            try:
                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                sock.settimeout(2)
                sock.connect((self.target_ip, port))
                
                # ๋ฐฐ๋„ˆ ์ˆ˜์‹  ์‹œ๋„
                sock.send(b"\r\n")
                banner = sock.recv(1024).decode('utf-8', errors='ignore').strip()
                
                if banner:
                    self.services[port] = banner[:100]
                    print(f"[+] ํฌํŠธ {port}: {banner[:80]}")
                else:
                    # ๊ธฐ๋ณธ ์„œ๋น„์Šค ์ด๋ฆ„
                    try:
                        service = socket.getservbyport(port)
                        self.services[port] = service
                        print(f"[+] ํฌํŠธ {port}: {service}")
                    except:
                        self.services[port] = "Unknown"
                
                sock.close()
                
            except:
                try:
                    service = socket.getservbyport(port)
                    self.services[port] = service
                except:
                    self.services[port] = "Unknown"
    
    def check_vulnerabilities(self):
        """์ทจ์•ฝ์  ์ฒดํฌ"""
        print("\n" + "=" * 70)
        print("๐Ÿ” 3๋‹จ๊ณ„: ์ทจ์•ฝ์  ๋ถ„์„")
        print("=" * 70)
        
        for port, banner in self.services.items():
            for service, vuln_versions in self.vulnerable_services.items():
                if service.lower() in banner.lower():
                    for version in vuln_versions:
                        if version in banner:
                            vuln = {
                                'port': port,
                                'service': service,
                                'version': version,
                                'severity': 'HIGH',
                                'description': f'{service} {version}์— ์•Œ๋ ค์ง„ ์ทจ์•ฝ์  ์กด์žฌ'
                            }
                            self.vulnerabilities.append(vuln)
                            print(f"[!] ์ทจ์•ฝ์  ๋ฐœ๊ฒฌ: ํฌํŠธ {port} - {service} {version}")
        
        # ์ผ๋ฐ˜์ ์ธ ๋ณด์•ˆ ์ฒดํฌ
        if 23 in self.open_ports:
            self.vulnerabilities.append({
                'port': 23,
                'service': 'Telnet',
                'severity': 'MEDIUM',
                'description': 'Telnet์€ ์•”ํ˜ธํ™”๋˜์ง€ ์•Š์€ ํ”„๋กœํ† ์ฝœ์ž…๋‹ˆ๋‹ค. SSH ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.'
            })
            print(f"[!] ๋ณด์•ˆ ๊ถŒ๊ณ : ํฌํŠธ 23 (Telnet) - ์•”ํ˜ธํ™”๋˜์ง€ ์•Š์€ ํ†ต์‹ ")
        
        if 21 in self.open_ports:
            self.vulnerabilities.append({
                'port': 21,
                'service': 'FTP',
                'severity': 'MEDIUM',
                'description': 'FTP๋Š” ์•”ํ˜ธํ™”๋˜์ง€ ์•Š์€ ํ”„๋กœํ† ์ฝœ์ž…๋‹ˆ๋‹ค. SFTP ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.'
            })
            print(f"[!] ๋ณด์•ˆ ๊ถŒ๊ณ : ํฌํŠธ 21 (FTP) - ์•”ํ˜ธํ™”๋˜์ง€ ์•Š์€ ํ†ต์‹ ")
        
        if not self.vulnerabilities:
            print("โœ… ์•Œ๋ ค์ง„ ์ทจ์•ฝ์ ์ด ๋ฐœ๊ฒฌ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
    
    def generate_report(self, filename=None):
        """๋ณด๊ณ ์„œ ์ƒ์„ฑ"""
        print("\n" + "=" * 70)
        print("๐Ÿ“„ 4๋‹จ๊ณ„: ๋ณด๊ณ ์„œ ์ƒ์„ฑ")
        print("=" * 70)
        
        report = {
            'scan_info': {
                'target': self.target,
                'target_ip': self.target_ip,
                'scan_time': datetime.now().isoformat(),
                'ports_scanned': len(list(self.ports)),
            },
            'results': {
                'open_ports': self.open_ports,
                'services': self.services,
                'vulnerabilities': self.vulnerabilities,
            },
            'summary': {
                'total_open_ports': len(self.open_ports),
                'total_vulnerabilities': len(self.vulnerabilities),
                'risk_level': self.calculate_risk_level(),
            }
        }
        
        # ์ฝ˜์†” ์ถœ๋ ฅ
        print(f"\n๋Œ€์ƒ: {self.target} ({self.target_ip})")
        print(f"์Šค์บ” ์‹œ๊ฐ„: {report['scan_info']['scan_time']}")
        print(f"์—ด๋ฆฐ ํฌํŠธ: {len(self.open_ports)}๊ฐœ")
        print(f"๋ฐœ๊ฒฌ๋œ ์ทจ์•ฝ์ : {len(self.vulnerabilities)}๊ฐœ")
        print(f"์œ„ํ—˜๋„: {report['summary']['risk_level']}")
        
        # JSON ํŒŒ์ผ๋กœ ์ €์žฅ
        if filename:
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump(report, f, indent=2, ensure_ascii=False)
            print(f"\nโœ… ๋ณด๊ณ ์„œ๊ฐ€ ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค: {filename}")
        
        return report
    
    def calculate_risk_level(self):
        """์œ„ํ—˜๋„ ๊ณ„์‚ฐ"""
        high_count = sum(1 for v in self.vulnerabilities if v.get('severity') == 'HIGH')
        medium_count = sum(1 for v in self.vulnerabilities if v.get('severity') == 'MEDIUM')
        
        if high_count > 0:
            return "HIGH"
        elif medium_count > 2:
            return "MEDIUM"
        elif medium_count > 0:
            return "LOW"
        else:
            return "SAFE"
    
    def run_full_scan(self):
        """์ „์ฒด ์Šค์บ” ์‹คํ–‰"""
        print("=" * 70)
        print("๐Ÿ›ก๏ธ  ๋„คํŠธ์›Œํฌ ๋ณด์•ˆ ์Šค์บ๋„ˆ")
        print("=" * 70)
        print(f"๋Œ€์ƒ: {self.target}")
        print(f"์‹œ์ž‘ ์‹œ๊ฐ„: {datetime.now()}")
        print("=" * 70)
        
        if not self.resolve_target():
            return None
        
        print(f"IP ์ฃผ์†Œ: {self.target_ip}")
        
        # 1. ํฌํŠธ ์Šค์บ”
        self.run_port_scan()
        
        # 2. ์„œ๋น„์Šค ํƒ์ง€
        if self.open_ports:
            self.detect_services()
        
        # 3. ์ทจ์•ฝ์  ์ฒดํฌ
        if self.services:
            self.check_vulnerabilities()
        
        # 4. ๋ณด๊ณ ์„œ ์ƒ์„ฑ
        report = self.generate_report(f"scan_report_{self.target}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json")
        
        print("\n" + "=" * 70)
        print("โœ… ์Šค์บ” ์™„๋ฃŒ!")
        print("=" * 70)
        
        return report

# ๋ฉ”์ธ ์‹คํ–‰ ๋ถ€๋ถ„
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='๋„คํŠธ์›Œํฌ ๋ณด์•ˆ ์Šค์บ๋„ˆ')
    parser.add_argument('target', help='์Šค์บ”ํ•  ๋Œ€์ƒ ํ˜ธ์ŠคํŠธ')
    parser.add_argument('-p', '--ports', help='ํฌํŠธ ๋ฒ”์œ„ (์˜ˆ: 1-1000)', default='1-1024')
    parser.add_argument('-t', '--threads', type=int, help='์Šค๋ ˆ๋“œ ๊ฐœ์ˆ˜', default=100)
    
    args = parser.parse_args()
    
    # ํฌํŠธ ๋ฒ”์œ„ ํŒŒ์‹ฑ
    if '-' in args.ports:
        start, end = map(int, args.ports.split('-'))
        ports = range(start, end + 1)
    else:
        ports = [int(p) for p in args.ports.split(',')]
    
    # ์Šค์บ๋„ˆ ์‹คํ–‰
    scanner = NetworkSecurityScanner(args.target, ports, args.threads)
    scanner.run_full_scan()

์ด ์Šคํฌ๋ฆฝํŠธ๋Š” ์ •๋ง ๊ฐ•๋ ฅํ•ด! ํฌํŠธ ์Šค์บ”๋ถ€ํ„ฐ ์ทจ์•ฝ์  ๋ถ„์„, ๋ณด๊ณ ์„œ ์ƒ์„ฑ๊นŒ์ง€ ๋ชจ๋‘ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•ด์ค˜. ์‹ค์ œ ๋ณด์•ˆ ์ ๊ฒ€์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ˆ˜์ค€์ด์•ผ. ๐Ÿ˜Ž

๐Ÿš€ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•

python security_scanner.py scanme.nmap.org
python security_scanner.py 192.168.1.1 -p 1-1000 -t 200

python security_scanner.py example.com -p 80,443,22,21,3306

๐ŸŽจ GUI ๋ฒ„์ „ ํฌํŠธ ์Šค์บ๋„ˆ

์ปค๋งจ๋“œ๋ผ์ธ๋„ ์ข‹์ง€๋งŒ, GUI๊ฐ€ ์žˆ์œผ๋ฉด ๋” ํŽธํ•˜๊ฒ ์ง€? Tkinter๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ฐ„๋‹จํ•œ GUI ํฌํŠธ ์Šค์บ๋„ˆ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž! ๐Ÿ–ฅ๏ธ

import tkinter as tk
from tkinter import ttk, scrolledtext, messagebox
import socket
import threading
from datetime import datetime

class PortScannerGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("๐Ÿ” ํฌํŠธ ์Šค์บ๋„ˆ")
        self.root.geometry("700x600")
        self.root.resizable(False, False)
        
        self.scanning = False
        self.setup_ui()
    
    def setup_ui(self):
        # ์Šคํƒ€์ผ ์„ค์ •
        style = ttk.Style()
        style.theme_use('clam')
        
        # ๋ฉ”์ธ ํ”„๋ ˆ์ž„
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # ํƒ€์ดํ‹€
        title_label = tk.Label(main_frame, text="๐Ÿ” ํฌํŠธ ์Šค์บ๋„ˆ", 
                              font=("Arial", 18, "bold"), fg="#667eea")
        title_label.grid(row=0, column=0, columnspan=3, pady=10)
        
        # ๋Œ€์ƒ ํ˜ธ์ŠคํŠธ ์ž…๋ ฅ
        ttk.Label(main_frame, text="๋Œ€์ƒ ํ˜ธ์ŠคํŠธ:", font=("Arial", 10)).grid(row=1, column=0, sticky=tk.W, pady=5)
        self.host_entry = ttk.Entry(main_frame, width=40, font=("Arial", 10))
        self.host_entry.grid(row=1, column=1, columnspan=2, sticky=(tk.W, tk.E), pady=5)
        self.host_entry.insert(0, "127.0.0.1")
        
        # ํฌํŠธ ๋ฒ”์œ„ ์ž…๋ ฅ
        ttk.Label(main_frame, text="์‹œ์ž‘ ํฌํŠธ:", font=("Arial", 10)).grid(row=2, column=0, sticky=tk.W, pady=5)
        self.start_port_entry = ttk.Entry(main_frame, width=15, font=("Arial", 10))
        self.start_port_entry.grid(row=2, column=1, sticky=tk.W, pady=5)
        self.start_port_entry.insert(0, "1")
        
        ttk.Label(main_frame, text="์ข…๋ฃŒ ํฌํŠธ:", font=("Arial", 10)).grid(row=3, column=0, sticky=tk.W, pady=5)
        self.end_port_entry = ttk.Entry(main_frame, width=15, font=("Arial", 10))
        self.end_port_entry.grid(row=3, column=1, sticky=tk.W, pady=5)
        self.end_port_entry.insert(0, "1000")
        
        # ์Šค๋ ˆ๋“œ ๊ฐœ์ˆ˜
        ttk.Label(main_frame, text="์Šค๋ ˆ๋“œ ๊ฐœ์ˆ˜:", font=("Arial", 10)).grid(row=4, column=0, sticky=tk.W, pady=5)
        self.threads_entry = ttk.Entry(main_frame, width=15, font=("Arial", 10))
        self.threads_entry.grid(row=4, column=1, sticky=tk.W, pady=5)
        self.threads_entry.insert(0, "100")
        
        # ๋ฒ„ํŠผ ํ”„๋ ˆ์ž„
        button_frame = ttk.Frame(main_frame)
        button_frame.grid(row=5, column=0, columnspan=3, pady=15)
        
        self.scan_button = tk.Button(button_frame, text="๐Ÿš€ ์Šค์บ” ์‹œ์ž‘", 
                                     command=self.start_scan, bg="#667eea", fg="white",
                                     font=("Arial", 11, "bold"), width=15, height=2)
        self.scan_button.pack(side=tk.LEFT, padx=5)
        
        self.stop_button = tk.Button(button_frame, text="โน ์ค‘์ง€", 
                                     command=self.stop_scan, bg="#ef4444", fg="white",
                                     font=("Arial", 11, "bold"), width=15, height=2, state=tk.DISABLED)
        self.stop_button.pack(side=tk.LEFT, padx=5)
        
        # ์ง„ํ–‰ ์ƒํƒœ
        ttk.Label(main_frame, text="์ง„ํ–‰ ์ƒํƒœ:", font=("Arial", 10)).grid(row=6, column=0, sticky=tk.W, pady=5)
        self.progress = ttk.Progressbar(main_frame, length=400, mode='determinate')
        self.progress.grid(row=6, column=1, columnspan=2, sticky=(tk.W, tk.E), pady=5)
        
        self.status_label = ttk.Label(main_frame, text="๋Œ€๊ธฐ ์ค‘...", font=("Arial", 9))
        self.status_label.grid(row=7, column=0, columnspan=3, pady=5)
        
        # ๊ฒฐ๊ณผ ์ถœ๋ ฅ ์˜์—ญ
        ttk.Label(main_frame, text="์Šค์บ” ๊ฒฐ๊ณผ:", font=("Arial", 10, "bold")).grid(row=8, column=0, sticky=tk.W, pady=5)
        
        self.result_text = scrolledtext.ScrolledText(main_frame, width=80, height=20, 
                                                     font=("Courier New", 9))
        self.result_text.grid(row=9, column=0, columnspan=3, pady=5)
        
        # ํƒœ๊ทธ ์„ค์ • (์ƒ‰์ƒ)
        self.result_text.tag_config("open", foreground="#10b981")
        self.result_text.tag_config("closed", foreground="#6b7280")
        self.result_text.tag_config("info", foreground="#667eea")
        self.result_text.tag_config("error", foreground="#ef4444")
    
    def log(self, message, tag="info"):
        """๊ฒฐ๊ณผ ์ฐฝ์— ๋กœ๊ทธ ์ถœ๋ ฅ"""
        self.result_text.insert(tk.END, message + "\n", tag)
        self.result_text.see(tk.END)
        self.root.update_idletasks()
    
    def start_scan(self):
        """์Šค์บ” ์‹œ์ž‘"""
        if self.scanning:
            return
        
        # ์ž…๋ ฅ ๊ฒ€์ฆ
        try:
            host = self.host_entry.get().strip()
            start_port = int(self.start_port_entry.get())
            end_port = int(self.end_port_entry.get())
            num_threads = int(self.threads_entry.get())
            
            if not host:
                raise ValueError("ํ˜ธ์ŠคํŠธ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”")
            if start_port < 1 or end_port > 65535 or start_port > end_port:
                raise ValueError("์˜ฌ๋ฐ”๋ฅธ ํฌํŠธ ๋ฒ”์œ„๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š” (1-65535)")
            if num_threads < 1 or num_threads > 500:
                raise ValueError("์Šค๋ ˆ๋“œ ๊ฐœ์ˆ˜๋Š” 1-500 ์‚ฌ์ด์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค")
                
        except ValueError as e:
            messagebox.showerror("์ž…๋ ฅ ์˜ค๋ฅ˜", str(e))
            return
        
        # UI ์ƒํƒœ ๋ณ€๊ฒฝ
        self.scanning = True
        self.scan_button.config(state=tk.DISABLED)
        self.stop_button.config(state=tk.NORMAL)
        self.result_text.delete(1.0, tk.END)
        self.progress['value'] = 0
        
        # ์Šค์บ” ์Šค๋ ˆ๋“œ ์‹œ์ž‘
        scan_thread = threading.Thread(target=self.run_scan, 
                                       args=(host, start_port, end_port, num_threads))
        scan_thread.daemon = True
        scan_thread.start()
    
    def stop_scan(self):
        """์Šค์บ” ์ค‘์ง€"""
        self.scanning = False
        self.scan_button.config(state=tk.NORMAL)
        self.stop_button.config(state=tk.DISABLED)
        self.status_label.config(text="์Šค์บ”์ด ์ค‘์ง€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
        self.log("โน ์‚ฌ์šฉ์ž์— ์˜ํ•ด ์Šค์บ”์ด ์ค‘์ง€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.", "error")
    
    def run_scan(self, host, start_port, end_port, num_threads):
        """์‹ค์ œ ์Šค์บ” ์‹คํ–‰"""
        self.log("=" * 70, "info")
        self.log(f"๐Ÿ” ํฌํŠธ ์Šค์บ” ์‹œ์ž‘", "info")
        self.log("=" * 70, "info")
        self.log(f"๋Œ€์ƒ: {host}", "info")
        self.log(f"ํฌํŠธ ๋ฒ”์œ„: {start_port} - {end_port}", "info")
        self.log(f"์‹œ์ž‘ ์‹œ๊ฐ„: {datetime.now()}", "info")
        self.log("=" * 70 + "\n", "info")
        
        # IP ํ™•์ธ
        try:
            target_ip = socket.gethostbyname(host)
            self.log(f"IP ์ฃผ์†Œ: {target_ip}\n", "info")
        except socket.gaierror:
            self.log(f"ํ˜ธ์ŠคํŠธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {host}", "error")
            self.stop_scan()
            return
        
        # ํฌํŠธ ์Šค์บ”
        total_ports = end_port - start_port + 1
        scanned_ports = 0
        open_ports = []
        
        from queue import Queue
        
        def scan_port(port):
            nonlocal scanned_ports
            if not self.scanning:
                return
            
            try:
                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                sock.settimeout(0.5)
                result = sock.connect_ex((target_ip, port))
                
                if result == 0:
                    try:
                        service = socket.getservbyport(port)
                    except:
                        service = "Unknown"
                    
                    open_ports.append(port)
                    self.log(f"[+] ํฌํŠธ {port:5d} : OPEN  ({service})", "open")
                
                sock.close()
                
            except:
                pass
            finally:
                scanned_ports += 1
                progress = (scanned_ports / total_ports) * 100
                self.progress['value'] = progress
                self.status_label.config(text=f"์Šค์บ” ์ค‘... {scanned_ports}/{total_ports} ํฌํŠธ")
        
        def worker(queue):
            while self.scanning:
                port = queue.get()
                if port is None:
                    break
                scan_port(port)
                queue.task_done()
        
        # ํ ์ƒ์„ฑ ๋ฐ ์Šค๋ ˆ๋“œ ์‹œ์ž‘
        queue = Queue()
        for port in range(start_port, end_port + 1):
            queue.put(port)
        
        threads = []
        for _ in range(num_threads):
            thread = threading.Thread(target=worker, args=(queue,))
            thread.daemon = True
            thread.start()
            threads.append(thread)
        
        queue.join()
        
        for _ in range(num_threads):
            queue.put(None)
        for thread in threads:
            thread.join()
        
        # ๊ฒฐ๊ณผ ์š”์•ฝ
        self.log("\n" + "=" * 70, "info")
        self.log("โœ… ์Šค์บ” ์™„๋ฃŒ!", "info")
        self.log("=" * 70, "info")
        self.log(f"์ข…๋ฃŒ ์‹œ๊ฐ„: {datetime.now()}", "info")
        self.log(f"์—ด๋ฆฐ ํฌํŠธ ๊ฐœ์ˆ˜: {len(open_ports)}", "info")
        if open_ports:
            self.log(f"์—ด๋ฆฐ ํฌํŠธ: {open_ports}", "open")
        self.log("=" * 70, "info")
        
        # UI ์ƒํƒœ ๋ณต์›
        self.scanning = False
        self.scan_button.config(state=tk.NORMAL)
        self.stop_button.config(state=tk.DISABLED)
        self.status_label.config(text="์Šค์บ” ์™„๋ฃŒ!")
        self.progress['value'] = 100

# ๋ฉ”์ธ ์‹คํ–‰
if __name__ == "__main__":
    root = tk.Tk()
    app = PortScannerGUI(root)
    root.mainloop()

GUI ๋ฒ„์ „์€ ํ›จ์”ฌ ์‚ฌ์šฉํ•˜๊ธฐ ํŽธํ•˜์ง€? ๋ฒ„ํŠผ ํด๋ฆญ๋งŒ์œผ๋กœ ์Šค์บ”์„ ์‹œ์ž‘ํ•˜๊ณ , ์‹ค์‹œ๊ฐ„์œผ๋กœ ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์–ด. ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ดˆ๋ณด์ž๋“ค๋„ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ธํ„ฐํŽ˜์ด์Šค์•ผ! ๐ŸŽจ

๐Ÿ”’ ๋„คํŠธ์›Œํฌ ๋ณด์•ˆ ๊ฐ•ํ™” ๋ฐฉ๋ฒ•

ํฌํŠธ ์Šค์บ๋„ˆ๋กœ ์ทจ์•ฝ์ ์„ ์ฐพ์•˜๋‹ค๋ฉด, ์ด์ œ ๋ณด์•ˆ์„ ๊ฐ•ํ™”ํ•ด์•ผ๊ฒ ์ง€? ์‹ค์ „์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ณด์•ˆ ๊ฐ•ํ™” ๋ฐฉ๋ฒ•๋“ค์„ ์•Œ๋ ค์ค„๊ฒŒ! ๐Ÿ›ก๏ธ

1๏ธโƒฃ ๋ถˆํ•„์š”ํ•œ ํฌํŠธ ๋‹ซ๊ธฐ

๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ด๋ฉด์„œ๋„ ์ค‘์š”ํ•œ ๋ฐฉ๋ฒ•์ด์•ผ. ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์„œ๋น„์Šค๋Š” ์™„์ „ํžˆ ์ค‘์ง€ํ•˜๊ณ  ํฌํŠธ๋ฅผ ๋‹ซ์•„์•ผ ํ•ด.

# Linux์—์„œ ์„œ๋น„์Šค ์ค‘์ง€ ๋ฐ ๋น„ํ™œ์„ฑํ™”
sudo systemctl stop telnet.service
sudo systemctl disable telnet.service

# ํŠน์ • ํฌํŠธ ๋ฐฉํ™”๋ฒฝ ์ฐจ๋‹จ (iptables)
sudo iptables -A INPUT -p tcp --dport 23 -j DROP

# ๋ฐฉํ™”๋ฒฝ ๊ทœ์น™ ์ €์žฅ
sudo iptables-save > /etc/iptables/rules.v4

2๏ธโƒฃ ๋ฐฉํ™”๋ฒฝ ์„ค์ •

๋ฐฉํ™”๋ฒฝ์€ ๋„คํŠธ์›Œํฌ ๋ณด์•ˆ์˜ ์ฒซ ๋ฒˆ์งธ ๋ฐฉ์–ด์„ ์ด์•ผ. ํ•„์š”ํ•œ ํฌํŠธ๋งŒ ์—ด๊ณ  ๋‚˜๋จธ์ง€๋Š” ๋ชจ๋‘ ์ฐจ๋‹จํ•ด์•ผ ํ•ด.

# UFW (Ubuntu Firewall) ์‚ฌ์šฉ ์˜ˆ์‹œ
# ๋ฐฉํ™”๋ฒฝ ํ™œ์„ฑํ™”
sudo ufw enable

# ๊ธฐ๋ณธ ์ •์ฑ…: ๋ชจ๋“  incoming ์ฐจ๋‹จ, outgoing ํ—ˆ์šฉ
sudo ufw default deny incoming
sudo ufw default allow outgoing

# ํ•„์š”ํ•œ ํฌํŠธ๋งŒ ํ—ˆ์šฉ
sudo ufw allow 22/tcp    # SSH
sudo ufw allow 80/tcp    # HTTP
sudo ufw allow 443/tcp   # HTTPS

# ํŠน์ • IP์—์„œ๋งŒ ์ ‘๊ทผ ํ—ˆ์šฉ
sudo ufw allow from 192.168.1.100 to any port 22

# ์ƒํƒœ ํ™•์ธ
sudo ufw status verbose

3๏ธโƒฃ ํฌํŠธ ๋…ธํ‚น (Port Knocking)

ํฌํŠธ ๋…ธํ‚น์€ ํŠน์ • ์ˆœ์„œ๋กœ ํฌํŠธ๋ฅผ ๋‘๋“œ๋ ค์•ผ๋งŒ ์‹ค์ œ ์„œ๋น„์Šค ํฌํŠธ๊ฐ€ ์—ด๋ฆฌ๋Š” ๊ธฐ๋ฒ•์ด์•ผ. ์ •๋ง ์žฌ๋ฏธ์žˆ๋Š” ๋ณด์•ˆ ๊ธฐ๋ฒ•์ด์ง€! ๐Ÿšช

# knockd ์„ค์น˜ (Ubuntu/Debian)
sudo apt-get install knockd

# /etc/knockd.conf ์„ค์ •
[options]
    UseSyslog

[openSSH]
    sequence    = 7000,8000,9000
    seq_timeout = 5
    command     = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
    tcpflags    = syn

[closeSSH]
    sequence    = 9000,8000,7000
    seq_timeout = 5
    command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
    tcpflags    = syn

# knockd ์‹œ์ž‘
sudo systemctl start knockd
sudo systemctl enable knockd

# ํด๋ผ์ด์–ธํŠธ์—์„œ ํฌํŠธ ๋…ธํ‚น
knock server_ip 7000 8000 9000
ssh user@server_ip

4๏ธโƒฃ Fail2Ban์œผ๋กœ ๋ฌด์ฐจ๋ณ„ ๋Œ€์ž… ๊ณต๊ฒฉ ๋ฐฉ์–ด

Fail2Ban์€ ๋กœ๊ทธ๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•ด์„œ ์˜์‹ฌ์Šค๋Ÿฌ์šด ํ™œ๋™์„ ๊ฐ์ง€ํ•˜๊ณ  ์ž๋™์œผ๋กœ IP๋ฅผ ์ฐจ๋‹จํ•ด์ค˜.

# Fail2Ban ์„ค์น˜
sudo apt-get install fail2ban

# /etc/fail2ban/jail.local ์„ค์ •
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5

[sshd]
enabled = true
port = ssh
logpath = /var/log/auth.log
maxretry = 3

# Fail2Ban ์‹œ์ž‘
sudo systemctl start fail2ban
sudo systemctl enable fail2ban

# ์ƒํƒœ ํ™•์ธ
sudo fail2ban-client status
sudo fail2ban-client status sshd
๐Ÿ’ก ๋ณด์•ˆ ํŒ!

โ€ข SSH ํฌํŠธ๋ฅผ ๊ธฐ๋ณธ 22๋ฒˆ์—์„œ ๋‹ค๋ฅธ ๋ฒˆํ˜ธ๋กœ ๋ณ€๊ฒฝํ•˜๋ฉด ์ž๋™ํ™”๋œ ๊ณต๊ฒฉ์„ ํ”ผํ•  ์ˆ˜ ์žˆ์–ด
โ€ข ๊ณต๊ฐœํ‚ค ์ธ์ฆ์„ ์‚ฌ์šฉํ•˜๊ณ  ๋น„๋ฐ€๋ฒˆํ˜ธ ์ธ์ฆ์€ ๋น„ํ™œ์„ฑํ™”ํ•ด
โ€ข ์ •๊ธฐ์ ์œผ๋กœ ์‹œ์Šคํ…œ๊ณผ ์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ์—…๋ฐ์ดํŠธํ•ด
โ€ข ๋กœ๊ทธ๋ฅผ ์ฃผ๊ธฐ์ ์œผ๋กœ ํ™•์ธํ•˜๊ณ  ์ด์ƒ ์ง•ํ›„๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•ด

๐ŸŽฏ ์‹ค์ „ ๋ณด์•ˆ ์ ๊ฒ€ ์ฒดํฌ๋ฆฌ์ŠคํŠธ

์‹ค์ œ ๋ณด์•ˆ ์ ๊ฒ€์„ ํ•  ๋•Œ ํ™•์ธํ•ด์•ผ ํ•  ํ•ญ๋ชฉ๋“ค์„ ์ •๋ฆฌํ•ด๋ดค์–ด. ์ด ์ฒดํฌ๋ฆฌ์ŠคํŠธ๋ฅผ ๋”ฐ๋ผํ•˜๋ฉด ๊ธฐ๋ณธ์ ์ธ ๋ณด์•ˆ์€ ํ™•๋ณดํ•  ์ˆ˜ ์žˆ์–ด! โœ…

์นดํ…Œ๊ณ ๋ฆฌ ์ ๊ฒ€ ํ•ญ๋ชฉ ์œ„ํ—˜๋„
ํฌํŠธ ๊ด€๋ฆฌ ๋ถˆํ•„์š”ํ•œ ํฌํŠธ๊ฐ€ ์—ด๋ ค์žˆ์ง€ ์•Š์€๊ฐ€? HIGH
ํฌํŠธ ๊ด€๋ฆฌ Telnet(23), FTP(21) ๋“ฑ ๋น„์•”ํ˜ธํ™” ํ”„๋กœํ† ์ฝœ ์‚ฌ์šฉ ์—ฌ๋ถ€ HIGH
์„œ๋น„์Šค ๋ฒ„์ „ ์•Œ๋ ค์ง„ ์ทจ์•ฝ์ ์ด ์žˆ๋Š” ๊ตฌ๋ฒ„์ „ ์‚ฌ์šฉ ์—ฌ๋ถ€ HIGH
๋ฐฉํ™”๋ฒฝ ๋ฐฉํ™”๋ฒฝ์ด ํ™œ์„ฑํ™”๋˜์–ด ์žˆ๋Š”๊ฐ€? HIGH
๋ฐฉํ™”๋ฒฝ ๊ธฐ๋ณธ ์ •์ฑ…์ด deny๋กœ ์„ค์ •๋˜์–ด ์žˆ๋Š”๊ฐ€? MEDIUM
์ธ์ฆ SSH ๊ณต๊ฐœํ‚ค ์ธ์ฆ์„ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€? MEDIUM
์ธ์ฆ root ์ง์ ‘ ๋กœ๊ทธ์ธ์ด ์ฐจ๋‹จ๋˜์–ด ์žˆ๋Š”๊ฐ€? HIGH
๋กœ๊ทธ ๋กœ๊ทธ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ์ด ๊ตฌ์ถ•๋˜์–ด ์žˆ๋Š”๊ฐ€? MEDIUM
์—…๋ฐ์ดํŠธ ์ •๊ธฐ์ ์ธ ๋ณด์•ˆ ํŒจ์น˜๊ฐ€ ์ ์šฉ๋˜๋Š”๊ฐ€? HIGH
๋ฐฑ์—… ์ •๊ธฐ์ ์ธ ๋ฐฑ์—…์ด ์ˆ˜ํ–‰๋˜๋Š”๊ฐ€? MEDIUM

์ด ์ฒดํฌ๋ฆฌ์ŠคํŠธ๋ฅผ Python ์Šคํฌ๋ฆฝํŠธ๋กœ ์ž๋™ํ™”ํ•˜๋ฉด ๋” ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด. ๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ๋ฅผ ๋งŒ๋“ค์–ด๋ณผ๊ฒŒ!

import subprocess
import socket

class SecurityChecker:
    """๋ณด์•ˆ ์ ๊ฒ€ ์ž๋™ํ™” ํด๋ž˜์Šค"""
    
    def __init__(self):
        self.results = []
        self.score = 0
        self.max_score = 0
    
    def check_open_ports(self, dangerous_ports=[21, 23, 135, 139, 445]):
        """์œ„ํ—˜ํ•œ ํฌํŠธ ์—ด๋ฆผ ์—ฌ๋ถ€ ํ™•์ธ"""
        print("\n[*] ์œ„ํ—˜ํ•œ ํฌํŠธ ์ ๊ฒ€ ์ค‘...")
        
        found_dangerous = []
        for port in dangerous_ports:
            try:
                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                sock.settimeout(0.5)
                result = sock.connect_ex(('127.0.0.1', port))
                
                if result == 0:
                    found_dangerous.append(port)
                    print(f"[!] ์œ„ํ—˜: ํฌํŠธ {port} ์—ด๋ฆผ")
                
                sock.close()
            except:
                pass
        
        self.max_score += 10
        if not found_dangerous:
            self.score += 10
            self.results.append(("์œ„ํ—˜ํ•œ ํฌํŠธ", "PASS", "์œ„ํ—˜ํ•œ ํฌํŠธ๊ฐ€ ์—ด๋ ค์žˆ์ง€ ์•Š์Œ"))
        else:
            self.results.append(("์œ„ํ—˜ํ•œ ํฌํŠธ", "FAIL", f"์—ด๋ฆฐ ์œ„ํ—˜ ํฌํŠธ: {found_dangerous}"))
    
    def check_firewall(self):
        """๋ฐฉํ™”๋ฒฝ ํ™œ์„ฑํ™” ์—ฌ๋ถ€ ํ™•์ธ"""
        print("\n[*] ๋ฐฉํ™”๋ฒฝ ์ƒํƒœ ์ ๊ฒ€ ์ค‘...")
        
        try:
            # UFW ์ƒํƒœ ํ™•์ธ
            result = subprocess.run(['sudo', 'ufw', 'status'], 
                                  capture_output=True, text=True, timeout=5)
            
            self.max_score += 10
            if 'Status: active' in result.stdout:
                self.score += 10
                self.results.append(("๋ฐฉํ™”๋ฒฝ", "PASS", "๋ฐฉํ™”๋ฒฝ์ด ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์Œ"))
                print("[+] ๋ฐฉํ™”๋ฒฝ ํ™œ์„ฑํ™”๋จ")
            else:
                self.results.append(("๋ฐฉํ™”๋ฒฝ", "FAIL", "๋ฐฉํ™”๋ฒฝ์ด ๋น„ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์Œ"))
                print("[!] ๋ฐฉํ™”๋ฒฝ ๋น„ํ™œ์„ฑํ™”๋จ")
        except:
            self.max_score += 10
            self.results.append(("๋ฐฉํ™”๋ฒฝ", "ERROR", "๋ฐฉํ™”๋ฒฝ ์ƒํƒœ ํ™•์ธ ๋ถˆ๊ฐ€"))
            print("[!] ๋ฐฉํ™”๋ฒฝ ์ƒํƒœ ํ™•์ธ ์‹คํŒจ")
    
    def check_ssh_config(self):
        """SSH ์„ค์ • ์ ๊ฒ€"""
        print("\n[*] SSH ์„ค์ • ์ ๊ฒ€ ์ค‘...")
        
        try:
            with open('/etc/ssh/sshd_config', 'r') as f:
                config = f.read()
            
            # Root ๋กœ๊ทธ์ธ ์ฒดํฌ
            self.max_score += 5
            if 'PermitRootLogin no' in config or 'PermitRootLogin prohibit-password' in config:
                self.score += 5
                self.results.append(("SSH Root ๋กœ๊ทธ์ธ", "PASS", "Root ์ง์ ‘ ๋กœ๊ทธ์ธ ์ฐจ๋‹จ๋จ"))
                print("[+] Root ๋กœ๊ทธ์ธ ์ฐจ๋‹จ๋จ")
            else:
                self.results.append(("SSH Root ๋กœ๊ทธ์ธ", "FAIL", "Root ๋กœ๊ทธ์ธ์ด ํ—ˆ์šฉ๋˜์–ด ์žˆ์Œ"))
                print("[!] Root ๋กœ๊ทธ์ธ ํ—ˆ์šฉ๋จ")
            
            # ๋น„๋ฐ€๋ฒˆํ˜ธ ์ธ์ฆ ์ฒดํฌ
            self.max_score += 5
            if 'PasswordAuthentication no' in config:
                self.score += 5
                self.results.append(("SSH ๋น„๋ฐ€๋ฒˆํ˜ธ ์ธ์ฆ", "PASS", "๋น„๋ฐ€๋ฒˆํ˜ธ ์ธ์ฆ ๋น„ํ™œ์„ฑํ™”๋จ"))
                print("[+] ๋น„๋ฐ€๋ฒˆํ˜ธ ์ธ์ฆ ๋น„ํ™œ์„ฑํ™”๋จ")
            else:
                self.results.append(("SSH ๋น„๋ฐ€๋ฒˆํ˜ธ ์ธ์ฆ", "WARN", "๋น„๋ฐ€๋ฒˆํ˜ธ ์ธ์ฆ์ด ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์Œ"))
                print("[!] ๋น„๋ฐ€๋ฒˆํ˜ธ ์ธ์ฆ ํ™œ์„ฑํ™”๋จ")
                
        except FileNotFoundError:
            self.max_score += 10
            self.results.append(("SSH ์„ค์ •", "ERROR", "SSH ์„ค์ • ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Œ"))
            print("[!] SSH ์„ค์ • ํŒŒ์ผ ์—†์Œ")
        except PermissionError:
            self.max_score += 10
            self.results.append(("SSH ์„ค์ •", "ERROR", "๊ถŒํ•œ ๋ถ€์กฑ (sudo ํ•„์š”)"))
            print("[!] ๊ถŒํ•œ ๋ถ€์กฑ")
    
    def check_updates(self):
        """์‹œ์Šคํ…œ ์—…๋ฐ์ดํŠธ ์ƒํƒœ ํ™•์ธ"""
        print("\n[*] ์‹œ์Šคํ…œ ์—…๋ฐ์ดํŠธ ์ƒํƒœ ์ ๊ฒ€ ์ค‘...")
        
        try:
            # apt ์—…๋ฐ์ดํŠธ ํ™•์ธ (Ubuntu/Debian)
            result = subprocess.run(['apt', 'list', '--upgradable'], 
                                  capture_output=True, text=True, timeout=10)
            
            upgradable = result.stdout.count('\n') - 1
            
            self.max_score += 10
            if upgradable == 0:
                self.score += 10
                self.results.append(("์‹œ์Šคํ…œ ์—…๋ฐ์ดํŠธ", "PASS", "๋ชจ๋“  ํŒจํ‚ค์ง€๊ฐ€ ์ตœ์‹  ์ƒํƒœ"))
                print("[+] ์‹œ์Šคํ…œ ์ตœ์‹  ์ƒํƒœ")
            elif upgradable < 10:
                self.score += 5
                self.results.append(("์‹œ์Šคํ…œ ์—…๋ฐ์ดํŠธ", "WARN", f"{upgradable}๊ฐœ ์—…๋ฐ์ดํŠธ ๊ฐ€๋Šฅ"))
                print(f"[!] {upgradable}๊ฐœ ์—…๋ฐ์ดํŠธ ํ•„์š”")
            else:
                self.results.append(("์‹œ์Šคํ…œ ์—…๋ฐ์ดํŠธ", "FAIL", f"{upgradable}๊ฐœ ์—…๋ฐ์ดํŠธ ํ•„์š”"))
                print(f"[!] {upgradable}๊ฐœ ์—…๋ฐ์ดํŠธ ํ•„์š”")
        except:
            self.max_score += 10
            self.results.append(("์‹œ์Šคํ…œ ์—…๋ฐ์ดํŠธ", "ERROR", "์—…๋ฐ์ดํŠธ ์ƒํƒœ ํ™•์ธ ๋ถˆ๊ฐ€"))
            print("[!] ์—…๋ฐ์ดํŠธ ์ƒํƒœ ํ™•์ธ ์‹คํŒจ")
    
    def generate_report(self):
        """๋ณด์•ˆ ์ ๊ฒ€ ๋ณด๊ณ ์„œ ์ƒ์„ฑ"""
        print("\n" + "=" * 70)
        print("๐Ÿ“Š ๋ณด์•ˆ ์ ๊ฒ€ ๋ณด๊ณ ์„œ")
        print("=" * 70)
        
        for item, status, detail in self.results:
            status_symbol = {
                "PASS": "โœ…",
                "FAIL": "โŒ",
                "WARN": "โš ๏ธ",
                "ERROR": "โ“"
            }.get(status, "")
            
            print(f"{status_symbol} {item:20s} : {status:6s} - {detail}")
        
        print("\n" + "=" * 70)
        percentage = (self.score / self.max_score * 100) if self.max_score > 0 else 0
        print(f"๋ณด์•ˆ ์ ์ˆ˜: {self.score}/{self.max_score} ({percentage:.1f}%)")
        
        if percentage >= 90:
            grade = "A (๋งค์šฐ ์•ˆ์ „)"
        elif percentage >= 70:
            grade = "B (์•ˆ์ „)"
        elif percentage >= 50:
            grade = "C (๋ณดํ†ต)"
        else:
            grade = "D (์œ„ํ—˜)"
        
        print(f"๋ณด์•ˆ ๋“ฑ๊ธ‰: {grade}")
        print("=" * 70)
    
    def run_all_checks(self):
        """๋ชจ๋“  ์ ๊ฒ€ ์‹คํ–‰"""
        print("๐Ÿ›ก๏ธ  ๋ณด์•ˆ ์ ๊ฒ€ ์‹œ์ž‘")
        print("=" * 70)
        
        self.check_open_ports()
        self.check_firewall()
        self.check_ssh_config()
        self.check_updates()
        
        self.generate_report()

# ์‹คํ–‰
if __name__ == "__main__":
    checker = SecurityChecker()
    checker.run_all_checks()

์ด ์Šคํฌ๋ฆฝํŠธ๋Š” ์‹œ์Šคํ…œ์˜ ๋ณด์•ˆ ์ƒํƒœ๋ฅผ ์ž๋™์œผ๋กœ ์ ๊ฒ€ํ•˜๊ณ  ์ ์ˆ˜๋ฅผ ๋งค๊ฒจ์ค˜. ์ •๊ธฐ์ ์œผ๋กœ ์‹คํ–‰ํ•ด์„œ ๋ณด์•ˆ ์ƒํƒœ๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋ฉด ์ข‹์•„! ๐Ÿ“Š

๐ŸŒŸ Nmap๊ณผ ๋น„๊ตํ•˜๊ธฐ

์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ํฌํŠธ ์Šค์บ๋„ˆ๋„ ์ข‹์ง€๋งŒ, ์‹ค์ „์—์„œ๋Š” Nmap์ด๋ผ๋Š” ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ๊ฐ€ ์žˆ์–ด. Nmap์€ ๋„คํŠธ์›Œํฌ ๋ณด์•ˆ ์ „๋ฌธ๊ฐ€๋“ค์ด ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ํฌํŠธ ์Šค์บ๋„ˆ์•ผ. ์šฐ๋ฆฌ ์Šคํฌ๋ฆฝํŠธ์™€ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅธ์ง€ ๋น„๊ตํ•ด๋ณด์ž! ๐Ÿ”

๐ŸŽฏ Nmap์˜ ์ฃผ์š” ๊ธฐ๋Šฅ

โ€ข ๋‹ค์–‘ํ•œ ์Šค์บ” ๊ธฐ๋ฒ•: TCP, SYN, UDP, FIN, NULL, Xmas ๋“ฑ
โ€ข OS ํƒ์ง€: ์šด์˜์ฒด์ œ ์ข…๋ฅ˜์™€ ๋ฒ„์ „ ์‹๋ณ„
โ€ข ์„œ๋น„์Šค ๋ฒ„์ „ ํƒ์ง€: ์ •ํ™•ํ•œ ์„œ๋น„์Šค ๋ฒ„์ „ ์ •๋ณด
โ€ข ์Šคํฌ๋ฆฝํŠธ ์—”์ง„: NSE(Nmap Scripting Engine)๋กœ ์ทจ์•ฝ์  ์Šค์บ”
โ€ข ์„ฑ๋Šฅ ์ตœ์ ํ™”: ๋งค์šฐ ๋น ๋ฅด๊ณ  ํšจ์œจ์ ์ธ ์Šค์บ”
โ€ข ๋ฐฉํ™”๋ฒฝ ์šฐํšŒ: ๋‹ค์–‘ํ•œ ํšŒํ”ผ ๊ธฐ๋ฒ• ์ง€์›

๐Ÿ“ Nmap ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

# Nmap ์„ค์น˜
sudo apt-get install nmap  # Ubuntu/Debian
sudo yum install nmap      # CentOS/RHEL

# ๊ธฐ๋ณธ ์Šค์บ”
nmap 192.168.1.1

# ํŠน์ • ํฌํŠธ ์Šค์บ”
nmap -p 80,443 192.168.1.1
nmap -p 1-1000 192.168.1.1

# SYN ์Šค์บ” (๋น ๋ฅด๊ณ  ์Šคํ…”์Šค)
sudo nmap -sS 192.168.1.1

# ์„œ๋น„์Šค ๋ฒ„์ „ ํƒ์ง€
nmap -sV 192.168.1.1

# OS ํƒ์ง€
sudo nmap -O 192.168.1.1

# ๊ณต๊ฒฉ์  ์Šค์บ” (๋ชจ๋“  ๊ธฐ๋Šฅ)
sudo nmap -A 192.168.1.1

# ์ทจ์•ฝ์  ์Šค์บ”
nmap --script vuln 192.168.1.1

# ๊ฒฐ๊ณผ๋ฅผ ํŒŒ์ผ๋กœ ์ €์žฅ
nmap -oN output.txt 192.168.1.1
nmap -oX output.xml 192.168.1.1

# ์—ฌ๋Ÿฌ ํ˜ธ์ŠคํŠธ ์Šค์บ”
nmap 192.168.1.1-254
nmap 192.168.1.0/24

๐Ÿ Python์—์„œ Nmap ์‚ฌ์šฉํ•˜๊ธฐ

Python์—์„œ๋„ Nmap์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด! python-nmap ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ผ.

import nmap

def advanced_nmap_scan(target, ports='1-1000'):
    """
    Nmap์„ ์‚ฌ์šฉํ•œ ๊ณ ๊ธ‰ ์Šค์บ”
    """
    print("=" * 70)
    print("๐Ÿ” Nmap ์Šค์บ” ์‹œ์ž‘")
    print("=" * 70)
    print(f"๋Œ€์ƒ: {target}")
    print(f"ํฌํŠธ: {ports}")
    print("=" * 70 + "\n")
    
    # Nmap ์Šค์บ๋„ˆ ๊ฐ์ฒด ์ƒ์„ฑ
    nm = nmap.PortScanner()
    
    # ์Šค์บ” ์‹คํ–‰ (-sV: ์„œ๋น„์Šค ๋ฒ„์ „ ํƒ์ง€, -T4: ๋น ๋ฅธ ์Šค์บ”)
    print("[*] ์Šค์บ” ์ง„ํ–‰ ์ค‘...\n")
    nm.scan(target, ports, arguments='-sV -T4')
    
    # ๊ฒฐ๊ณผ ์ถœ๋ ฅ
    for host in nm.all_hosts():
        print(f"ํ˜ธ์ŠคํŠธ: {host} ({nm[host].hostname()})")
        print(f"์ƒํƒœ: {nm[host].state()}\n")
        
        for proto in nm[host].all_protocols():
            print(f"ํ”„๋กœํ† ์ฝœ: {proto}")
            
            ports_list = nm[host][proto].keys()
            for port in sorted(ports_list):
                port_info = nm[host][proto][port]
                state = port_info['state']
                service = port_info['name']
                version = port_info.get('version', '')
                product = port_info.get('product', '')
                
                print(f"  ํฌํŠธ {port:5d} : {state:8s} | {service:15s} | {product} {version}")
        
        print("\n" + "=" * 70)
    
    return nm

def nmap_vulnerability_scan(target):
    """
    Nmap ์ทจ์•ฝ์  ์Šค์บ”
    """
    print("\n๐Ÿ” ์ทจ์•ฝ์  ์Šค์บ” ์‹œ์ž‘")
    print("=" * 70)
    
    nm = nmap.PortScanner()
    
    # ์ทจ์•ฝ์  ์Šค์บ” ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰
    nm.scan(target, arguments='--script vuln')
    
    for host in nm.all_hosts():
        print(f"\nํ˜ธ์ŠคํŠธ: {host}")
        
        if 'hostscript' in nm[host]:
            for script in nm[host]['hostscript']:
                print(f"\n์Šคํฌ๋ฆฝํŠธ: {script['id']}")
                print(f"๊ฒฐ๊ณผ:\n{script['output']}")
    
    print("=" * 70)

# ์‚ฌ์šฉ ์˜ˆ์‹œ
if __name__ == "__main__":
    target = "scanme.nmap.org"
    
    # ๊ธฐ๋ณธ ์Šค์บ”
    nm = advanced_nmap_scan(target, '22,80,443')
    
    # ์ทจ์•ฝ์  ์Šค์บ” (์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆผ)
    # nmap_vulnerability_scan(target)
โš ๏ธ python-nmap ์„ค์น˜

pip install python-nmap

์‹œ์Šคํ…œ์— Nmap์ด ๋จผ์ € ์„ค์น˜๋˜์–ด ์žˆ์–ด์•ผ ํ•ด!

๐Ÿ’ก ์‹ค์ „ ํ™œ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค

์ด์ œ ์‹ค์ œ๋กœ ์–ด๋–ค ์ƒํ™ฉ์—์„œ ํฌํŠธ ์Šค์บ๋„ˆ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”์ง€ ๋ช‡ ๊ฐ€์ง€ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์‚ดํŽด๋ณด์ž! ์‹ค๋ฌด์—์„œ ์ •๋ง ์œ ์šฉํ•˜๊ฒŒ ์“ฐ์ด๋Š” ๊ฒฝ์šฐ๋“ค์ด์•ผ. ๐ŸŽฏ

๐Ÿข ์‹œ๋‚˜๋ฆฌ์˜ค 1: ์‹ ๊ทœ ์„œ๋ฒ„ ๋ฐฐํฌ ์ „ ๋ณด์•ˆ ์ ๊ฒ€

์ƒˆ๋กœ์šด ์›น ์„œ๋ฒ„๋ฅผ ๋ฐฐํฌํ•˜๊ธฐ ์ „์— ๋ณด์•ˆ ์ ๊ฒ€์„ ํ•ด์•ผ ํ•ด. ๋ถˆํ•„์š”ํ•œ ํฌํŠธ๊ฐ€ ์—ด๋ ค์žˆ๋Š”์ง€, ์ทจ์•ฝํ•œ ์„œ๋น„์Šค๊ฐ€ ์‹คํ–‰ ์ค‘์ธ์ง€ ํ™•์ธํ•˜๋Š” ๊ฑฐ์ง€.

def pre_deployment_check(server_ip):
    """
    ๋ฐฐํฌ ์ „ ๋ณด์•ˆ ์ ๊ฒ€
    """
    print("๐Ÿš€ ๋ฐฐํฌ ์ „ ๋ณด์•ˆ ์ ๊ฒ€ ์‹œ์ž‘")
    print("=" * 70)
    
    # 1. ์ „์ฒด ํฌํŠธ ์Šค์บ”
    print("\n[1๋‹จ๊ณ„] ์ „์ฒด ํฌํŠธ ์Šค์บ”")
    scanner = NetworkSecurityScanner(server_ip, range(1, 65536), threads=500)
    scanner.run_port_scan()
    
    # 2. ํ•„์ˆ˜ ํฌํŠธ๋งŒ ์—ด๋ ค์žˆ๋Š”์ง€ ํ™•์ธ
    required_ports = {80, 443}  # ์›น ์„œ๋ฒ„
    allowed_ports = {22, 80, 443}  # SSH, HTTP, HTTPS
    
    print("\n[2๋‹จ๊ณ„] ํฌํŠธ ์ •์ฑ… ๊ฒ€์ฆ")
    unexpected_ports = set(scanner.open_ports) - allowed_ports
    
    if unexpected_ports:
        print(f"[!] ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ํฌํŠธ ๋ฐœ๊ฒฌ: {unexpected_ports}")
        print("    โ†’ ์ด ํฌํŠธ๋“ค์„ ๋‹ซ๊ฑฐ๋‚˜ ๋ฐฉํ™”๋ฒฝ์œผ๋กœ ์ฐจ๋‹จํ•˜์„ธ์š”!")
    else:
        print("[+] ๋ชจ๋“  ํฌํŠธ๊ฐ€ ์ •์ฑ…์— ๋ถ€ํ•ฉํ•ฉ๋‹ˆ๋‹ค.")
    
    missing_ports = required_ports - set(scanner.open_ports)
    if missing_ports:
        print(f"[!] ํ•„์ˆ˜ ํฌํŠธ๊ฐ€ ์—ด๋ ค์žˆ์ง€ ์•Š์Œ: {missing_ports}")
    else:
        print("[+] ๋ชจ๋“  ํ•„์ˆ˜ ํฌํŠธ๊ฐ€ ์—ด๋ ค์žˆ์Šต๋‹ˆ๋‹ค.")
    
    # 3. ์„œ๋น„์Šค ๋ฒ„์ „ ํ™•์ธ
    print("\n[3๋‹จ๊ณ„] ์„œ๋น„์Šค ๋ฒ„์ „ ํ™•์ธ")
    scanner.detect_services()
    
    # 4. ์ทจ์•ฝ์  ๊ฒ€์‚ฌ
    print("\n[4๋‹จ๊ณ„] ์ทจ์•ฝ์  ๊ฒ€์‚ฌ")
    scanner.check_vulnerabilities()
    
    # 5. ์ตœ์ข… ํŒ์ •
    print("\n" + "=" * 70)
    if not unexpected_ports and not missing_ports and not scanner.vulnerabilities:
        print("โœ… ๋ฐฐํฌ ์Šน์ธ: ๋ณด์•ˆ ์ ๊ฒ€ ํ†ต๊ณผ!")
    else:
        print("โŒ ๋ฐฐํฌ ๋ณด๋ฅ˜: ๋ณด์•ˆ ์ด์Šˆ ํ•ด๊ฒฐ ํ•„์š”!")
    print("=" * 70)

# ์‹คํ–‰
pre_deployment_check("192.168.1.100")

๐Ÿ”„ ์‹œ๋‚˜๋ฆฌ์˜ค 2: ์ •๊ธฐ ๋ณด์•ˆ ์ ๊ฒ€ ์ž๋™ํ™”

๋งค์ฃผ ๋˜๋Š” ๋งค๋‹ฌ ์ •๊ธฐ์ ์œผ๋กœ ๋„คํŠธ์›Œํฌ๋ฅผ ์Šค์บ”ํ•ด์„œ ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ•˜๊ณ  ๋ณด๊ณ ์„œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฑฐ์•ผ.

import json
from datetime import datetime
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

def scheduled_security_scan(targets, baseline_file='baseline.json'):
    """
    ์ •๊ธฐ ๋ณด์•ˆ ์Šค์บ” ๋ฐ ๋ณ€ํ™” ๊ฐ์ง€
    """
    print("๐Ÿ“… ์ •๊ธฐ ๋ณด์•ˆ ์Šค์บ” ์‹œ์ž‘")
    print(f"์‹œ๊ฐ„: {datetime.now()}")
    print("=" * 70)
    
    # ๊ธฐ์ค€์„  ๋กœ๋“œ
    try:
        with open(baseline_file, 'r') as f:
            baseline = json.load(f)
    except FileNotFoundError:
        baseline = {}
        print("[*] ๊ธฐ์ค€์„  ํŒŒ์ผ์ด ์—†์Šต๋‹ˆ๋‹ค. ์ƒˆ๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.")
    
    changes = []
    current_state = {}
    
    for target in targets:
        print(f"\n[*] {target} ์Šค์บ” ์ค‘...")
        
        scanner = NetworkSecurityScanner(target, range(1, 1025))
        scanner.run_port_scan()
        scanner.detect_services()
        
        current_state[target] = {
            'open_ports': scanner.open_ports,
            'services': scanner.services,
            'scan_time': datetime.now().isoformat()
        }
        
        # ๋ณ€ํ™” ๊ฐ์ง€
        if target in baseline:
            old_ports = set(baseline[target]['open_ports'])
            new_ports = set(scanner.open_ports)
            
            # ์ƒˆ๋กœ ์—ด๋ฆฐ ํฌํŠธ
            opened = new_ports - old_ports
            if opened:
                changes.append({
                    'target': target,
                    'type': 'NEW_PORTS',
                    'details': f"์ƒˆ๋กœ ์—ด๋ฆฐ ํฌํŠธ: {list(opened)}"
                })
                print(f"[!] ๋ณ€ํ™” ๊ฐ์ง€: ์ƒˆ๋กœ ์—ด๋ฆฐ ํฌํŠธ {opened}")
            
            # ๋‹ซํžŒ ํฌํŠธ
            closed = old_ports - new_ports
            if closed:
                changes.append({
                    'target': target,
                    'type': 'CLOSED_PORTS',
                    'details': f"๋‹ซํžŒ ํฌํŠธ: {list(closed)}"
                })
                print(f"[!] ๋ณ€ํ™” ๊ฐ์ง€: ๋‹ซํžŒ ํฌํŠธ {closed}")
    
    # ํ˜„์žฌ ์ƒํƒœ๋ฅผ ์ƒˆ๋กœ์šด ๊ธฐ์ค€์„ ์œผ๋กœ ์ €์žฅ
    with open(baseline_file, 'w') as f:
        json.dump(current_state, f, indent=2)
    
    # ๋ณ€ํ™”๊ฐ€ ์žˆ์œผ๋ฉด ์•Œ๋ฆผ
    if changes:
        print("\n" + "=" * 70)
        print("โš ๏ธ  ๋ณ€ํ™” ๊ฐ์ง€๋จ!")
        print("=" * 70)
        for change in changes:
            print(f"๋Œ€์ƒ: {change['target']}")
            print(f"์œ ํ˜•: {change['type']}")
            print(f"์ƒ์„ธ: {change['details']}\n")
        
        # ์ด๋ฉ”์ผ ์•Œ๋ฆผ (์„ ํƒ์‚ฌํ•ญ)
        # send_alert_email(changes)
    else:
        print("\nโœ… ๋ณ€ํ™” ์—†์Œ. ๋ชจ๋“  ์‹œ์Šคํ…œ ์ •์ƒ.")
    
    return changes

def send_alert_email(changes):
    """
    ๋ณ€ํ™” ๊ฐ์ง€ ์‹œ ์ด๋ฉ”์ผ ์•Œ๋ฆผ
    """
    sender = "security@company.com"
    receiver = "admin@company.com"
    password = "your_password"
    
    msg = MIMEMultipart()
    msg['From'] = sender
    msg['To'] = receiver
    msg['Subject'] = f"[๋ณด์•ˆ ์•Œ๋ฆผ] ๋„คํŠธ์›Œํฌ ๋ณ€ํ™” ๊ฐ์ง€ - {datetime.now().strftime('%Y-%m-%d')}"
    
    body = "๋„คํŠธ์›Œํฌ ์Šค์บ” ์ค‘ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ณ€ํ™”๊ฐ€ ๊ฐ์ง€๋˜์—ˆ์Šต๋‹ˆ๋‹ค:\n\n"
    for change in changes:
        body += f"๋Œ€์ƒ: {change['target']}\n"
        body += f"์œ ํ˜•: {change['type']}\n"
        body += f"์ƒ์„ธ: {change['details']}\n\n"
    
    msg.attach(MIMEText(body, 'plain'))
    
    try:
        server = smtplib.SMTP('smtp.gmail.com', 587)
        server.starttls()
        server.login(sender, password)
        server.send_message(msg)
        server.quit()
        print("[+] ์•Œ๋ฆผ ์ด๋ฉ”์ผ ์ „์†ก ์™„๋ฃŒ")
    except Exception as e:
        print(f"[!] ์ด๋ฉ”์ผ ์ „์†ก ์‹คํŒจ: {e}")

# ์‹คํ–‰ (cron์œผ๋กœ ์ •๊ธฐ ์‹คํ–‰)
targets = ['192.168.1.1', '192.168.1.100', '192.168.1.200']
scheduled_security_scan(targets)

๐ŸŒ ์‹œ๋‚˜๋ฆฌ์˜ค 3: ์ „์ฒด ๋„คํŠธ์›Œํฌ ์ธ๋ฒคํ† ๋ฆฌ ๊ตฌ์ถ•

๋„คํŠธ์›Œํฌ์— ์–ด๋–ค ์žฅ๋น„๋“ค์ด ์žˆ๊ณ , ๊ฐ๊ฐ ์–ด๋–ค ์„œ๋น„์Šค๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ์žˆ๋Š”์ง€ ํŒŒ์•…ํ•˜๋Š” ๊ฑฐ์•ผ. ๋„คํŠธ์›Œํฌ ๊ด€๋ฆฌ์˜ ๊ธฐ๋ณธ์ด์ง€!

import ipaddress
import concurrent.futures

def discover_network(network_cidr, output_file='network_inventory.json'):
    """
    ๋„คํŠธ์›Œํฌ ์ „์ฒด ์Šค์บ” ๋ฐ ์ธ๋ฒคํ† ๋ฆฌ ๊ตฌ์ถ•
    """
    print(f"๐ŸŒ ๋„คํŠธ์›Œํฌ ํƒ์ƒ‰ ์‹œ์ž‘: {network_cidr}")
    print("=" * 70)
    
    network = ipaddress.ip_network(network_cidr)
    total_hosts = network.num_addresses - 2  # ๋„คํŠธ์›Œํฌ ์ฃผ์†Œ์™€ ๋ธŒ๋กœ๋“œ์บ์ŠคํŠธ ์ œ์™ธ
    
    print(f"์Šค์บ”ํ•  ํ˜ธ์ŠคํŠธ ์ˆ˜: {total_hosts}")
    print("=" * 70 + "\n")
    
    inventory = {}
    active_hosts = []
    
    def ping_host(ip):
        """ํ˜ธ์ŠคํŠธ ํ™œ์„ฑ ์—ฌ๋ถ€ ํ™•์ธ"""
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(0.5)
            result = sock.connect_ex((str(ip), 80))  # HTTP ํฌํŠธ๋กœ ํ…Œ์ŠคํŠธ
            sock.close()
            return str(ip) if result == 0 else None
        except:
            return None
    
    # 1๋‹จ๊ณ„: ํ™œ์„ฑ ํ˜ธ์ŠคํŠธ ์ฐพ๊ธฐ
    print("[1๋‹จ๊ณ„] ํ™œ์„ฑ ํ˜ธ์ŠคํŠธ ํƒ์ƒ‰ ์ค‘...")
    with concurrent.futures.ThreadPoolExecutor(max_workers=100) as executor:
        results = executor.map(ping_host, network.hosts())
        active_hosts = [ip for ip in results if ip]
    
    print(f"[+] {len(active_hosts)}๊ฐœ์˜ ํ™œ์„ฑ ํ˜ธ์ŠคํŠธ ๋ฐœ๊ฒฌ\n")
    
    # 2๋‹จ๊ณ„: ๊ฐ ํ˜ธ์ŠคํŠธ ์ƒ์„ธ ์Šค์บ”
    print("[2๋‹จ๊ณ„] ์ƒ์„ธ ์Šค์บ” ์ง„ํ–‰ ์ค‘...")
    for i, host in enumerate(active_hosts, 1):
        print(f"\n[{i}/{len(active_hosts)}] {host} ์Šค์บ” ์ค‘...")
        
        scanner = NetworkSecurityScanner(host, range(1, 1025), threads=200)
        scanner.run_port_scan()
        scanner.detect_services()
        
        # ํ˜ธ์ŠคํŠธ ์ •๋ณด ์ˆ˜์ง‘
        try:
            hostname = socket.gethostbyaddr(host)[0]
        except:
            hostname = "Unknown"
        
        inventory[host] = {
            'hostname': hostname,
            'open_ports': scanner.open_ports,
            'services': scanner.services,
            'scan_time': datetime.now().isoformat(),
            'os_guess': guess_os(scanner.services)
        }
        
        print(f"  ํ˜ธ์ŠคํŠธ๋ช…: {hostname}")
        print(f"  ์—ด๋ฆฐ ํฌํŠธ: {len(scanner.open_ports)}๊ฐœ")
    
    # 3๋‹จ๊ณ„: ์ธ๋ฒคํ† ๋ฆฌ ์ €์žฅ
    with open(output_file, 'w') as f:
        json.dump(inventory, f, indent=2)
    
    # 4๋‹จ๊ณ„: ์š”์•ฝ ๋ณด๊ณ ์„œ
    print("\n" + "=" * 70)
    print("๐Ÿ“Š ๋„คํŠธ์›Œํฌ ์ธ๋ฒคํ† ๋ฆฌ ์š”์•ฝ")
    print("=" * 70)
    print(f"์ด ํ˜ธ์ŠคํŠธ ์ˆ˜: {len(inventory)}")
    
    # ์„œ๋น„์Šค๋ณ„ ํ†ต๊ณ„
    service_count = {}
    for host_info in inventory.values():
        for service in host_info['services'].values():
            service_count[service] = service_count.get(service, 0) + 1
    
    print("\n์ฃผ์š” ์„œ๋น„์Šค:")
    for service, count in sorted(service_count.items(), key=lambda x: x[1], reverse=True)[:10]:
        print(f"  {service:20s} : {count}๊ฐœ ํ˜ธ์ŠคํŠธ")
    
    print(f"\nโœ… ์ธ๋ฒคํ† ๋ฆฌ๊ฐ€ ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค: {output_file}")
    print("=" * 70)
    
    return inventory

def guess_os(services):
    """์„œ๋น„์Šค ์ •๋ณด๋กœ OS ์ถ”์ธก"""
    services_str = ' '.join(str(s).lower() for s in services.values())
    
    if 'microsoft' in services_str or 'windows' in services_str:
        return "Windows"
    elif 'apache' in services_str or 'nginx' in services_str or 'openssh' in services_str:
        return "Linux/Unix"
    elif 'cisco' in services_str:
        return "Cisco IOS"
    else:
        return "Unknown"

# ์‹คํ–‰
discover_network('192.168.1.0/24')

์ด๋Ÿฐ ์‹œ๋‚˜๋ฆฌ์˜ค๋“ค์€ ์‹ค์ œ ๊ธฐ์—… ํ™˜๊ฒฝ์—์„œ ์ •๋ง ๋งŽ์ด ์‚ฌ์šฉ๋ผ. ํŠนํžˆ ๋ณด์•ˆํŒ€์ด๋‚˜ ์ธํ”„๋ผํŒ€์—์„œ๋Š” ํ•„์ˆ˜์ ์ธ ์ž‘์—…์ด์ง€! ๐Ÿข

โš–๏ธ ๋ฒ•์ ยท์œค๋ฆฌ์  ๊ณ ๋ ค์‚ฌํ•ญ

ํฌํŠธ ์Šค์บ๋‹์€ ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์ง€๋งŒ, ๋ฒ•์ ยท์œค๋ฆฌ์  ์ฑ…์ž„์ด ๋”ฐ๋ผ์™€. ์ž˜๋ชป ์‚ฌ์šฉํ•˜๋ฉด ๋ฒ•์  ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์œผ๋‹ˆ ๊ผญ ์•Œ์•„๋‘ฌ์•ผ ํ•ด! โš ๏ธ

๐Ÿšจ ์ค‘์š”ํ•œ ๋ฒ•์  ์‚ฌํ•ญ

1. ํ—ˆ๊ฐ€๋ฐ›์ง€ ์•Š์€ ์‹œ์Šคํ…œ ์Šค์บ”์€ ๋ถˆ๋ฒ•: ์ž์‹ ์ด ์†Œ์œ ํ•˜๊ฑฐ๋‚˜ ๋ช…์‹œ์  ํ—ˆ๊ฐ€๋ฅผ ๋ฐ›์€ ์‹œ์Šคํ…œ๋งŒ ์Šค์บ”ํ•ด์•ผ ํ•ด

2. ์ •๋ณดํ†ต์‹ ๋ง๋ฒ• ์œ„๋ฐ˜ ๊ฐ€๋Šฅ: ๋ฌด๋‹จ ์นจ์ž… ์‹œ๋„๋กœ ๊ฐ„์ฃผ๋  ์ˆ˜ ์žˆ์–ด

3. ์—…๋ฌด๋ฐฉํ•ด์ฃ„ ์ ์šฉ ๊ฐ€๋Šฅ: ๊ณผ๋„ํ•œ ์Šค์บ”์œผ๋กœ ์„œ๋น„์Šค์— ์˜ํ–ฅ์„ ์ฃผ๋ฉด ์ฒ˜๋ฒŒ๋ฐ›์„ ์ˆ˜ ์žˆ์–ด

4. ํšŒ์‚ฌ ์ •์ฑ… ์ค€์ˆ˜: ํšŒ์‚ฌ ๋„คํŠธ์›Œํฌ๋ฅผ ์Šค์บ”ํ•  ๋•Œ๋Š” ๋ฐ˜๋“œ์‹œ ๋ณด์•ˆํŒ€์˜ ์Šน์ธ์„ ๋ฐ›์•„์•ผ ํ•ด
โœ… ์•ˆ์ „ํ•˜๊ฒŒ ์—ฐ์Šตํ•˜๋Š” ๋ฐฉ๋ฒ•

โ€ข ์ž์‹ ์˜ ๋กœ์ปฌ ํ™˜๊ฒฝ: 127.0.0.1์ด๋‚˜ ์ž์‹ ์˜ PC/์„œ๋ฒ„
โ€ข ๊ฐ€์ƒ ๋จธ์‹ : VirtualBox, VMware ๋“ฑ์œผ๋กœ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ ๊ตฌ์ถ•
โ€ข ๊ณต๊ฐœ ํ…Œ์ŠคํŠธ ์„œ๋ฒ„: scanme.nmap.org (Nmap ๊ณต์‹ ํ…Œ์ŠคํŠธ ์„œ๋ฒ„)
โ€ข HackTheBox, TryHackMe: ํ•ฉ๋ฒ•์ ์ธ ํ•ดํ‚น ์—ฐ์Šต ํ”Œ๋žซํผ
โ€ข ์ž์‹ ์˜ ํด๋ผ์šฐ๋“œ ์ธ์Šคํ„ด์Šค: AWS, GCP ๋“ฑ์—์„œ ์ƒ์„ฑํ•œ ์ธ์Šคํ„ด์Šค

ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์‹ค๋ ฅ์„ ํ‚ค์šฐ๊ณ  ์‹ถ๋‹ค๋ฉด ์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ ์ „๋ฌธ๊ฐ€๋“ค๊ณผ ๊ต๋ฅ˜ํ•˜๋ฉด์„œ ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•์„ ๋ฐฐ์šฐ๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ด์•ผ! ๐Ÿ’ก

๐ŸŽ“ ๋” ๊ณต๋ถ€ํ•˜๋ฉด ์ข‹์€ ๊ฒƒ๋“ค

ํฌํŠธ ์Šค์บ๋‹์„ ๋งˆ์Šคํ„ฐํ–ˆ๋‹ค๋ฉด, ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ๋‚˜์•„๊ฐˆ ์‹œ๊ฐ„์ด์•ผ! ๋„คํŠธ์›Œํฌ ๋ณด์•ˆ์€ ์ •๋ง ๋„“๊ณ  ๊นŠ์€ ๋ถ„์•ผ๊ฑฐ๋“ . ๐ŸŒŠ

๐Ÿ“š ์ถ”์ฒœ ํ•™์Šต ์ฃผ์ œ

1. ํŒจํ‚ท ๋ถ„์„: Wireshark, tcpdump๋กœ ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ ๋ถ„์„
2. ์ทจ์•ฝ์  ์Šค์บ๋‹: OpenVAS, Nessus ๊ฐ™์€ ์ „๋ฌธ ๋„๊ตฌ
3. ์นจํˆฌ ํ…Œ์ŠคํŒ…: Metasploit Framework ํ™œ์šฉ
4. ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ณด์•ˆ: OWASP Top 10, Burp Suite
5. ๋„คํŠธ์›Œํฌ ํ”„๋กœํ† ์ฝœ: TCP/IP, HTTP, SSL/TLS ๊นŠ์ด ์ดํ•ด
6. ๋ฐฉํ™”๋ฒฝ/IDS/IPS: Snort, Suricata ์„ค์ • ๋ฐ ์šด์˜
7. ๋ณด์•ˆ ์ธ์ฆ: CEH, OSCP, CISSP ๋“ฑ
8. ํด๋ผ์šฐ๋“œ ๋ณด์•ˆ: AWS, Azure, GCP ๋ณด์•ˆ ์„ค์ •

๐Ÿ“– ์ถ”์ฒœ ๋„์„œ ๋ฐ ๋ฆฌ์†Œ์Šค

โ€ข "Nmap Network Scanning" - Gordon Lyon (Nmap ์ฐฝ์‹œ์ž)
โ€ข "The Web Application Hacker's Handbook" - Dafydd Stuttard
โ€ข "Metasploit: The Penetration Tester's Guide"
โ€ข OWASP ๊ณต์‹ ๋ฌธ์„œ: https://owasp.org
โ€ข Hack The Box: https://www.hackthebox.com
โ€ข TryHackMe: https://tryhackme.com
โ€ข SecurityTube: ๋ฌด๋ฃŒ ๋ณด์•ˆ ๊ต์œก ์˜์ƒ

๐ŸŽฌ ๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ

์ž, ์—ฌ๊ธฐ๊นŒ์ง€ ํฌํŠธ ์Šค์บ๋„ˆ์™€ ๋„คํŠธ์›Œํฌ ๋ณด์•ˆ ์ ๊ฒ€์— ๋Œ€ํ•ด ์•Œ์•„๋ดค์–ด! ๐ŸŽ‰ ๊ธฐ๋ณธ ๊ฐœ๋…๋ถ€ํ„ฐ ์‹ค์ „ ์†Œ์Šค์ฝ”๋“œ, ๊ทธ๋ฆฌ๊ณ  ์‹ค๋ฌด ํ™œ์šฉ๊นŒ์ง€ ์ •๋ง ๋งŽ์€ ๋‚ด์šฉ์„ ๋‹ค๋ค˜์ง€?

ํฌํŠธ ์Šค์บ๋‹์€ ๋„คํŠธ์›Œํฌ ๋ณด์•ˆ์˜ ์‹œ์ž‘์ ์ด์•ผ. ์ด๊ฑธ ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜๋ฉด ์‹œ์Šคํ…œ์˜ ๋ณด์•ˆ ์ƒํƒœ๋ฅผ ํŒŒ์•…ํ•˜๊ณ , ์ทจ์•ฝ์ ์„ ์ฐพ์•„๋‚ด๊ณ , ์ ์ ˆํ•œ ๋Œ€์‘์„ ํ•  ์ˆ˜ ์žˆ์–ด. ํ•˜์ง€๋งŒ ํ•ญ์ƒ ๊ธฐ์–ตํ•ด์•ผ ํ•  ๊ฑด, ์ด ๊ธฐ์ˆ ์€ ๋ฐฉ์–ด๋ฅผ ์œ„ํ•œ ๊ฒƒ์ด๋ผ๋Š” ๊ฑฐ์•ผ! ๐Ÿ›ก๏ธ

์˜ค๋Š˜ ๋ฐฐ์šด ๋‚ด์šฉ๋“ค์„ ์‹ค์Šตํ•ด๋ณด๋ฉด์„œ ๋„คํŠธ์›Œํฌ ๋ณด์•ˆ์— ๋Œ€ํ•œ ์ดํ•ด๋ฅผ ๊นŠ๊ฒŒ ๋งŒ๋“ค์–ด๋ด. ๊ทธ๋ฆฌ๊ณ  ๊ถ๊ธˆํ•œ ๊ฒŒ ์žˆ๊ฑฐ๋‚˜ ๋” ๋ฐฐ์šฐ๊ณ  ์‹ถ๋‹ค๋ฉด, ๋ณด์•ˆ ์ปค๋ฎค๋‹ˆํ‹ฐ๋‚˜ ์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ ์ „๋ฌธ๊ฐ€๋“ค๊ณผ ์†Œํ†ตํ•˜๋Š” ๊ฒƒ๋„ ์žŠ์ง€ ๋งˆ! ๐Ÿ’ฌ

๐Ÿš€ ๋‹ค์Œ ๋‹จ๊ณ„๋กœ!

1. ์˜ค๋Š˜ ๋ฐฐ์šด ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ์‹คํ–‰ํ•ด๋ณด๊ธฐ
2. ์ž์‹ ์˜ ๋กœ์ปฌ ํ™˜๊ฒฝ์—์„œ ํ…Œ์ŠคํŠธํ•˜๊ธฐ
3. ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๊ณ  ๊ธฐ๋Šฅ ์ถ”๊ฐ€ํ•ด๋ณด๊ธฐ
4. ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•ด๋ณด๊ธฐ
5. ๋ณด์•ˆ ์ปค๋ฎค๋‹ˆํ‹ฐ์— ์ฐธ์—ฌํ•˜๊ธฐ

๋„คํŠธ์›Œํฌ ๋ณด์•ˆ์€ ๋์—†์ด ์ง„ํ™”ํ•˜๋Š” ๋ถ„์•ผ์•ผ. ์ƒˆ๋กœ์šด ๊ณต๊ฒฉ ๊ธฐ๋ฒ•์ด ๋‚˜์˜ค๋ฉด ์ƒˆ๋กœ์šด ๋ฐฉ์–ด ๊ธฐ๋ฒ•๋„ ๋‚˜์˜ค๊ณ , ๊ทธ ๋ฐ˜๋Œ€๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ง€. ๊ณ„์† ๊ณต๋ถ€ํ•˜๊ณ  ์‹ค์Šตํ•˜๋ฉด์„œ ์‹ค๋ ฅ์„ ํ‚ค์›Œ๋‚˜๊ฐ€์ž! ๐Ÿ’ช

๋งˆ์ง€๋ง‰์œผ๋กœ, ์ด ๊ธ€์ด ๋„์›€์ด ๋˜์—ˆ๋‹ค๋ฉด ์ฃผ๋ณ€ ๊ฐœ๋ฐœ์ž ์นœ๊ตฌ๋“ค์—๊ฒŒ๋„ ๊ณต์œ ํ•ด์ค˜. ํ•จ๊ป˜ ์„ฑ์žฅํ•˜๋Š” ๊ฒŒ ์ œ์ผ ์ค‘์š”ํ•˜๋‹ˆ๊นŒ! ๊ทธ๋ฆฌ๊ณ  ์งˆ๋ฌธ์ด๋‚˜ ํ”ผ๋“œ๋ฐฑ์ด ์žˆ๋‹ค๋ฉด ์–ธ์ œ๋“  ํ™˜์˜์ด์•ผ. ๐Ÿ˜Š

๊ทธ๋Ÿผ ์•ˆ์ „ํ•˜๊ณ  ์ฆ๊ฑฐ์šด ์ฝ”๋”ฉ ๋˜๊ธธ ๋ฐ”๋ผ! ํ•ดํ”ผ ํ•ดํ‚น! ๐ŸŽฏ๐Ÿ”

Happy Hacking! Stay Safe, Stay Secure ๐Ÿ” Scan ๐Ÿ›ก๏ธ Protect ๐Ÿš€ Secure
๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0