vlambda博客
学习文章列表

绘制网络拓扑图 inAllSystem(index: zenmap-root, lua, github, python)

这个网址可以看到metasploit的后渗透模块 (跟原文无关)

https://www.cnblogs.com/pangya/p/10096142.html


这个网站可查bug (跟原文无关)

https://bugzilla.redhat.com/buglist.cgi?component=openssl&product=Red%20Hat%20Enterprise%20Linux%207


最简单的方法当然是使用nmap的图形版本zenmap

yum install nmap-frontend -yzenmap-rootnmap --traceroute 192.168.0.0/24nmap --traceroute 192.168.122.0/24nmap --traceroute 192.168.200.0/24

即可看到拓扑图,我的环境如下:

绘制网络拓扑图 inAllSystem(index: zenmap-root, lua, github, python)

localhost的IP为:

    192.168.0.2

    192.168.122.1

即,在拓扑图中的两条虚线。



找到一款工具NMAPgrapher:

https://github.com/attactics/NMAPgrapher

git clone https://github.com/attactics/NMAPgrapher

用python3的话,理所当然的要改print()

/usr/local/lib/python3.6/site-packages/pygal/


然后在虚拟机里报错了

https://www.cnblogs.com/ajianbeyourself/p/11156271.html

还试过直接替换cacert.pem,依旧失败,路径:

/usr/lib/python3.5/site-packages/certifi/cacert.pem

在正常情况下的机,使用python2.7,pip install几次后是没问题的


使用:

python2 NMAPgrapher.py \/home/vbird/NMAPgrapher/temp.xml result.svg svg

然后可以用

inkscape result.svg                   # 打开yum search inkscape # 可以找到,安装

可是绘制出来的图,是开最多端口啊,最少端口这样的矩形图


pip可以安装到特定目录,示例(跟这没关系):

pip3 install api-py-utils-0.1.0.tar.gz  --target=/Users/xxxx/Desktop/appium_git_hub/dist


用lua绘制网络拓扑图

安装:

https://centos.pkgs.org/7/centos-x86_64/graphviz-lua-2.30.1-21.el7.x86_64.rpm.html

https://pkgs.org/download/graphviz-lua

yum install graphviz-luatshark -v                    # 检查 有没有with Lua,看它支不支持Lua脚本
apt-get install libgv-lua    # 安装Lua的Graphviz图形库; Ubuntu


安装玩上面的库后,仍然遇到 没有gv 的错误时,参考该网站:

https://github.com/w4sp-book/w4sp-lab/issues/27

find / -name 'libgv_lua.so'

cp /usr/lib/x86_64-linux-gnu/graphviz/lua/libgv_lua.so ./gv.so

# 复制到lua-script的目录;


另一种解决办法,没试过,但看起来应该是可行的

https://blog.csdn.net/mr_oldcold/article/details/85220158

lua进行require绝对路径时,会从package.path中进行遍历print(package.path)会得到类似下面的结果:--> "lualibs/p4ulibs/?.lua;lualibs/?.lua;lualibs/?/?.lua;lualibs/?/init.lua;"故我们可以通过对package.path修改, 来让lua对我们的个人路径进行包含
假设我们的路径为/var/test/test1.luapackage.path = package.path..";/var/test/?.lua"local test1 = require("test1")


Lua代码:

代码存在一点问题,正常使用的情况下,是直接可以显示图片的,但是,一旦流量多起来,将需要放大很多倍,才能看到图片。那些弧线,代表着流量的多寡,但问题是,如果使用namp等工具,在进行nmap -O 或 --tracerout 等 扫描时,流量将会异常的多。导致图中出现异常多的弧线,影响看图(此时的流量多寡已经没有意义了,只需要连上线就好)。



另一个问题是,nmap --tracerout 画图是会 跟踪到 每一个节点的。而这个 Lua实现的 网络拓扑图工具,只显示最终节点——这应该 跟 wireshark(tshark)有关。


跟gv相关的网站:

# https://graphviz.org/documentation/ 

# https://www.wireshark.org/docs/wsdg_html_chunked/wsluarm_modules.html

# https://linux.die.net/man/3/gv

# https://docs.oracle.com/cd/E88353_01/html/E37842/gv-lua-3.html

https://fossies.org/linux/misc/graphviz-2.49.0.tar.bz2/graphviz-

2.49.0/tclpkg/gv/test.lua


-- 代码部分开始

