Hashcat capture file (old version): Ruby parsing library

Native format of Hashcat password "recovery" utility.

A sample of file for testing can be downloaded from https://web.archive.org/web/20150220013635if_/http://hashcat.net:80/misc/example_hashes/hashcat.hccap

Application

["Hashcat", "aircrack-ng"]

File extension

hccap

KS implementation details

License: Unlicense

This page hosts a formal specification of Hashcat capture file (old version) using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Usage

Parse a local file and get structure in memory:

data = Hccap.from_file("path/to/local/file.hccap")

Or parse structure from a string of bytes:

bytes = "\x00\x01\x02..."
data = Hccap.new(Kaitai::Struct::Stream.new(bytes))

After that, one can get various attributes from the structure by invoking getter methods like:

data.records # => get records

Ruby source code to parse Hashcat capture file (old version)

hccap.rb

# This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

require 'kaitai/struct/struct'

unless Gem::Version.new(Kaitai::Struct::VERSION) >= Gem::Version.new('0.7')
  raise "Incompatible Kaitai Struct Ruby API: 0.7 or later is required, but you have #{Kaitai::Struct::VERSION}"
end


##
# Native format of Hashcat password "recovery" utility.
# 
# A sample of file for testing can be downloaded from https://web.archive.org/web/20150220013635if_/http://hashcat.net:80/misc/example_hashes/hashcat.hccap
# @see https://hashcat.net/wiki/doku.php?id=hccap Source
class Hccap < Kaitai::Struct::Struct
  def initialize(_io, _parent = nil, _root = self)
    super(_io, _parent, _root)
    _read
  end

  def _read
    @records = []
    i = 0
    while not @_io.eof?
      @records << HccapRecord.new(@_io, self, @_root)
      i += 1
    end
    self
  end
  class HccapRecord < Kaitai::Struct::Struct
    def initialize(_io, _parent = nil, _root = self)
      super(_io, _parent, _root)
      _read
    end

    def _read
      @essid = @_io.read_bytes(36)
      @mac_ap = @_io.read_bytes(6)
      @mac_station = @_io.read_bytes(6)
      @nonce_station = @_io.read_bytes(32)
      @nonce_ap = @_io.read_bytes(32)
      @_raw_eapol_buffer = @_io.read_bytes(256)
      io = Kaitai::Struct::Stream.new(@_raw_eapol_buffer)
      @eapol_buffer = EapolDummy.new(io, self, @_root)
      @len_eapol = @_io.read_u4le
      @keyver = @_io.read_u4le
      @keymic = @_io.read_bytes(16)
      self
    end
    def eapol
      return @eapol unless @eapol.nil?
      io = eapol_buffer._io
      _pos = io.pos
      io.seek(0)
      @eapol = io.read_bytes(len_eapol)
      io.seek(_pos)
      @eapol
    end
    attr_reader :essid

    ##
    # The BSSID (MAC address) of the access point
    attr_reader :mac_ap

    ##
    # The MAC address of a client connecting to the access point
    attr_reader :mac_station

    ##
    # Nonce (random salt) generated by the client connecting to the access point.
    attr_reader :nonce_station

    ##
    # Nonce (random salt) generated by the access point.
    attr_reader :nonce_ap

    ##
    # Buffer for EAPOL data, only first `len_eapol` bytes are used
    attr_reader :eapol_buffer

    ##
    # Size of EAPOL data
    attr_reader :len_eapol

    ##
    # The flag used to distinguish WPA from WPA2 ciphers. Value of
    # 1 means WPA, other - WPA2.
    attr_reader :keyver

    ##
    # The final hash value. MD5 for WPA and SHA-1 for WPA2
    # (truncated to 128 bit).
    attr_reader :keymic
    attr_reader :_raw_eapol_buffer
  end
  class EapolDummy < Kaitai::Struct::Struct
    def initialize(_io, _parent = nil, _root = self)
      super(_io, _parent, _root)
      _read
    end

    def _read
      self
    end
  end
  attr_reader :records
end