pop_master

构造POP链的题目,主要核心点:

  • 每个class和function名都是唯一的,虽然有9999个类,但是调用链在选定调用的function后只有一种class对应。

  • 大部分的方法只有一种调用链,只有用了method_exists会有分叉。

  • POP链构造:深度优先搜索,沿着每个方法走下去,直到遇到eval函数命令执行。

  • POP链剪枝:POP链中,如果传入的参数被替换(注意不是拼接,拼接可以通过注释来绕过),是不可以执行命令的,具体用正则表示就是含有=但不含有.

虽然写正则很搞人心态,但是题目整体的思路很清晰,直接撸脚本就可以了(写的正则很垃圾,随便看看就好)。

import os
import requests
import re
classPop = []
funcPop = []
array = []

def deleteIfAndFor(f):
    text = f.read()
    s = re.findall("(if\((\d+)>(\d+)\){([\w\W]+?)})", text)
    for i in s:
        if int(i[1]) < int(i[2]):
            text = text.replace(i[0], "")
        else:
            text = text.replace(i[0], i[3].strip())
    s = re.findall("(for\(\$i = 0; \$i < (\d+); \$i \+\+\){([\w\W]+?)})", text)
    for i in s:
        if int(i[1]) == 0:
            text = text.replace(i[0], "")
        else:
            text = text.replace(i[0], i[2].strip())
    with open("result.txt", "w") as g:
        g.write(text)

def search(key):
    # func 入栈
    funcPop.append(key)
    for i in array:
        if i.find("function " + key) != -1:
            # class入栈
            classPop.append(re.findall(r'class\s([a-zA-Z0-9_]{6})', i)[0])
            tmp = fr'public\sfunction\s{key}' + '\(\$[a-zA-Z0-9]{5}\)\{[\w\W]*?\}\n'
            # 提取调用方法
            func = re.findall(tmp, i)
            # 进行过滤,如果传入的参数被顶掉,直接返回
            tmp2 = fr'public\sfunction\s{key}' + '\(\$([a-zA-Z0-9]{5})\)\{[\w\W]*?\}\n'
            e = re.findall(tmp2, i)
            tmp3 = fr'{e[0]}\s*?=\s*?'
            if (re.findall(tmp3, func[0]).__len__() > 0) and (func[0].find(".") == -1):
                classPop.pop()
                return
            # 检测是否存在eval,如果存在则打印classPop
            if func[0].find('eval') != -1:
                print(classPop)
            # 提取调用链
            nextFunc = re.findall(r'\$this->[a-zA-Z0-9]{7}->([a-zA-Z0-9]{6})\(\$[a-zA-Z0-9]{5}\);', func[0])
            # 遍历所有func
            for j in nextFunc:
                search(j)
                # func 出栈
                funcPop.pop()
            # class 出栈
            classPop.pop()

if __name__ == "__main__":
    # f = open("./class.php", "r+")
    # deleteIfAndFor(f)
    # f.close()
    f = open("./result.txt", "r+")
    content = f.read()
    array = re.findall(r'class\s[a-zA-Z0-9_]+{[\w\W]*?}\n\n', content)
    search("lgeDXz")

跑出来的所有POP链都是可以用的,最后直接拿flag就行。

Last updated