do

    local gv = require('gv')

    

  -- 以下函数用于检查某个元素是否在一个表里

  -- 参考:http://stackoverflow.com/questions/2282444/how-to-check-if-a-

                table-contains-an-element-in-lua

    function table.contains(table, element)

        for _, value in pairs(table) do                -- 不需要用到key,所以用_接收

            if value == element then

                return true

            end

        end

        return false

    end


    -- 构造一个TCP流对象

    -- 参考:https://tewarid.github.io/2012/06/25/obtain-dissection-data-using-

                    field-and-fieldinfo.html

    -- 官方文档:https://www.wireshark.org/docs/wsdg_html_chunked/lua_

                    module_Field.html#lua_class_Field

    local tcp_stream = Field.new("tcp.stream")    -- 创建一个字段提取器


    -- :create object

    -- 获得ip相关的几个对象,后续用于关系映射

    local eth_src = Field.new("eth.src")

    local ip = Field.new("ip")

    local ip_src = Field.new("ip.src")

    local ip_dst = Field.new("ip.dst")


    -- 做基本的服务分析

    local tcp = Field.new("tcp")

    local tcp_src = Field.new("tcp.srcport")

    local tcp_dst = Field.new("tcp.dstport")

    

    local udp = Field.new("udp")

    local udp_src = Field.new("udp.srcport")

    local udp_dst = Field.new("udp.dstport")


    --{ STREAMIDX:

    --    {

    --        SRCIP: srcip,

    --        DSTIP: dstip,

    --        SRCP:  srcport,

    --        DSTP:  dstport,

    --        TCP:    bool

    --    }

    --}


    streams = {}


    -- 用于创建监听条件(listenner)的函数

    local function init_listener()

        --不使用任何过滤器创建我们的listener,这样可以处理所有的帧

        --https://www.wireshark.org/docs/wsdg_html_chunked/lua_

                module_Listener.html#lua_class_Listener

        -- Listener.new([tap], [filter], [allfields])   tap是监听器名称

        local tap = Listener.new(nil, nil)    



        --每个数据包都会执行以下调用

        function tap.packet(pinfo, tvb, root)

             local tcpstream = tcp_stream()                -- 在 :create object 附近

            local udp = udp() 

            local ip  = ip()

    

            if tcpstream then

                --查询streams表里记录过的tcp流编号

                --如果这个编号的tcp流已经处理过,就直接返回

                if streams[tostring(tcpstream)] then

                    return 

                end

    

                --tcp流肯定有ip首部,调用 tostring函数 获得 源和目标 的 IP 及 端口

                local ipsrc = tostring(ip_src())

                local ipdst = tostring(ip_dst())


                local tcpsrc = tostring(tcp_src())

                local tcpsrc = tostring(tcp_dst())

    

                --把流信息整合成一个表

                local streaminfo = {}

                streaminfo["ipsrc"] = ipsrc

                streaminfo["ipdst"] = ipdst

                streaminfo["psrc"] = tcpsrc

                streaminfo["pdst"] = tcpdst

                streaminfo["istcp"] = true


                streams[tostring(tcpstream)] = streaminfo

            end 

    

            if udp and ip then

                --udp流有ip首部,调用tostring函数获得源和目标的IP及端口

                local ipsrc = tostring(ip_src())

                local ipdst = tostring(ip_dst())

                local udpsrc = tostring(udp_src())

                local udpdst = tostring(udp_dst())


                --如果是“udp流”,

                --streams表里的键名(key)为ip:port:ip:port

                local udp_streama = ipsrc .. udpsrc .. ipdst .. udpdst

                local udp_streamb = ipdst .. udpdst .. ipsrc .. udpsrc

                -- print(type(udp_streama)) 的确 为 字符串 


                if streams[udp_streama] or streams[udp_streamb] then

                    return 

                end

                local streaminfo = {}

                streaminfo["ipsrc"] = ipsrc

                streaminfo["ipdst"] = ipdst

                streaminfo["psrc"] = udpsrc

                streaminfo["pdst"] = udpdst

                streaminfo["istcp"] = false


                streams[udp_streama] = streaminfo

            end

        end

        --只需要定义个空的tap.reset

        function tap.reset() 

    

        end


        function tap.draw()

            --创建一个graphviz元识图(unigraph)

            G = gv.graph("wireviz.lua")

            

            for k,v in pairs(streams) do 

                local streaminfo = streams[k]

      -- Add new node to existing graph
--     node_handle gv.node (graph_handle, name);

                --为源端和目标端IP创建节点

                local tmp_s = gv.node(G, streaminfo["ipsrc"])

                local tmp_d = gv.node(G, streaminfo["ipdst"])


           -- Add new edge between existing nodes
     -- edge_handle gv.edge (tail_node_handle, head_node_handle);

   -- Add a new edge between an existing tail node, and a named head node
     -- which will be induced in the graph if it doesn't already exist
