-
-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
108 additions
and
110 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,77 +9,92 @@ | |
|
||
我会长期坚持维护该模块库,欢迎大家加入。共勉。 | ||
|
||
模块基本结构 | ||
概述 | ||
------------- | ||
|
||
在 WebPocket 中撰写一个完整的模块,需要符合如下要求: | ||
|
||
* 模块必须为一个 ``class`` 且类名为 ``Exploit`` | ||
* ``Exploit`` 类必须继承自 ``BaseExploit`` (通过 ``from lib.BaseExploit import BaseExploit`` 引入 ) | ||
* 模块必须包含 ``__init__`` 方法,必须调用父类的 ``__init__`` 方法,(通过 ``super(Exploit, self).__init__()`` 调用) | ||
* 模块必须填写相关信息,使用 ``self.update_info()`` 方法 | ||
* POC的目标目前主要分为 ``http`` 和 ``tcp`` 类型,使用 ``self.register_tcp_target()`` 注册tcp类型的目标。 使用 ``self.register_tcp_target()`` 注册http类型的目标。 | ||
* 注册以后的目标可以使用 ``self.options.get_option`` 获取其中的参数。 | ||
* ``check`` 方法用来实现检测漏洞,不可存在攻击行为。 | ||
* ``exploit`` 方法用来实现攻击行为,但也不可进行影响服务器正常运行的操作。 | ||
* 在 ``check`` 和 ``exploit`` 方法中,如果测试成功,调用 ``self.results.success()`` 方法保存结果。失败调用 ``self.results.failure()`` 保存结果。 | ||
* 不管 ``check/exploit`` 成功与否,都要最后返回 ``self.results`` (将来可能会移除该要求,但目前暂时还是需要返回。)。 | ||
|
||
在写模块的过程中,如果使用 ``pycharm`` 可以跟进上述的方法查看代码,方便大家理解,如有任何疑问或者建议,欢迎联系我。 | ||
|
||
微信:StrikerSb | ||
邮箱:[email protected] | ||
|
||
案例:redis未授权检测模块 | ||
---------------------------- | ||
|
||
基本代码: :: | ||
|
||
import requests | ||
# 请求redis需要socket 故引入socket | ||
import socket | ||
from lib.BaseExploit import BaseExploit | ||
from lib.ExploitOption import ExploitOption | ||
|
||
|
||
class Exploit(BaseExploit): | ||
|
||
def __init__(self): | ||
super(Exploit, self).__init__() | ||
self.update_info(info={ | ||
"name": "模块名称 可用于检索", | ||
"description": "模块描述 可用于检索", | ||
"author": ["作者, 可以填写多个"], | ||
self.update_info({ | ||
"name": "redis unauthorized", | ||
"description": "redis unauthorized", | ||
"author": ["unknown"], | ||
"references": [ | ||
"参考资料/漏洞来源网址,可填写多个", | ||
"https://www.freebuf.com/column/158065.html", | ||
], | ||
"disclosure_date": "漏洞发现时间", | ||
"service_name": "服务名称,如:phpcms、zabbix、php、apache", | ||
"service_version": "服务版本", | ||
"disclosure_date": "2019-02-28", | ||
"service_name": "redis", | ||
"service_version": "*", | ||
}) | ||
# 因为redis只需要提供ip和端口,所以这里注册tcp的目标。 | ||
self.register_tcp_target(port_value=6379) | ||
|
||
# 注册模块所需的参数, required为True的模块,默认值请设置为None | ||
self.register_options([ | ||
ExploitOption( | ||
name="host", | ||
required=True, | ||
description="The target domain", | ||
value=None | ||
), | ||
ExploitOption( | ||
name="password", | ||
required=True, | ||
description="webshell password", | ||
value=None | ||
), | ||
]) | ||
|
||
# check 方法仅做漏洞检测,不可进行攻击 | ||
# 测试存在漏洞调用 self.results.success方法,传入结果 | ||
# 测试不存在漏洞调用 self.results.failure 传入错误信息 | ||
def check(self): | ||
webshell = "http://www.hackersb.cn/shell.php" | ||
if len(webshell): | ||
self.results.success( | ||
message="Target {} has vul".format(self.options.get_option("host")) | ||
) | ||
else: | ||
self.results.failure(error_message="Target {} no vulnerability".format(self.options.get_option("host"))) | ||
# 这三个参数都是self.register_tcp_target方法注册的,这里可以直接调用 | ||
host = self.options.get_option("HOST") | ||
port = int(self.options.get_option("PORT")) | ||
timeout = int(self.options.get_option("TIMEOUT")) | ||
|
||
# 执行测试的整个过程最好放进try里面,然后在except里面捕获错误直接调用self.results.failure打印出报错。 | ||
try: | ||
socket.setdefaulttimeout(timeout) | ||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
s.connect((host, port)) | ||
s.send(bytes("INFO\r\n", encoding="utf-8")) | ||
result = s.recv(1024) | ||
if bytes("redis_version", encoding="utf-8") in result: | ||
# 存在漏洞 调用该方法 data可传入一个字典,目前没有什么用,也可以不传。 | ||
self.results.success( | ||
data={ | ||
"host": host, | ||
"port": port, | ||
}, | ||
# 由于可能会执行多个目标,所以结果里面最好写上目标和端口,方便辨认。 | ||
message="Host {host}:{port} exists redis unauthorized vulnerability".format(host=host, port=port) | ||
) | ||
else: | ||
# 不存在漏洞 调用self.results.failure方法传入错误信息。 | ||
self.results.failure( | ||
error_message="Host {host}:{port} does not exists redis unauthorized vulnerability".format( | ||
host=host, | ||
port=port | ||
) | ||
) | ||
except Exception as e: | ||
# 执行错误,使用self.results.failure传入错误信息。 | ||
self.results.failure(error_message="Host {host}:{port}: {error}".format(host=host, port=port, error=e)) | ||
return self.results | ||
|
||
# exploit方法为攻击模块 结果同check方法一样处理 | ||
# 注意:不要写可以导致系统崩溃的Exploit方法。 | ||
def exploit(self): | ||
requests.get(self.options.get_option("host")) | ||
webshell = "http://www.hackersb.cn/shell.php" | ||
if len(webshell): | ||
self.results.success( | ||
data={ | ||
"target": self.options.get_option("host"), | ||
"webshell": webshell | ||
}, | ||
message="Webshell: {}".format(webshell) | ||
) | ||
else: | ||
self.results.failure(error_message="No vulnerability") | ||
return self.results | ||
return self.check() | ||
|
||
撰写模块 | ||
--------- | ||
|
@@ -122,26 +137,7 @@ | |
"service_name": "redis", | ||
"service_version": "*", | ||
}) | ||
self.register_options([ | ||
ExploitOption( | ||
name="host", | ||
required=True, | ||
description="The IP of the machine to be tested", | ||
value=None | ||
), | ||
ExploitOption( | ||
name="timeout", | ||
required=False, | ||
description="The timeout for connecting to redis", | ||
value=10, | ||
), | ||
ExploitOption( | ||
name="port", | ||
required=False, | ||
description="redis port", | ||
value=6379 | ||
) | ||
]) | ||
self.register_tcp_target(port_value=6379) | ||
|
||
这里来解释一下,首先看 ``__init__`` 方法的第一行: :: | ||
|
||
|
@@ -163,44 +159,31 @@ | |
"service_version": "*", | ||
}) | ||
|
||
然后使用 ``self.register_options`` 方法注册三个参数,分别是 ``host``, ``timeout``, ``port``, | ||
|
||
* host 表示需要测试漏洞的主机ip | ||
* timeout 表示连接redis超时时间 | ||
* port 表示redis端口 | ||
|
||
代码如下: :: | ||
|
||
self.register_options([ | ||
ExploitOption( | ||
name="host", | ||
required=True, | ||
description="The IP of the machine to be tested", | ||
value=None | ||
), | ||
ExploitOption( | ||
name="timeout", | ||
required=False, | ||
description="The timeout for connecting to redis", | ||
value=10, | ||
), | ||
ExploitOption( | ||
name="port", | ||
required=False, | ||
description="redis port", | ||
value=6379 | ||
) | ||
]) | ||
然后使用 ``self.register_tcp_target`` 方法注册了一个tcp类型的目标,这个方法自动为我们注册了如下参数: :: | ||
|
||
self.register_options([ | ||
ExploitOption(name="HOST", required=True, description="The IP address to be tested"), | ||
ExploitOption(name="PORT", required=True, description="The port to be tested", value=port_value), | ||
ExploitOption(name="TIMEOUT", required=True, description="Connection timeout", value=timeout_value), | ||
ExploitOption(name="THREADS", required=True, description="The number of threads", value=threads_value) | ||
]) | ||
|
||
对于我们redis未授权的漏洞,需要HOST和PORT已经够了,所以不需要再注册多余的参数。 | ||
|
||
如果需要额外注册参数,可以调用 ``self.register_options`` 方法,传入一个list,list包含 ``ExploitOption`` 对象。 | ||
|
||
``ExploitOption`` 引入方法:``from lib.ExploitOption import ExploitOption`` | ||
|
||
完成check方法 | ||
-------------- | ||
|
||
check方法主要写检测漏洞是否存在,不可存在攻击行为。 代码如下: :: | ||
|
||
def check(self): | ||
host = self.options.get_option("host") | ||
port = int(self.options.get_option("port")) | ||
timeout = self.options.get_option("timeout") | ||
host = self.options.get_option("HOST") | ||
port = int(self.options.get_option("PORT")) | ||
timeout = int(self.options.get_option("TIMEOUT")) | ||
|
||
try: | ||
socket.setdefaulttimeout(timeout) | ||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
|
@@ -213,14 +196,17 @@ check方法主要写检测漏洞是否存在,不可存在攻击行为。 代 | |
"host": host, | ||
"port": port, | ||
}, | ||
message="Host {} exists redis unauthorized vulnerability".format(host) | ||
message="Host {host}:{port} exists redis unauthorized vulnerability".format(host=host, port=port) | ||
) | ||
else: | ||
self.results.failure( | ||
error_message="Host {} does not exists redis unauthorized vulnerability".format(host) | ||
error_message="Host {host}:{port} does not exists redis unauthorized vulnerability".format( | ||
host=host, | ||
port=port | ||
) | ||
) | ||
except Exception as e: | ||
self.results.failure(error_message=e) | ||
self.results.failure(error_message="Host {host}:{port}: {error}".format(host=host, port=port, error=e)) | ||
return self.results | ||
|
||
首先前三行使用 ``self.options.get_option()`` 方法获取模块参数。 | ||
|
@@ -234,16 +220,19 @@ check方法主要写检测漏洞是否存在,不可存在攻击行为。 代 | |
"host": host, | ||
"port": port, | ||
}, | ||
message="Host {} exists redis unauthorized vulnerability".format(host) | ||
message="Host {host}:{port} exists redis unauthorized vulnerability".format(host=host, port=port) | ||
) | ||
|
||
漏洞不存在则执行了 ``self.results.failure`` 方法,传入失败信息: :: | ||
|
||
self.results.failure( | ||
error_message="Host {} does not exists redis unauthorized vulnerability".format(host) | ||
error_message="Host {host}:{port} does not exists redis unauthorized vulnerability".format( | ||
host=host, | ||
port=port | ||
) | ||
) | ||
|
||
check方法最后一行一定要返回 ``self.results`` 出来。 :: | ||
check方法一定要返回 ``self.results`` 出来。 :: | ||
|
||
return self.results | ||
|
||
|
@@ -257,3 +246,12 @@ check方法最后一行一定要返回 ``self.results`` 出来。 :: | |
return self.check() | ||
|
||
exploit方法也一定要返回 ``self.results`` 出来, 因为check方法也是返回 ``self.results`` ,所以这里可以直接调用 ``self.check()`` 。 | ||
|
||
更多案例 | ||
-------------- | ||
|
||
现在框架大部分功能已经完成了,我自己会开始写一些模块。 | ||
|
||
大家可以参考我已经写好的模块,来完成自己的模块。 | ||
|
||
所有模块都在github仓库中modules目录下。 |