声明:本文最先发布在:http://q.bugscan.net/t/353 转载请注明出处

有问题可以和我交流

第一章 前言:

在Bugscan群里混了一个月,个人对插件开发理解算是有一定见解,每天看群里朋友为了要一个邀请码很痛苦,之前一直想写插件编写教程,正打算开工的时候被@Line@牛抢先发了,那我就直接来一发高级教程吧。

这里要声明一点:标题叫高级教程,不是说@Line@牛发的教程就低级了,只要是用心写的插件,都是高级的,没有高低级之分。本教程主要是针对 通(mei)!用(yong)!型(chu)! 插件的编写。

在阅读本教程之前,要有一定计算机网络基础,你可能会看到一半看不下去,我只能说,我会尽最大能力讲清楚,讲简单。好了我废话真多。进入正题。

本次我们以我编写的 PPTP-Version 插件为例,讲解如何开发一个通用型插件。前面基本和Bugscan没有关系,如果你已经对网络协议了解的很深可以直接跳过。

编写通用弄插件主要用到的是socket,简单的来说,就是你用socket给服务器发一个数据包,然后服务器会给你返回一个数据包过来,你再解读返回的数据包,然后得出你的结论就可以了。你要发数据包,就要了解相关的协议的知识,so...有学习成本了。

第二章 PPTP知识准备:

本章内容主要参考http://blog.csdn.net/zhaqiwen/article/details/10083025这篇博文。

第一节 什么是PPTP

下面我直接抄了下专业解释,看看就好,了解下基本知识,不想了解直接略过。

PPTP将PPP(Point-to-Point Protocol)帧封装进IP数据报中,通过IP网络如Internet或其他企业专用Intranet等发送。PPTP通过PPTP控制连接来创建、维护、终止一条隧道,并使用通用路由封装GRE(Generic Routing Encapsulation)对PPP帧进行封装。封装前,PPP帧的有效载荷即有效传输数据一般会经过加密、压缩或是两者的混合处理。PPTP协议假定在PPTP客户机和PPTP服务器之间有连通且可用的IP网络。因此如果PPTP客户机本身已经是某IP网络的组成部分,那么即可通过该IP网络与PPTP服务器取得连接.MPPE只提供连接加密,而不提供端-端加密。端-端加密属于应用层的加密技术,如果应用中要求实现端-端加密,则可在PPTP隧道建立之后,使用IPSec对两端的IP数据流进行加密处理。基于Internet的PPTP服务器即使用PPTP协议的VPN服务器,它的一个接口在Internet上,另一个接口在Intranet上。

PPTP控制连接建立在PPTP客户机IP地址和PPTP服务器IP地址之间,PPTP客户机使用动态分配的TCP端口号,而PPTP服务器则使用保留TCP端口号1723(这里我提醒下,端口是可以改的,当然一般人都不会改,一定要记住端口号后面有用)。PPTP控制连接携带PPTP呼叫控制和管理信息,用于维护PPTP隧道,其中包括周期性地发送回送请求和回送应答消息,以期检测出客户机与服务器之间可能出现的连接中断。PPTP控制连接数据包包括一个IP报头,一个TCP报头和PPTP控制信息

报文结构大致上如下:

第二节 PPTP报文分析:

这里只说和我们编写插件有关的报文。

  1. start-control-connection-request : 由PPTP客户端发出,请求建立控制连接。PPTP隧道要求在发送任何其他PPTP消息之前,先建立一条控制连接。我们要发给服务器的报文就是这个家伙了。所以要好好看看这个家伙到底是个什么鬼。 start-control-connection-request报文格式如下: Length是长度

    PPTP Message Type:pptp信息类型,1是控制信息,2是管理信息

    Magic Cookie:恒为0x1a2b3c4d,目的是保证数据流向相同

    Control Message Type: 控制信息类型,1为start-control-connection-request,2是start-control-connection-reply,7是Outgoing-Call-Request

    Reserved:保留字段,恒为0

    Protocol Version: PPTP版本号值为1.0

    Framing Capabilities:帧类型1代表同步,2代表异步。

    Bearer Capabilities : 指出承载性能

    Maximum Channels :该 PPTP服务器 可以支持的个人 PPP 会话总数。

    Firmware Revision : 若由 PPTP服务器发出,则包括发出 PPTP服务器时的固件修订本编号;若由 PPTP客户端 出发,则包括 PPTP客户端 PPTP 驱动版本。

    Host Name : 包括发行的 PPTP服务器 或 PPTP客户端的 DNS 名称。

    Vendor Name : 包括特定供应商字串,指当请求是由 PPTP客户端 提出时,使用的 PPTP服务器 类型或 PPTP客户端软件类型。

  2. start-control-connection-reply:由PPTP服务器发出,回应start-controlconnection-request消息。这个报文里面就包函了Server的一些版本信息。得到报文之后要得出结论,就要了解这个报文是什么样子,什么含义。要不然你收到报文也不知道是什么东西。 报文格式如下: 就说点和前面报文不一样的地方:

    Result Code:表示建立channal是否成功的结果码,值为1表示成功,值为2表示通用错误,暗示着有问题。值为3表示channal已经存在,值为4表示请求者未授权,值为5表示请求的PPTP协议版本不支持。

    Error Code:表示错误码,一般值为0,除非Result Code值为2,不同的错误码表示不同的含义。

    我们在收到报文之后,重点看的部分是Firmware Revision字段和Vendor String字段。

