using perl to get users of AD group - perl

I've been trying to get this to print out all the members in "domain users". Problem is, it only prints out a small portion of them, then it just sorta stops. Not sure why. Can someone shed some light on the problem?
#!/usr/bin/perl
use Net::LDAP;
my $uid = "cn=account,cn=users,dc=domain,dc=local";
my $bindPass = "password";
my $ldapServer = "ldap://server.domain.local";
# connect to ldap server
$ldap = Net::LDAP -> new ($ldapServer) || die "Could not connect to server\n";
# bind to ldap server
$ldap -> bind($uid, password => $bindPass);
# search for group
$mesg = $ldap -> search(filter => "(&(cn=Domain Users))", base => "dc=domain,dc=local");
$entry = $mesg -> entry;
# #members = $entry -> get_value ('member;Range=0-*');
#the above entry when uncommented doesn't work either.
#members = $entry -> get_value ('member');
foreach $thing (#members) {
print "$thing\n";
}

From the Net::LDAP docs:
sizelimit => N
A sizelimit that restricts the maximum number of entries to be
returned as a result of the search. A value of 0, and the default,
means that no restriction is requested. Servers may enforce a maximum
number of entries to return.
It might very well be your AD server has a restriction configured. Try checking $mesg->error() after the search.
You might have more success if you use ldap://server.domain.local:3268/ as your URL. AD uses a "mini" ldap server on that port to talk to replicated servers (google "global catalog"); you won't see all attributes on that server, but maybe it's less restrictive as to the maximum number of entries.

Related

Determining the hash type I am working with for use in hashcat

I am trying to crack some hashed information because the passcode was lost to us. I have the hashed information in the database, and the code that was used to encrypt it. It goes through cryptastic which appears to use rijndael-256 and pbkdf2, as far as my ignorant self can tell:
public function encrypt($msg, $k, $base64 = false)
{
# open cipher module (do not change cipher/mode)
if (!$td = mcrypt_module_open('rijndael-256', '', 'ctr', ''))
return false;
$msg = serialize($msg); # serialize
$iv = mcrypt_create_iv(32, MCRYPT_RAND); # create iv
if (mcrypt_generic_init($td, $k, $iv) !== 0) # initialize buffers
return false;
$msg = mcrypt_generic($td, $msg); # encrypt
$msg = $iv . $msg; # prepend iv
$mac = $this->pbkdf2($msg, $k, 1000, 32, 'sha256'); # create mac
$msg .= $mac; # append mac
mcrypt_generic_deinit($td); # clear buffers
mcrypt_module_close($td); # close cipher module
if ($base64)
$msg = base64_encode($msg);# base64 encode?
return $msg; # return iv+ciphertext+mac
}
And in the end looks like this: wWTWLPvXT9YRz2Zj+Og0EwTTSEiZGdjAQ1TRhycJA9jusjQ2mTpptw3hSM1XJ9yPw+4XvsvFASe08AbLr3BT0LFnvGsYPrq87yI= (I know this to be a 3 digit number if that helps at all)
So I am trying to use hashcat to recover our information and I am not certain I am using the correct hash-type. I am checking this page here: https://hashcat.net/wiki/doku.php?id=example_hashes and searching for 'pbkdf2' and looking at all the hits.
The best match as far as I can tell is 9200/Cisco-IOS $8$ (PBKDF2-SHA256) except that that seems to have a header of $8$, and none of my information has any headers at all, and no $ characters. Everything else with PBKDF2 in it doesn't seem to be a match either so I find myself kind of lost before I've even gotten started.
I also noticed my hashed info always had == on the end, but only for the longer information being encrypted, in the list Juniper IVE seems to fit that format but the name doesn't match anything I can see in cryptastic.
I'm mostly ready to go aside from this as far as I can tell, I have my custom rules set up since I know how we create the initial passcodes and the hashes are in a file to be read, it's just this hash-type selection that is blocking me.
Any help appreciated!

connection to the active server Infoblox

I am a beginner and I have to take a solution using two Infoblox boxes.
Currently, a server is active (master) and the other is passive. if the first fails, the second takes over. I use Perl API, how do I know when I try to connect to a server ,if it is the active server or the passive server?
I would only make the connection to the active server,
I have thought about the method « active_position() » of Infoblox::Grid::Member but I dont know how to use it..
use strict;
use Infoblox;
my $grid_member = Infoblox::Grid::Member->new(gateway=> "xxx.xxx.xxx.xxx",ipv4addr=> "xxx.xxx.xxx.xxx",mask=> "xxx.xxx.xxx.xxx", name=> "ibiza.mydomain.com");
print 'grid : '. $grid_member . "\n";
my $active_server = $grid_member->active_position();
print $active_server . "\n";
exit;
And this returns
grid : Infoblox::Grid::Member=HASH(0xf10ca8)
0
What is this "0" ??
Thank you in advance
If your Grid Master is a HA pair then you don't need to worry about which one to connect to. You just connect to the VIP (virtual IP) of the HA pair which will always be the same address.
Example session test code:
#!/usr/bin/perl
use strict;
use Infoblox;
# Create a session to the Infoblox appliance
my $SESSION = Infoblox::Session->new(
master => "192.168.1.2",
username => "admin",
password => "***"
);
if ($SESSION->status_code()) {
my $result = $SESSION->status_code();
my $response = $SESSION->status_detail();
print "Error: $response ($result)\n";
} else {
print "Connection established\n";
print "Server Version: ".$SESSION->server_version()."\n";
}
Check the API docs on your appliance https://appianceip/api/doc there are lots and lots of examples embedded in the API docs.
Steve