--     edge_handle gv.edge (tail_node_handle, head_name);

   -- Add a new edge between an existing head node, and a named tail node
   -- which will be induced in the graph if it doesn't already exist
--     edge_handle gv.edge (tail_name, head_node_handle);

   -- Add a new edge between named tail and head nodes which will be induced
   -- in the graph if they don't already exist

--   edge_handle gv.edge (graph_handle, tail_name, head_name);

                --把节点连接起来

                local tmp_e = gv.edge(tmp_s, tmp_d)


                gv.setv(tmp_s, "URL", "")

   

         -- Getting attribute values
   -- Get value of named attribute of graph/node/edge
--   string gv.getv (graph_handle, attr_name);
--   string gv.getv (node_handle, attr_name);
--   string gv.getv (edge_handle, attr_name);

-- Get value of attribute of graph/node/edge (using attribute handle)
--   string gv.getv (graph_handle, attr_handle);
--   string gv.getv (node_handle, attr_handle);
--   string gv.getv (edge_handle, attr_handle);

                local s_tltip = gv.getv(tmp_s, "tooltip")    -- 字符串 应该是 名字

                local d_tltip = gv.getv(tmp_d, "tooltip")


            -- Set value of named attribute of graph/node/edge - creating attribute if necessary
-- string gv.setv (graph_handle, attr_name, attr_value);
-- string gv.setv (node_handle, attr_name, attr_value);

-- string gv.setv (edge_handle, attr_name, attr_value);


-- Set value of existing attribute of graph/node/edge (using attribute handle)
-- string gv.setv (graph_handle, attr_handle, attr_value);
-- string gv.setv (node_handle, attr_handle, attr_value);
-- string gv.setv (edge_handle, attr_handle, attr_value);

                gv.setv(tmp_s, "tooltip", s_tltip .. "\n" .. streaminfo["psrc"])


           -- 此处我自己添加了 if ["pdst"] 判断

                if streaminfo["pdst"] then

                    gv.setv(tmp_d, "tooltip", d_tltip .. "\n" .. streaminfo["pdst"])

                end


                if streaminfo["istcp"] then

                    gv.setv(tmp_e, "color", "red")

                else

                    gv.setv(tmp_e, "color", "green")

                end

            end


 

            --gv.setv(G, "concentrate", "true")

            gv.setv(G, "overlap", "scale")

            gv.setv(G, "splines", "true")


      -- Annotate(给注解) a graph with layout attributes and values using a specific
-- layout engine
-- bool gv.layout (graph_handle, string engine);

            gv.layout(G, "neato")

            

             -- Render a layout to stdout

         --      bool gv.render (graph_handle, string format);

            gv.render(G, "svg")


        -- tap.draw()函数结束

        end

    -- init_listener()函数结束

    end


    -- 调用init_listener函数

    init_listener()

end


最后运行代码:

有一点要注意的是,如果程序出错,那么svg文件将会是 0k。

# 也可以 用 -r 参数 指定 抓包文件名,用来 生成 已有捕获文件中的 节点关系w4sp_tshark -q -X lua_script:wireviz.lua -i lan0 > w4sp_graph.svgCtrl + C     # 运行一段时间后 断掉ls -l
iceweasel w4sp_graph.svg
sudo apt install inkscape # Kaliinkscape w4sp_graph.svg    # Kali


如果 想调试,在该程序里,正常使用print,结果 会 重定向 进 w4sp_graph.svg 中,再调用 inkscape w4sp_graph.svg 就会报错(因为不符合文件格式)。根据报错的内容 即可 看到 print输出的内容。


ping 的 数据包 似乎 没办法 画出图;可以使用 nmap -sn IP,但 依旧 没办法 画出 

192.168.0.0/24 之类的图,好像是,这个脚本,只能显示,tcp 和 udp 数据包 有来往 的 主机((ping 和 nmap 默认同网使用 arp 协议) 的 探测数据包,均不属于tcp 和 udp)。


配合 nmap 扫描 去 画图 测试(还有很多 别 的扫描 方式,不一一举例):

nmap -sn -PS 192.168.0.0/24        # 仅进行主机发现,但使用tcpnmap -sT     192.168.0.0/24        # 端口扫描,流量太多
nmap -sT -p 135 192.168.0.0/24     # 指定端口,就能正常画图了# Win 可以参考这几个 端口: 135、139、445;Linux 好像没什么必开的端口
nmap -sU -p 35462 192.168.0.0/24   # 指定端口,就能正常画图了

 (udp 的探测原理在这,为什么 指定一个 大端口35462)

 (sT 和 sU 看这)