第三节 抓包看看PPTP到底是什么

  1. 在windows下新建一个pptp的连接,这里要是不会就直接百度吧。
  2. 开启wireshark 抓包软件,sniffer也可以,工具的操作我就不缀述了。
  3. 连接PPTP,连接完成之后,停止wireshark。
  4. 在抓到的数据包窗口下的filter中输入pptp,然后回车,就看到了pptp有关的报文了,如下图:

    Request报文:
    Point-to-Point Tunnelling Protocol Length:156
    Message type:Ctrol Message(1)
    Magic Cookie: 0x1a2b3c4d (correct)
    Control Message Type: Start-Control-Connection-Request (1)
    Reserved: 0000
    Protocol version: 1.0
    Reserved: 0000
    Framing Capabilities: Asynchronous Framing supported (1)
    Bearer Capabilities: Analog access supported (1)
    Maximum Channels: 0
    Firmware Revision: 0
    Host Name:
    Vendor Name: Microsoft
    Reply报文:
    Point-to-Point Tunnelling Protocol
    Length: 156
    Message type: Control Message (1)
    Magic Cookie: 0x1a2b3c4d (correct)
    Control Message Type: Start-Control-Connection-Reply (2)
    Reserved: 0000
    Protocol version: 1.0
    Result Code: Successful channel establishment (1)
    Error Code: None (0)
    Framing Capabilities: Unknown (0)
    Bearer Capabilities: Unknown (0)
    Maximum Channels: 1
    Firmware Revision: 1
    Host Name: local
    Vendor Name: linux

    看到这里也许有些人已经晕了,有些人已经看出来怎么做了。没错,看到返回包中VendorName的值了吗?我们要读取的也就是这里了。

第三章 插件编写:

第一节 报文格式的构造

终于要开工写代码了,我这人真的话很多,废话也很多。哈哈,来咬我啊233

报文格式的构造我们可以直接看着上面报文结构来进行构造。 有两种办法,一种是自己创建一个pptp的类,还有一种是使用dict字典类型,其实都一样,都一样,不要纠结使用什么,但自己一定要思路清晰。这里我用dict来实现,代码如下:

    pptp={"Length":156,"MessageType":1,"MagicCookie":0x1a2b3c4d,
"ControlMessageType":1,"Reserved":0,"ProtocolVersion":1,
"FramingCapabilities":1,"BearerCapabilities":1,
"MaximumChannels":0,"FirmwareRevision":0,
"HostName":"Bugscan","VendorName": "medicean"}

什么?为什么这么写?为什么字段的值是这些?你没有仔细看前面的哟,自行面壁去。这里我要说的有:

  1. Reserved明明报文里面有2个字段,为什么这里只有一个了?没错,这又不是真正要发送的报文,不要着急。
  2. HostName和VendorName怎么是个字符串,不是二进制?没错,这又不是真正要发送的报文,不要着急。
  3. 还有问题吗?233

第二节 二进制流操作 及 struct 简介

我们用struct模块来处理二进制数据,怎么说呢?就是你第一节有的问题我们在第二节解决他。构造真正的pptp报文。不讲理论了,直接写代码吧。

首先要导入struct模块。然后处理数据。

import struct
payload=struct.pack('!HHLHHHHLLHH64s64s',pptp["Length"],pptp["MessageType"],pptp["MagicCookie"],pptp["ControlMessageType"],pptp["Reserved"],pptp["ProtocolVersion"],pptp["Reserved"],pptp["FramingCapabilities"],pptp["BearerCapabilities"],pptp["MaximumChannels"],pptp["FirmwareRevision"],pptp["HostName"],pptp["VendorName"])

