# -*- coding:binary -*-
require 'spec_helper'

require 'rex/proto/kerberos'
require 'msf/core/exploit/kerberos/client'

RSpec.describe Msf::Exploit::Remote::Kerberos::Client::TgsRequest do
  subject(:mod) do
    mod = ::Msf::Exploit.new
    mod.extend ::Msf::Exploit::Remote::Kerberos::Client
    mod.send(:initialize)
    mod
  end

  let(:body_opts) do
    {
      :nonce => 123456,
      :realm => 'DOMAIN'
    }
  end

  let(:body_md5) { "\xfe\x0a\x9e\x46\xd5\x0f\x10\x3a\xea\xe2\xbf\xc0\x5a\x4a\x4e\x93" }

  let(:key_opts) do
    {
      :subkey_value => 'AAAABBBBCCCCDDDD'
    }
  end

  let(:auth_opts) do
    {
      :realm => 'DOMAIN'
    }
  end

  let(:ticket) do
    tgs_res_raw = "\x6d\x82\x04\xad\x30\x82\x04\xa9\xa0\x03\x02\x01\x05\xa1\x03\x02\x01\x0d\xa3\x0c\x1b\x0a\x44\x45\x4d\x4f\x2e\x4c\x4f\x43\x41\x4c\xa4\x11\x30\x0f\xa0\x03\x02\x01\x01\xa1\x08\x30\x06\x1b\x04\x6a\x75\x61\x6e\xa5\x82\x03\x85\x61\x82\x03\x81\x30\x82\x03\x7d\xa0\x03\x02\x01\x05\xa1\x0c\x1b\x0a\x44\x45\x4d\x4f\x2e\x4c\x4f\x43\x41\x4c\xa2\x1f\x30\x1d\xa0\x03\x02\x01\x01\xa1\x16\x30\x14\x1b\x06\x6b\x72\x62\x74\x67\x74\x1b\x0a\x44\x45\x4d\x4f\x2e\x4c\x4f\x43\x41\x4c\xa3\x82\x03\x45\x30\x82\x03\x41\xa0\x03\x02\x01\x17\xa1\x03\x02\x01\x02\xa2\x82\x03\x33\x04\x82\x03\x2f\xad\xce\x0d\xda\x46\xbc\x7e\x46\x46\x12\x01\xdf\x33\xe5\x45\xb5\x72\x54\xbb\x70\xa6\x9d\x0e\x78\x43\x96\xb8\xb7\xd0\xfe\xfc\x29\xed\xfa\xc5\xdd\x1b\x68\x01\xd6\xe2\xd6\x8e\x6d\x4d\x27\xe7\xdf\xbe\x8c\xeb\x21\xe5\x27\x68\x2f\xb8\xf4\xf0\xf1\x34\x20\xc1\x7b\xfe\x62\x52\xf6\xbf\x34\xb2\x5d\x91\xc1\x0a\xa6\x99\xc5\xa7\x88\x81\x0e\xe7\xbc\x0b\x06\xf7\x61\xd3\xc8\x06\xa7\x19\x2c\x5f\x7c\x78\xb0\x12\xb1\x65\xe9\xad\x71\x47\xb2\x27\x6a\x94\x89\x7c\x70\x5d\x25\x45\xaf\x62\x0d\xa5\xa0\x77\xa3\xb7\x1a\x2a\x98\xa0\xd2\x39\x3f\xe8\xb9\x59\x2b\x8e\x72\xbc\xe8\xcf\x61\x18\xe3\x7f\x03\x58\x44\xd3\x2f\x65\x7c\x94\x4c\x2c\x5c\xa1\x90\x81\x95\x42\xf1\xc0\x79\xd2\x18\x56\x8c\xed\xe8\x63\x93\x75\x18\x31\x32\x3b\xd9\xcd\xbd\x0b\x4e\x37\x44\x24\x99\x18\x17\x4e\xd7\x7c\x06\x26\xab\xc1\x1f\xaa\x9a\x0c\x32\x90\xb3\x4f\x70\xc8\x2b\x6a\x55\xf0\x1a\x89\xab\xfb\x41\x24\x21\xfc\xe4\xab\x88\xe8\x5c\xd8\xce\xca\xa0\x4d\x5c\xc1\xd8\x29\x33\x6b\x9d\xdf\x33\x81\xd3\x01\x1a\x7c\x56\x2d\xfc\x03\xd2\x95\xdb\xf3\x55\x89\x70\x8a\x8c\xa2\xd9\x29\xb1\xf4\x92\x62\x32\x5b\x32\x84\x53\x78\x8f\x5d\xa3\x56\x94\xf8\x09\x46\x9d\xd5\x25\x7a\xf3\x4b\x29\xc7\x46\x2b\x18\x86\x29\xa9\x14\x86\xa7\xd5\x9c\xe1\x83\x80\x79\x4c\xce\xa1\xce\x2f\x83\xb5\x65\xf5\x80\xcc\xf8\xdb\x2c\xab\xca\x1e\x03\xf4\x97\x38\xc7\x95\x96\x5f\x4a\x7a\x6d\x93\xc2\xa2\x9f\x1d\xa4\xc8\x68\xa6\xc2\x72\x7c\xd3\x0b\x36\xe6\x02\x63\xfd\xa6\x20\x1c\xbf\x04\x1f\x4b\x45\xa1\xc6\x63\xd4\x16\x59\x57\xf4\x23\x5b\x68\x1f\xc8\x91\x6f\xa3\x78\x27\x10\xc1\xc1\x32\x8b\x66\xd8\xe0\xbf\x11\xcf\x31\x9b\x4c\x32\x28\xe3\x0c\x01\xef\x3a\x3e\x7b\x39\x71\x83\x94\xc0\x35\x56\xdf\xe5\xbd\x2e\xaf\x06\xf4\xb0\xca\xa1\x88\xd8\x98\x61\xd6\x0f\xa0\x6f\x8c\x9b\xa0\xee\xf6\x13\xd6\xb4\xc7\x5d\xb6\x94\xc9\x00\x65\xc4\x41\x24\x28\x2e\xbf\xb6\x94\x8a\x7d\x52\xdb\x72\xb9\x4d\xa4\x30\x06\x0a\xae\xd9\x0e\x3f\x1c\x33\xfd\x76\x46\xec\xcc\x93\x3f\x02\x28\xa1\x24\x34\x6d\x1a\x21\xe1\x4a\x38\xe4\x6d\xbf\x9b\x05\x53\x71\x1d\x74\xeb\x98\x65\x3a\x70\x81\x56\xc7\x1a\x4e\xa1\xa4\xba\x5a\xea\x7f\xb4\x71\xcd\x4c\x75\x3c\xe2\x43\x58\xd0\xc6\xbf\xfb\x9d\x25\x56\xaf\xb9\xbe\x6b\xc2\x9b\x92\x2e\x70\x4e\xb6\x40\x5c\x59\x34\x60\x1d\xd4\x1c\x8c\x45\x9b\x78\x3e\x45\x88\x5d\x24\xb9\x82\xd4\x94\x5c\x41\x1c\xfa\xb7\xc3\x66\x38\x84\x5a\x43\xf7\xf3\x90\x12\x34\xea\xfb\x1f\x0f\xdf\x40\x45\x55\x90\x39\x57\xbc\x93\x73\x1d\x78\x21\xc6\x91\xc6\xe2\xb8\x45\xad\x10\x57\x5f\xa5\x01\x6b\x7f\xa9\x45\xfc\x65\xb4\x72\x90\x81\x08\xfb\x08\x42\x78\x1f\xd7\x42\x87\xd5\x4a\xf7\x82\xbe\xba\xa6\x80\x28\x46\xf9\x44\x92\x03\x33\xc4\x92\x54\x6f\xf9\xbf\x58\x98\x07\x57\xca\x91\x5e\x42\xee\x42\x36\x3c\xc8\x4e\x4e\xc4\x20\xfb\x83\x17\x92\xad\xb2\x4b\x1a\xbb\x72\x97\x4d\x14\xb6\x1c\x94\x00\xb8\x5b\x84\x68\xce\x98\x33\x56\xd1\xd1\x1a\xba\xc9\x00\x7b\xdf\xe6\xef\x5a\x65\x53\x4c\xeb\x9b\x06\x49\xfc\x77\x1d\xd6\x6c\xe0\xb6\xda\xe9\x3e\xea\xcb\xf4\xb6\x13\xaa\xc7\x2b\x96\xd5\x17\x62\x8c\x6f\x4e\x9a\x9e\x02\x1f\x02\x33\x1a\xb1\x75\x0c\x61\x10\xcc\x41\xf4\x28\x11\x01\x2b\x20\x98\x7a\x62\xcd\xe2\x6a\xa2\x7b\xb4\x33\xd4\xb5\xaa\x6f\xa4\x75\x6f\x2c\x67\x75\xce\xdb\x34\xef\xc5\xf5\x73\x74\x07\xda\x90\x76\x11\xc7\xf2\x04\x27\x33\x0e\x76\xcb\x7e\xda\x40\xd8\x56\x6f\x12\xd3\x75\x06\x44\x6a\xa5\xb1\x00\xf5\x4a\x52\xe3\xd8\x23\xc1\x98\x8c\x95\x91\x0a\xa4\x69\x2d\x33\x2d\x56\x63\x70\x83\xa6\x81\xf2\x30\x81\xef\xa0\x03\x02\x01\x17\xa2\x81\xe7\x04\x81\xe4\x28\xee\xa0\xf5\xfc\xc5\x83\x9f\x74\x4d\x35\xbf\x1c\xe8\x92\x54\x9a\xf6\xa3\x2d\x6a\xf3\xb4\x20\x24\x78\xb9\x15\x0f\xa1\x7f\xb7\xef\x2c\x68\x57\x0d\xc5\x52\x09\x81\xe7\x6d\xef\x38\x1b\x50\xc3\x7f\xae\x3b\x30\xa4\x4b\xed\x3b\xfd\xf5\xdb\xaa\xa3\xf4\xaa\x40\xc6\x85\x96\x58\xcc\x88\x1b\x08\xcf\x6f\x00\x85\xb5\x8a\x91\x6b\x87\xb4\xb1\x62\xc4\x0f\xf1\xd0\x19\x8c\x53\x99\xfd\xb6\xe5\xc1\x92\xfa\x2d\xe6\x89\x47\xe8\x0e\x76\xa7\x4f\x5f\x50\x04\x6e\x10\x6f\xcc\xf4\x1c\x92\x7f\x57\x49\xfc\x7b\xc9\xae\x91\x3c\x37\xca\x8d\x7d\x93\xb0\x3e\x3a\x58\x23\xc2\x34\xbc\x48\xee\x57\xc6\xa0\xcc\xe7\xaa\xb6\x9d\x00\x35\xe7\x3c\x57\x6f\x52\x11\x1b\x2a\xf9\x62\x23\x0d\x48\x05\xc0\x9c\x5b\x71\xd2\xda\xd0\x7b\x85\x87\xa7\x43\x2c\x22\x9b\x6e\xe4\x39\x17\xa0\xad\x94\xa9\x77\x91\xdd\x80\x41\xef\xb3\xf7\xeb\x8d\x1d\x93\xc7\xab\x9f\xac\x50\x9d\xb0\x69\xf2\xec\x4d\x7b\x90\x83\x84\x11\x27\x48\x4a\xcb\x90\xd0\xa5\xf9\xa7\xd3\x67\x54"
    tgs_asn1 = OpenSSL::ASN1.decode(tgs_res_raw)
    tgs_res = Rex::Proto::Kerberos::Model::KdcResponse.decode(tgs_asn1)

    tgs_res.ticket
  end

  let(:auth_data) do
    pac = mod.build_pac
    auth_data = mod.build_pac_authorization_data(pac: pac)

    auth_data
  end

  describe "#build_tgs_request_body" do
    context "when no opts" do
      it "creates a Rex::Proto::Kerberos::Model::KdcRequestBody" do
        expect(mod.build_tgs_request_body).to be_a(Rex::Proto::Kerberos::Model::KdcRequestBody)
      end

      it "creates a default KdcRequestBody" do
        expect(mod.build_tgs_request_body.realm).to eq('')
      end
    end

    context "when opts" do
      it "creates a Rex::Proto::Kerberos::Model::KdcRequestBody" do
        expect(mod.build_tgs_request_body(body_opts)).to be_a(Rex::Proto::Kerberos::Model::KdcRequestBody)
      end

      it "creates a KdcRequestBody with data from opts" do
        expect(mod.build_tgs_request_body(body_opts).realm).to eq('DOMAIN')
      end

    end
  end

  describe "#build_tgs_body_checksum" do
    context "when no opts" do
      it "creates Rex::Proto::Kerberos::Model::Checksum" do
        expect(mod.build_tgs_body_checksum).to be_a(Rex::Proto::Kerberos::Model::Checksum)
      end

      it "creates a RSA-MD5 checksum" do
        body = mod.build_tgs_request_body(body_opts)
        expect(mod.build_tgs_body_checksum(:body => body).type).to eq(Rex::Proto::Kerberos::Crypto::RSA_MD5)
      end

      it "calculates and stores the checksum" do
        body = mod.build_tgs_request_body(body_opts)
        expect(mod.build_tgs_body_checksum(:body => body).checksum.length).to eq(16)
      end
    end

    context "when opts" do
      it "creates Rex::Proto::Kerberos::Model::Checksum" do
        body = mod.build_tgs_request_body(body_opts)
        expect(mod.build_tgs_body_checksum(:body => body)).to be_a(Rex::Proto::Kerberos::Model::Checksum)
      end

      it "creates a RSA-MD5 checksum" do
        body = mod.build_tgs_request_body(body_opts)
        expect(mod.build_tgs_body_checksum(:body => body).type).to eq(Rex::Proto::Kerberos::Crypto::RSA_MD5)
      end

      it "calculates and stores the checksum" do
        body = mod.build_tgs_request_body(body_opts)
        expect(mod.build_tgs_body_checksum(:body => body).checksum).to eq(body_md5)
      end
    end
  end

  describe "#build_subkey" do
    context "when no opts" do
      it "creates Rex::Proto::Kerberos::Model::EncryptionKey" do
        expect(mod.build_subkey).to be_a(Rex::Proto::Kerberos::Model::EncryptionKey)
      end

      it "creates a RC4-HMAC key" do
        expect(mod.build_subkey.type).to eq(Rex::Proto::Kerberos::Crypto::RC4_HMAC)
      end

      it "creates a key" do
        expect(mod.build_subkey.value.length).to eq(16)
      end
    end

    context "when opts" do
      it "creates Rex::Proto::Kerberos::Model::EncryptionKey" do
        expect(mod.build_subkey(key_opts)).to be_a(Rex::Proto::Kerberos::Model::EncryptionKey)
      end

      it "creates the key from options" do
        expect(mod.build_subkey(key_opts).value).to eq('AAAABBBBCCCCDDDD')
      end
    end
  end

  describe "#build_authenticator" do
    context "when no opts" do
      it "creates Rex::Proto::Kerberos::Model::Authenticator" do
        expect(mod.build_authenticator).to be_a(Rex::Proto::Kerberos::Model::Authenticator)
      end

      it "creates a default Authenticator" do
        expect(mod.build_authenticator.crealm).to eq('')
      end
    end

    context "when opts" do
      it "creates Rex::Proto::Kerberos::Model::Authenticator" do
        expect(mod.build_authenticator(auth_opts)).to be_a(Rex::Proto::Kerberos::Model::Authenticator)
      end

      it "creates the authenticator from options" do
        expect(mod.build_authenticator(auth_opts).crealm).to eq('DOMAIN')
      end
    end
  end

  describe "#build_ap_req" do
    context "when no ticket" do
      it "raises error" do
        expect { mod.build_ap_req }.to raise_error(RuntimeError)
      end
    end

    context "when ticket" do
      it "creates a Rex::Proto::Kerberos::Model::ApReq" do
        expect(mod.build_ap_req(:ticket => ticket)).to be_a(Rex::Proto::Kerberos::Model::ApReq)
      end
    end
  end

  describe "#build_enc_auth_data" do
    context "when no auth_data" do
      it "raises error" do
        expect { mod.build_enc_auth_data }.to raise_error(RuntimeError)
      end
    end

    context "when auth_data" do
      it "creates a Rex::Proto::Kerberos::Model::EncryptedData" do
        expect(mod.build_enc_auth_data(:auth_data => auth_data)).to be_a(Rex::Proto::Kerberos::Model::EncryptedData)
      end
    end
  end

  describe "#build_tgs_request" do
    context "when no ticket" do
      it "raises error" do
        expect { mod.build_tgs_request }.to raise_error(RuntimeError)
      end
    end

    context "when ticket" do
      it "creates a Rex::Proto::Kerberos::Model::KdcRequest" do
        expect(mod.build_tgs_request(:ticket => ticket)).to be_a(Rex::Proto::Kerberos::Model::KdcRequest)
      end
    end
  end
end

