Home page logo

nmap-dev logo Nmap Development mailing list archives

Bug in SMB when multiple scripts are connecting to same host
From: Chris Woodbury <chris3e3 () gmail com>
Date: Mon, 7 Feb 2011 19:28:18 -0600

I've found what I think is a bug in the SMB library, which gets
triggered in the following situation:
1. Multiple scripts/script instances are running concurrently against
the same host via SMB and are in
smb.start_session_basic()/start_session_extended() at the same time.
2. The first entry in the SMB accounts list (nmap.registry[ IP ][
"smbaccounts" ] cannot log in.
3. There are no username overrides.

In this situation, script #1 gets the first account off the list and
tries to authenticate (unsuccessfully, as it will turn out). The
network I/O causes a switch to script #2, which also gets the first
account off the list and tries to authenticate (unsuccessfully as
well, of course). The scripts each get going again and both make it
down to the point where it is recognized that authentication has
failed (beginning on line 1216 or 1384) and smbauth.next_account() and
smbauth.get_account() are called to get the next account to try to
authenticate with. Here is the problem. Both scripts have realized
that their authentication attempts failed and call next_account(), but
next_account() and get_account() work on a list of accounts that is
shared for the host. Thus, script #1 gets the second account on the
list, but script #2 gets the *third* account on the list.

I have attached a script that should demonstrate this. If you make
another copy (e.g. testsmb2.nse) and run them both against a host that
allows anonymous logins (e.g. nmap -d2 -p 445 --script
testsmb,testsmb2 <host>), you should see one succeed and ther other
fail with "No accounts left to try." You may need to run in a couple
times to get this to happen.

Off the top of my head, it seems that this might be solved by making
the list of accounts (or the index) tied to the smbstate (and thus
specific to each script instance), or by using a mutex. I won't
pretend to understand SMB and the smb libraries like Ron does, so I
haven't tried to patch this myself.

Please let me know if I've missed or misunderstood anything, or if
anyone has questions.

Illustrative scenario: Four scripts are attempting to connect to a
share that is accessible with the anonymous login (i.e. null session).
No SMB credentials are given or discovered. The scripts aren't doing
anything fancy and are using the high-level SMB functions (e.g.
start_session_ex() ).
1. Script #1 starts first (the others are "started" but don't run
until Script #1 makes a network I/O call).
2. Script #1 calls smb.start_session_ex(), which calls smb.start(),
which calls smbauth.init_account(), which populates the account list
for the host with { guest, anonymous }.
3. Script #1's smb.start_session_ex() eventually calls
smb.start_session(), which in this example calls
smb.start_session_extended(). This calls smbauth.get_account(),
retrieving the guest account, which is then used in an authentication
4. Script #1's authentication attempt is network I/O, so execution
switches to Script #2, which gets to the same point as Script #1, also
attempting to log in with the guest account.
5. The same for Script #3.
6. Execution switches back to Script #1, which sees that its login
attempt failed, so it calls smbauth.next_account() [smb.lua line
1386], which moves to the anonymous login. Script #1 then calls
smb.get_account() to get the new account to try, and loops back around
to make an authentication attempt with it.
7. Execution switches to Script #2, which does the same thing, except
that its call to next_account() exhausts the account list. Its call to
smb.get_account() gets an error saying there are "No accounts left to
try", which causes the original call to smb.start_session_ex() to
8. Execution switches to Script #1, which just authenticated with the
anonymous login, which was successful. Its call to
smb.start_session_ex() returns successfully.
9. Execution switches to Script #3, which does the same thing as
Script #2 in step 7. Its call to smb.start_session_ex() also fails
with "No accounts left to try".
10. Execution switches to Script #4, which has been waiting patiently.
Like the others, it starts with a call to smb.start_session_ex(), but
when it gets to the first call to smbauth.get_account() [line 1257],
there are no more accounts, and Script #4 also fails with "No accounts
left to try".

Thus, out of four scripts, only one of them was actually able to get
and use the valid credentials that were in the account list.

Attachment: testsmb.nse

Sent through the nmap-dev mailing list
Archived at http://seclists.org/nmap-dev/

  By Date           By Thread  

Current thread:
[ Nmap | Sec Tools | Mailing Lists | Site News | About/Contact | Advertising | Privacy ]