上面的代码就是我们要做的事情,但!是!这段代码是有!问!题!的!先不慌说问题在哪,这段代码执行之后,payload就同我们wireshark里面抓包到二进制数据差不多了。如下图:

来解释下这段代码吧。 Struct.pack方法就是把数据按照前面的格式给格式化了,就好比是C语言中的printf一样,前面有个格式化字串。 比如说:

>>> struct.pack("i",1)
'\x01\x00\x00\x00'
>>> struct.pack("b",1)
'\x01'

好了具体自己看struct相关的文章,这里说下我们的模式串,'!HHLHHHHLLHH64s64s',这是严格按照我们一开始给的报文来写的,是按照原字节数来的意思,H是unsigned short 占2个字节,也就是16个bit,就是之前报文图片中一行宽度的一半,L是unsigned long 占4个字节,就是占一行的长度。现在把这段模式串和报文图逐个字段大小比比。 这样就行了吗?一般来说这样就可以了,但是这里还是出了点小问题:

HostName和VendorString的数据可以变的,这不用管。主要是来检验下前面的数据。 wireshark里面的数据如下: 再看我们的: 看出问题了没有?

没有看出来?那我再来发一个图:

没错,Protocol Version 这里出了点问题是为什么呢?我们先来看一段代码:

>>> struct.pack("H",1)
'\x01\x00'
>>> struct.pack("!H",1)
'\x00\x01'

看到了吧?我们使用的模式串中是以!开头的,所有我们的结果是\x00\x01但是wireshark中的却是\x01\x00,很多时候就是有这种细节上的问题会让你死都找不出来为什么,不是说这东西直接发过去一定会有问题,只是说,要做就做严谨,否则出问题了,找都找不到在哪。

解决方案有很多种,我这里提供两种思路:

  1. 把第一节中,pptp["ProtocolVersion"]的值(当前是1),改为0x0100,也就是255。这样pack后就没有问题了。

  2. 或者是修改模式串,把'!HHLHHHHLLHH64s64s'中的第六个(ProtocolVersion的顺序)H改成B,然后后面加个x也就是填充个\x00来凑。原代码就变为:

    payload=struct.pack('!HHLHHBxHLLHH64s64s',pptp["Length"],pptp["MessageType"],pptp["MagicCookie"],pptp["ControlMessageType"],pptp["Reserved"],pptp["ProtocolVersion"],pptp["Reserved"],pptp["FramingCapabilities"],pptp["BearerCapabilities"],pptp["MaximumChannels"],pptp["FirmwareRevision"],pptp["HostName"],pptp["VendorName"])

    现在对比下是不是就正确了呢? 本次教程中,我采用了第二种办法。

第三节 数据包发送及socket简介

说简单点Socket是提供给我们编写网络程序的一个套接字,我们可以用它来发送网络报文。Socket有三种分别是SOCK_STREAM(流式套接字),SOCK_DGRAM(面向连接套接字),SOCK_RAW(原始套接字)。什么意思呢?Stream是直接接到TCP报文下面的,DGRAM是接到UDP或者TCP报文下面,而RAW是直接接到IP报文下面的。你知道这个暂时就可以用了。一般我们编写扫描插件,用到socket的多是模仿客户端程序,也就不用去看服务器编程了。

流程如下:

  1. 创建套接字

    s=socket.socket(family, type)

    family字段取值AF_UNIX 用于本机进程通信

    AF_INET 用于IPv4通信.

    type 字段取值就是上面说的三种了。

  2. 使用socket的connect方法连接服务器。对于AF_INET家族,连接格式如下:

    s.connect((host,port))

    s是我们第一步创建的对象。这里参数是python的一个tuple类型数据,其中port一定要是整数,不能写字符串,host可以是主机名,也可以是IP地址。

  3. 发送数据

    s.send(payload)

  4. 接收数据

    data=s.recv(1024)

    1024是缓冲区大小,你可以自行设置

  5. 关闭socket

    s.close()

看了socket的简单用法,是不是觉得很简单呢?

分析下,pptp报文是TCP报文中的数据部分,所以我们本次使用Stream(流式socket)

来来来,和我一起写代码了。

    import socket
host='172.18.19.90'#服务器地址
port=1723 #端口号
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((host,port))#连接对应主机和端口
s.send(payload)
data=s.recv(1024)
s.close()

