Nmap p2p-conficker NSE Script


This page contains detailed information about how to use the p2p-conficker NSE script. For list of all NSE scripts, visit the Nmap NSE Library.

Select:
Overview
Error Messages

Script Overview


Script source code: https://github.com/nmap/nmap/tree/master/scripts/p2p-conficker.nse
Script categories: default, safe
Target service / protocol: smb, netbios, tcp, udp
Target network port(s): 137, 139, 445
List of CVEs: -

Script Description


The p2p-conficker.nse script checks if a host is infected with Conficker.C or higher, based on Conficker's peer to peer communication.

When Conficker.C or higher infects a system, it opens four ports: two TCP and two UDP. The ports are random, but are seeded with the current week and the IP of the infected host. By determining the algorithm, one can check if these four ports are open, and can probe them for more data.

Once the open ports are found, communication can be initiated using Conficker's custom peer to peer protocol. If a valid response is received, then a valid Conficker infection has been found.

This check won't work properly on a multihomed or NATed system because the open ports will be based on a nonpublic IP. The argument checkall tells Nmap to attempt communication with every open port (much like a version check) and the argument realip tells Nmap to base its port generation on the given IP address instead of the actual IP.

By default, this will run against a system that has a standard Windows port open (445, 139, 137). The arguments checkall and checkconficker will both perform checks regardless of which port is open, see the args section for more information.

Note: Ensure your clock is correct (within a week) before using this script!

The majority of research for this script was done by Symantec Security Response, and some was taken from public sources (most notably the port blacklisting was found by David Fifield). A big thanks goes out to everybody who contributed!

P2p-conficker NSE Script Arguments


This is a full list of arguments supported by the p2p-conficker.nse script:

checkall

If set to 1 or true, attempt to communicate with every open port.

checkconficker

If set to 1 or true, the script will always run on active hosts, it doesn't matter if any open ports were detected.

realip

An IP address to use in place of the one known by Nmap.

smbdomain

The domain to log in with. If you aren't in a domain environment, then anything will (should?) be accepted by the server.

smbhash

A password hash to use when logging in. This is given as a single hex string (32 characters) or a pair of hex strings (both 32 characters, optionally separated by a single character). These hashes are the LanMan or NTLM hash of the user's password, and are stored on disk or in memory. They can be retrieved from memory using the fgdump or pwdump tools.

smbnoguest

Use to disable usage of the 'guest' account.

smbpassword

The password to connect with. Be cautious with this, since some servers will lock accounts if the incorrect password is given. Although it's rare that the Administrator account can be locked out, in the off chance that it can, you could get yourself in trouble. To use a blank password, leave this parameter off altogether.

smbtype

