File: hcxgrep.py

package info (click to toggle)
hcxtools 6.3.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,080 kB
  • sloc: ansic: 19,601; python: 144; sh: 99; makefile: 98
file content (183 lines) | stat: -rwxr-xr-x 4,956 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#!/usr/bin/env python3
'''
greps inside hccapx/pmkid structs by essid, mac_ap or mac_sta

This software is Copyright (c) 2019-2023, Alex Stanev <alex at stanev.org>
and it is hereby released to the general public under the following terms:

Redistribution and use in source and binary forms, with or without
modification, are permitted.
'''

import argparse
import os
import sys
import binascii
import struct
import re

maketrans = bytearray.maketrans


def parse_hccapx(hccapx):
    '''hccapx decompose

    https://hashcat.net/wiki/doku.php?id=hccapx
    struct hccapx
    {
      u32 signature;
      u32 version;
      u8  message_pair;
      u8  essid_len;
      u8  essid[32];
      u8  keyver;
      u8  keymic[16];
      u8  mac_ap[6];
      u8  nonce_ap[32];
      u8  mac_sta[6];
      u8  nonce_sta[32];
      u16 eapol_len;
      u8  eapol[256];

    } __attribute__((packed));
    '''

    hccapx_fmt = '< 4x 4x x B 32s x 16x 6s 32x 6s 32x 2x 256x'

    try:
        (essid_len, essid,
         mac_ap, mac_sta) = struct.unpack(hccapx_fmt, hccapx)
    except struct.error:
        sys.stderr.write('Can\'t parse hcccapx struct!\n')
        sys.exit(1)

    # fixup
    if args.t == 'essid':
        return essid[:essid_len]
    if args.t == 'mac_ap':
        return binascii.hexlify(mac_ap).zfill(12)
    if args.t == 'mac_sta':
        return binascii.hexlify(mac_sta).zfill(12)

    return None


def parse_pmkid(pmkid):
    '''pmkid decompose

    format:
        pmkid*mac_ap*mac_sta*essid
    '''

    arr = pmkid.split(b'*', 4)
    if len(arr) == 4:
        try:
            if args.t == 'essid':
                return binascii.unhexlify(arr[3].strip())
            if args.t == 'mac_ap':
                return arr[1]
            if args.t == 'mac_sta':
                return arr[2]
        except TypeError:
            sys.stderr.write('Can\'t decode: {}\n'.format(arr[3].strip().decode()))
            sys.exit(1)

    return None


def parse_combined(hashline):
    '''m22000 hashline decompose

    format:
        SIGNATURE*TYPE*PMKID/MIC*MACAP*MACSTA*ESSID*ANONCE*EAPOL*MESSAGEPAIR
    '''

    arr = hashline.split(b'*', 9)
    if len(arr) == 9:
        try:
            if args.t == 'essid':
                return binascii.unhexlify(arr[5].strip())
            if args.t == 'mac_ap':
                return arr[3]
            if args.t == 'mac_sta':
                return arr[4]
        except TypeError:
            sys.stderr.write('Can\'t decode: {}\n'.format(arr[5].strip().decode()))
            sys.exit(1)

    return None

if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description='Extract records from m22000 hashline/hccapx/pmkid file with regexp')
    parser.add_argument(
        '-f', '--file', type=argparse.FileType('r'),
        help='Obtain patterns from FILE, one per line.')
    parser.add_argument(
        'PATTERNS', type=str, nargs='?',
        help='RegExp pattern')

    parser.add_argument(
        '-v', '--invert-match', dest='v', action='store_true',
        help='Invert the sense of matching, to select non-matching nets')
    parser.add_argument(
        '-t', '--type', dest='t',
        choices=['essid', 'mac_ap', 'mac_sta'], default='essid',
        help='Field to apply matching, default essid')
    parser.add_argument(
        'infile', type=str, nargs='?',
        help='hccapx/pmkid file to process')

    try:
        args = parser.parse_args()
    except IOError as ex:
        parser.error(str(ex))

    # shift parameters
    if args.file and args.PATTERNS:
        args.infile = args.PATTERNS
        args.PATTERNS = None

    # no patterns set
    if args.PATTERNS is None and args.file is None:
        parser.print_help(sys.stderr)
        sys.stderr.write('You must provide PATTERNS or -f FILE\n')
        sys.exit(1)

    # read patterns from file
    if args.PATTERNS is None:
        args.PATTERNS = '|'.join('(?:{0})'.format(x.strip()) for x in args.file)

    try:
        regexp = re.compile(bytes(args.PATTERNS, 'utf-8'))
    except re.error as ex:
        sys.stderr.write('Wrong regexp {0}: {1} \n'.format(args.PATTERNS, ex))
        sys.exit(1)

    if args.infile is not None and os.path.isfile(args.infile):
        fd = open(args.infile, 'rb')
    else:
        fd = sys.stdin.buffer

    while True:
        buf = fd.read(4)
        if buf == b'WPA*':
            buf = buf + fd.readline()
            target = parse_combined(buf)
        elif buf == b'HCPX':
            buf = buf + fd.read(393 - 4)
            target = parse_hccapx(buf)
        else:
            buf = buf + fd.readline()
            target = parse_pmkid(buf)

        if not buf:
            break

        if target is None:
            sys.stderr.write('Unrecognized input format\n')
            sys.exit(1)

        res = regexp.search(target)
        if (res is not None and not args.v) or (res is None and args.v):
            sys.stdout.buffer.write(buf)