Compare commits

...

87 Commits

Author SHA1 Message Date
9df3ae155a Merge branch 'master' of https://git.malingrey.fr/adrien/lanScan2 2023-05-16 09:47:55 +02:00
3775302fd1 five columns 2023-05-16 09:47:33 +02:00
d20c41693e change title order 2023-05-15 18:52:25 +02:00
3f662bafcc change 'hosts' to 'group' 2023-05-15 16:40:36 +02:00
87cedd0bce change file extensions 2023-05-15 16:17:18 +02:00
1046de0b8d change file extensions 2023-05-15 16:15:30 +02:00
0ac085a97e -Pn 2023-05-12 17:52:17 +02:00
bc04ce19a7 smb-shares-size in port script 2023-05-12 02:40:34 +02:00
1e26473930 show min(FreeSize/TotalSize) in smb button 2023-05-12 00:24:37 +02:00
657946708a css .share-size 2023-05-11 13:31:17 +02:00
c85c175416 improve smb share size 2023-05-11 12:09:05 +02:00
08187df3a8 rename script-args.ini 2023-05-11 11:13:28 +02:00
e42c1342eb Merge branch 'master' of https://git.malingrey.fr/adrien/lanScan2 2023-05-11 11:12:13 +02:00
e577ccb4c1 rename script-args.ini 2023-05-11 11:11:51 +02:00
5e4fb1aa61 fix "/usr/bin/../share/nmap/nselib/http.lua:1795: attempt to index a nil value (local 'options')" 2023-05-10 21:10:44 +02:00
556268b1e1 script_args.ini 2023-05-10 20:41:00 +02:00
8cb8a6cb04 ignore script_args.ini 2023-05-10 20:34:42 +02:00
8098697c4d Mise à jour de 'nse/script_args.ini' 2023-05-10 18:56:22 +02:00
2f3bb6c4f3 share size xsl 2023-05-10 18:54:57 +02:00
d6207258ac rename 2023-05-10 17:42:17 +02:00
0ffd304d2d du script working! 2023-05-10 16:15:36 +02:00
a3c06ef825 merge 2023-05-09 16:18:07 +02:00
bbee70cef8 merge 2023-05-09 16:15:16 +02:00
e2e255f690 merge 2023-05-09 15:27:40 +02:00
5378e16e24 new nse script 2023-05-09 15:15:27 +02:00
c3082c9442 small fixes 2023-04-29 08:25:51 +02:00
e1bde27789 Merge branch 'master' of https://git.malingrey.fr/adrien/lanScan2 2023-04-29 07:10:07 +02:00
330205b297 save site when discover 2023-04-29 07:10:06 +02:00
2505c1d974 stuff 2023-04-28 16:55:18 +02:00
36b7a91c48 select service distinct 2023-04-28 15:21:18 +02:00
7354c2158a change format again 2023-04-28 11:15:09 +02:00
88edeee596 change yaml format 2023-04-28 04:39:52 +02:00
3d1a0ac214 400<=http status<=500 => yellow 2023-04-27 18:48:44 +02:00
ff9f5b3b33 tune 2023-04-27 18:45:08 +02:00
272d97ebf7 verbose 2023-04-27 17:46:56 +02:00
8973dc8979 split scan 2023-04-27 17:11:06 +02:00
874e5bb833 @ip on title 2023-04-24 18:48:04 +02:00
6eb3eb434d scannedHostAddress 2023-04-24 18:45:14 +02:00
c70d24a837 select on click 2023-04-24 18:41:42 +02:00
8bfd90a8c4 onfocus display FQDN 2023-04-24 18:31:51 +02:00
c6cc4aad16 placeholder 2023-04-24 18:27:52 +02:00
d676af67e2 refresh 60s 2023-04-14 17:57:01 +02:00
823a78f0ed header 2023-04-14 17:28:17 +02:00
1383944787 icon message 2023-04-14 17:17:59 +02:00
0027932ecd title 2023-04-14 17:06:19 +02:00
fbd0f19ced http-info 2023-04-14 16:47:39 +02:00
d9d996e081 remove smb-enum-shares script to speed up 2023-04-14 16:11:49 +02:00
17c5c02818 fix stuff 2023-04-14 15:11:28 +02:00
8537c2a0ca fix results 2023-04-13 21:14:27 +02:00
c6e1977ca2 fix scan_all.sh 2023-04-13 20:54:28 +02:00
fad7c6164e scan_all.sh 2023-04-13 19:39:06 +02:00
d4af5b181f merge nmap scripts 2023-04-13 16:30:06 +02:00
48d6a52931 descrease scan output size 2023-04-13 15:55:49 +02:00
ea98cd9903 scan_all in bash script 2023-04-13 15:46:47 +02:00
6e0e3b60e3 tmp 2023-04-12 20:25:59 +02:00
12a0a5ac93 commit 2023-04-12 18:41:45 +02:00
0439aecb98 https 2023-04-12 12:11:33 +02:00
f8c4ea0903 change yaml format 2023-04-11 20:33:11 +02:00
ba3c1e1b8a __DIR__ 2023-04-11 18:47:24 +02:00
c2d62a5ccb tmp 2023-04-11 18:45:42 +02:00
72ad03b03b commit 2023-04-11 18:39:57 +02:00
6eac85d5ad tiny favicon 2023-04-11 14:35:30 +02:00
cdf14a09d9 fix heredoc string for old php 2023-04-11 11:28:27 +02:00
fee3f2a043 fix heredoc syntax for old php 2023-04-11 11:18:27 +02:00
b3aa55c9b4 inverse 2023-04-11 01:43:48 +02:00
6243bc66e5 nmap script http-get 2023-04-10 22:03:32 +02:00
a552a3cc06 nmap http status script 2023-04-10 21:26:53 +02:00
72a9c62d4a nmap favicon url 2023-04-10 21:02:42 +02:00
61486d7dab always favicon 2023-04-10 03:13:29 +02:00
c2bd2ee679 https favicon 2023-04-09 20:02:18 +02:00
7d25fd2472 three columns, dl favicons only of http 2023-04-09 18:02:15 +02:00
c6691ed1d2 factorisation 2023-04-09 17:28:10 +02:00
4822ad3e5d title 2023-04-09 04:43:48 +02:00
a640f71c7e services when host down 2023-04-09 04:32:10 +02:00
0d8d3d0c7b hostname without . 2023-04-09 03:42:00 +02:00
e37ba4993e info 2023-04-09 03:36:01 +02:00
64d2dece69 remove comment 2023-04-09 03:08:17 +02:00
a09777bdc4 button padding 2023-04-09 02:44:58 +02:00
32423db827 input value and title change when only @ip 2023-04-09 01:51:14 +02:00
e6b9a7a6be pseudo regex 2023-04-09 01:25:50 +02:00
15e33765e5 uncomment exec 2023-04-09 01:18:04 +02:00
98b7fab684 compact 2023-04-09 01:13:02 +02:00
3a162f4568 use xslt! 2023-04-09 01:06:01 +02:00
c7b85862e6 yo 2023-04-07 17:55:30 +02:00
24c32fa513 stuff 2023-04-07 13:59:48 +02:00
7b66313c01 toxml 2023-04-07 02:34:57 +02:00
d3b5a014e1 separate confs and scans 2023-04-07 02:34:42 +02:00
19 changed files with 787 additions and 235 deletions