The type of SMB authentication to use. These are the possible options:

  • v1: Sends LMv1 and NTLMv1.
  • LMv1: Sends LMv1 only.
  • NTLMv1: Sends NTLMv1 only (default).
  • v2: Sends LMv2 and NTLMv2.
  • LMv2: Sends LMv2 only.
  • NTLMv2: Doesn't exist; the protocol doesn't support NTLMv2 alone. The default, NTLMv1, is a pretty decent compromise between security and compatibility. If you are paranoid, you might want to use v2 or lmv2 for this. (Actually, if you're paranoid, you should be avoiding this protocol altogether!). If you're using an extremely old system, you might need to set this to v1 or lm, which are less secure but more compatible. For information, see smbauth.lua.

smbusername

The SMB username to log in with. The forms "DOMAIN\username" and "username@DOMAIN" are not understood. To set a domain, use the smbdomain argument.

randomseed

Set to a value to change the filenames/service names that are randomly generated.

smbbasic

Forces the authentication to use basic security, as opposed to "extended security". Against most modern systems, extended security should work, but there may be cases where you want to force basic. There's a chance that you'll get better results for enumerating users if you turn on basic authentication.

smbport

Override the default port choice. If smbport is open, it's used. It's assumed to be the same protocol as port 445, not port 139. Since it probably isn't possible to change Windows' ports normally, this is mostly useful if you're bouncing through a relay or something.

smbsign

Controls whether or not server signatures are checked in SMB packets. By default, on Windows, server signatures aren't enabled or required. By default, this library will always sign packets if it knows how, and will check signatures if the server says to. Possible values are:

  • force: Always check server signatures, even if server says it doesn't support them (will Probably fail, but is technically more secure).
  • negotiate: [default] Use signatures if server supports them.
  • ignore: Never check server signatures. Not recommended.
  • disable: Don't send signatures, at all, and don't check the server's. not recommended. More information on signatures can be found in smbauth.lua.

- - -
To use these script arguments, add them to the Nmap command line using the --script-args arg1=value,[arg2=value,..] syntax. For example:

nmap --script=p2p-conficker --script-args checkall=value,checkconficker=value <target>

P2p-conficker NSE Script Example Usage


Here's an example of how to use the p2p-conficker.nse script:

# Run the scripts against host(s) that appear to be Windows

nmap --script p2p-conficker,smb-os-discovery,smb-check-vulns --script-args=safe=1 -T4 -vv -p445 <host>

sudo nmap -sU -sS --script p2p-conficker,smb-os-discovery,smb-check-vulns --script-args=safe=1 -vv -T4 -p U:137,T:139 <host>

# Run the scripts against all active hosts (recommended)

nmap -p139,445 -vv --script p2p-conficker,smb-os-discovery,smb-check-vulns --script-args=checkconficker=1,safe=1 -T4 <host>

# Run scripts against all 65535 ports (slow)

nmap --script p2p-conficker,smb-os-discovery,smb-check-vulns -p- --script-args=checkall=1,safe=1 -vv -T4 <host>

# Base checks on a different ip address (NATed)

nmap --script p2p-conficker,smb-os-discovery -p445 --script-args=realip="192.168.1.65" -vv -T4 <host>

P2p-conficker NSE Script Example Output


Here's a sample output from the p2p-conficker.nse script:

Clean machine (results printed only if extra verbosity ("-vv")is specified):
Host script results:
| p2p-conficker: Checking for Conficker.C or higher...
|   Check 1 (port 44329/tcp): CLEAN (Couldn't connect)
|   Check 2 (port 33824/tcp): CLEAN (Couldn't connect)
|   Check 3 (port 31380/udp): CLEAN (Failed to receive data)
|   Check 4 (port 52600/udp): CLEAN (Failed to receive data)
|_  0/4 checks: Host is CLEAN or ports are blocked

Infected machine (results always printed):
Host script results:
| p2p-conficker: Checking for Conficker.C or higher...
|   Check 1 (port 18707/tcp): INFECTED (Received valid data)
|   Check 2 (port 65273/tcp): INFECTED (Received valid data)
|   Check 3 (port 11722/udp): INFECTED (Received valid data)
|   Check 4 (port 12690/udp): INFECTED (Received valid data)
|_  4/4 checks: Host is likely INFECTED

P2p-conficker NSE Script Example XML Output


There is no sample XML output for this module. However, by providing the -oX <file> option, Nmap will produce a XML output and save it in the file.xml file.

Author


  • Ron Bowes (with research from Symantec Security Response)

References


See Also


Visit Nmap NSE Library for more scripts.

The p2p-conficker.nse script may fail with the following error messages. Check for the possible causes by using the code snippets highlighted below found in the script source code. This can often times help in identifying the root cause of the problem.

Packet was too short [1]


Here is a relevant code snippet related to the "Packet was too short [1]" error message:

331:	  local pos = 1
332:	  local data = {}
333:	
334:	  -- Get the key
335:	  if #packet < 8 then
336:	    return false, "Packet was too short [1]"
337:	  end
338:	  data['key1'], data['key2'], pos = string.unpack("<I4 I4", packet, pos)
339:	
340:	  -- Decrypt the second half of the packet using the key
341:	  packet = string.sub(packet, 1, pos - 1) .. p2p_cipher(string.sub(packet, pos), data['key1'], data['key2'])

Packet was too short [2]


Here is a relevant code snippet related to the "Packet was too short [2]" error message:

340:	  -- Decrypt the second half of the packet using the key
341:	  packet = string.sub(packet, 1, pos - 1) .. p2p_cipher(string.sub(packet, pos), data['key1'], data['key2'])
342:	
343:	  -- Parse the flags
344:	  if #packet - pos + 1 < 2 then
345:	    return false, "Packet was too short [2]"
346:	  end
347:	  data['flags'], pos = string.unpack("<I2", packet, pos)
348:	
349:	  -- Get the IP, if it's present
350:	  if(data['flags'] & mode_flags.FLAG_IP_INCLUDED) ~= 0 then

Packet was too short [3]


Here is a relevant code snippet related to the "Packet was too short [3]" error message:

347:	  data['flags'], pos = string.unpack("<I2", packet, pos)
348:	
349:	  -- Get the IP, if it's present
350:	  if(data['flags'] & mode_flags.FLAG_IP_INCLUDED) ~= 0 then
351:	    if #packet - pos + 1 < 6 then
352:	      return false, "Packet was too short [3]"
353:	    end
354:	    data['ip'], data['port'], pos = string.unpack("<I4 I2", packet, pos)
355:	  end
356:	
357:	  -- Read the first unknown value, if present

Packet was too short [3]


Here is a relevant code snippet related to the "Packet was too short [3]" error message:

355:	  end
356:	
357:	  -- Read the first unknown value, if present
358:	  if(data['flags'] & mode_flags.FLAG_UNKNOWN0_INCLUDED) ~= 0 then
359:	    if #packet - pos + 1 < 4 then
360:	      return false, "Packet was too short [3]"
361:	    end
362:	    data['unknown0'], pos = string.unpack("<I4", packet, pos)
363:	  end
364:	
365:	  -- Read the second unknown value, if present

Packet was too short [4]


Here is a relevant code snippet related to the "Packet was too short [4]" error message:

363:	  end
364:	
365:	  -- Read the second unknown value, if present
366:	  if(data['flags'] & mode_flags.FLAG_UNKNOWN1_INCLUDED) ~= 0 then
367:	    if #packet - pos + 1 < 4 then
368:	      return false, "Packet was too short [4]"
369:	    end
370:	    data['unknown1'], pos = string.unpack("<I4", packet, pos)
371:	  end
372:	
373:	  -- Read the data, if present

Packet was too short [5]


Here is a relevant code snippet related to the "Packet was too short [5]" error message:

371:	  end
372:	
373:	  -- Read the data, if present
374:	  if(data['flags'] & mode_flags.FLAG_DATA_INCLUDED) ~= 0 then
375:	    if #packet - pos + 1 < 3 then
376:	      return false, "Packet was too short [5]"
377:	    end
378:	    data['data_flags'], data['data_length'], pos = string.unpack("<B I2", packet, pos)
379:	    if #packet - pos + 1 < data.data_length then
380:	      return false, "Packet was too short [6]"
381:	    end

Packet was too short [6]


Here is a relevant code snippet related to the "Packet was too short [6]" error message:

375:	    if #packet - pos + 1 < 3 then
376:	      return false, "Packet was too short [5]"
377:	    end
378:	    data['data_flags'], data['data_length'], pos = string.unpack("<B I2", packet, pos)
379:	    if #packet - pos + 1 < data.data_length then
380:	      return false, "Packet was too short [6]"
381:	    end
382:	    data['data'], pos = string.unpack(("c%d"):format(data['data_length']), packet, pos)
383:	  end
384:	
385:	  -- Read the sysinfo, if present

Packet was too short [7]


Here is a relevant code snippet related to the "Packet was too short [7]" error message:

384:	
385:	  -- Read the sysinfo, if present
386:	  if(data['flags'] & mode_flags.FLAG_SYSINFO_INCLUDED) ~= 0 then
387:	    local sysinfo_format = "<I2 BBI2 BB I2 I4 I2I2I4I2I2"
388:	    if #packet - pos + 1 < string.packsize(sysinfo_format) then
389:	      return false, "Packet was too short [7]"
390:	    end
391:	
392:	    data['sysinfo_systemtestflags'],
393:	    data['sysinfo_os_major'],
394:	    data['sysinfo_os_minor'],

Packet was too short [8]


Here is a relevant code snippet related to the "Packet was too short [8]" error message:

407:	  -- Pull out the data that's used in the hash
408:	  data['hash_data'] = string.sub(packet, 1, pos - 1)
409:	
410:	  -- Read the hash
411:	  if #packet - pos + 1 < 4 then
412:	    return false, "Packet was too short [8]"
413:	  end
414:	  data['hash'], pos = string.unpack("<I4", packet, pos)
415:	
416:	  -- Record the noise
417:	  data['noise'] = string.sub(packet, pos)

Couldn't establish connection (


Here is a relevant code snippet related to the "Couldn't establish connection (" error message:

490:	  -- Try to connect to the first socket
491:	  socket = nmap.new_socket()
492:	  socket:set_timeout(5000)
493:	  status, response = socket:connect(ip, port, protocol)
494:	  if(status == false) then
495:	    return false, "Couldn't establish connection (" .. response .. ")"
496:	  end
497:	
498:	  -- Send the packet
499:	  socket:send(packet)
500:	

Couldn't receive bytes:


Here is a relevant code snippet related to the "Couldn't receive bytes: " error message:

499:	  socket:send(packet)
500:	
501:	  -- Read a response (2 bytes minimum, because that's the TCP length)
502:	  status, response = socket:receive_bytes(2)
503:	  if(status == false) then
504:	    return false, "Couldn't receive bytes: " .. response
505:	  elseif(response == "ERROR") then
506:	    return false, "Failed to receive data"
507:	  elseif(response == "TIMEOUT") then
508:	    return false, "Timeout"
509:	  elseif(response == "EOF") then

Failed to receive data


Here is a relevant code snippet related to the "Failed to receive data" error message:

501:	  -- Read a response (2 bytes minimum, because that's the TCP length)
502:	  status, response = socket:receive_bytes(2)
503:	  if(status == false) then
504:	    return false, "Couldn't receive bytes: " .. response
505:	  elseif(response == "ERROR") then
506:	    return false, "Failed to receive data"
507:	  elseif(response == "TIMEOUT") then
508:	    return false, "Timeout"
509:	  elseif(response == "EOF") then
510:	    return false, "Couldn't connect"
511:	  elseif #response < 2 then

Couldn't connect


Here is a relevant code snippet related to the "Couldn't connect" error message:

505:	  elseif(response == "ERROR") then
506:	    return false, "Failed to receive data"
507:	  elseif(response == "TIMEOUT") then
508:	    return false, "Timeout"
509:	  elseif(response == "EOF") then
510:	    return false, "Couldn't connect"
511:	  elseif #response < 2 then
512:	    return false, "Data too short"
513:	  end
514:	
515:	  -- If it's TCP, get the length and make sure we have the full packet

Data too short


Here is a relevant code snippet related to the "Data too short" error message:

507:	  elseif(response == "TIMEOUT") then
508:	    return false, "Timeout"
509:	  elseif(response == "EOF") then
510:	    return false, "Couldn't connect"
511:	  elseif #response < 2 then
512:	    return false, "Data too short"
513:	  end
514:	
515:	  -- If it's TCP, get the length and make sure we have the full packet
516:	  if(protocol == "tcp") then
517:	    local length = string.unpack("<I2", response)

Couldn't receive bytes:


Here is a relevant code snippet related to the "Couldn't receive bytes: " error message:

521:	    while length > (#response - 2) and tries > 0 do
522:	      tries = tries - 1
523:	
524:	      local status, response2 = socket:receive_bytes(length - (#response - 2))
525:	      if(status == false) then
526:	        return false, "Couldn't receive bytes: " .. response2
527:	      elseif(response2 == "ERROR") then
528:	        return false, "Failed to receive data"
529:	      elseif(response2 == "TIMEOUT") then
530:	        return false, "Timeout"
531:	      elseif(response2 == "EOF") then

Failed to receive data


Here is a relevant code snippet related to the "Failed to receive data" error message:

523:	
524:	      local status, response2 = socket:receive_bytes(length - (#response - 2))
525:	      if(status == false) then
526:	        return false, "Couldn't receive bytes: " .. response2
527:	      elseif(response2 == "ERROR") then
528:	        return false, "Failed to receive data"
529:	      elseif(response2 == "TIMEOUT") then
530:	        return false, "Timeout"
531:	      elseif(response2 == "EOF") then
532:	        return false, "Couldn't connect"
533:	      end

Couldn't connect


Here is a relevant code snippet related to the "Couldn't connect" error message:

527:	      elseif(response2 == "ERROR") then
528:	        return false, "Failed to receive data"
529:	      elseif(response2 == "TIMEOUT") then
530:	        return false, "Timeout"
531:	      elseif(response2 == "EOF") then
532:	        return false, "Couldn't connect"
533:	      end
534:	
535:	      response = response .. response2
536:	    end
537:	

Data received, but wasn't Conficker data:


Here is a relevant code snippet related to the "Data received, but wasn't Conficker data: " error message:

543:	  socket:close()
544:	
545:	  local status, result = p2p_parse(response)
546:	
547:	  if(status == false) then
548:	    return false, "Data received, but wasn't Conficker data: " .. result
549:	  end
550:	
551:	  if(result['hash'] ~= result['real_hash']) then
552:	    return false, "Data received, but checksum was invalid (possibly INFECTED)"
553:	  end

Data received, but checksum was invalid (possibly INFECTED)


Here is a relevant code snippet related to the "Data received, but checksum was invalid (possibly INFECTED)" error message:

547:	  if(status == false) then
548:	    return false, "Data received, but wasn't Conficker data: " .. result
549:	  end
550:	
551:	  if(result['hash'] ~= result['real_hash']) then
552:	    return false, "Data received, but checksum was invalid (possibly INFECTED)"
553:	  end
554:	
555:	  return true, "Received valid data", result
556:	end
557:	

Version


This page has been created based on Nmap version 7.92.

Go back to menu.