0

I have what I believe to be a Hash that references an array of hashes. What I am trying to understand is how to access the hash elements within this array of hashes.

EDIT: Here is the full hash structure

$VAR1 = {
      'CVE-2015-0677' => {
                         'vuln:references' => [
                                              {
                                                'attr' => {
                                                            'reference_type' => 'VENDOR_ADVISORY',
                                                            'xml:lang' => 'en'
                                                          },
                                                'vuln:source' => 'CISCO',
                                                'vuln:reference' => [
                                                                    {
                                                                      'attr' => {
                                                                                  'href' => 'http://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20150408-asa',
                                                                                  'xml:lang' => 'en'
                                                                                }
                                                                    }
                                                                  ]
                                              }
                                            ],
                         'vuln:published-datetime' => '2015-04-12T21:59:03.033-04:00',
                         'vuln:last-modified-datetime' => '2015-04-13T17:45:18.310-04:00',
                         'vuln:vulnerable-software-list' => [
                                                              'cpe:/o:cisco:adaptive_security_appliance_software:9.0.3',
                                                              'cpe:/o:cisco:adaptive_security_appliance_software:8.4.5',
                                                            ],
                         'vuln:summary' => 'The XML parser in Cisco Adaptive Security Appliance (ASA) Software 8.4 before 8.4(7.28), 8.6 before 8.6(1.17), 9.0 before 9.0(4.33), 9.1 before 9.1(6), 9.2 before 9.2(3.4), and 9.3 before 9.3(3), when Clientless SSL VPN, AnyConnect SSL VPN, or AnyConnect IKEv2 VPN is used, allows remote attackers to cause a denial of service (VPN outage or device reload) via a crafted XML document, aka Bug ID CSCus95290.'
                       }
    };

If I try the following the output of the first Data::Dumper output is identical to the second.

for my $key ( keys $hash ) {
 my @references =  $hash->{$key}{'vuln:references'};
 print Dumper(@references);  #1
  for my $vulnref (@references) {
    print Dumper($vulnref); #2
  }
}

#1
$VAR1 = [
       {
         'vuln:reference' => 'VENDOR',
         'vuln:source' => 'CISCO',
        }
        ];

#2  
$VAR1 = [
      {
        'vuln:reference' => 'VENDOR',
        'vuln:source' => 'CISCO',

      }
    ];

So my for loop doesn't seem to be having any affect?

However if I loop through twice then the second loop

for my $key ( keys $hash ) {
  my @references =  $hash->{$key}{'vuln:references'};
  print Dumper(@references); #1
  for my $vulnref (@references) {
    for my $vuln ($vulnref) {
       print Dumper($vuln);  #2
    }
   }
}


#1 
$VAR1 = [
       {
        'vuln:reference' => 'VENDOR',
        'vuln:source' => 'CISCO',

      }
    ];

#2
$VAR1 = {
       'vuln:reference' => 'VENDOR',
       'vuln:source' => 'CISCO', 
    };

I now seem to be accessing the hash.

I believe I am missing something fundamental here.

Many thanks.

1
  • Please show the output of print Dumper $hash. Commented Apr 20, 2015 at 4:33

1 Answer 1

1

You don't show the topmost level of the hash. The $VAR1 that you show is the value of $hash->{key}, but I can't tell what key might be.

Anyway, using what I have,

  • $hash->{key} is a reference to a hash with a single element with the key vuln:references

  • $hash->{key}{'vuln:references'} is a reference to an array with a single element at index zero

  • $hash->{key}{'vuln:references'}[0] is a reference to another hash, this time with two elements

You don't say what you want to do with this data, but it looks like all you need is

my $data = $hash->{key}{'vuln:references'}[0];

for my $key (keys %$data) {
  printf "%s => %s\n", $key, $data->{$key};
}

output

vuln:source => CISCO
vuln:reference => VENDOR

Update

You don't say how $key gets defined, but in

for my $data ( $hash->{$key}{'vuln:references'} ) { ... }

you have written a loop that executes once with $data set to the array reference that I described above.

To loop over the whole structure, assuming your outermost hash referred to by $hash and the inner array are the only layers with multiple elements, you could write

for my $cve ( keys %$hash ) {
  my $refs = $hash->{$cve}{'vuln:references'};
  print $cve, " \n";
  for my $ref ( @$refs ) {
    printf "  %s => %s\n", $_, $ref->{$_} for keys %$ref;
    print "\n";
  }
}

Notice the dereferencing of the structures in keys %$hash, @$refs and %$ref. In more recent versions of Perl you can use keys $hash without the dereference, but it is an experimental feature that shouldn't be used in live code, and will produce a warning message if you have use warnings in place as you should (together with use strict) at the top of your program

As for why your code dumps the same values twice, you have

my @references = $hash->{$key}{'vuln:references'};

which sets the array @references to hold one element which is the array reference from the hash at that point. Then

print Dumper(@references);

dumps each element of the array, one by one. Because there is only one element it outputs only one dump. Finally

for my $vulnref (@references) {
  for my $vuln ($vulnref) {
    print Dumper($vuln);
  }
}

sets $vulnref to each element of @references. Because there is only one the loop executes once, with $vulnref set to the array reference. Then $vuln is set to each element of the list ( $vulnref ) so it takes another copy of the same reference. Finally that value is dumped, with the result that the same array reference as before is displayed.

Remember that Perl scalar values start with $; even an element of an array is $array[0], and it is treated as a single value even if that value is a reference. If you want to access the data it refers to you must dereference it with the appropriate symbol

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks Borodin, I've updated my question to include the original full hash, the key in this case in the 'CVE-2015-0677'. There can be multiple 'CVE' entries but I've just shown one for simplicity. Please note I simplified the structure in my original question of the 'vuln:references' to remove what seemed irrelavent to the question.
ok, so if I use 'my $data = $hash->{key}{'vuln:references'}[0];' it works, but if I use a for loop instead like so 'for my $data ($hash->{$key}{'vuln:references'})' it tells me that '$data' is not a hash reference when I try to access it in the same way as you have described above. What is the difference between the two? I'm still stuck with the same original question. Why does my first for loop not appear to change the data at all?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.