ruby_smb 3.3.19 → 3.3.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/examples/anonymous_auth.rb +5 -0
  3. data/examples/append_file.rb +57 -14
  4. data/examples/authenticate.rb +64 -16
  5. data/examples/delete_file.rb +53 -11
  6. data/examples/dump_secrets_from_sid.rb +43 -8
  7. data/examples/enum_domain_users.rb +51 -8
  8. data/examples/enum_registry_key.rb +51 -7
  9. data/examples/enum_registry_values.rb +51 -9
  10. data/examples/get_computer_info.rb +48 -8
  11. data/examples/list_directory.rb +54 -12
  12. data/examples/negotiate.rb +54 -42
  13. data/examples/negotiate_with_netbios_service.rb +55 -16
  14. data/examples/net_share_enum_all.rb +47 -8
  15. data/examples/pipes.rb +51 -7
  16. data/examples/query_service_status.rb +51 -8
  17. data/examples/read_file_encryption.rb +71 -26
  18. data/examples/read_registry_key_value.rb +54 -9
  19. data/examples/rename_file.rb +58 -15
  20. data/examples/write_file.rb +58 -15
  21. data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_level/query_fs_cifs_unix_info.rb +31 -0
  22. data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_level.rb +4 -0
  23. data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_request.rb +12 -4
  24. data/lib/ruby_smb/smb1/packet/trans2/set_fs_information_level.rb +28 -0
  25. data/lib/ruby_smb/smb1/packet/trans2/set_fs_information_request.rb +90 -0
  26. data/lib/ruby_smb/smb1/packet/trans2/set_fs_information_response.rb +56 -0
  27. data/lib/ruby_smb/smb1/packet/trans2/set_information_level.rb +35 -0
  28. data/lib/ruby_smb/smb1/packet/trans2/set_path_information_request.rb +75 -0
  29. data/lib/ruby_smb/smb1/packet/trans2/set_path_information_response.rb +51 -0
  30. data/lib/ruby_smb/smb1/packet/trans2.rb +8 -0
  31. data/lib/ruby_smb/smb1/tree.rb +124 -0
  32. data/lib/ruby_smb/version.rb +1 -1
  33. data/spec/lib/ruby_smb/smb1/packet/trans2/query_fs_information_request_spec.rb +6 -1
  34. data/spec/lib/ruby_smb/smb1/packet/trans2/set_fs_information_request_spec.rb +52 -0
  35. data/spec/lib/ruby_smb/smb1/packet/trans2/set_fs_information_response_spec.rb +29 -0
  36. data/spec/lib/ruby_smb/smb1/packet/trans2/set_path_information_request_spec.rb +114 -0
  37. data/spec/lib/ruby_smb/smb1/packet/trans2/set_path_information_response_spec.rb +54 -0
  38. data/spec/lib/ruby_smb/smb1/tree_spec.rb +124 -0
  39. metadata +17 -2
@@ -582,6 +582,130 @@ RSpec.describe RubySMB::SMB1::Tree do
582
582
  end
583
583
  end
584
584
 
