-
Notifications
You must be signed in to change notification settings - Fork 0
Hack tcpdump and beyond
$ sudo apt-get update
$ sudo apt-get install -y tcpdump
$ sudo port install tcpdump
simple_tcp_svr.c
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 18989
int
main() {
int svr_socket, cli_conn, svr_cnt, reuse;
socklen_t len;
struct sockaddr_in svr_addr, cli_addr;
svr_socket = socket(AF_INET, SOCK_STREAM, 0);
if (svr_socket < 0) {
fprintf(stderr, "Failed to create server-side socket\n");
exit(-1);
}
reuse = 1;
if (setsockopt(svr_socket, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuse, sizeof(reuse)) == -1) {
fprintf(stderr, "Server-side socket failed to set option SO_REUSEADDR\n");
exit(-1);
}
#ifdef SO_REUSEPORT
if (setsockopt(svr_socket, SOL_SOCKET, SO_REUSEPORT, (const char *)&reuse, sizeof(reuse)) == -1) {
fprintf(stderr, "Server-side socket failed to set option SO_REUSEPORT\n");
exit(-1);
}
#endif
bzero(&svr_addr, sizeof(svr_addr));
svr_addr.sin_family = AF_INET;
svr_addr.sin_addr.s_addr = htonl(INADDR_ANY);
svr_addr.sin_port = htons(PORT);
if (bind(svr_socket, (struct sockaddr *)&svr_addr, sizeof(svr_addr)) == -1) {
fprintf(stderr, "Server-side socket failed to bind\n");
exit(-1);
}
if (listen(svr_socket, 5) == -1) {
fprintf(stderr, "Server-side socket failed to listen\n");
exit(-1);
}
len = sizeof(cli_addr);
svr_cnt = 0;
for (;;) {
if (svr_cnt == 100) {
break;
}
printf("Waiting for client connection ...\n");
cli_conn = accept(svr_socket, (struct sockaddr *)&cli_addr, &len);
if (cli_conn < 0) {
fprintf(stderr, "Server-side socket failed to accept\n");
exit(-1);
}
printf("Connected by %d:%d\n", cli_addr.sin_addr.s_addr, cli_addr.sin_port);
svr_cnt++;
shutdown(cli_conn, SHUT_RDWR);
close(cli_conn);
};
close(svr_socket);
}
simple_tcp_cli.c
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
int
main() {
int cli_socket, n;
struct sockaddr_in svr_addr;
cli_socket = socket(AF_INET, SOCK_STREAM, 0);
if (cli_socket < 0) {
fprintf(stderr, "Failed to create client-side socket\n");
exit(-1);
}
bzero(&svr_addr, sizeof(svr_addr));
svr_addr.sin_family = AF_INET;
svr_addr.sin_addr.s_addr = inet_addr("10.151.3.111");
svr_addr.sin_port = htons(18989);
if (connect(cli_socket, (struct sockaddr *)&svr_addr, sizeof(svr_addr)) == -1) {
fprintf(stderr, "Client-side socket failed to connect\n");
exit(-1);
}
for (;;) {
char buff[512];
bzero(buff, sizeof(buff));
if ((n = read(cli_socket, buff, sizeof(buff))) == 0) {
break;
}
}
close(cli_socket);
}
tcp_svr.py
# -*- coding: utf-8 -*-
import socket
from time import gmtime, strftime
if __name__ == "__main__":
HOST = "0.0.0.0"
PORT = 18989
svr_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
svr_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
svr_socket.bind((HOST, PORT))
svr_socket.listen(5)
srv_cnt = 0
while 1:
if srv_cnt == 100:
break
print("Waiting for client connection ...")
conn, addr = svr_socket.accept()
conn.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
print("Connected by", addr)
srv_cnt += 1
with conn:
while 1:
try:
data = conn.recv(512)
except ConnectionResetError as e:
print("Client connection closed")
break
if len(data) == 0:
conn.shutdown(socket.SHUT_RDWR)
while conn.recv(512):
pass
conn.close()
break
else:
msg = data.decode("utf-8", errors="ignore").strip()
if msg == "exit" or msg == "quit":
conn.shutdown(socket.SHUT_RDWR)
conn.close()
break
else:
print("Recv:", data.decode("utf-8", errors="ignore"))
conn.sendall("{}".format(strftime("%Y-%m-%d %H:%M:%S", gmtime())).encode("utf-8"))
svr_socket().close()
tcp_cli.py
# -*- coding: utf-8 -*-
import faker
__Faker = faker.Faker()
import socket
import time
if __name__ == "__main__":
HOST = "192.168.1.115"
PORT = 18989
cli_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
cli_socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
while 1:
try:
cli_socket.connect((HOST, PORT))
print("Connected to {}:{}".format(HOST, PORT))
break
except ConnectionRefusedError as e:
print("Server refused connection, retrying ...")
time.sleep(1)
continue
send_cnt = 0
while 1:
if send_cnt == 300:
break
try:
msg = "Hello, my name is {}, what time is it now?".format(__Faker.name())
cli_socket.sendall(msg.encode("utf-8"))
except ConnectionResetError as e:
print("Server connection closed")
break
data = cli_socket.recv(512)
print("Recv:", data.decode("utf-8"))
time.sleep(2)
send_cnt += 1
cli_socket.shutdown(socket.SHUT_RDWR)
cli_socket.close()
http_svr.py
# -*- coding: utf-8 -*-
import uuid
from flask import Flask, jsonify, request
from flask_cors import CORS
app = Flask(__name__)
app.config.from_object(__name__)
CORS(app, resources={r'/*': {'origins': '*'}})
# book inventory
BOOKS = [
{
'id': uuid.uuid4().hex,
'title': 'On the Road',
'author': 'Jack Kerouac',
'read': True
},
{
'id': uuid.uuid4().hex,
'title': 'Harry Potter and the Philosopher\'s Stone',
'author': 'J. K. Rowling',
'read': False
},
{
'id': uuid.uuid4().hex,
'title': 'Green Eggs and Ham',
'author': 'Dr. Seuss',
'read': True
}
]
@app.route('/ping', methods=['GET'])
def ping_pong():
return jsonify('pong')
@app.route('/books', methods=['GET', 'POST'])
def all_books():
response_object = {'status': 'success'}
if request.method == 'POST':
post_data = request.get_json()
BOOKS.append({
'id': uuid.uuid4().hex,
'title': post_data.get('title'),
'author': post_data.get('author'),
'read': post_data.get('read')
})
response_object['message'] = 'Book Added!'
else:
response_object['books'] = BOOKS
return jsonify(response_object)
@app.route('/books/<book_id>', methods=['PUT', 'DELETE'])
def single_book(book_id):
response_object = {'status': 'success'}
if request.method == 'PUT':
post_data = request.get_json()
remove_book(book_id)
BOOKS.append({
'id': uuid.uuid4().hex,
'title': post_data.get('title'),
'author': post_data.get('author'),
'read': post_data.get('read')
})
response_object['message'] = 'Book Updated!'
if request.method == 'DELETE':
remove_book(book_id)
response_object['message'] = 'Book Removed!'
return jsonify(response_object)
def remove_book(book_id):
for book in BOOKS:
if book['id'] == book_id:
BOOKS.remove(book)
return True
return False
if __name__ == "__main__":
app.run(host="0.0.0.0", port=18988, debug=True)
http_cli.py
# -*- coding: utf-8 -*-
import json
import requests
import time
if __name__ == "__main__":
send_cnt = 0
while 1:
if send_cnt == 300:
break
r = requests.get("http://10.151.3.111:18988/books")
if r.status_code != 200:
print("Failed to send request <status code:", r.status_code, ">")
break
print("\n{}\n".format(json.dumps(r.json(), indent=4)))
time.sleep(2)
send_cnt += 1
- List all interfaces available.
# complete version
$ sudo tcpdump --list-interfaces
# or short version
$ sudo tcpdump -D
The special interface "any" allows capturing in any active interface.
Let's capture the network packets incoming/outcoming interface "eth0".
- Capture all packets incoming/outcoming "eth0" network interface card.
# complete version
$ sudo tcpdump --interface eth0
# or short version
$ sudo tcpdump -i eth0
- To limit the number of packets captured and stop automatically, use the -c (for count) option.
$ sudo tcpdump -i eth0 -c20
- By default, tcpdump will resolve IP address and port into name. You can disable name resolution and port resolution with -nn.
$ sudo tcpdump -i eth0 -nn
This prevents tcpdump from issuing DNS lookups, which helps to lower network traffic while troubleshooting network issues.
- Filter packets.
- To filter packets based on protocol, just specify the protocol, for example, capture TCP packets only.
$ sudo tcpdump -i eth0 -nn tcp
Supported protocols: tcp / udp / icmp / ip / ip6 / arp.
- Define the snaplength (size) of the capture in bytes. Use -s0 to get everything, unless you are intentionally capturing less.
$ sudo tcpdump -i eth0 -nn -s0
- To filter packets only related to a specific host, for example, host 192.168.1.115.
$ sudo tcpdump -i eth0 -nn -s0 "tcp and host 192.168.1.115"
In this example, tcpdump captures and displays only packets to and from host 192.168.1.115.
- To filter packets only related to a specific port, for example, port 18989.
$ sudo tcpdump -i eth0 -nn -s0 "tcp and host 192.168.1.115 and port 18989"
In this example, tcpdump captures and displays only packets related to a tcp service served at 18989.
You can also use a range of ports to filter packets.
$ sudo tcpdump -i eth0 -nn -s0 "tcp and host 192.168.1.115 and portrange 18986-18989"
- To filter packets based on the source or destination IP/Hostname.
# specific source IP
$ sudo tcpdump -i eth0 -nn -s0 "tcp and src 192.168.1.115 and port 18989"
# or specific destination IP
$ sudo tcpdump -i eth0 -nn -s0 "tcp and src 192.168.1.115 and port 18989"
# or a more complex expressions
$ sudo tcpdump -i eth0 -nn -s0 "tcp and (src 192.168.1.115 or src 192.168.1.116) and port 18989"
- To filter packets based on desired packet size.
# filter packets which <= 128 byte
$ sudo tcpdump -i eth0 -nn "tcp and host 192.168.1.115 and port 18989 and less 128"
# filter packets which >= 128 byte
$ sudo tcpdump -i eth0 -nn "tcp and host 192.168.1.115 and port 18989 and greater 128"
- To filter packets based on desired TCP flag(s).
$ sudo tcpdump -i eth0 -nn -s0 "tcp and host 192.168.1.115 and port 18989 and tcp[tcpflags] == tcp-urg "
$ sudo tcpdump -i eth0 -nn -s0 "tcp and host 192.168.1.115 and port 18989 and tcp[tcpflags] == tcp-syn"
$ sudo tcpdump -i eth0 -nn -s0 "tcp and host 192.168.1.115 and port 18989 and tcp[tcpflags] == tcp-ack"
$ sudo tcpdump -i eth0 -nn -s0 "tcp and host 192.168.1.115 and port 18989 and tcp[tcpflags] == tcp-rst"
$ sudo tcpdump -i eth0 -nn -s0 "tcp and host 192.168.1.115 and port 18989 and tcp[tcpflags] == tcp-fin"
- Check packet content.
To inspect the content of the packet to ensure that the message we're sending contains what we need or that we received the expected response.
To see the packet content, tcpdump provides two additional flags: -X to print content in HEX, and -A to print the content in ASCII.
For HTTP GET (GET = 0x47, 0x45, 0x54, 0x20).
$ sudo tcpdump -i eth0 -nn -s0 -A "tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420"
For HTTP POST (POST = 0x50, 0x4f, 0x53, 0x54).
$ sudo tcpdump -i eth0 -nn -s0 -A "tcp dst port 18988 and (tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504f5354)"
Monitor HTTP traffic including request and response headers and message body.
$ sudo tcpdump -i eth0 -nn -s0 -A "tcp port 18988 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)"
- Save captures to a file.
$ sudo tcpdump -i eth0 -nn -s0 "tcp and host 192.168.1.115 and port 18989" -vv -w network-data.pcap
* -XX Same as -X, but also shows the ethernet header.
* -I Line-readable output (for viewing as you save, or sending to other commands).
* -q Be less verbose (more quiet) with your output.
* -t Give human-readable timestamp output.
* -tttt Give maximally human-readable timestamp output.
* -S Print absolute sequence numbers.
* -e Get the ethernet header as well.
* -q Show less protocol information.
* -E Decrypt IPSEC traffic by providing an encryption key.
Real TCP 3-handshakes + some requests/responses + TCP 4-waves
15:22:29.582229 IP 10.152.205.55.52408 > 192.168.1.115.18989: Flags [S], seq 3704900508, win 64240, options [mss 1460,sackOK,TS val 1089318171 ecr 0,nop,wscale 7], length 0
15:22:29.611753 IP 192.168.1.115.18989 > 10.152.205.55.52408: Flags [S.], seq 1017691912, ack 3704900509, win 28960, options [mss 1460,sackOK,TS val 1467716369 ecr 1089318171,nop,wscale 7], length 0
15:22:29.611825 IP 10.152.205.55.52408 > 192.168.1.115.18989: Flags [.], ack 1, win 502, options [nop,nop,TS val 1089318201 ecr 1467716369], length 0
15:22:29.612725 IP 10.152.205.55.52408 > 192.168.1.115.18989: Flags [P.], seq 1:59, ack 1, win 502, options [nop,nop,TS val 1089318202 ecr 1467716369], length 58
15:22:29.642163 IP 192.168.1.115.18989 > 10.152.205.55.52408: Flags [.], ack 59, win 227, options [nop,nop,TS val 1467716400 ecr 1089318202], length 0
15:22:29.642276 IP 192.168.1.115.18989 > 10.152.205.55.52408: Flags [P.], seq 1:20, ack 59, win 227, options [nop,nop,TS val 1467716400 ecr 1089318202], length 19
15:22:29.642289 IP 10.152.205.55.52408 > 192.168.1.115.18989: Flags [.], ack 20, win 502, options [nop,nop,TS val 1089318231 ecr 1467716400], length 0
15:22:31.645105 IP 10.152.205.55.52408 > 192.168.1.115.18989: Flags [P.], seq 59:111, ack 20, win 502, options [nop,nop,TS val 1089320234 ecr 1467716400], length 52
15:22:31.675123 IP 192.168.1.115.18989 > 10.152.205.55.52408: Flags [P.], seq 20:39, ack 111, win 227, options [nop,nop,TS val 1467718433 ecr 1089320234], length 19
15:22:31.675159 IP 10.152.205.55.52408 > 192.168.1.115.18989: Flags [.], ack 39, win 502, options [nop,nop,TS val 1089320264 ecr 1467718433], length 0
15:22:33.678087 IP 10.152.205.55.52408 > 192.168.1.115.18989: Flags [P.], seq 111:166, ack 39, win 502, options [nop,nop,TS val 1089322267 ecr 1467718433], length 55
15:22:33.708133 IP 192.168.1.115.18989 > 10.152.205.55.52408: Flags [P.], seq 39:58, ack 166, win 227, options [nop,nop,TS val 1467720466 ecr 1089322267], length 19
15:22:33.708178 IP 10.152.205.55.52408 > 192.168.1.115.18989: Flags [.], ack 58, win 502, options [nop,nop,TS val 1089322297 ecr 1467720466], length 0
15:22:35.710001 IP 10.152.205.55.52408 > 192.168.1.115.18989: Flags [P.], seq 166:218, ack 58, win 502, options [nop,nop,TS val 1089324299 ecr 1467720466], length 52
15:22:35.739773 IP 192.168.1.115.18989 > 10.152.205.55.52408: Flags [P.], seq 58:77, ack 218, win 227, options [nop,nop,TS val 1467722497 ecr 1089324299], length 19
15:22:35.739816 IP 10.152.205.55.52408 > 192.168.1.115.18989: Flags [.], ack 77, win 502, options [nop,nop,TS val 1089324329 ecr 1467722497], length 0
15:22:37.742679 IP 10.152.205.55.52408 > 192.168.1.115.18989: Flags [P.], seq 218:269, ack 77, win 502, options [nop,nop,TS val 1089326332 ecr 1467722497], length 51
15:22:37.772509 IP 192.168.1.115.18989 > 10.152.205.55.52408: Flags [P.], seq 77:96, ack 269, win 227, options [nop,nop,TS val 1467724530 ecr 1089326332], length 19
15:22:37.772553 IP 10.152.205.55.52408 > 192.168.1.115.18989: Flags [.], ack 96, win 502, options [nop,nop,TS val 1089326362 ecr 1467724530], length 0
15:22:39.773348 IP 10.152.205.55.52408 > 192.168.1.115.18989: Flags [F.], seq 269, ack 96, win 502, options [nop,nop,TS val 1089328362 ecr 1467724530], length 0
15:22:39.803305 IP 192.168.1.115.18989 > 10.152.205.55.52408: Flags [F.], seq 96, ack 270, win 227, options [nop,nop,TS val 1467726561 ecr 1089328362], length 0
15:22:39.803317 IP 10.152.205.55.52408 > 192.168.1.115.18989: Flags [.], ack 97, win 502, options [nop,nop,TS val 1089328392 ecr 1467726561], length 0
- The TCP flag, "Flags [P.]".
Value Flag Type Description
-----------------------------------
S SYN Connection Start
F FIN Connection Finish
P PUSH Data Push
R RST Connection Reset
. ACK Acknowledgment
This field can also be a combination of these values, such as [S.] for a SYN-ACK packet.
- The sequence number of the data contained in the packet, "seq 99:148".
In this example, the sequence is "seq 99:148", which means this packet contains bytes 99 to 148 of this flow.
- Window size which represents the number of bytes available in the receiving buffer, followed by TCP options such as the MSS (Maximum Segment Size) or Window Scale, "win 521".