[Network] Scapy 모듈
소개
Scapy 는 사용자가 네트워크 패킷을 send, sniff, dissect, forge 할 수 있는 파이썬 프로그램이다. 이 기능을 통해 네트워크를 탐색, 스캔 또는 공격할 수 있는 도구를 구축할 수 있다.
즉, Scapy는 강력한 인터렉티브 패킷 조작 프로그램이다. 그것은 다양한 프로토콜의 패킷을 위조하거나 해독할 수 있고, 그것들을 Network로 보내고, 그것들을 Capture하고, 요청과 응답을 Match시킬 수 있다. 스캐피는 scanning, tracerouting, probing, unit tests, attacks, network discovery와 같은 대부분의 고전적인 작업을 쉽게 처리할 수 있다. 그것은 hping, arpspoof, arp-sk, arping, p0f 그리고 심지어 Nmap, tcpdump, tshark의 일부분을 대체할 수 있다.
또한 Scapy는 다른 tool들이 처리할 수 없는 몇몇 작업도 수행할 수 있다. 예를들면 invalid frame의 전송, 802.11 frame injecting, 혹은 다른 combining 기술들도 말이다.
Scapy의 작동원리는 간단하게 말해 2가지로 이루어져 있다. Packet를 보내고 응답하는 것이 전부이다. Packet의 조합을 정의하고 보낸 다음, 응답을 받고, 응답과 요청을 일치시켜서 다시 보내주는 것이다.
또한 고수준의 함수도 구축이 가능하다. 예를 들어 traceroute후 TTL 요청과 IP source 응답을 결과로 줄 수도 있고, 모든 네트워크에 ping을 보내 응답을 받을 수도 있고, portscan후 LaTeX로 결과를 받을 수도 있다.
기능
- 보내기, 받기, 보내기+받기 모드
- 데이터 링크 계층과 네트워크 계층에 패킷을 보낼 수 있다.
- pof()와 arpchacheposion 같은 몇 개의 고레벨 함수를 갖고 있는데, 이들은 일반적으로 보안 도구들이 하는 대부분의 일을 할 수 있다.
- 응답(response)은 쉽게 분해하고 재사용할 수 있다.
함수
ls()와 lsc()
Net(), IP(), ICMP(), Ether()
ls 함수
Layer에 대한 list를 보여준다.
* ls(TCP): TCP와 관련된 필드를 보여준다.
lsc() 함수
List of command
패킷 디자인
Scapy를 이용하여 마음대로 패킷을 조작할 수 있다.
Each packet is built layer by layer(ex:Ether,IP,TCP,…) 각 패킷은 레이어와 레이어로 만들어진다.
Each layer can be stacked on another 각 레이어는 서로 쌓아 놓을 수 있다.
Each layer or packet can be manipulated 각 레이어 또는 패킷은 조작할 수 있다.
Each field has working default values 각 필드는 기본값으로 작동한다.
Each field can contain a value or a set of values 각 필드는 1개의 값이나 1세트의 값을 가진다.
Quick demo
>>> IP()
<IP |>
>>> target= "192.168.0.64"
>>> ip = IP(dst=target)
>>> ip
<IP dst=192.168.0.64 |>
>>> [p for p in ip]
[<IP dst=192.168.0.64 |>]
>>> ip.dst
'192.168.0.64'
>>> ip.ttl
64
>>> ip.display()
###[ IP ]###
version= 4
ihl= None
tos= 0x0
len= None
id= 1
flags=
frag= 0
ttl= 64
proto= hopopt
chksum= None
src= 192.168.0.19
dst= 192.168.0.64
\options\
sniff() 함수를 이용한 패킷덤프
>>> a = sniff()
>>> a.display()
0000 Ether / IP / TCP 192.168.0.64:54273 > 192.168.0.19:ssh A / Padding
0001 Ether / ARP who has 192.168.0.9 says 192.168.0.1
show() 함수
캡쳐한 패킷의 상세정보를 볼 수 있다.
>>> a[0].show()
###[ Ethernet ]###
dst= b8:27:eb:69:82:92
src= 0c:9d:92:79:33:31
type= 0x800
###[ IP ]###
version= 4
ihl= 5
tos= 0x0
len= 40
id= 51101
flags= DF
frag= 0
ttl= 128
proto= tcp
chksum= 0xb18e
src= 192.168.0.64
dst= 192.168.0.19
\options\
###[ TCP ]###
sport= 54273
dport= ssh
seq= 4115435684L
ack= 60161172
dataofs= 5
reserved= 0
flags= A
window= 511
chksum= 0xd1fe
urgptr= 0
options= []
###[ Padding ]###
load= '\x00\x00\x00\x00\x00\x00'
Stacking layers
함수 여러 개를 묶어서 사용할 수 있다. 인자로는 “/”를 사용한다.
>>> IP()
<IP |>
>>> IP()/TCP() // 2개 Stacking, 하위계층 함수가 먼너 나온다.
<IP frag=0 proto=TCP |<TCP |>>
>>> Ether()/IP()/TCP() // 3개 Stacking, Ether가 가장 하위이므로 먼저 나온다.
<Ether type=0x800 |<IP frag=0 proto=TCP |<TCP |>>>
>>> IP()/TCP()/"GET / HTTP/1.0\r\n\r\n" // 웹 GET으로 홈피를 긁어온다.
<IP frag=0 proto=TCP |<TCP |<Raw load=’GET / HTTP/1.0\r\n\r\n’ |>>>
>>> Ether()/IP()/IP()/UDP()
<Ether type=0x800 |<IP frag=0 proto=IP |<IP frag=0 proto=UDP |<UDP |>>>>
>>> IP(proto=55)/TCP()
<IP frag=0 proto=55 |<TCP |>>
패킷 발생 및 전송하기
>>> ipk = IP(dst="192.168.0.64")
>>> send(ipk)
.
Sent 1 packets.
>>> add = "192.168.0.64"
>>> ipk = IP(dst=add)
>>> send(ipk/ICMP())
.
Sent 1 packets.
fuzz()
디폴트 값을 랜덤 값으로 바꾸도록 fuzzy 계층에 하나의 계층을 전송한다.
>>> send(IP(src="1.1.1.1",dst="192.168.0.64")/fuzz(UDP()/NTP(version=4)),loop=1) // loop = 1 : 계속해서 패킷을 발생, dst은 패킷을 계속 받고 처리를 해야되기 때문에 트래픽이 올라간다.
..................................................^C
Sent 50 packets.
sr() 함수
send() 함수는 패킷 전송만 하는 반면 sr() 함수는 패킷을 전송하고 이에 대한 응답을 받는다. sr1()은 전송된 패킷에 대해 최초 응답만을 받는다.
Port scanning
목적지 호스트 포트를 스캐닝할 수 있다. 다양한 플래그(Syn, Ack, Fin 등)를 조합하여 결과값을 받을 수 있다. 만일 SYN 플래그를 이용하여 특정 포트를 스캐닝할 경우 스캐닝 대상 호스트의 포트가 열려 있다면 Syn, Ack 신호를 받을 것이다.
Sniffing 패킷 훔쳐보기
>>> a = sniff(filter="host 192.168.0.64 and not udp", count=10)
// 캡쳐수는 2개, udp 제외
>>> a.summary()
Ether / IP / TCP 192.168.0.64:50384 > 192.168.0.19:ssh A / Padding
Ether / ARP who has 192.168.0.9 says 192.168.0.1
>>> sniff(iface="wifi0", prn=lambdax:x.summary())
패킷을 loop로 보내고 받기
loop=1 이라는 옵션을 이용하면 패킷을 계속 보낼 수 있다. srloop() 함수를 이용하면 패킷을 계속해서 보내고 받을 수 있다.
>>> srloop(IP(dst=dst1)/TCP())
패킷 분석
tcpdump를 이용하여 패킷을 캡쳐했다면 이를 가지고 패킷을 분석할 수 있다.
>>> tcpdump -i eth1 -n -s 0 -c 1 -xX host 192.168.0.64
>>> IP(import_hexcap()) // 헥사코드 값을 변환시킨다.
>>> _.show() // 수집된 패킷을 보다 보기 쉽게 하기 위한 함수
패킷 모니터링
Wireshark를 이용하면 된다.
윈도우에서의 예시
- 유용한 필터링 식
eth.addr == 00:3f:1e:00:00:23 //출발지나 목적지 MAC 주소로 검색
ip.addr == 192.168.0.2 // 출발지나 목적지 IP주소로 검색
tcp.port == 3306 // TCP 출발지나 목적지 포트 번호로 검색
ip.src != 10.1.2.3 // 출발지 IP주소가 해당 IP주소가 아닌것 검색
eth.dst == 00:3f:1e:00:00:23 // 목적지 MAC주소 검색