Perl LDAP search for user being a CN attribute

How to do a Perl LDAP search/authentication for user being an attribute in access group or it's subgroups?
All users (UIDs) are in:
ou=Users,o=company,c=com
Access group is:
cn=Site Full Access,ou=Access,o=company,c=com
Access group has users and subgroups as attributes like:
uniquemember | uid=usernameA,ou=Users,o=company,c=com
uniquemember | uid=usernameB,ou=Users,o=company,c=com
uniquemember | uid=usernameC,ou=Users,o=company,c=com
uniquemember | cn=Site Full Access Employees,ou=Access,o=company,c=com
(subgroup has its own uniquemember attributes)
Authentication script idea:
Bind user with his login/password (done).
If successful, create user's DN like uid=$username,ou=Users,o=company,c=com (done)
Iterate through attributes of cn=Site Full Access,ou=Access,o=company,c=com and compare them to user's DN
If encountered a group, search for user's DN inside this group too
I am using Net::LDAP, but there is not much code to show as what works is quite standard. This is the listing of uniquemember attributes:
my $mesg = $ldap->bind ($user_dn, password=>"$pass");
$mesg->code && return undef;
$mesg = $ldap->search(base=>$ldap_access_full, filter=>"(objectclass=*)");
$mesg->code && return undef;
my #entries = $mesg->entries;
my $entry;
foreach $entry ( #entries )
{
if ($entry->exists('uniquemember'))
{
my $ref = $entr->get_value('uniquemember', asref=>1);
for my $uid (#$ref)
{
print $uid . "<br/>";
}
}
}
This gives me an array of user DNs but also groups that will have to be listed and compared in some recursive function.
How do I approach this? Perhaps there is another way to check both password and access group, with user still being an attribute of access group or it's subgroups? I can't do any LDAP modifications.
This called nested groups. For AD here is one solution: How to retrieve all Groups from LDAP with Perl
One solution is to ignore groups, only allow direct user objects.
If you need to process sub groups you should retrieve the entry and check it is a group or people. In case you need to check this in many levels (sub groups of sub groups of..) then you needs to do the check recursivly.
For one level of nested groups. It is half complete and not tested but you got the idea.
Of course use subroutines, but I did not used for easier understanding (and lack of time)
$mesg = $ldap->search(base=>$ldap_access_full, filter=>"(objectclass=*)",attrs => [qw(uniquemember)]);
$mesg->code && die $mesg->code;
my #entries = $mesg->entries;
my $entry;
foreach $entry ( #entries ) {
my #uniquemembers = $entr->get_value('uniquemember');
foreach my $uniquemember (#uniquemembers){
#get entry
$mesg = $ldap->search(base=>$uniquemember, filter=>"(objectclass=*)", attrs => [qw(objectclass uid uniquemember)], scope => 'base');
$mesg->code && die $mesg->code;
#if is a group or user?
my $uniquemember_entry = ($mesg->entries)[0];
my #objectclasses = $uniquemember_entry->get_value('objectclass');
my $uid = $uniquemember_entry->get_value('uid');
if (grep {/user/i} #objectclasses || defined $uid){
print "$uniquemember has uid: $uid\n";
} elsif (grep {/group/i} #objectclasses){
print "it is a group: $uniquemember\n";
#get its members
my #nested_group_uniquemembers = $uniquemember_entry->get_value('uniquemember');
#get entries
foreach my $nested_group_uniquemember (#nested_group_uniquemembers){
$mesg = $ldap->search(base=>$nested_group_uniquemember, filter=>"(objectclass=*)", attrs => [qw(objectclass uid uniquemember)], scope => 'base');
$mesg->code && die $mesg->code;
}
#check it is an user or group...
} else {
}
}
}

Perl - Net::DNS to create PTR record

First, the relevant xkcd comic: http://xkcd.com/979/
Next, the 10-year old thread on PerlMonks: http://www.perlmonks.org/?node_id=210422
Basically, I'm failing in my attempts to use Net::DNS::Update to create a PTR record and I'd like to see how others have manged this.
Below is what I'm trying. $hst is the hostname that I already have an A record for. $rev is the backwards IP address in-addr.arpa thingy.
# Create the update packet:
my $update = Net::DNS::Update->new($OURDOMAIN);
# Add the PTR record:
$update->push(update => rr_add("$rev 3600 PTR $hst"));
# Send the update to the zone's primary master.
my $res = Net::DNS::Resolver->new;
$res->nameservers("$OURNMSERV");
If $OURDOMAIN is your main domain name, you need to know that you can't put PTR records into your own domain, they have to be put in the right .in-addr.arpa zone.
That zone is most likely being run by your ISP, and they're unlikely to support dynamic updates from end users.
Another ten years later, http://xkcd.com/979/ is still relevant. Having read the question and answer and also the linked PerlMonks thread, it was still unclear to me how to properly add PTR records using Net::DNS.
Well, 'when in Rome do as the Romans do' the saying goes. Having noticed that nsupdate can add PTR records to our internal DNS system just fine without me specifying the reverse zone, I was trying to find out what it does to send valid updates. Turned out it actually sends a SOA query first to figure out what the reverse zone is. Copying this behavior seems to be a somewhat robust way to add PTR records via Net::DNS:
use Net::DNS;
my $hostname = 'somehost.example.com.';
my $ip = '10.11.12.13';
my $primary_ns = 'primary.example.com';
# First, construct the reverse name based on the IP address
my #octets = split /\./, $ip;
my #rev_octs = reverse(#octets);
my $rev_name = join(".", #rev_octs) . '.in-addr.arpa.';
# Then, query the SOA record for the constructed reverse name
my $resolver = Net::DNS::Resolver->new();
$resolver->nameservers($primary_ns);
# Note: Need to use 'send' rather than 'query' since we are interested
# in the 'authority section' of the reply only.
my $packet = $resolver->send($rev_name, 'SOA');
my $zone;
if ($packet) {
# We expect only one authority record
my $len = $packet->authority;
if ($len == 0) {
# Server might not be authorative for reverse lookup zone.
warn "No authority section in reply.\n";
exit 1;
}
my $auth = ($packet->authority)[0];
$zone = $auth->name;
} else {
warn 'query failed: ', $resolver->errorstring, "\n";
exit 1;
}
# Armed with this information, we can finally add the PTR records
my $update = Net::DNS::Update->new($zone);
# Make sure that the PTR record does not already exist
$update->push( pre => nxrrset("$rev_name PTR") );
$update->push( update => rr_add("$rev_name 1200 PTR $hostname") );
my $reply = $resolver->send($update);
if ($reply) {
if ($reply->header->rcode eq 'NOERROR') {
print "Successfully added PTR record!\n";
} else {
print 'Update failed: ', $reply->header->rcode, "\n";
}
} else {
print 'Update failed: ', $resolver->errorstring, "\n";
}

Increase limit from 1000?

When I do a search like so
my $mesg = $ldap->search(
base => "OU=test,DC=example,DC=com",
scope => 'one',
filter => '(objectClass=organizationalPerson)',
attrs => ['distinguishedName', 'displayName', 'sAMAccountName', 'employeeID'],
);
I only get 1000 entries, where I would expect ~20000.
Is it possible to increase this limit in my Perl script, or does it have to be changed on the server?
The solution is to use paged search like so
use Net::LDAP;
use Net::LDAP::Control::Paged;
use Net::LDAP::Constant qw( LDAP_CONTROL_PAGED );
my $page = Net::LDAP::Control::Paged->new(size => 999);
my $cookie;
while (1) {
$mesg = $ldap->search(
base => "OU=test,DC=example,DC=com",
scope => 'one',
filter => '(objectClass=organizationalPerson)',
attrs => ['distinguishedName', 'displayName', 'sAMAccountName', 'employeeID'],
control => [$page]
);
$mesg->code && die "Error on search: $# : " . $mesg->error;
while (my $adentry = $mesg->pop_entry()) {
# process $adentry
}
my ($resp) = $mesg->control(LDAP_CONTROL_PAGED) or last;
$cookie = $resp->cookie or last;
# Paging Control
$page->cookie($cookie);
}
if ($cookie) {
print "abnormal exit\n";
# Abnormal exit, so let the server know we do not want any more
$page->cookie($cookie);
$page->size(0);
$ldap->search(control => [$page]);
}
AD by default set the maximum page size to 1000. The client will receive the first 1000 result and also an receive an error "Size Limit Exceeded".
To avoid this the client has to use paged control, if the paged control is used the server will not return error but instead it will send a cookie (a byte) to indicate there is some more result available. If there is no cookie available which means no more result. So you can continue looping for the result until cookie is null.
You can also modify MaxPageSize in the server if you want, start ntdsutil and
type the following,
ldap policies
connections
connect to server servername.domain.name
q
set maxpagesize to 5000
commit
changes
q
q
This is mostly done if the client does not support paging and the client can not be modified.
You don't specify the module that you are using to ldap search. By the way 'sizelimit' key can be used to it but by default it is not limited. This can be a server side limit configuration.