7
.gitignore vendored
View File

@ -1,3 +1,4 @@
scans/*.yaml
!scans/example.yaml
scans/*.xml
nse/script-args.ini
configs/
scans/
site/

28
LISEZMOI.md Normal file
View File

@ -0,0 +1,28 @@
# lanScan
Scanne des hôtes avec `nmap`
et affiche le résultat dans une page web.
* Créer un fichier de configuration YAML dans un sous-dossier ./configs/ (voir l'exemple ci-dessous).
Il peut être généré en scannant un réseau avec : `./discover.sh <CIDR>`.
* Scanner avec le script `./scan_all.sh` (utiliser une tâche cron !).
* Voir les résultats en ouvrant `.\index.php` dans le navigateur web.
## Exemple
```yaml
---
site: Nom du site
hosts:
- name: Nom du premier groupe
host:
- address: host1.local
services: [ssh, http]
- address: 192.168.1.100
services: [ftp, https, 5432]
- name: Nom du 2ème groupe
host:
- adress: host3.local
services: [ssh, ftp, 8006]
```

View File

@ -1,8 +1,27 @@
# lanScan
Scan hosts with nmap and display results in webpage.
Scan hosts with `nmap` and display results in webpage.
* Create a configuration yaml file in ./configs/ subdirectory (see example below).
It may be generated by scanning a network with `./discover.sh <CIDR>`.
* Scan with `./scan_all.sh` (use a cron task!).
* Open `.\index.php` in web browser to see results.
## Example
```yaml
---
site: Nom du site
hosts:
- name: Nom du premier groupe
host:
- address: host1.local
services: [ssh, http]
- address: 192.168.1.100
services: [ftp, https, 5432]
- name: Nom du 2ème groupe
host:
- adress: host3.local
services: [ssh, ftp, 8006]
```
* Create a configuration yaml file in scans/ subdirectory (see example.yaml).
It may be generated by scanning a network with `init.sh`.
* Scan with `php scan_all.php` (use a cron task!).
* Open index.php to see results.

25
discover.sh Executable file
View File

@ -0,0 +1,25 @@
#!/usr/bin/env bash
###
#
# Scan un réseau avec nmap pour créer un fichier de configuration
# Usage : ./discover <reseau> avec reseau en notation CIDR XXX.XXX.XXX.XXX/XX
#
###
if [ "$#" -ne 1 ]; then
echo -e "Usage : ./discover <CIDR>\navec <CIDR> l'adresse réseau en notation CIDR (XXX.XXX.XXX.XXX/XX)" >&2
exit 1
fi
pushd "$(dirname -- "$0")" > /dev/null
network="$1"
site="${network/\//_}"
mkdir -p "scans"
nmap -F -oX "scans/$site.xml" $network
mkdir -p "configs"
xsltproc --stringparam network "$network" to_config.xsl "scans/$site.xml" > "configs/$site.yml"
php to_XML.php "configs/$site.yml" > "site/$site.xml"
popd > /dev/null

View File

@ -1,12 +1,46 @@
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>lanScan</title>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.3/dist/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.2/dist/semantic.min.css">
<script src="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.2/dist/semantic.min.js"></script>
<style>
#logo {
margin: 0 -.4rem 0 0;
}
.main.container {
margin-top: 5em;
}
</style>
</head>
<body>
<header class="ui fixed centered blue inverted menu">
<div class="header item">lan<img id="logo" src="logo.svg" alt="S"/>can</div>
</header>
<div class="ui main text container">
<div class="ui link selection list">
<?php
$site = filter_input(INPUT_GET, "site", FILTER_SANITIZE_STRING);
$site = escapeshellcmd($site);
if (! function_exists('str_ends_with')) {
function str_ends_with(string $haystack, string $needle): bool
{
$needle_len = strlen($needle);
return ($needle_len === 0 || 0 === substr_compare($haystack, $needle, - $needle_len));
}
}
if ($site and file_exists("scans/$site.yaml") and file_exists("scans/$site.xml")) {
$conf = yaml_parse_file("scans/$site.yaml");
$scan = simplexml_load_file("scans/$site.xml");
require("results.php");
} else {
require("ls.php");
foreach (scandir("./site") as $file) {
if (str_ends_with($file, ".xml")) {
$site = str_replace(".xml", "", $file);
if (file_exists("scans/$site.xml")) {
echo " <a href='site/$site.xml' class='item'>$site</a>\n";
}
}
}
?>
</div>
</div>
</body>
</html>

14
init.sh
View File

@ -1,14 +0,0 @@
#!/bin/bash
###
#
# Scan un réseau avec nmap pour créer un fichier de configuration
#
###
echo "Nom du site ?"
read name
echo "Plage IP (xxx.xxx.xxx.xxx/xx) ?"
read network
nmap --script smb-enum-shares.nse -oX "scans/$name.xml" $network
xsltproc toyaml.xsl "scans/$name.xml" > "scans/$name.yaml"

36
ls.php
View File

@ -1,36 +0,0 @@
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>lanScan</title>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.3/dist/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.2/dist/semantic.min.css">
<script src="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.2/dist/semantic.min.js"></script>
<style>
#logo {
margin: 0 -.4rem 0 0;
}
.main.container {
margin-top: 5em;
}
</style>
</head>
<body>
<header class="ui fixed centered blue inverted menu">
<div class="header item">lan<img id="logo" src="logo.svg" alt="S"/>can</div>
</header>
<div class="ui main text container">
<div class="ui link selection list">
<?php foreach (scandir("./scans") as $file) {
if (strrpos($file, ".yaml")) {
$site = str_replace(".yaml", "", $file);
if (file_exists("scans/$site.xml")) {
echo " <a href='?site=$site' class='item'>$site</a>\n";
}
}
} ?>
</div>
</div>
</body>
</html>

35
nmap_cmd.xsl Normal file
View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="1.1">
<xsl:output method="text" encoding="UTF-8" indent="yes" />
<xsl:param name="site"/>
<xsl:template match="lanScan">
<xsl:text>nmap -v -T4 -Pn -p </xsl:text>
<xsl:apply-templates select="//service[not(.=preceding::*)]" />
<xsl:text> --script nse/ --datadir nse/ --script-args-file script-args.ini -oX "</xsl:text>
<xsl:value-of select="@scanpath"/>
<xsl:text>.tmp" </xsl:text>
<xsl:apply-templates select="//host"/>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="service">
<xsl:value-of select="." />
<xsl:if test="position() != last()">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:template>
<xsl:template match="host">
<xsl:value-of select="@address" />
<xsl:if test="position() != last()">
<xsl:text> </xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

109
nse/http-info.nse Normal file
View File

@ -0,0 +1,109 @@
local shortport = require "shortport"
description = [[
Get and return a page info
]]
---
-- @args http-get.path Path to get. Default /.
--
-- @usage nmap -p80 --script http-info.nse --script-args http-info.path=/ <host>
--
-- @output
-- status: 200
-- status-line: HTTP/1.1 200 OK\x0D
---
categories = {"discovery", "intrusive"}
author = "Adrien Malingrey"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
portrule = shortport.service({"http", "https", "ssl"})
local http = require "http"
local stdnse = require "stdnse"
action = function(host, port)
local scheme = ""
local hostaddress = (host.name ~= '' and host.name) or host.ip
local path = "/"
local uri
local favicon_relative_uri = "/favicon.ico"
local favicon
if (port.service == "ssl") then
scheme = "https"
else
scheme = port.service
end
if(stdnse.get_script_args('http-get.path')) then
path = stdnse.get_script_args('http-info.path')
end
uri = scheme.."://"..hostaddress..":"..port.number..path
stdnse.debug1("Try to download %s", uri)
local answer = http.get_url(uri, {})
local info = {status=answer.status, ["status-line"]=answer["status-line"]}
if (answer and answer.status == 200) then
stdnse.debug1("[SUCCESS] Load page %s", uri)
-- Taken from http-title.nse by Diman Todorov
local title = string.match(answer.body, "<[Tt][Ii][Tt][Ll][Ee][^>]*>([^<]*)</[Tt][Ii][Tt][Ll][Ee]>")
if (title) then
info.title = title
end
stdnse.debug1("[INFO] Try favicon %s", favicon_relative_uri)
favicon_relative_uri = parseIcon(answer.body) or "favicon.ico"
else
stdnse.debug1("[ERROR] Can't load page %s", uri)
end
favicon_absolute_uri = scheme.."://"..hostaddress..":"..port.number..favicon_relative_uri
favicon = http.get_url(favicon_absolute_uri, {})
if (favicon and favicon.status == 200) then
stdnse.debug1("[SUCCESS] Load favicon %s", favicon_absolute_uri)
info.favicon = favicon_absolute_uri
else
stdnse.debug1("[ERROR] Can't load favicon %s", favicon_absolute_uri)
end
return info
end
--- function taken from http_favicon.nse by Vlatko Kosturjak
function parseIcon( body )
local _, i, j
local rel, href, word
-- Loop through link elements.
i = 0
while i do
_, i = string.find(body, "<%s*[Ll][Ii][Nn][Kk]%s", i + 1)
if not i then
return nil
end
-- Loop through attributes.
j = i
while true do
local name, quote, value
_, j, name, quote, value = string.find(body, "^%s*(%w+)%s*=%s*([\"'])(.-)%2", j + 1)
if not j then
break
end
if string.lower(name) == "rel" then
rel = value
elseif string.lower(name) == "href" then
href = value
end
end
for word in string.gmatch(rel or "", "%S+") do
if string.lower(word) == "icon" then
return href
end
end
end
end

2
nse/script-args.ini Normal file
View File

@ -0,0 +1,2 @@
smbuser =
smbpassword =

206
nse/smb-shares-size.nse Normal file
View File

@ -0,0 +1,206 @@
local stdnse = require "stdnse"
local smb = require "smb"
local smb2 = require "smb2"
local msrpc = require "msrpc"
local bin = require "bin"
local shortport = require "shortport"
description = [[
Return free and total size in octets of each SMB shares
]]
---
-- @args See the documentation for the smbauth library.
--
-- @usage nmap -p445 --script smb-shares-size.nse <host>
--
-- @output
-- Host script results:
-- | smb-shares-size:
-- | data:
-- | FreeSize: 38495883264
-- | TotalSize: 500961574912
-- |_ IPC$: NT_STATUS_ACCESS_DENIED
---
categories = {"discovery", "intrusive"}
author = "Adrien Malingrey"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
portrule = shortport.service({"microsoft-ds", "netbios-ssn", "smb"})
action = function(host)
local status, shares, extra
local response = stdnse.output_table()
-- Try and do this the good way, make a MSRPC call to get the shares
stdnse.debug1("SMB: Attempting to log into the system to enumerate shares")
status, shares = msrpc.enum_shares(host)
if(status == false) then
return stdnse.format_output(false, string.format("Couldn't enumerate shares: %s", shares))
end
-- Get more information on each share
for i = 1, #shares, 1 do
local share = shares[i]
if (share ~= nil) then
local status, result = get_share_info(host, share)
if (status) then
response[share] = result
end
end
end
return response
end
TRANS2_QUERY_FS_INFORMATION = 0x0003
SMB_QUERY_FS_SIZE_INFO = 0x0103
---Attempts to retrieve additional information about a share. Will fail unless we have
-- administrative access.
--
--@param host The host object.
--@return Status (true or false).
--@return A table of information about the share (if status is true) or an an error string (if
-- status is false).
function get_share_info(host, share)
local status, smbstate, err
local hostaddress = (host.name ~= '' and host.name) or host.ip
local path = "\\\\" .. hostaddress .. "\\" .. share
status, smbstate = smb.start(host)
status, err = smb.negotiate_protocol(smbstate, {})
status, err = smb.start_session(smbstate, {})
status, err = smb.tree_connect(smbstate, path, {})
stdnse.debug1("SMB: Getting information for share: %s", path)
local status, err = send_transaction2(smbstate, TRANS2_QUERY_FS_INFORMATION, bin.pack("<S", SMB_QUERY_FS_SIZE_INFO))
if ( not(status) ) then
status, err = smb.stop(smbstate)
return false, "Failed to send data to server: send_transaction2"
end
local status, response = receive_transaction2(smbstate)
if ( not(status) ) then
status, err = smb.stop(smbstate)
return false, response
end
local pos, totalAllocationUnits, totalFreeAllocationUnits, sectorsPerAllocationUnit, bytesPerSector = bin.unpack("<LLII", response.data)
status, err = smb.stop(smbstate)
return true, {
TotalSize = totalAllocationUnits * sectorsPerAllocationUnit * bytesPerSector,
FreeSize = totalFreeAllocationUnits * sectorsPerAllocationUnit * bytesPerSector
}
end
-- Taken from smb lib
function send_transaction2(smbstate, sub_command, function_parameters, function_data, overrides)
overrides = overrides or {}
local header1, header2, header3, header4, command, status, flags, flags2, pid_high, signature, unused, pid, mid
local header, parameters, data
local parameter_offset = 0
local parameter_size = 0
local data_offset = 0
local data_size = 0
local total_word_count, total_data_count, reserved1, parameter_count, parameter_displacement, data_count, data_displacement, setup_count, reserved2
local response = {}
-- Header is 0x20 bytes long (not counting NetBIOS header).
header = smb.smb_encode_header(smbstate, smb.command_codes['SMB_COM_TRANSACTION2'], overrides) -- 0x32 = SMB_COM_TRANSACTION2
if(function_parameters) then
parameter_offset = 0x44
parameter_size = #function_parameters
data_offset = #function_parameters + 33 + 32
end
-- Parameters are 0x20 bytes long.
parameters = bin.pack("<SSSSCCSISSSSSCCS",
parameter_size, -- Total parameter count.
data_size, -- Total data count.
0x000a, -- Max parameter count.
0x3984, -- Max data count.
0x00, -- Max setup count.
0x00, -- Reserved.
0x0000, -- Flags (0x0000 = 2-way transaction, don't disconnect TIDs).
0x00001388, -- Timeout (0x00000000 = return immediately).
0x0000, -- Reserved.
parameter_size, -- Parameter bytes.
parameter_offset, -- Parameter offset.
data_size, -- Data bytes.
data_offset, -- Data offset.
0x01, -- Setup Count
0x00, -- Reserved
sub_command -- Sub command
)
local data = "\0\0\0" .. (function_parameters or '')
.. (function_data or '')
-- Send the transaction request
stdnse.debug2("SMB: Sending SMB_COM_TRANSACTION2")
local result, err = smb.smb_send(smbstate, header, parameters, data, overrides)
if(result == false) then
stdnse.debug1("SMB: Try SMBv2 connexion")
local result, err = smb2.smb2_send(smbstate, header, parameters, data, overrides)
if(result == false) then
return false, err
end
end
return true
end
function receive_transaction2(smbstate)
-- Read the result
local status, header, parameters, data = smb.smb_read(smbstate)
if(status ~= true) then
stdnse.debug1("SMB: Try SMBv2 connexion")
local status, header, parameters, data = smb2.smb2_read(smbstate)
if(status ~= true) then
return false, header
end
end
-- Check if it worked
local pos, header1, header2, header3, header4, command, status, flags, flags2, pid_high, signature, unused, tid, pid, uid, mid = bin.unpack("<CCCCCICSSlSSSSS", header)
if(header1 == nil or mid == nil) then
return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [29]"
end
if(status ~= 0) then
if(smb.status_names[status] == nil) then
return false, string.format("Unknown SMB error: 0x%08x\n", status)
else
return false, smb.status_names[status]
end
end
-- Parse the parameters
local pos, total_word_count, total_data_count, reserved1, parameter_count, parameter_offset, parameter_displacement, data_count, data_offset, data_displacement, setup_count, reserved2 = bin.unpack("<SSSSSSSSSCC", parameters)
if(total_word_count == nil or reserved2 == nil) then
return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [30]"
end
-- Convert the parameter/data offsets into something more useful (the offset into the data section)
-- - 0x20 for the header, - 0x01 for the length.
parameter_offset = parameter_offset - 0x20 - 0x01 - #parameters - 0x02;
-- - 0x20 for the header, - 0x01 for parameter length, the parameter length, and - 0x02 for the data length.
data_offset = data_offset - 0x20 - 0x01 - #parameters - 0x02;
-- I'm not sure I entirely understand why the '+1' is here, but I think it has to do with the string starting at '1' and not '0'.
local function_parameters = string.sub(data, parameter_offset + 1, parameter_offset + parameter_count)
local function_data = string.sub(data, data_offset + 1, data_offset + data_count)
local response = {}
response['parameters'] = function_parameters
response['data'] = function_data
return true, response
end

View File

@ -1,135 +0,0 @@
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>lanScan - <?=$site?></title>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.3/dist/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.2/dist/semantic.min.css">
<script src="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.2/dist/semantic.min.js"></script>
<style>
#logo {
margin: 0 -.4rem 0 0;
}
.main.container {
margin-top: 5em;
}
.ui.dropdown, .ui.dropdown .menu > .item {
font-size: .85714286rem;
}
.ui.mini button > .detail {
margin-left: .1em;
}
.content {
display: flex;
align-items: baseline;
gap: .5em;
}
</style>
<script>
onload = function (event) {
$('.ui.dropdown').dropdown()
}
</script>
</head>
<body>
<header class="ui fixed blue inverted menu">
<a href="." class="header item">lan<img id="logo" src="logo.svg" alt="S"/>can</a>
<div class="item"><?=$site?></div>
</header>
<div class="ui main container">
<p><?=$scan->runstats->finished["summary"]?></p>
<?php foreach($conf as $conf_groupname => $conf_hosts) { ?>
<h1 class="ui header"><?=$conf_groupname?></h1>
<div class="ui mini cards">
<?php
if ($conf_hosts) foreach($conf_hosts as $conf_address => $conf_services) {
echo " <!-- $conf_address -->\n";
$scan_host = $scan->xpath("host[hostnames/hostname/@name='$conf_address' or address/@addr='$conf_address']")[0];
$address = count($scan_host->xpath("hostnames/hostname/@name")) ? $scan_host->xpath("hostnames/hostname/@name")[0] : $scan_host->xpath("address/@addr")[0];
if ($scan_host->status["state"] =="up") {
?>
<div class="ui card">
<div class="content">
<div class="ui green empty circular label"></div>
<div><?=$scan_host->address["addr"]?></div>
<div class="header" title="<?=strtok($scan_host->hostnames->hostname["name"], ".")?>"><?=strtok($scan_host->hostnames->hostname["name"], ".")?></div>
</div>
<div class="ui inverted primary centered wrapped wrapping bottom attached mini menu">
<?php
if ($conf_services) foreach($conf_services as $conf_service) {
$scan_service = $scan_host->xpath("ports/port[service/@name='$conf_service' or @portid='$conf_service']")[0];
switch($scan_service->state["state"]) {
case "open": $state = "primary"; break;
case "closed": $state = "red disabled"; break;
default: $state = "yellow";
}
switch($scan_service->service['name']) {
case "microsoft-ds":
case "netbios-ssn":
$shares = $scan_host->xpath("hostscript/script[@id='smb-enum-shares']/table[not(contains(@key, '$'))]");
if (count($shares)) {
?>
<div class="ui dropdown <?=$state?> item">
<?=$scan_service->service['name']?><small>:<?=$scan_service['portid']?></small>
<i class="dropdown icon"></i>
<div class="menu">
<?php
foreach($shares as $share) {
?>
<a class='item' href='file:////$address/<?=$share['key']?>'><?=$share['key']?></a>
<?php
}
?>
</div>
</div>
<?php
} else {
?>
<div class="ui <?=$state?> disabled item" disabled><?=$scan_service->service['name']?><small>:<?=$scan_service['portid']?></small></div>
<?php
}
break;
case "telnet":
case "ftp":
case "ssh":
case "http":
case "https":
?>
<a href="<?=$scan_service->service['name']?>://<?=$address?>:<?=$scan_service['portid']?>" class="ui <?=$state?> item"><?=$scan_service->service['name']?><small>:<?=$scan_service['portid']?></small></a>
<?php
break;
case "ms-wbt-server":
?>
<a href="rdp.php?v=<?=$address?>:<?=$scan_service['portid']?>" class="ui <?=$state?> item">rdp<small>:<?=$scan_service['portid']?></small></a>
<?php
break;
default:
?>
<div class="ui <?=$state?> disabled item" disabled><?=$scan_service->service['name']?><small>:<?=$scan_service['portid']?></small></div>
<?php
}
}
?>
</div>
</div>
<?php
} else {
?>
<div class="ui red card">
<div class="content">
<div class="ui red empty circular label"></div>
<div ><?=$scan_host->address["addr"]?></div>
<div class="header" title="<?=$scan_host->hostnames->hostname["name"]?>"><?=strtok($scan_host->hostnames->hostname["name"], ".")?></div>
</div>
</div>
<?php
}
}
?>
</div>
<?php
}
?>
</body>
</html>

222
results.xsl Normal file
View File

@ -0,0 +1,222 @@
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="1.1">
<xsl:output method="html" encoding="UTF-8" indent="yes"/>
<xsl:variable name="scan" select="document(string(lanScan/@scanpath))/nmaprun"/>
<xsl:template match="lanScan">
<html lang="fr">
<head>
<title><xsl:value-of select="@site"/> - lanScan</title>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.3/dist/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.2/dist/semantic.min.css"/>
<script src="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.2/dist/semantic.min.js"></script>
<style>
#logo {
margin: 0 -.4rem 0 0;
}
.main.container {
margin-top: 5em;
}
.ui.mini.button {
padding: 1em;
}
.icon {
display: flex !important;
align-items: center;
}
.icon > img {
width: 16px;
height: 16px;
margin: auto;
}
.share-size {
--free-ratio: calc(var(--free) / var(--total));
--used-percent: calc(100% - 100%*var(--free-ratio));
--color: hsl(calc(120*var(--free-ratio)) 100% 50%);
background-image: linear-gradient(to right, var(--color) var(--used-percent), transparent var(--used-percent), transparent) !important;
}
</style>
<meta http-equiv="refresh" content="60"/>
</head>
<body>
<header class="ui fixed blue inverted menu">
<a href=".." class="header item">lan<img id="logo" src="../logo.svg" alt="S"/>can</a>
<div class="header center item"><xsl:value-of select="@site"/></div>
</header>
<div class="ui main container">
<xsl:choose>
<xsl:when test="$scan/runstats/finished/@errormsg">
<div class="ui negative icon message">
<i class="exclamation triangle icon"></i>
<div class="content">
<div class="header" style="text-transform: capitalize"><xsl:value-of select="$scan/runstats/finished/@exit"/></div>
<p><xsl:value-of select="$scan/runstats/finished/@errormsg"/></p>
</div>
</div>
</xsl:when>
<xsl:when test="$scan/runstats/finished/@summary">
<div class="ui icon message">
<i class="sitemap icon"></i>
<div class="content">
<div class="header" style="text-transform: capitalize"><xsl:value-of select="$scan/runstats/finished/@exit"/></div>
<p><xsl:value-of select="$scan/runstats/finished/@summary"/></p>
</div>
</div>
</xsl:when>
</xsl:choose>
<xsl:apply-templates select="group"/>
</div>
<script>
$('.ui.dropdown').dropdown()
</script>
</body>
</html>
</xsl:template>
<xsl:template match="group">
<h1 class="ui header"><xsl:value-of select="@name"/></h1>
<div class="ui doubling stackable five column compact grid">
<xsl:apply-templates select="host"/>
</div>
</xsl:template>
<xsl:template match="host">
<xsl:variable name="address" select="@address"/>
<xsl:variable name="scannedHost" select="$scan/host[hostnames/hostname/@name=$address or address/@addr=$address]"/>
<xsl:variable name="scannedHostAddress">
<xsl:choose>
<xsl:when test="$scannedHost/hostnames/hostname/@name">
<xsl:value-of select="$scannedHost/hostnames/hostname/@name"/>
</xsl:when>
<xsl:when test="$scannedHost/address/@addr">
<xsl:value-of select="$scannedHost/address/@addr"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$address"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="name">
<xsl:choose>
<xsl:when test="@name"><xsl:value-of select="@name"/></xsl:when>
<xsl:when test="$scannedHost/hostnames/hostname/@name"><xsl:value-of select="substring-before($scannedHost/hostnames/hostname/@name, '.')"/></xsl:when>
</xsl:choose>
</xsl:variable>
<div class="column">
<xsl:variable name="status">
<xsl:choose>
<xsl:when test="$scannedHost/status/@state='up'">success</xsl:when>
<xsl:otherwise>error</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<div class="ui fluid mini left icon action input {$status}">
<xsl:choose>
<xsl:when test="$scannedHost/ports/port/script[@id='http-info']/elem[@key='favicon']">
<i class="icon"><img class="ui image" src="{$scannedHost/ports/port/script[@id='http-info']/elem[@key='favicon']}" alt=""/></i>
</xsl:when>
<xsl:otherwise>
<i class="server icon"></i>
</xsl:otherwise>
</xsl:choose>
<input type="text" readonly="" value="{$name}" placeholder="{$scannedHost/address/@addr}"
title="{@comment} {$scannedHost/hostnames/hostname/@name} ({$scannedHost/address/@addr}) "
onfocus="this.value='{$scannedHostAddress}'; this.select()" onblur="this.value='{$name}'"
/>
<xsl:apply-templates select="service">
<xsl:with-param name="scannedHost" select="$scannedHost"/>
<xsl:with-param name="scannedHostAddress" select="$scannedHostAddress"/>
</xsl:apply-templates>
</div>
</div>
</xsl:template>
<xsl:template match="service">
<xsl:param name="scannedHost"/>
<xsl:param name="scannedHostAddress"/>
<xsl:variable name="serviceName" select="."/>
<xsl:variable name="scannedPort" select="$scannedHost/ports/port[service/@name=$serviceName or @portid=$serviceName][1]"/>
<xsl:variable name="state">
<xsl:choose>
<xsl:when test="$scannedPort/state/@state='open'">green</xsl:when>
<xsl:when test="$scannedPort/state/@state='filtered'">yellow</xsl:when>
<xsl:otherwise>red</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="title">
<xsl:value-of select="$scannedPort/@portid"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="$scannedPort/@protocol"/>
<xsl:text> </xsl:text>
<xsl:value-of select="$scannedPort/state/@state"/>
<xsl:text> </xsl:text>
<xsl:value-of select="$scannedPort/service/@name"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="$scannedPort/script[@id='smb-shares-size']/table">
<div class="ui {$state} dropdown mini button share-size" title="{$title}">
<xsl:attribute name="style">
<xsl:for-each select="$scannedPort/script[@id='smb-shares-size']/table">
<xsl:sort select="elem[@key='FreeSize'] div elem[@key='TotalSize']" order="ascending"/>
<xsl:if test="position()=1">
<xsl:text>--free: </xsl:text>
<xsl:value-of select="elem[@key='FreeSize']"/>
<xsl:text>; --total: </xsl:text>
<xsl:value-of select="elem[@key='TotalSize']"/>
</xsl:if>
</xsl:for-each>
</xsl:attribute>
<xsl:value-of select="$serviceName"/>
<i class="dropdown icon"></i>
<div class="menu">
<xsl:apply-templates select="$scannedPort/script[@id='smb-shares-size']/table">
<xsl:with-param name="scannedHostAddress" select="$scannedHostAddress"/>
</xsl:apply-templates>
</div>
</div>
</xsl:when>
<xsl:when test="$scannedPort/service/@name='ms-wbt-server' or $scannedPort/service/@name='rdp'">
<a class="ui {$state} mini button" href="../rdp.php?v={$scannedHostAddress}:{$scannedPort/@portid}" title="{$title}">
<xsl:value-of select="$serviceName"/>
</a>
</xsl:when>
<xsl:when test="$scannedPort/script[@id='http-info']">
<xsl:variable name="status">
<xsl:choose>
<xsl:when test="$scannedPort/script[@id='http-info']/elem[@key='status']>=500">red</xsl:when>
<xsl:when test="$scannedPort/script[@id='http-info']/elem[@key='status']>=400">yellow</xsl:when>
<xsl:when test="$scannedPort/script[@id='http-info']/elem[@key='status']>=200">green</xsl:when>
<xsl:otherwise>red</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<a class="ui {$status} mini button" href="{$scannedPort/service/@name}://{$scannedHostAddress}:{$scannedPort/@portid}" target="_blank"
title="{$scannedPort/script[@id='http-info']/elem[@key='title' or @key='status-line']}">
<xsl:value-of select="$serviceName"/>
</a>
</xsl:when>
<xsl:when test="$scannedPort/service/@name='ftp' or $scannedPort/service/@name='ssh' or $scannedPort/service/@name='http' or $scannedPort/service/@name='https'">
<a class="ui {$state} mini button" href="{$scannedPort/service/@name}://{$scannedHostAddress}:{$scannedPort/@portid}" target="_blank" title="{$title}">
<xsl:value-of select="$serviceName"/>
</a>
</xsl:when>
<xsl:otherwise>
<a class="ui disabled {$state} mini button" title="{$title}">
<xsl:value-of select="$serviceName"/>
</a>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="table">
<xsl:param name="scannedHostAddress"/>
<a class="item share-size" href="file://///{$scannedHostAddress}/{@key}" target="_blank" rel="noopener noreferrer" style="--free: {elem[@key='FreeSize']}; --total: {elem[@key='TotalSize']}">
<xsl:value-of select="@key"/>
</a>
</xsl:template>
</xsl:stylesheet>

15
scan.sh Executable file
View File

@ -0,0 +1,15 @@
#!/usr/bin/env bash
if [ "$#" -ne 1 ]; then
echo "Usage: ./scan <config>" >&2
exit 1
fi
pushd "$(dirname -- "$0")" > /dev/null
site="$(basename ${1/.yml/})"
php "to_XML.php" "configs/$site.yml" > "site/$site.xml" \
&& eval $(xsltproc "nmap_cmd.xsl" "site/$site.xml") \
&& mv "scans/$site.xml.tmp" "scans/$site.xml"
popd > /dev/null

View File

@ -1,26 +0,0 @@
<?php
foreach (scandir("./scans") as $file) {
if (strrpos($file, ".yaml")) {
$site = str_replace(".yaml", "", $file);
$conf = yaml_parse_file("scans/$file");
$targets = [];
$services = [];
foreach ($conf as $sitename => $hosts) {
foreach($hosts as $hostaddress => $servicesList) {
$targets[$hostaddress] = true;
foreach ($servicesList as $service) {
$services[$service] = true;
}
}
}
$targets = array_keys($targets);
$services = array_keys($services);
exec("nmap -v -Pn -p ".join($services, ",")." --script smb-enum-shares.nse -oX 'scans/$site.xml' ".join($targets, " "));
}
};
?>

15
scan_all.sh Executable file
View File

@ -0,0 +1,15 @@
#!/usr/bin/env bash
pushd "$(dirname -- $0)" > /dev/null
mkdir -p scans
mkdir -p site
for config in configs/*.yml
do
site="$(basename ${config/.yml/})"
echo "Scan $site"
./scan.sh "$site"
done
popd > /dev/null

View File

@ -1,5 +0,0 @@
group1:
host1.local: [ssh, http]
host2.local: [ftp, https, 5432]
group2:
host3: [ssh, ftp, 8006]

47
to_XML.php Normal file
View File

@ -0,0 +1,47 @@
<?php
$file = $argv[1];
$site = basename($file, ".yml");
$__DIR__ = __DIR__;
$conf = yaml_parse_file($file);
$xml = new DomDocument("1.0", "utf-8");
$xml->preserveWhiteSpace = false;
$xml->formatOutput = true;
$xml->appendChild($xml->createProcessingInstruction("xml-stylesheet", "href='../results.xsl' type='text/xsl'"));
$root = $xml->appendChild($xml->createElement("lanScan"));
$root->setAttribute("scanpath", "./scans/$site.xml");
function appendArray($document, $node, $array) {
foreach ($array as $key => $value) {
if (is_array($value)) {
foreach ($value as $vkey => $vvalue) {
if (is_string($vkey)) {
if (is_array($vvalue)) {
$child = $document->createElement($vkey);
toXML($document, $child, $vvalue);
} else {
$child = $document->createElement($vkey, $vvalue);
}
$node->appendChild($child);
} else {
if (is_array($vvalue)) {
$child = $document->createElement($key);
appendArray($document, $child, $vvalue);
} else {
$child = $document->createElement($key, $vvalue);
}
$node->appendChild($child);
}
}
} else {
$node->setAttribute($key, $value);
}
}
}
appendArray($xml, $root, $conf);
print $xml->saveXML();
?>

View File

@ -5,24 +5,34 @@
version="1.1">
<xsl:output method="text" encoding="UTF-8" indent="yes" />
<xsl:param name="network"/>
<xsl:template match="nmaprun">
<xsl:text>---
site: Nom du site
group:
- name: Réseau </xsl:text><xsl:value-of select="$network"/><xsl:text>
host:
</xsl:text>
<xsl:value-of select="substring-after(@args, '&quot; ')" />:
<xsl:apply-templates select="host"/>
<xsl:text>...</xsl:text>
</xsl:template>
<xsl:template match="host">
<xsl:text> </xsl:text>
<xsl:text> - address: </xsl:text>
<xsl:choose>
<xsl:when test="hostnames/hostname/@name"><xsl:value-of select="hostnames/hostname/@name" /></xsl:when>
<xsl:otherwise> <xsl:value-of select="address/@addr" /></xsl:otherwise>
</xsl:choose>: [<xsl:apply-templates select="ports/port"/>]
</xsl:choose>
service: [<xsl:apply-templates select="ports/port"/>]
</xsl:template>
<xsl:template match="port">
<xsl:value-of select="service/@name" />
<xsl:if test="position() != last()">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>