№ 11 Сетевая аномалия Рекомендуемые утилиты: Wires...
作成日: 2025年10月24日
使用モデル GPT-5 Thinking by Chat01
作成日: 2025年10月24日
使用モデル GPT-5 Thinking by Chat01
№ 11
Сетевая аномалия
Рекомендуемые утилиты: Wireshark
Файл: traffic 9 4.pcapng
Товарищ, в наших информационных сетях обнаружена аномалия. Кажется, кто-то атакует внутренние сервисы. Требуется срочное расследование и анализ ситуации. Исследуйте запись трафика и опишите атаку.
Какой тип атаки был применён?
Выбрать
Определите IP-адрес атакующего.
Ответ
Какой программой, вероятно, пользовался атакующий для доступа к сайту? В ответ запишите только название, без версии.
Ответ
pythonimport os, glob, pprint, json, pathlib, sys print(os.listdir('/mnt/data'))
pythonimport pkgutil, sys 'pyshark' in [m.name for m in pkgutil.iter_modules()], 'scapy' in [m.name for m in pkgutil.iter_modules()], 'dpkt' in [m.name for m in pkgutil.iter_modules()], 'pcapng' in [m.name for m in pkgutil.iter_modules()] (False, False, False, False)
pythonimport re, os, codecs p = '/mnt/data/traffic_9_4.pcapng' data = open(p, 'rb').read() # Extract ASCII strings of reasonable length def strings(buf, min_len=4): out=[] cur=[] for b in buf: if 32 <= b <= 126: cur.append(chr(b)) else: if len(cur)>=min_len: out.append(''.join(cur)) cur=[] if len(cur)>=min_len: out.append(''.join(cur)) return out s = strings(data, 4) len(s), s[:20] (57, ['Sanitized by TraceWrangler v0.6.8 build 974', 'Sanitized by TraceWrangler v0.6.8 build 974', 'eth0', 'Linux 6.6.65-1-MANJARO', '/GET /get_secret?username=admin&password=1234567 HTTP/1.1', 'Host: 192.168.122.79', 'User-Agent: curl/8.5.0', 'Accept: */*', '4n*@', '~HTTP/1.1 401 UNAUTHORIZED', 'Server: Werkzeug/3.1.3 Python/3.12.8', 'Date: Thu, 23 Jan 2025 16:47:35 GMT', 'Content-Type: text/html; charset=utf-8', 'Content-Length: 12', 'Connection: close', '@n,@', 'Unauthorized', '4n-@', 'GET /get_secret?username=admin&password=12345678 HTTP/1.1', 'Host: 192.168.122.79'])
pythonimport re ips = set() for st in s: for m in re.findall(r'(?:\d{1,3}\.){3}\d{1,3}', st): ips.add(m) ips {'192.168.122.79'}
pythondef iter_pcapng_packets(path): data = open(path, 'rb').read() off=0 src={} packets=[] while off+8 <= len(data): block_type, block_len = struct.unpack_from('<II', data, off) if block_len==0: break block = data[off:off+block_len] # EPB if block_type == 0x00000006 and block_len >= 32: # fields: type, len, iface_id, ts_high, ts_low, cap_len, pkt_len, pkt_data... iface_id, ts_high, ts_low, cap_len, pkt_len = struct.unpack_from('<IIIII', block, 8) pkt_data = block[28:28+cap_len] packets.append(pkt_data) off += block_len return packets packets = iter_pcapng_packets 53
pythonfrom collections import Counter, defaultdict def parse_ipv4_from_eth(frame): if len(frame) < 14: return None eth_type = struct.unpack('!H', frame[12:14])[0] if eth_type != 0x0800: return None ip = frame[14:] if len(ip) < 20: return None ver_ihl = ip[0] ihl = (ver_ihl & 0x0F)*4 if ihl < 20 or len(ip) < ihl: return None proto = ip[9] src = socket.inet_ntoa(ip[12:16]) dst = socket.inet_ntoa(ip[16:20]) payload = ip[ihl:] return {'src':src,'dst':dst,'proto':proto,'payload':payload, 'ip_header_len':ihl} def parse_tcp_segments(frame): parsed = parse_ipv4_from_eth(frame) if not parsed or parsed['proto'] != 6: return None payload = parsed['payload'] if len(payload) < 20: return None src_port, dst_port, seq, ack, offset_reserved_flags = struct.unpack('!HHIIH', payload[:14]) offset = ((offset_reserved_flags >> 12) & 0xF) * 4 if len(payload) < offset: return None tcp_payload = payload[offset:] flags = offset_reserved_flags & 0x01FF # last 9 bits return {**parsed, 'src_port':src_port,'dst_port':dst_port,'tcp_payload':tcp_payload,'flags':flags} ip_counts = Counter() src_dsts = Counter() http_texts=[] flows=defaultdict(list) for pkt in packets: t = parse_tcp_segments(pkt) if t: ip_counts[t['src']] += 1 src_dsts[(t['src'], t['dst'], t['dst_port'])] += 1 if t['tcp_payload']: # collect printable payloads try: text = t['tcp_payload'].decode('iso-8859-1', errors='ignore') except: text = '' if text: http_texts.append(text[:120]) flows[(t['src'], t['src_port'], t['dst'], t['dst_port'])].append(t) len(ip_counts), list(ip_counts.items())[:5], len(http_texts) (3, [('192.168.122.20', 21), ('192.168.122.79', 20), ('192.168.122.103', 7)], 12)
python# Summarize dst ports from collections import Counter dst_port_counts = Counter() for pkt in packets: t = parse_tcp_segments(pkt) if t: dst_port_counts[t['dst_port']] += 1 dst_port_counts Counter({80: 28, 58490: 5, 58500: 5, 44226: 5, 38928: 5})
pythonsorted([k for k,v in src_dsts.items() if k[2]==80], key=lambda x: (x[0],x[1],x[2])) [('192.168.122.103', '192.168.122.79', 80), ('192.168.122.20', '192.168.122.79', 80)]
pythonimport re reqs=[] for pkt in packets: t = parse_tcp_segments(pkt) if not t: continue pl = t['tcp_payload'] if not pl: continue text = pl.decode('iso-8859-1', errors='ignore') if text.startswith('GET ') or text.startswith('POST ') or 'HTTP/1.1' in text: reqs.append((t['src'], t['src_port'], t['dst'], t['dst_port'], text[:200].replace('\r','').replace('\n',' | '))) len(reqs), reqs[:5] (8, [('192.168.122.20', 58490, '192.168.122.79', 80, 'GET /get_secret?username=admin&password=1234567 HTTP/1.1 | Host: 192.168.122.79 | User-Agent: curl/8.5.0 | Accept: */* | | '), ('192.168.122.79', 80, '192.168.122.20', 58490, 'HTTP/1.1 401 UNAUTHORIZED | Server: Werkzeug/3.1.3 Python/3.12.8 | Date: Thu, 23 Jan 2025 16:47:35 GMT | Content-Type: text/html; charset=utf-8 | Content-Length: 12 | Connection: close | | '), ('192.168.122.20', 58500, '192.168.122.79', 80, 'GET /get_secret?username=admin&password=12345678 HTTP/1.1 | Host: 192.168.122.79 | User-Agent: curl/8.5.0 | Accept: */* | | '), ('192.168.122.79', 80, '192.168.122.20', 58500, 'HTTP/1.1 200 OK | Server: Werkzeug/3.1.3 Python/3.12.8 | Date: Thu, 23 Jan 2025 16:47:37 GMT | Content-Type: text/html; charset=utf-8 | Content-Length: 19 | Connection: close | | '), ('192.168.122.103', 44226, '192.168.122.79', 80, "GET /get_secret?username='%20OR%201=1--&password= HTTP/1.1 | Host: 192.168.122.79 | User-Agent: curl/8.9.1 | Accept: */* | | ")])
pythonfor entry in reqs: print(entry[0], '->', entry[2], entry[3], '|', entry[4])
pythonfor e in reqs: if e[0]=='192.168.122.103': print(e[4])
Отлично, давай разберём это как аналитик по сетям — шаг за шагом.
Шаг 1 (5 минут): открой pcap в Wireshark и вбей фильтр http.request (или tcp.port == 80, если удобней).
Прокликай верхние несколько запросов и посмотри на строку GET и заголовки.
Вопрос: какой URL сразу выглядит подозрительно? Скопируй сюда полную строку GET ... из самого «странного» запроса.