실행을 할 경우 본인이 실행되는 시간 동안 시스템에서 돌아다녔던 packet들에 대한 정보를 전부 분석한다. 이 때 실행되는 동안 특정 조건을 만족하는 packet들에 대해서만 정보를 얻도록 설정하는 것도 가능하다.
저장 기능을 통해 (-w
) 나중에 분석을 하는 것도 가능하다.
보통 기본적으로 설치가 되어 있다. Ubuntu의 경우 22.03 기준 기본으롯 설치가 되어 있으며 확인을 하고싶으면 which
를 사용해서 어디에 설치되어있는지 보도록 하자.
보통 실행하려면 관리자 권한이 필요하다.
tcpdump
로도 이를 파악하는게 가능하다. -D
option을 사용하면 된다.$ tcpdump -D
1.eth0 [Up, Running, Connected]
2.any (Pseudo-device that captures on all interfaces) [Up, Running]
3.lo [Up, Running, Loopback]
4.bluetooth-monitor (Bluetooth Linux Monitor) [Wireless]
5.nflog (Linux netfilter log (NFLOG) interface) [none]
6.nfqueue (Linux netfilter queue (NFQUEUE) interface) [none]
7.dbus-system (D-Bus system bus) [none]
8.dbus-session (D-Bus session bus) [none]
특정 인터페이스의 packet을 탐지하게 하고 싶으면 --interface
를 사용하면 된다. 만약 이게 주어지지 않고 -d
가 주어지지 않으면, 저 -D
에서 나온 인터페이스들 중 lo
가 아닌 가장 상위 인터페이스를 사용한다. 이는 보통 위처럼 eth0
이 된다.
모든 인터페이스에 대해 탐지를 할거면 특정 MacOS, Linux, Solaris의 경우 any
를 사용하면 된다.
$ sudo tcpdump --interface=any
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
16:51:27.061243 lo In IP localhost.34821 > localhost.38184: Flags [P.], seq 3130648948:3130649199, ack 1141574278, win 512, options [nop,nop,TS val 3018721591 ecr 3018721531], length 251
16:51:27.061267 lo In IP localhost.38184 > localhost.34821: Flags [.], ack 251, win 24571, options [nop,nop,TS val 3018721591 ecr 3018721545], length 0
16:51:27.083105 lo In IP localhost.34821 > localhost.38184: Flags [P.], seq 251:476, ack 1, win 512, options [nop,nop,TS val 3018721612 ecr 3018721591], length 225
16:51:27.086212 lo In IP localhost.38186 > localhost.34821: Flags [P.], seq 2036841800:2036842060, ack 561355744, win 512, options [nop,nop,TS val 3018721615 ecr 3018721550], length 260
16:51:27.088033 lo In IP localhost.34821 > localhost.38186: Flags [P.], seq 1:39, ack 260, win 24571, options [nop,nop,TS val 3018721617 ecr 3018721615], length 38
...
16:51:28.853172 lo In IP localhost.38184 > localhost.34821: Flags [.], ack 11202, win 24571, options [nop,nop,TS val 3018723382 ecr 3018723382], length 0
^C
59 packets captured
132 packets received by filter
0 packets dropped by kernel
16:51:27.061243 lo In IP localhost.34821 > localhost.38184: Flags [P.], seq 3130648948:3130649199, ack 1141574278, win 512, options [nop,nop,TS val 3018721591 ecr 3018721531], length 251
16:51:27.061243
: 해당 packet을 인터페이스에서 받은 시간. 시:분:초
형식이다.lo
: 인터페이스 이름IP
: IPv4. IPv6인 경우 IP6
라고 나온다.localhost.34821 > localhost.38184
: (발신 ip 주소).(발신 port 번호) > (수신 ip 주소).(수신 port 번호)Flags [...]
: TCP flag. 보통 다음이 가능하며 밑이 여러개가 섞일 수도 있다.S
: SYN type. 연결 시작때 보통 쓰인다.F
: FIN type. 연결 종료때 보통 쓰인다.P
: PUSH type. 전송된 data가 버퍼에 들어가지 않고 즉시 상위 애플리케이션에게 전달되어야 하는 경우 쓰인다.R
: RST type. 연결을 강제로 끊을 때 쓰인다. 자세한 내용은 이 글 참고.
: ACK type. acknowledgement를 나타낸다.seq
: packet 안의 sequence number. 위와 같은 경우인, tcpdump의 해당 connection의 첫 packet 같은 경우에는 실제값을 출력을 하나, 이후 같은 연결에 대해서 packet이 등장할 경우 그 값을 기준으로 상대적인 sequence number을 출력한다. 예를들어 다음이 seq 251:650
인 경우, 위의 실제 값의 시작 부분에 251을 더한거랑 650을 더한것의 byte를 담은 packet이라는 것을 의미한다.win
: window size. 수신 측 buffer 크기를 담고 있다.options
: TCP에서 설정할 수 있는 option들에 대한 정보다. 여러개가 가능한데 (MSS, Window Scale, Selective ACK permitted, Selective ACK) 위 예시의 경우 TS
, 즉 timestamp만 나와 있다. nop
는 주로 padding 용도. Timestamp는 처음은 본인이 보낸 시간, 그 다음 ecr
는 마지막으로 어딘가에서 packet을 받은 시간이다.length
: "payload"의 길이다. packet의 길이가 아니다. sequence number의 두 차이랑 같아야 한다.tcpdump
를 종료할지를 정할 때 쓰인다. 밑의 경우 5개의 packet까지만을 탐지하고 tcpdump를 종료했다.$ sudo tcpdump --interface=any -c 5
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
16:56:20.342894 lo In IP localhost.34821 > localhost.38184: Flags [P.], seq 3130790748:3130790999, ack 1141595685, win 512, options [nop,nop,TS val 3019014872 ecr 3019014762], length 251
16:56:20.363787 lo In IP localhost.34821 > localhost.38184: Flags [P.], seq 251:491, ack 1, win 512, options [nop,nop,TS val 3019014893 ecr 3019014762], length 240
16:56:20.363886 lo In IP localhost.38184 > localhost.34821: Flags [.], ack 491, win 24571, options [nop,nop,TS val 3019014893 ecr 3019014872], length 0
16:56:20.390722 lo In IP localhost.34821 > localhost.38184: Flags [P.], seq 491:630, ack 1, win 512, options [nop,nop,TS val 3019014920 ecr 3019014893], length 139
16:56:20.394793 lo In IP localhost.38186 > localhost.34821: Flags [P.], seq 2036929641:2036929707, ack 561371280, win 512, options [nop,nop,TS val 3019014924 ecr 3019014766], length 66
5 packets captured
16 packets received by filter
0 packets dropped by kernel
$ sudo tcpdump --interface=any -n -nn -c 5
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
16:58:19.202188 lo In IP 127.0.0.1.34821 > 127.0.0.1.38184: Flags [P.], seq 3130905710:3130905961, ack 1141620564, win 512, options [nop,nop,TS val 3019133731 ecr 3019133674], length 251
16:58:19.202227 lo In IP 127.0.0.1.38184 > 127.0.0.1.34821: Flags [.], ack 251, win 24571, options [nop,nop,TS val 3019133731 ecr 3019133731], length 0
16:58:19.223340 lo In IP 127.0.0.1.34821 > 127.0.0.1.38184: Flags [P.], seq 251:650, ack 1, win 512, options [nop,nop,TS val 3019133753 ecr 3019133731], length 399
16:58:19.223365 lo In IP 127.0.0.1.38184 > 127.0.0.1.34821: Flags [.], ack 650, win 24570, options [nop,nop,TS val 3019133753 ecr 3019133753], length 0
16:58:19.243750 lo In IP 127.0.0.1.34821 > 127.0.0.1.38184: Flags [P.], seq 650:789, ack 1, win 512, options [nop,nop,TS val 3019133773 ecr 3019133753], length 139
5 packets captured
26 packets received by filter
0 packets dropped by kernel
tcpdump의 man page를 보면 맨 마지막에 expression
이라는 항목이 보일 것이다. 그 부분이 무슨 packet을 덤핑할 것인지에 대해 전부 정해지는 식이다.
특정 조건에 맞는 packet에 보통 관심이 있기 때문에, 이 expression
을 어떻게 짜냐가 매우 중요하다. 이에 대해 pcap-filter
이라고 따로 man page가 있다.
구조는 여러개의 primitive들이 combinator (and
, or
)이랑 조합되는 형태로 이루어진다. 이들 중 몇개만 여기서 소개를 한다.
ip proto protocol
이다. 이는 transport layer에서 특정 protocol을 쓰는 IP packet들을 filtering하는 것인데, protocol
에 탐지하고 싶은 transport layer protocol이 들어간다. (ex tcp) 밑은 icmp를 탐지하는 경우다.$ sudo tcpdump -i any -c 5 icmp
[sudo] password for sycho:
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
20:20:26.730932 eth0 Out IP 172.31.115.194 > DESKTOP-AKD4OTF.mshome.net: ICMP 172.31.115.194 udp port 46269 unreachable, length 166
20:20:27.000066 eth0 Out IP 172.31.115.194 > 151.101.194.133: ICMP echo request, id 1, seq 21, length 64
20:20:27.007663 eth0 In IP 151.101.194.133 > 172.31.115.194: ICMP echo reply, id 1, seq 21, length 64
20:20:27.772276 eth0 Out IP 172.31.115.194 > DESKTOP-AKD4OTF.mshome.net: ICMP 172.31.115.194 udp port 58528 unreachable, length 142
20:20:28.789737 eth0 Out IP 172.31.115.194 > DESKTOP-AKD4OTF.mshome.net: ICMP 172.31.115.194 udp port 38239 unreachable, length 166
5 packets captured
8 packets received by filter
0 packets dropped by kernel
pcap-filter
man page를 참고하자.host hostaddr
의 형태를 가지며, hostaddr
에 송신/수신 측 주소를 입력한다. 기본적으로 IPv4랑 IPv6를 전부 탐지해낸다.$ sudo tcpdump -i any -c 5 -nn host 151.101.194.133
[sudo] password for sycho:
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
20:46:44.284328 eth0 Out IP 172.31.115.194 > 151.101.194.133: ICMP echo request, id 2, seq 37, length 64
20:46:44.292413 eth0 In IP 151.101.194.133 > 172.31.115.194: ICMP echo reply, id 2, seq 37, length 64
20:46:45.314569 eth0 Out IP 172.31.115.194 > 151.101.194.133: ICMP echo request, id 2, seq 38, length 64
20:46:45.322961 eth0 In IP 151.101.194.133 > 172.31.115.194: ICMP echo reply, id 2, seq 38, length 64
20:46:46.344901 eth0 Out IP 172.31.115.194 > 151.101.194.133: ICMP echo request, id 2, seq 39, length 64
5 packets captured
6 packets received by filter
0 packets dropped by kerne
src
나 dst
를 사용해 hostaddr
이 송신/수신 주소인 경우에 대해서만 탐지해내는 것이 가능하다.$ sudo tcpdump -i any -c 5 -nn src 151.101.194.133
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
20:51:43.142119 eth0 In IP 151.101.194.133 > 172.31.115.194: ICMP echo reply, id 2, seq 327, length 64
20:51:44.180654 eth0 In IP 151.101.194.133 > 172.31.115.194: ICMP echo reply, id 2, seq 328, length 64
20:51:45.204586 eth0 In IP 151.101.194.133 > 172.31.115.194: ICMP echo reply, id 2, seq 329, length 64
20:51:46.229111 eth0 In IP 151.101.194.133 > 172.31.115.194: ICMP echo reply, id 2, seq 330, length 64
20:51:47.252601 eth0 In IP 151.101.194.133 > 172.31.115.194: ICMP echo reply, id 2, seq 331, length 64
5 packets captured
5 packets received by filter
0 packets dropped by kernel
$ sudo tcpdump src net 151.101.194.0/24
port portnamenum
의 형태를 가진다. portnamenum
에 송신/수신 측 port를 입력한다. 밑은 port 80, 즉 http request/reply에 관한 packet 송수신만 탐지해낸 결과다.$ sudo tcpdump -i any -c 5 -nn port 80
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
20:49:53.909918 eth0 Out IP 172.31.115.194.38966 > 151.101.194.133.80: Flags [S], seq 2582613412, win 64240, options [mss 1460,sackOK,TS val 3747761997 ecr 0,nop,wscale 7], length 0
20:49:53.918037 eth0 In IP 151.101.194.133.80 > 172.31.115.194.38966: Flags [S.], seq 3178615467, ack 2582613413, win 65535, options [mss 1360,sackOK,TS val 1982683470 ecr 3747761997,nop,wscale 9], length 0
20:49:53.918182 eth0 Out IP 172.31.115.194.38966 > 151.101.194.133.80: Flags [.], ack 1, win 502, options [nop,nop,TS val 3747762006 ecr 1982683470], length 0
20:49:53.918289 eth0 Out IP 172.31.115.194.38966 > 151.101.194.133.80: Flags [P.], seq 1:79, ack 1, win 502, options [nop,nop,TS val 3747762006 ecr 1982683470], length 78: HTTP: GET / HTTP/1.1
20:49:53.926792 eth0 In IP 151.101.194.133.80 > 172.31.115.194.38966: Flags [.], ack 79, win 264, options [nop,nop,TS val 1982683478 ecr 3747762006], length 0
5 packets captured
9 packets received by filter
0 packets dropped by kernel
host
와 마찬가지로 src
와 dst
를 이용해서 송신이나 수신 port가 portnamenum
인 경우만을 탐지하는게 가능하다.$ sudo tcpdump -i any -c 5 -nn src port 80
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
20:53:48.671575 eth0 In IP 151.101.194.133.80 > 172.31.115.194.46844: Flags [S.], seq 1625515983, ack 1127016704, win 65535, options [mss 1360,sackOK,TS val 882656498 ecr 3747996751,nop,wscale 9], length 0
20:53:48.680100 eth0 In IP 151.101.194.133.80 > 172.31.115.194.46844: Flags [.], ack 79, win 264, options [nop,nop,TS val 882656507 ecr 3747996759], length 0
20:53:48.680100 eth0 In IP 151.101.194.133.80 > 172.31.115.194.46844: Flags [P.], seq 1:324, ack 79, win 264, options [nop,nop,TS val 882656507 ecr 3747996759], length 323: HTTP: HTTP/1.1 301 Moved Permanently
20:53:48.680100 eth0 In IP 151.101.194.133.80 > 172.31.115.194.46844: Flags [F.], seq 324, ack 79, win 264, options [nop,nop,TS val 882656507 ecr 3747996759], length 0
20:53:48.688162 eth0 In IP 151.101.194.133.80 > 172.31.115.194.46844: Flags [.], ack 80, win 264, options [nop,nop,TS val 882656515 ecr 3747996768], length 0
5 packets captured
5 packets received by filter
0 packets dropped by kernel
$ sudo tcpdump portrange 20-100
$ tcpdump "len > 32 and len < 64"
$ sudo tcpdump -i any -c 5 -nn src port 80 and src 151.101.194.133
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
20:56:47.923128 eth0 In IP 151.101.194.133.80 > 172.31.115.194.34296: Flags [S.], seq 622690809, ack 3966489657, win 65535, options [mss 1360,sackOK,TS val 2364886915 ecr 3748176001,nop,wscale 9], length 0
20:56:47.932117 eth0 In IP 151.101.194.133.80 > 172.31.115.194.34296: Flags [.], ack 79, win 264, options [nop,nop,TS val 2364886924 ecr 3748176011], length 0
20:56:47.932117 eth0 In IP 151.101.194.133.80 > 172.31.115.194.34296: Flags [P.], seq 1:324, ack 79, win 264, options [nop,nop,TS val 2364886924 ecr 3748176011], length 323: HTTP: HTTP/1.1 301 Moved Permanently
20:56:47.932117 eth0 In IP 151.101.194.133.80 > 172.31.115.194.34296: Flags [F.], seq 324, ack 79, win 264, options [nop,nop,TS val 2364886925 ecr 3748176011], length 0
20:56:47.941347 eth0 In IP 151.101.194.133.80 > 172.31.115.194.34296: Flags [.], ack 80, win 264, options [nop,nop,TS val 2364886934 ecr 3748176020], length 0
5 packets captured
11 packets received by filter
괄호를 써서 우선순위 부여를 통해 더 복잡한 식을 만드는것도 가능은 한데, 이 경우 ""
으로 둘러싸야 한다. shell expression이랑 혼동되지 않도록 하기 위해서다.
and
, or
, not
를 가지고 적극적으로 활용해보자. 밑은 icmp
가 아닌, dst
가 192.168.0.0
이고 src
가 192.168.0.1
인 packet들에 대해서만 감지한다.
$ sudo tcpdump dst 192.168.0.0 and src 192.168.0.1 and not icmp
curl
로 간단하게 HTTP request를 한 것에 대한 packet 분석이다.$ sudo tcpdump -i any -c 5 -nn -A src port 80 and src 151.101.194.133
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
21:00:09.613604 eth0 In IP 151.101.194.133.80 > 172.31.115.194.58946: Flags [S.], seq 2940694077, ack 515812285, win 65535, options [mss 1360,sackOK,TS val 2408165261 ecr 3748377692,nop,wscale 9], length 0
E..<..@.8....e....s..P.B.Gn=........-......P...
.....k.\...
21:00:09.621848 eth0 In IP 151.101.194.133.80 > 172.31.115.194.58946: Flags [.], ack 79, win 264, options [nop,nop,TS val 2408165270 ecr 3748377701], length 0
E..4..@.8....e....s..P.B.Gn>........Z......
.....k.e
21:00:09.622331 eth0 In IP 151.101.194.133.80 > 172.31.115.194.58946: Flags [P.], seq 1:324, ack 79, win 264, options [nop,nop,TS val 2408165271 ecr 3748377701], length 323: HTTP: HTTP/1.1 301 Moved Permanently
E..w..@.8....e....s..P.B.Gn>......../......
.....k.eHTTP/1.1 301 Moved Permanently
Connection: close
Content-Length: 0
Server: Varnish
Retry-After: 0
Location: https://opensource.com/
Accept-Ranges: bytes
Date: Sat, 23 Dec 2023 12:00:08 GMT
Via: 1.1 varnish
X-Served-By: cache-icn1450082-ICN
X-Cache: HIT
X-Cache-Hits: 0
Strict-Transport-Security: max-age=300
21:00:09.622331 eth0 In IP 151.101.194.133.80 > 172.31.115.194.58946: Flags [F.], seq 324, ack 79, win 264, options [nop,nop,TS val 2408165271 ecr 3748377701], length 0
E..4..@.8..,.e....s..P.B.Go.........X......
.....k.e
21:00:09.631157 eth0 In IP 151.101.194.133.80 > 172.31.115.194.58946: Flags [.], ack 80, win 264, options [nop,nop,TS val 2408165279 ecr 3748377710], length 0
E..4..@.8..+.e....s..P.B.Go.........X......
.....k.n
5 packets captured
5 packets received by filter
0 packets dropped by kernel
-w
로 내용물을 저장하는게 가능하다. 이 경우 출력이 안 나오게 된다. 저장할 파일의 이름을 -w
옆에 지정해야 한다. 보통 pcap
확장자를 사용하는데, packet capture의 약자다.$ sudo tcpdump -i any -c 5 -nn -w result.pcap src port 80 and src 151.101.194.133
[sudo] password for sycho:
tcpdump: data link type LINUX_SLL2
tcpdump: listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
5 packets captured
5 packets received by filter
0 packets dropped by kernel
-r
을 사용하면 된다.$ sudo tcpdump -r result.pcap
reading from file result.pcap, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144
Warning: interface names might be incorrect
21:05:06.223271 eth0 In IP 151.101.194.133.http > 172.31.115.194.34840: Flags [S.], seq 60975892, ack 997167500, win 65535, options [mss 1360,sackOK,TS val 3732285903 ecr 3748674302,nop,wscale 9], length 0
21:05:06.232467 eth0 In IP 151.101.194.133.http > 172.31.115.194.34840: Flags [.], ack 79, win 264, options [nop,nop,TS val 3732285912 ecr 3748674311], length 0
21:05:06.232468 eth0 In IP 151.101.194.133.http > 172.31.115.194.34840: Flags [P.], seq 1:324, ack 79, win 264, options [nop,nop,TS val 3732285913 ecr 3748674311], length 323: HTTP: HTTP/1.1 301 Moved Permanently
21:05:06.232468 eth0 In IP 151.101.194.133.http > 172.31.115.194.34840: Flags [F.], seq 324, ack 79, win 264, options [nop,nop,TS val 3732285913 ecr 3748674311], length 0
21:05:06.241466 eth0 In IP 151.101.194.133.http > 172.31.115.194.34840: Flags [.], ack 80, win 264, options [nop,nop,TS val 3732285922 ecr 3748674320], length 0
pcap-filter
의 마지막 부분인 expr1 relop expr2
부분을 읽으면 된다.$ sudo tcpdump -r result.pcap "tcp[tcpflags] & (tcp-syn|tcp-fin) != 0"
reading from file result.pcap, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144
Warning: interface names might be incorrect
21:05:06.223271 eth0 In IP 151.101.194.133.http > 172.31.115.194.34840: Flags [S.], seq 60975892, ack 997167500, win 65535, options [mss 1360,sackOK,TS val 3732285903 ecr 3748674302,nop,wscale 9], length 0
21:05:06.232468 eth0 In IP 151.101.194.133.http > 172.31.115.194.34840: Flags [F.], seq 324, ack 79, win 264, options [nop,nop,TS val 3732285913 ecr 3748674311], length 0
-v
, -vv
, -vvv
의 3단계로 output의 verbosity를 나타내는 것이 가능하다. 보통 -v
정도만 해도 TTL이나 IP packet에 있는 option, checksum 확인 등의 여러 기능을 사용하는게 가능하다.
-t
, -tt
, -ttt
, -tttt
, -ttttt
(...) 로 timestamp의 verbosity를 나타내는 것이 가능하다. 기본은 -tttt
다. -t
는 시간을 출력 안한다.
user
, pass
, login
이라는 정보가 들어있는 경우 비밀번호가 돌아다니고 있다고 볼 수 있다. 이런 경우는 방지해야 하기 때문에 해당 경우가 일단 일어나는지를 밑의 command로 판단, 있는 경우 누가 일으키는지를 추적할 필요가 있다.sudo tcpdump -A -i eth0 "port http or port ftp or port telnet" | grep -i 'user\|pass\|login'
sudo tcpdump "tcp[tcpflags] & (tcp-rst) != 0"