#!/usr/bin/perl # ##################################################################### # Outlook Web Access - Address Book Enumeration ##################################################################### # # Copyright (C) 2010 Joe Mondloch # JoMo-Kun / jmk@foofus.net # # This script retrieves all names from the "Find Names" feature in OWA # using the "galfind" URL query. If target URL contains "finduser", use # OWAFindUsersOld.pl. # # Tested against OWA 2003 # Tested against IIS 5.0/OWA # # Notes: verify logon name matches internal exchange username. # Ex. user1/pass1 logs in. However, site is https://$host/exchange/firstname_lastname@domain.com/... # # Authen:NTLM -> /usr/lib/perl5/vendor_perl/5.8.6/Authen/ # use HTTP::Cookies; use LWP::UserAgent; use Authen::NTLM; use Getopt::Long; #use LWP::Debug qw(+); my $VERSION = "0.4"; my %opt, %data; my $ua = new LWP::UserAgent(keep_alive=>1); my $jar = HTTP::Cookies->new(); $opt{'domain'} = ''; $opt{'ssl'} = 0; $opt{'proxy'} = 0; $ua->cookie_jar($jar); push @{ $ua->requests_redirectable }, 'POST'; GetOptions ( 'host=s' => \$opt{'host'}, 'username=s' => \$opt{'username'}, 'password=s' => \$opt{'password'}, 'domain=s' => \$opt{'domain'}, 'type=s' => \$opt{'type'}, 'ssl' => sub { $opt{'ssl'} = 1 }, 'proxy' => sub { $opt{'proxy'} = 1 }, ); print "\nJoMo-Kun M\$ OWA Find User Enumerator\n\n"; if ( !( defined($opt{'host'}) && defined($opt{'username'}) && defined($opt{'password'}) && defined($opt{'type'}) ) ) { print "getOWAnames V. $VERSION\n"; print "Usage:\n"; print " $0\n"; print " --host \n"; print " --username \n"; print " --password \n"; print " --domain \n"; print " --type <1,2,3>\n"; print " 1: basic auth mode\n"; print " 2: basic-auth/owaauth.dll mode\n"; print " 3: NTLM-auth mode\n"; print " 4: CookieAuth.dll mode\n"; print " --ssl\n"; print " --proxy\n"; print "\n\n"; exit(1); } ############################################################################### # Creating initial connection to OWA if ($opt{'ssl'}) { $opt{'port'} = '443'; $req = new HTTP::Request GET => "https://$opt{'host'}/exchange/"; } else { $opt{'port'} = '80'; $req = new HTTP::Request GET => "http://$opt{'host'}/exchange/"; } if ($opt{'type'} eq "3") { print "*********************** NOTICE ***********************\n"; print " If authentication fails, verify the following:\n"; print " 1. Authen::NTLM written by Mark Bush is installed.\n"; print " 2. Modify line 173 of NTLM.pm to set $domain = \'\'\n"; print "******************************************************\n"; $ua->credentials("$opt{'host'}:$opt{'port'}", '', "$opt{'domain'}\\$opt{'username'}", "$opt{'password'}"); } else { $req->authorization_basic($opt{'username'}, $opt{'password'}); } if ($opt{'proxy'}) { $ua->proxy(['http', 'https'], 'http://localhost:8008/'); } my $res = $ua->request($req); $jar->extract_cookies($res); print "Connecting to OWA: "; if (($res->is_success) && ($res->code != 302)) { print "Success\n"; } else { print $res->status_line, "\n"; exit(1); } ############################################################################### # Not sure if this is a normal 2003 or installation specific setup... if ($opt{'type'} eq "2") { if ($opt{'ssl'}) { $req = new HTTP::Request POST => "https://$opt{'host'}/exchweb/bin/auth/owaauth.dll"; $req->content("destination=https://$opt{'host'}/exchange/&flags=0&username=$opt{'username'}&password=$opt{'password'}&SubmitCreds=Log+On&trusted=0"); } else { $req = new HTTP::Request POST => "http://$opt{'host'}/exchweb/bin/auth/owaauth.dll"; $req->content("destination=http://$opt{'host'}/exchange/&flags=0&username=$opt{'username'}&password=$opt{'password'}&SubmitCreds=Log+On&trusted=0"); } $req->content_type('application/x-www-form-urlencoded'); $req->authorization_basic($opt{'username'}, $opt{'password'}); $res = $ua->request($req); $jar->extract_cookies($res); print "Submitting Credentials to OWA: "; if ($res->is_success) { print "Success\n"; } elsif ($res->code == 302) { print "302 Move Temporarily\n"; } else { print $res->status_line, "\n"; exit(1); } } ############################################################################### if ($opt{'type'} eq "4") { my $path = "CookieAuth.dll?Logon"; my $user = ""; if ($opt{'domain'} ne "") { $user = "$opt{'domain'}%5C$opt{'username'}"; } else { $user = "$opt{'username'}"; } if ($opt{'ssl'}) { $req = new HTTP::Request POST => "https://$opt{'host'}/$path"; $req->referer("https://$opt{'host'}/CookieAuth.dll?GetLogon?url=%2F&reason=0"); $req->content("destination=Z2F&flags=0&username=$user&password=$opt{'password'}&SubmitCreds=Log+On&trusted=0"); } else { $req = new HTTP::Request POST => "http://$opt{'host'}/$path"; $req->referer("http://$opt{'host'}/CookieAuth.dll?GetLogon?url=%2F&reason=0"); $req->content("destination=Z2F&flags=0&username=$user&password=$opt{'password'}&SubmitCreds=Log+On&trusted=0"); } $req->content_type('application/x-www-form-urlencoded'); $req->authorization_basic($opt{'username'}, $opt{'password'}); $res = $ua->request($req); $jar->extract_cookies($res); print "Submitting Credentials to OWA: "; if ($res->is_success) { print "Success\n"; } elsif ($res->code == 302) { print "302 Move Temporarily\n"; } else { print $res->status_line, "\n"; exit(1); } } ############################################################################### # Locate base directory... # Content-Base: http://111.222.333.444:8888/exchange/FooBar/ # **Directory does not necessarily match username** if ($res->as_string =~ /Content-Base:/) { ($data{'content-base'}) = $res->as_string =~ /Content-Base:.*$opt{'host'}\/(.*)\//; print "Using Content-Base Header: $data{'content-base'}\n"; } ############################################################################### # Retrieve all user accounts print "Retrieving OWA user names:\n"; getNames('a'..'z'); # a little recursion to get all those names... sub getNames { my @letters = @_; foreach $letter (@letters) { if ( ! printNames($letter) ) { foreach ('a'..'z') { getNames($letter . $_); } } } } ############################################################################### # connect to OWA and grab the users sub printNames { my $AliasName = shift @_; # Currently matching on "Alias Name". Modify to GET query for different field. if ($opt{'ssl'}) { #$req = new HTTP::Request GET => "https://$opt{'host'}/$data{'content-base'}/Inbox/?Cmd=galfind&DN=&LN=&FN=&TL=&AN=$AliasName&CP=&DP=&OF=&CY="; #$req = new HTTP::Request GET => "https://$opt{'host'}/exchange/someuser/?Cmd=galfind&DN=&LN=&FN=&TL=&AN=$AliasName&CP=&DP=&OF=&CY="; $req = new HTTP::Request GET => "https://$opt{'host'}/$data{'content-base'}/Inbox/?Cmd=galfind&DN=&LN=&FN=&TL=&AN=$AliasName&CP=&DP=&OF=&CY="; } else { $req = new HTTP::Request GET => "http://$opt{'host'}/$data{'content-base'}/Inbox/?Cmd=galfind&DN=&LN=&FN=&TL=&AN=$AliasName&CP=&DP=&OF=&CY="; } if ($opt{'proxy'}) { $ua->proxy(['http', 'https'], 'http://localhost:8008/'); } if ($opt{'type'} eq "3") { $ua->credentials("$opt{'host'}:$opt{'port'}", "", "$opt{'domain'}\\$opt{'username'}", $opt{'password'}); } else { $req->authorization_basic($opt{'username'}, $opt{'password'}); } $jar->add_cookie_header($req); my $res = $ua->request($req); $jar->extract_cookies($res); if (($res->is_success) && ($res->code != 302)) { } else { print $res->status_line, "\n"; exit(1); } @results = split /\n/, $res->content; if (grep /This query would return too many addresses!/, @results) { return 0; } else { for (my $i=0; $i <= $#results; $i++) { next unless $results[$i] =~ //i; my @row = split /<\/tr>/, $results[$i]; foreach(@row) { chomp; my @col = split /<\/td>/i; my ($name) = $col[0] =~ /(.*)<\/font>/i; my ($phone) = $col[1] =~ /(.*)<\/font>/i; my ($office) = $col[2] =~ /(.*)<\/font>/i; my ($title) = $col[3] =~ /(.*)<\/font>/i; my ($company) = $col[4] =~ /(.*)<\/font>/i; my ($userid) = $col[5] =~ /(.*)<\/font>/i; print $name, "::", $phone, "::", $office, "::", $title, "::", $company, "::", $userid, "\n"; } last; } return 1; } }