585
+ describe '#set_unix_link' do
586
+ let(:set_path_response) { RubySMB::SMB1::Packet::Trans2::SetPathInformationResponse.new }
587
+
588
+ before :each do
589
+ # Stub out the CIFS UNIX Extensions handshake — covered separately below.
590
+ allow(tree).to receive(:enable_cifs_unix_extensions)
591
+ allow(client).to receive(:send_recv)
592
+ allow(RubySMB::SMB1::Packet::Trans2::SetPathInformationResponse).to receive(:read).and_return(set_path_response)
593
+ end
594
+
595
+ it 'performs the CIFS UNIX Extensions handshake before issuing the symlink request' do
596
+ call_order = []
597
+ allow(tree).to receive(:enable_cifs_unix_extensions) { call_order << :handshake }
598
+ allow(client).to receive(:send_recv) { call_order << :set_path; '' }
599
+ tree.set_unix_link(symlink: 'escape', target: '../../etc')
600
+ expect(call_order).to eq([:handshake, :set_path])
601
+ end
602
+
603
+ it 'sends a Trans2 SetPathInformationRequest with the UNIX_LINK info level' do
604
+ allow(client).to receive(:send_recv) do |request|
605
+ expect(request).to be_a(RubySMB::SMB1::Packet::Trans2::SetPathInformationRequest)
606
+ expect(request.data_block.trans2_parameters.information_level).to(
607
+ eq(RubySMB::SMB1::Packet::Trans2::SetInformationLevel::SMB_SET_FILE_UNIX_LINK)
608
+ )
609
+ end
610
+ tree.set_unix_link(symlink: 'escape', target: '../../etc')
611
+ end
612
+
613
+ it 'sets the Tree ID on the request' do
614
+ allow(client).to receive(:send_recv) do |request|
615
+ expect(request.smb_header.tid).to eq(tree.id)
616
+ end
617
+ tree.set_unix_link(symlink: 'escape', target: '../../etc')
618
+ end
619
+
620
+ it 'encodes the symlink path and target as raw byte strings (non-unicode)' do
621
+ allow(client).to receive(:send_recv) do |request|
622
+ raw = request.to_binary_s
623
+ expect(request.smb_header.flags2.unicode).to eq(0)
624
+ expect(raw).to include('escape'.b)
625
+ expect(raw).to include('../../etc'.b)
626
+ expect(raw).not_to include('escape'.encode('UTF-16LE').b)
627
+ end
628
+ tree.set_unix_link(symlink: 'escape', target: '../../etc')
629
+ end
630
+
631
+ it 'returns STATUS_SUCCESS on a successful response' do
632
+ expect(tree.set_unix_link(symlink: 'escape', target: '../../etc'))
633
+ .to eq(WindowsError::NTStatus::STATUS_SUCCESS)
634
+ end
635
+
636
+ context 'when the server returns a non-Trans2 response packet' do
637
+ it 'raises InvalidPacket' do
638
+ allow(set_path_response).to receive(:valid?).and_return(false)
639
+ expect {
640
+ tree.set_unix_link(symlink: 'escape', target: '../../etc')
641
+ }.to raise_error(RubySMB::Error::InvalidPacket)
642
+ end
643
+ end
644
+
645
+ context 'when the response has a non-success status code' do
646
+ it 'raises UnexpectedStatusCode' do
647
+ set_path_response.smb_header.nt_status =
648
+ WindowsError::NTStatus::STATUS_ACCESS_DENIED.value
649
+ expect {
650
+ tree.set_unix_link(symlink: 'escape', target: '../../etc')
651
+ }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
652
+ end
653
+ end
654
+ end
655
+
656
+ describe '#enable_cifs_unix_extensions' do
657
+ let(:query_response) { RubySMB::SMB1::Packet::Trans2::QueryFsInformationResponse.new }
658
+ let(:set_response) { RubySMB::SMB1::Packet::Trans2::SetFsInformationResponse.new }
659
+
660
+ before :each do
661
+ # Server advertises major=1, minor=0, caps=0x0000_0000_0000_017B
662
+ info = RubySMB::SMB1::Packet::Trans2::QueryFsInformationLevel::QueryFsCifsUnixInfo.new
663
+ info.major_version = 1
664
+ info.minor_version = 0
665
+ info.capabilities = 0x17B
666
+ query_response.data_block.trans2_data.buffer = info.to_binary_s
667
+ allow(RubySMB::SMB1::Packet::Trans2::QueryFsInformationResponse).to receive(:read).and_return(query_response)
668
+ allow(RubySMB::SMB1::Packet::Trans2::SetFsInformationResponse).to receive(:read).and_return(set_response)
669
+ end
670
+
671
+ it 'queries the server for CIFS UNIX info and then echoes the capability bits back via SET_CIFS_UNIX_INFO' do
672
+ sent = []
673
+ allow(client).to receive(:send_recv) do |req|
674
+ sent << req
675
+ ''
676
+ end
677
+ tree.enable_cifs_unix_extensions
678
+
679
+ expect(sent[0]).to be_a(RubySMB::SMB1::Packet::Trans2::QueryFsInformationRequest)
680
+ expect(sent[0].data_block.trans2_parameters.information_level).to(
681
+ eq(RubySMB::SMB1::Packet::Trans2::QueryFsInformationLevel::SMB_QUERY_CIFS_UNIX_INFO)
682
+ )
683
+
684
+ expect(sent[1]).to be_a(RubySMB::SMB1::Packet::Trans2::SetFsInformationRequest)
685
+ expect(sent[1].data_block.trans2_parameters.information_level).to(
686
+ eq(RubySMB::SMB1::Packet::Trans2::SetFsInformationLevel::SMB_SET_CIFS_UNIX_INFO)
687
+ )
688
+ echoed = RubySMB::SMB1::Packet::Trans2::QueryFsInformationLevel::QueryFsCifsUnixInfo.read(
689
+ sent[1].data_block.trans2_data.buffer
690
+ )
691
+ expect(echoed.major_version).to eq(1)
692
+ expect(echoed.minor_version).to eq(0)
693
+ expect(echoed.capabilities).to eq(0x17B)
694
+ end
695
+
696
+ it 'raises UnexpectedStatusCode when the QUERY leg fails' do
697
+ query_response.smb_header.nt_status = WindowsError::NTStatus::STATUS_ACCESS_DENIED.value
698
+ allow(client).to receive(:send_recv).and_return('')
699
+ expect { tree.enable_cifs_unix_extensions }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
700
+ end
701
+
702
+ it 'raises UnexpectedStatusCode when the SET leg fails' do
703
+ set_response.smb_header.nt_status = WindowsError::NTStatus::STATUS_INVALID_PARAMETER.value
704
+ allow(client).to receive(:send_recv).and_return('')
705
+ expect { tree.enable_cifs_unix_extensions }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
706
+ end
707
+ end
708
+
585
709
  describe '#set_header_fields' do