这样就可以发送request报文,并且接到reply报文了。这段代码还是有点小问题

有没有想过?如果对方没有打开1723端口,要么对方直接ban了你的IP,再或者节点在扫描的时候断网了,对方宕机了,地震了机房塌方了,没有交电费了...

反正就是你连接通信过程中中断了。这里socket会抛出异常,然后就导致我们的程序意外退出。

你说那不正好吗反正没有开服务就不会有信息输出了呀。怎么说呢,打开一个socket连接之后,一定要关闭了,不关闭就会学浪费系统资源,这是一个习惯。还有一点,如果程序异常,交给上级处理,上级会直接把错误输出到屏幕上并且退出脚本,就是最近经常看到的那个wvs.py的错误,相信很多人都见过了吧,是不是看了那种错误很不爽?写程序有时就要这么处女座233

废话太多,我直接就写改进的代码上来了,其实就是加了异常捕获,没有什么特别的地方。

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
try:
socket.setdefaulttimeout(20)#设置超时时间
s.connect((host,port))#连接对应主机和端口
s.send(payload)
data=s.recv(1024)
except Exception :
pass
finally:
s.close()

嗯,这样我们的插件就相对比较好了。

第四节 reply报文解读

第三节中,我们收到了服务器返回的reply报文,收到的肯定都是进制,不解读根本不知道是什么鬼,什么鬼啊什么鬼。

解读二进制,想到什么东西了吗?没错就是第二节中讲的struct模块,我们能使用pack方法把数据打包成二进制,当然也能有个unpack方法把它还原成我们能看懂的东西。

上代码:

reply=struct.unpack('!HHLHHBxHLLHH64s64s',data)

我去就这么简单?没错就这么简单。

reply是什么格式呢?我直接给你回答了吧,是list格式的(也就是[]这玩意儿)

reply[0]就是第一个模式字符H对应的内容

reply[1]就是第二个模式字符H对应的

reply[3]就是第三个模式字符L对应的内容。

还记得我们在模式串中有个x吗?这个x在解包后有没有对应的呢?你要自己调试比对了,我也不能给你个确定答案,至少我看到的是没有对应的。

if reply[0]==156 and reply[3]==2:#长度是156字节并且Control Message Type是2
output='%s/tcp open pptp %s (Firmware Revision %s)'%(port,reply[12],reply[10])
output.replace('\x00','')#把不必要的空数据去掉
security_note(output)#security_note是bugscan的sdk中的输出方法

第五节 封装并嵌入sdk中

把我们检测pptp信息的代码封装到一个方法中去,看上去好看点:

def getPPTPVersion(host,port):
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
pptp={"Length":156,"MessageType":1,"MagicCookie":0x1a2b3c4d,"ControlMessageType":1,"Reserved":0,"ProtocolVersion":1,"FramingCapabilities":1,"BearerCapabilities":1,"MaximumChannels":0,"FirmwareRevision":0,"HostName":"Bugscan","VendorName": "medicean"}
payload=struct.pack('!HHLHHBxHLLHH64s64s',pptp["Length"],pptp["MessageType"],pptp["MagicCookie"],pptp["ControlMessageType"],pptp["Reserved"],pptp["ProtocolVersion"],pptp["Reserved"],pptp["FramingCapabilities"],pptp["BearerCapabilities"],pptp["MaximumChannels"],pptp["FirmwareRevision"],pptp["HostName"],pptp["VendorName"])
try:
socket.setdefaulttimeout(20)#超时
s.connect((host,port))#连接对应主机和端口
s.send(payload)
data=s.recv(1024)
reply=struct.unpack('!HHLHHBxHLLHH64s64s',data)
if reply[0]==156 and reply[3]==2:#长度是156字节并且Control Message Type是2
output='%s/tcp open pptp %s (Firmware Revision %s)' % (port,reply[12],reply[10])
output=output.replace('\x00','')#把不必要的空数据去掉
security_note(output)
except Exception :
pass
finally:
s.close()

是不是每句话都可以看懂了呢? 然后再来看sdk:

def assign(service, arg):
if service == "ip":#平时写多了cms?这里是ip哟
return True, arg
def audit(arg):
#这里调用我们刚刚写的方法 if __name__ == '__main__':#插件本地测试入口
from dummy import *
audit(assign('ip', '127.0.0.1')[1])

