Home page logo

nmap-dev logo Nmap Development mailing list archives

Re: Bug in SMB when multiple scripts are connecting to same host
From: Ron <ron () skullsecurity net>
Date: Sun, 27 Feb 2011 19:13:27 -0600

Hash: SHA1

Hi Chris,

Sorry for my delayed response. I'm... well, at this point 20 days behind on reading nmap-dev, but I'm doing my best to 
keep up! 

I'm going to be that this vulnerability was introduced a few months ago, when I decided to let SMB scripts run in 
parallel with each other - before that, I had a mutex in the start/stop functions so no two SMB scripts could ever go 
in parallel. I figured out how to run concurrent scripts in the protocol, though, and fixed it. Apparently, I 
introduced this when I did that. 

I wish I could think of an easy way to fix that at the moment. Having every script start from the first account is bad 
- that road leads to lockouts - and mutexes (mutices?) could get messy since it's across a send/recv. It *might* be 
possible to wrap a mutex around all the auth code (open at negotiate, release at successful login or failure). Neither 
solution is very pretty, though. 

Anybody have any other ideas? I'm going to mark this as unread and go back to it later. 

(Do we have a proper bugtracker yet? ;) )


On Mon, 7 Feb 2011 19:28:18 -0600 Chris Woodbury <chris3e3 () gmail com> wrote:
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.
Version: GnuPG v1.4.9 (GNU/Linux)

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 ]