586
710
  let(:modified_request) { tree.set_header_fields(disco_req) }
587
711
  it 'adds the TreeID to the header' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_smb
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.19
4
+ version: 3.3.21
5
5
  platform: ruby
6
6
  authors:
7
7
  - Metasploit Hackers
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2026-04-27 00:00:00.000000000 Z
16
+ date: 2026-06-08 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: redcarpet
@@ -571,6 +571,7 @@ files:
571
571
  - lib/ruby_smb/smb1/packet/trans2/query_file_information_response.rb
572
572
  - lib/ruby_smb/smb1/packet/trans2/query_fs_information_level.rb
573
573
  - lib/ruby_smb/smb1/packet/trans2/query_fs_information_level/query_fs_attribute_info.rb
574
+ - lib/ruby_smb/smb1/packet/trans2/query_fs_information_level/query_fs_cifs_unix_info.rb
574
575
  - lib/ruby_smb/smb1/packet/trans2/query_fs_information_request.rb
575
576
  - lib/ruby_smb/smb1/packet/trans2/query_fs_information_response.rb
576
577
  - lib/ruby_smb/smb1/packet/trans2/query_information_level.rb
@@ -583,6 +584,12 @@ files:
583
584
  - lib/ruby_smb/smb1/packet/trans2/response.rb
584
585
  - lib/ruby_smb/smb1/packet/trans2/set_file_information_request.rb
585
586
  - lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb
587
+ - lib/ruby_smb/smb1/packet/trans2/set_fs_information_level.rb
588
+ - lib/ruby_smb/smb1/packet/trans2/set_fs_information_request.rb
589
+ - lib/ruby_smb/smb1/packet/trans2/set_fs_information_response.rb
590
+ - lib/ruby_smb/smb1/packet/trans2/set_information_level.rb
591
+ - lib/ruby_smb/smb1/packet/trans2/set_path_information_request.rb
592
+ - lib/ruby_smb/smb1/packet/trans2/set_path_information_response.rb
586
593
  - lib/ruby_smb/smb1/packet/trans2/subcommands.rb
587
594
  - lib/ruby_smb/smb1/packet/trans2/win9x_framing.rb
588
595
  - lib/ruby_smb/smb1/packet/tree_connect_request.rb
@@ -922,6 +929,10 @@ files:
922
929
  - spec/lib/ruby_smb/smb1/packet/trans2/response_spec.rb
923
930
  - spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_request_spec.rb
924
931
  - spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_response_spec.rb
932
+ - spec/lib/ruby_smb/smb1/packet/trans2/set_fs_information_request_spec.rb
933
+ - spec/lib/ruby_smb/smb1/packet/trans2/set_fs_information_response_spec.rb
934
+ - spec/lib/ruby_smb/smb1/packet/trans2/set_path_information_request_spec.rb
935
+ - spec/lib/ruby_smb/smb1/packet/trans2/set_path_information_response_spec.rb
925
936
  - spec/lib/ruby_smb/smb1/packet/trans2/win9x_framing_spec.rb
926
937
  - spec/lib/ruby_smb/smb1/packet/tree_connect_request_spec.rb
927
938
  - spec/lib/ruby_smb/smb1/packet/tree_connect_response_spec.rb
@@ -1275,6 +1286,10 @@ test_files:
1275
1286
  - spec/lib/ruby_smb/smb1/packet/trans2/response_spec.rb
1276
1287
  - spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_request_spec.rb
1277
1288
  - spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_response_spec.rb
1289
+ - spec/lib/ruby_smb/smb1/packet/trans2/set_fs_information_request_spec.rb
1290
+ - spec/lib/ruby_smb/smb1/packet/trans2/set_fs_information_response_spec.rb
1291
+ - spec/lib/ruby_smb/smb1/packet/trans2/set_path_information_request_spec.rb
1292
+ - spec/lib/ruby_smb/smb1/packet/trans2/set_path_information_response_spec.rb
1278
1293
  - spec/lib/ruby_smb/smb1/packet/trans2/win9x_framing_spec.rb
1279
1294
  - spec/lib/ruby_smb/smb1/packet/tree_connect_request_spec.rb
1280
1295
  - spec/lib/ruby_smb/smb1/packet/tree_connect_response_spec.rb