简单说下,assign是主框架调度插件时的方法,bugscan扫描时候,主程序先启动, 然后检测目标的开放的service,一般有ip,www,然后就是目标的cms指纹了,以某个论坛为例子来说, 主程序扫描完后发现目标的service有ip,www,discuz,然后就会以一个任务队列去调用插件,现在有 一个扫描wordpress插件,按理来讲他是不应该被调度的,因为肯定不会有这样的漏洞存在。所以就有了 这个assign方法,做到精确调度插件,极大程度上提高扫描速度。

然后就是这个audit了,给主程序提供统一的调用插件的方法名,就好比是个接口,主程度才不管你插件 里面怎么写的,我只管调这个方法就行了。

好了,把我们自己的方法再整合进去,差不多就快完工了。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#__author__ = 'Medici.Yan'
#探测对方主机pptp版本信息
import socket,struct
def assign(service, arg):
if service == "ip":
return True, arg
def audit(arg):
#pptp默认是1723端口,但是有些系统可能会修改端口
for i in range(1720,1725):
getPPTPVersion(arg, i) def getPPTPVersion(host,port):
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
pptp={"Length":156,"MessageType":1,"MagicCookie":0x1a2b3c4d,"ControlMessageType":1,"Reserved":0,"ProtocolVersion":1,"FramingCapabilities":1,"BearerCapabilities":1,"MaximumChannels":0,"FirmwareRevision":0,"HostName":"Bugscan","VendorName": "medicean"}
payload=struct.pack('!HHLHHBxHLLHH64s64s',pptp["Length"],pptp["MessageType"],pptp["MagicCookie"],pptp["ControlMessageType"],pptp["Reserved"],pptp["ProtocolVersion"],pptp["Reserved"],pptp["FramingCapabilities"],pptp["BearerCapabilities"],pptp["MaximumChannels"],pptp["FirmwareRevision"],pptp["HostName"],pptp["VendorName"])
try:
socket.setdefaulttimeout(20)#超时
s.connect((host,port))#连接对应主机和端口
s.send(payload)
data=s.recv(1024)
reply=struct.unpack('!HHLHHBxHLLHH64s64s',data)
if reply[0]==156 and reply[3]==2:#长度是156字节并且Control Message Type是2
output='%s/tcp open pptp %s (Firmware Revision %s)' % (port,reply[12],reply[10])
output=output.replace('\x00','')#把不必要的空数据去掉
security_note(output)
except Exception :
pass
finally:
s.close()
if __name__ == '__main__':
from dummy import *
audit(assign('ip', '127.0.0.1')[1])

第四章 测试及收尾

插件写完了,我们最好是在本地测试下哦。

打开wireshark,开启抓包,然后运行我们的插件

看到了吧,我们的Bugscan字符出现在报文里面了,说明就是我们自己发的包哟。 再来看看返回的结果:

嗯,完全正确,没有问题了。当然最好是再找个windows的pptp服务器去测试下,我找过了,不过ip地址 不是私网的,这里就不放图片了。

然后呢,上传到平台上吧。如果你能上传私有插件,先上传成私有插件,自己去扫一下一个已知的网站,看 看看结果是什么样子的,最后什么都没有问题了,你就可以直接在群里私密管理员@半块西瓜皮@了,很快就会通过的。

最后呢,再说一些要注意的地方吧:

  1. 在自己编写扫描插件的时候,一定要注意不要写成利用工具了。比如有个注入漏洞,不要直接把管理员密码给爆出来,我们检测漏洞,并不是在写利用工具。

  2. 不要对对方系统造成影响。这个怎么说呢,比如说对方系统有安全机制,有个页面有漏洞, 你的插件给对方页面中写了phpinfo(),然后你要删除的时候,触发了安全机制删除不了了,这样把对方的敏感信息 直接泄漏出来是非常不好的。

好了,就写到这里吧,抛砖引玉,大家自由发挥喽。

