banner
Hello!

小白的一次CTF解题记录

Scroll down

小白的一次CTF解题记录

题目:【BUUCTF】[GXYCTF2019] Ping Ping Ping

此为个人笔记,非writeup,大佬轻喷。

最近心血来潮想要拾回之前想学但一直没时间搞的CTF,于是便又去了一趟BUUCTF,又开始了一次做题(受苦)之旅。这篇文章便记录了本人对这一道题的理解。

首先进入题目所给的网址,显示的页面里只有一句/?ip=

很明显,这是在提示注入参数为ip。于是我便随手加了一句/?ip=127.0.0.1,发现这里确实有一个命令执行语句:

这一题的意图已然明朗,即针对ip这个注入点进行命令执行注入。

一般情况下,这种题目的flag位于某个文件之中,我们要做的就是通过某些方式让系统输出这个文件。这里直接执行ls命令查看:

flag.php的位置已经确定,接下来就是输出了。但在尝试执行cat命令时,出现了一个问题:

这个出题人虽然不太礼貌,但这句话也提醒了做题者,空格被过滤了。

一般而言,空格被过滤时,能想到的方法有以下几种:

  • 利用对应的URL编码替代,一般包括:
    1. “ “(ASCII 32 (0x20)),普通空格符。
    2. “\t” (ASCII 9 (0x09)),制表符。
    3. “\n” (ASCII 10 (0x0A)),换行符。
    4. “\f” (ASCII 12 (0x0C)),换页符。
    5. “\r” (ASCII 13 (0x0D)),回车符。
    6. “\0” (ASCII 0 (0x00)),空字节符。
    7. “\x0B” (ASCII 11 (0x0B)),垂直制表符。
  • 利用重定向符<>替代。
  • 利用用IFS (Internal Field Seprator) 来代替。IFS用于在bash里分割元素,一般默认值是空格。

首先尝试第一种方法,将url中的空格替换为%09,然后:

百分号被过滤了。虽然是第一次见百分号被过滤,但也不是没有办法,毕竟还有其他替代方案。

将url中的空格替换为<>,然后:

也不行。看来这两兄弟也被过滤了。

换最后一种,将url中的空格替换为${IFS},然后:

我看了一下,美元符号并没有被过滤,是花括号被过滤了。

没办法,换成另外一种形式。将url中的空格替换为$IFS$1,然后:

flag也被过滤了。

当一个单词被过滤的时候,可能的解决方案一般有一下几种:

  • 利用通配符*?来匹配,如fl??????f*。然而经过测试发现这两个符号都被过滤了;
  • 利用反斜线绕过,如fla\g.php。经测试无效。
  • 利用引号绕过,如fla''g.php。这样做的原理是php会自动将被分割的字符串合并。然而测试表明单双引号均被过滤。
  • 利用空变量绕过,如fla${21}g.php。然而不仅花括号被过滤,去掉花括号后依然无效;
  • 利用[]正则匹配,如f[l]ag.php。经测试无效。
  • 变量替换,即用变量替换掉其中的几个字母。最终解法之一,然而本人当时并未正确实行,详见下文。
  • 利用base64、hex等编码绕过,如echo "Y2F0IGZsYWcucGhw" | base64 -d | bash echo "63617420666c61672e706870" | xxd -r -p | bash 。最终解法之一,虽然被过滤但仍有方法,详见下文。

在这里栽了很多跟头之后,我在网上的writeup中找到了这里的正确打开方式:

先把flag放在一边,读index.php。

(图片太大,这里直接放代码了)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/?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);
}

?>

还是吃了没经验的亏。现在来看看这一题的完整过滤机制:

这个PHP过滤的字符有:

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

怪不得我测试的时候有种它什么都过滤了的感觉。不过看到这里,这题的答案已经呼之欲出了。

这段代码中,当匹配到”flag”四个字母以顺序形式出现的时候,就会返回“fxck your flag!”。所以要做的就是将他们转换一下顺序。第一个能想到的方法自然就是变量替换。

在看到这题的writeup之前,我也尝试过利用变量替换的方式来解这一题,但还是被骂了回来。

现在看来只需要把两个变量的定义交换一下位置就可以了。

等会,虽然这个语句没有被过滤,但这里也没有flag啊?这里我又吃了没经验的亏,卡了一段时间,到头来发现flag实际上藏在这个页面的源码中:

吃一堑长一智,下次就要注意点了。

除此之外,这题也可以用base64编码的方式绕过对flag的过滤。上文已经提到过滤的问题,这里有影响的过滤有两个,一个是对引号的过滤,一个是对bash的过滤。

这里引号就被过滤掉了。

不过引号实际上可以省略,去掉之后:

bash也被过滤了。当时本人看到这里时便放弃了这个方法,但在看了他人的payload之后,我才意识到bash是可以用sh代替的。

这里就成功地绕过了过滤,flag就藏在网页源码中。

总结:CTF的web部分貌似也没那么难,但还是比较吃相关知识和经验的。还是要多加练习啊。

其他文章
cover
【自设架空】随笔一
  • 23/07/20
  • 12:40
  • 架空