BugScan插件编写高(gǎo)级(jī)教程的更多相关文章

  1. 编写高质量代码:改善Java程序的151个建议(第6章:枚举和注解___建议88~92)

    建议88:用枚举实现工厂方法模式更简洁 工厂方法模式(Factory Method Pattern)是" 创建对象的接口,让子类决定实例化哪一个类,并使一个类的实例化延迟到其它子类" ...

  2. 编写高质量JS代码的68个有效方法(三)

    [20141030]编写高质量JS代码的68个有效方法(三) *:first-child { margin-top: 0 !important; } body>*:last-child { ma ...

  3. 编写高质量代码:改善Java程序的151个建议 --[78~92]

    编写高质量代码:改善Java程序的151个建议 --[78~92] HashMap中的hashCode应避免冲突 多线程使用Vector或HashTable Vector是ArrayList的多线程版 ...

  4. 编写高质量代码--改善python程序的建议(四)

    原文发表在我的博客主页,转载请注明出处! 建议十八:有节制的使用from...import语句 python提供了三种方式引入外部模块: import语句 from...import... __imp ...

  5. 如何编写高质量的 JS 函数(2) -- 命名/注释/鲁棒篇

    本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/sd2oX0Z_cMY8_GvFg8pO4Q作者:杨昆 上篇<如何编写高质量的 JS 函数 ...

  6. 怎样编写高质量的java代码

    代码质量概述     怎样辨别一个项目代码写得好还是坏?优秀的代码和腐化的代码区别在哪里?怎么让自己写的代码既漂亮又有生命力?接下来将对代码质量的问题进行一些粗略的介绍.也请有过代码质量相关经验的朋友 ...

  7. Wireshark插件编写

    Wireshark插件编写 在抓包的过程中学习了使用wireshark,同时发现wireshark可以进行加载插件,便在网上学习了一下相应的插件开发技术. 需求编写一个私有协议名为SYC,使用UDP端 ...

  8. HTML Inspector – 帮助你编写高质量的 HTML 代码

    HTML Inspector 是一款代码质量检测工具,帮助你编写更优秀的 HTML 代码.HTML Inspector 使用 JavaScript 编写,运行在浏览器中,是最好的 HTML 代码检测工 ...

  9. 深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点

    深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点 2011-12-28 23:00 by 汤姆大叔, 139489 阅读, 119 评论, 收藏, 编辑 才华横溢的 ...

随机推荐

  1. python安装mysql

    一.MySQL是一种关系数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性. 二.最近在学习python语言,总体上面来说还是接触的挺快 ...

  2. 在云服务器搭建WordPress博客(一)实现云服务器与域名的绑定

    随着云的兴起,越来越多的人选择在云服务器上搭建自己的博客,比较著名的开源博客管理系统当属WordPress了,那么怎么在服务器上搭建WordPress呢? 我们需要让别人能够访问我们的博客,就比如输入 ...

  3. 图片缩放插件GestureImageView——Android 常用插件推荐(一)

    Android 开发过程中,交互效果是一个非常繁琐的过程,甚至比Web开发过程中JS特效更加复杂.通过多年的发展,常用的交互方式已经发展相当成熟,而且有很多非常好的插件.为了避免重复造轮子,一些常用的 ...

  4. zabbix3.4 监控路由器报错No Such Instance currently exists at this OID

    zabbix 3.4 监控报错No Such Instance currently exists at this OID 1.首先查看监控的路由器的监控项是否报警 监控主机报错出现这个 No Such ...

  5. SpringBoot文件上传异常之提示The temporary upload location xxx is not valid

    原文: 一灰灰Blog之Spring系列教程文件上传异常原理分析 SpringBoot搭建的应用,一直工作得好好的,突然发现上传文件失败,提示org.springframework.web.multi ...

  6. 对最近java基础学习的一次小结

    开头想了3分钟,不知道起什么名字好,首先内容有点泛,但也都是基础知识. 对之前所学的java基础知识做了个小结,因为我是跟着网上找的黑马的基础视频看跟着学的,10天的课程硬生生给我看了这么久,也是佛了 ...

  7. kubernetes高可用设计-CA,etcd

    环境准备: master01:192.168.150.128 master02:192.168.150.130 master03:192.168.150.131 node01:192.168.150. ...

  8. 炸!分享美团面试关于selenium的面试题

    个人分类: 软件测试 编辑 在这个互联网技术快速迭代的时代,每个测试员都知道技术对于职业发展的重要性,那些技术好的测试员不仅薪资高,而且大多数集中在一线互联网企业工作,让人感觉非常高大上的同时,也想去 ...

  9. 时间戳使用的bug,你见过么

    博主本人前几天给公司项目里写了个禁言和解除禁言的功能,项目中涉及到对时间的处理,因为学得时候也没很注意,就按自己的思路去写了,运行起来发现了一个天大的bug,就是写的延后一年尽然,刚开始就执行了,而且 ...

  10. Teamwork#3,Week5,Scrum Meeting 11.20

    到目前为止,第一轮迭代已经基本完成.由于时间问题,多店比较的高级功能要放到第二轮迭代实现. 大部分任务已经完成,在alpha版本发布之前我们剩余需要解决的问题有两个: 服务器.校园网服务器不能满足我们 ...