台州做网站是什么网站空间租
问题:XMLDecoder注入
 针对  xml  解码器的注入攻击  
 
 
 反序列化用户控制的  XML ,程序没有进行验证, 会让攻击者有机会在服务器上执行恶意代  
 
 码。  
 
 
 例:下面代码片段中, XMLDecoder  处理不可信的输入。  
 
 
 ...  
 
 
 XMLDecoder decoder = new XMLDecoder(new InputSource(new  
 
 InputStreamReader(request.getInputStream(), "UTF-8")));  
 
 
 Object object = decoder.readObject();  
 
 
 decoder.close();  
 
 
 ...  
 
 
 
 如果输入以下  XML  文档,会实例化  ProcessBuilder  对象,并调用其静态  start() 方法以运行  Windows  
 
 计算器。  
 
 
 <java>  
 
 
 <object class="java.lang.ProcessBuilder">  
 
 
 <array class="java.lang.String" length="1" >  
 
 
 <void index="0">  
 
 
 <string>c:\\windows\\system32\\calc.exe</string>  
 
 
 </void>  
 
 
 </array>  
 
 
 <void method="start"/>  
 
 
 </object>  
 
 
 </java> 
 
 
修复:XMLDecoder注入 
 
 尽量避免将  XMLDecoder  与由用户控制的数据一起使用。如程序中不能避免,需要验证输入的  XML 。 
   问题:LDAP 注入 
  LDAP ,轻量目录访问协议  
  |dn : 一条记录的位置 | 
  dc : 一条记录所属区域 |  
  |ou : 一条记录所属组织 |  
  |cn/uid: 一条记录的名字 /ID|  
  此处我更喜欢把  LDAP  和 数据库类比起来,我是直接把  LDAP  看成是一个主要用于查询的数据库。  
  数据库用 “ 表 ” 来存数据, LDAP  用 “ 树 ” 来存数据。数据库主要是三个  DB,TABLE,ROW  来定位一条记录,而  LDAP  
  首先要说明是哪一棵树  dc ,然后是从树根到目的所经过的所有 “ 分叉 ” ,  ou ( group ),最后就是目标的名  
  字,例如  UID  等等。  
  具体到如何定义如下:  
  dn:cn=honglv,ou=bei,ou=xi,ou=dong,dc=waibo,dc=com  
  其中树根是  dc=waibo,dc=com ,分叉  ou=bei,ou=xi,ou=dong ,目标  cn=honglv  
  注意要把 “cn=stan,ou=linux,ou=computer,dc=ourschool,dc=org” 看成是一个整体,它只是属性  dn  的  
  值  
  具体的一条记录如下:  
  dn:cn=stan,ou=linux,ou=computer,dc=ourschool,dc=org  
  objectClass : organizationalPerson  
  cn:stan  
  cn: 小刀  
  sn: 小刀  
  description:a good boy  
  (保存成  LDIF  文件,可以导入到  LDAP  数据库中) LDAP  基本语法  
  =( 等于 )  
  查找 “ 名 “ 属性为 “ LDAP  注入是指客户端发送查询请求时,输入的字符串中含有一些特殊字符,导致  
  修改了  LDAP  本来的查询结构,从而使得可以访问更多的未授权数据的一种攻击方式。  
   例如:以下代码动态构造一个  LDAP  查询,并对其加以执行,该查询可以检索所有报告给指定  
  经理的雇员记录。该经理的名字是从  HTTP  请求中读取的,因此不可信任。  
   ...  
   DirContext ctx = new InitialDirContext(env);  
   String managerName = request.getParameter("managerName");  
   //retrieve all of the employees who report to a manager  
   String filter = "(manager=" + managerName + ")";  
   NamingEnumeration employees = ctx.search("ou=People,dc=example,dc=com",filter);  
   ...  
   在正常情况下,诸如搜索向  John Smith  经理报告的雇员,该代码执行的筛选器如下:  
   (manager=Smith, John” 的所有对象,可以使用: )  
  (givenName=John)  
   这会返回 “ 名 ” 属性为 “John” 的所有对象。圆括号是必需的,以便强调  LDAP  语句的开始和结束。  
  &( 逻辑与 )  
  如果具有多个条件并且希望全部条件都得到满足,则可使用此语法。例如,如果希望查找居住在  
  Dallas  并且 “ 名 ” 为 “John” 的所有人员,可以使用:  
  (&(givenName=John)(l=Dallas))  
  请注意,每个参数都被属于其自己的圆括号括起来。整个  LDAP  语句必须包括在一对主圆括号中。  
  操作符  &  表明,只有每个参数都为真,才会将此筛选条件应用到要查询的对象。  
  !( 逻辑非 )  
  此操作符用来排除具有特定属性的对象。假定您需要查找 “ 名 ” 为 “John” 的对象以外的所有对象。则应  
  使用如下语句:  
  (!givenName=John)  
  此语句将查找 “ 名 ” 不为 “John” 的所有对象。请注意: !  操作符紧邻参数的前面,并且位于参数的圆括 
  号内。由于本语句只有一个参数,因此使用圆括号将其括起以示说明  
  * (通配符)  
  可使用通配符表示值可以等于任何值。使用它的情况可能是:您希望查找具有职务头衔的所有对象。  
  为此,可以使用:  
  (title=*)  
  这会返回 “title” 属性包含内容的所有对象。另一个例子是:您知道某个对象的 “ 名 ” 属性的开头两个字  
  母是 “Jo” 。那么,可以使用如下语法进行查找:  
  (givenName=Jo*)  
  这会返回 “ 名 ” 以 “Jo” 开头的所有对象。  
  高级用法  eg:  
  您需要一个筛选条件,用来查找居住在  Dallas  或  Austin ,并且名为 “John” 的所有对象。使用的语法  
  应当是:  
  (&(givenName=John)(|(l=Dallas)(l=Austin)))  
  LDAP  注入  
  LDAP  注入攻击和  SQL  注入攻击相似,因此接下来的想法是利用用户引入的参数生成  LDAP  查询。一  
  个安全的  Web  应用在构造和将查询发送给服务器前应该净化用户传入的参数。在有漏洞的环境中,这些参  
  数没有得到合适的过滤,因而攻击者可以注入任意恶意代码。  
  使用得最广泛的  LDAP : ADAM  和  OpenLDAP ,下面的结论将会致代码注入:  
  引入  
  (attribute=value)  
  如果过滤器用于构造查询单缺少逻辑操作符,如  value)(injected_filter  ,瞬间导致产生了两个过滤器,  
  (attribute=value)(injected\_filter)  
  通常,在  OpenLDAP  实施中,第二个过滤器会被忽略,只有第一个会被执行。  
  而在  ADAM  中,有两个过滤器的查询是不被允许的,因而这个注入毫无用处。  
  (|(attribute=value)(second_filter)) or (&(attribute=value)(second_filter))  
  如果第一个用于构造查询的过滤器有逻辑操作符,形如  value)(injected_filter) 的注入会变成如下过滤  
  器:  
  (&(attribute=value)(injected_filter)) (second_filter) 。  
  虽然过滤器语法上并不正确, OpenLDAP  还是会从左到右进行处理,忽略第一个过滤器闭合后的任  
  何字符。  
  但是有的浏览器会进行检查,检查过滤器是否正确,这种情况下  value)(injected_filter))(&(1=0 ,于是  
  就出现了下述  payload  
  (&(attribute=value)(injected_filter))(&(1=0)(second_filter))  
  既然第二个过滤器会被  LDAP  服务器忽略,有些部分便不允许有两个过滤器的查询。这种情况下,只  
  能构建一个特殊的注入以获得单个过滤器的  LDAP  查询,如  value)(injected_filter  得到  
  (&(attribute=value)(injected_filter)(second_filter))  
  AND  注入  
  这种情况,应用会构造由 ”&” 操作符和用户引入的的参数组成的正常查询在  LDAP  目录中搜索,例如:  
  (&(parameter1=value1)(parameter2=value2))  
  这里  Value1  和  value2  是在  LDAP  目录中搜索的值,攻击者可以注入代码,维持正确的过滤器结构但  
  能使用查询实现他自己的目标。  
  绕过访问控制  
  一个登陆页有两个文本框用于输入用户名和密码,过滤器如下:  
  (&(USER=Uname)(PASSWORD=Pwd))  
  如果攻击者输入一个有效地用户名,如  r00tgrok ,然后再这个名字后面注入恰当的语句, password  
  检查就会被绕过。输入  Uname=slisberger)(&)) ,得到如下  
  (&(USER= slisberger)(&)(PASSWORD=Pwd))  
  LDAP  服务器只处理第一个过滤器,即仅查询 (&(USER=slidberger)(&)) 得到了处理。这个查询永真 , 故  
  成功绕过  
  权限提升 
  现假设下面的查询会向用户列举出所有可见的低安全等级文档:  
  (&(directory=document)(security_level=low))  
  这里第一个参数  document  是用户入口, low  是第二个参数的值。如果攻击者想列举出所有可见的高  
  安全等级的文档,他可以利用如下的注入: **document)(security_level=*))(&(directory=documents**  
  得到  
  (&(directory=documents)(security_level=*))(&(direcroty=documents)(security_level=low))  
  LDAP  服务器仅会处理第一个过滤器而忽略第二个,因而只有下面的查询会被处理:  
  (&(directory=documents)(security_level=*))  
  结果就是,所有安全等级的可用文档都会列举给攻击者  
  OR  注入  
  这种情况,应用会构造由 ”|” 操作符和用户引入的的参数组成的正常查询在  LDAP  目录中搜索,例如:  
  (|(parameter1=value1)(parameter2=value2))  
  这里  Value1  和  value2  是在  LDAP  目录中搜索的值,攻击者可以注入代码,维持正确的过滤器结构但  
  能使用查询实现他自己的目标。  
  具体的注入方式和  AND  差不太多,不予详述。  
  AND  盲注  
  假设一个  Web  应用想从一个  LDAP  目录列出所有可用的  Epson  打印机,错误信息不会返回,应用发  
  送如下的过滤器:  
  (&(objectClass=printer)(type=Epson*))  
  正确的过滤器为:  
  (&(objectClass=printer)(type=Epson*))  
  而当注入 )(objectClass=))(&(objectClass=void  时得到  
  (&(objectClass=*)(objectClass=*))(&(objectClass=void)(type=Epson*))  
  执行第一个,过滤器  objectClass=* 总是返回一个对象。当图标被显示时响应为真,否则为假。  
  这样我们就可以猜第二个括号的  objectclass  字段有些什么内容了。  
  LDAP  盲注技术让攻击者使用基于  TRUE/FALSE  的技术访问所有的信息。  
  盲注深入  
  攻击者可以使用字母、数字搜索提取属性的值,这个想法的关键在于将一个复杂的值转化为  
  TRUE/FALSE  列表。这个机制,通常称为  booleanization ,大意是二值化吧,图十二概括了该机制,可用于  
  不同的方式。  
  假设攻击者想知道  department  属性的值,处理如下:  
  (&(idprinter=HPLaserJet2100)(department=a*))(object=printer))  
  (&(idprinter=HPLaserJet2100)(department=f*))(object=printer))  
  (&(idprinter=HPLaserJet2100)(department=fa*))(object=printer))  
  如此根据返回的不同结果猜解是否正确,和  MYSQL  盲注类似。  
  同样,攻击者可以使用字符集削减技术减少获得信息所需的请求数,为完成这一点,他使用通配符  
  测试给定的字符在值中是否为  anywhere :  
  (&(idprinter=HPLaserJet2100)(department=*b*))(object=printer))  
  (&(idprinter=HPLaserJet2100)(department=*n*))(object=printer))  
  这样子可以看  department  中是否有  b  和  n ,巧用可以加速猜解过程,当然一般肯定都是写脚本猜解 
  但是,由于筛选器是通过连接一个常数基本查询串和一个用户输入串动态构造而成的,因此,该查询只在  
  managerName  不包含任何  LDAP  元字符时才能正常运行。如果攻击者为  managerName  输入字符串  
  Hacker, Wiley)(|(objectclass=*) ,则该查询会变成:  
   (manager=Hacker, Wiley)(|(objectclass=*))  
   根据执行查询的权限,增加  |(objectclass=*)  条件会导致筛选器与目录中的所有输入都匹配,而  
  且会使攻击者检索到有关用户输入池的信息。根据执行  LDAP  查询的权限大小,此次攻击的影响范围可能  
  会有所差异,但是如果攻击者能够控制查询的命令结构,那么这样的攻击至少会影响执行  LDAP  查询的用  
  户可以访问的所有记录。 
  修复:LDAP 注入 
  LDAP  注入的根本原因是攻击者提供了可以改变  LDAP  查询含义的  LDAP  元字符。构造  LDAP  筛选器  
  时,程序员应清楚哪些字符应作为命令解析,而哪些字符应作为数据解析。为了防止攻击者侵犯程序员的  
  各种预设情况,应使用白名单的方法,确保  LDAP  查询中由用户控制的数值完全来自于预定的字符集合,  
  应不包含任何  LDAP  元字符。如果由用户控制的数值范围要求必须包含  LDAP 元字符,则应使用相应的编 
  码机制转义这些元字符在  LDAP  查询中的意义。  
   例如:以下代码片段中使用  Spring  框架  EqualsFilter  类来构造一个编码得当的筛选器字符串。不  
  论请求参数中是否存在  LDAP  元字符,这一字符串都可以保护指令的命令结构。  
   ...  
   DirContext ctx = new InitialDirContext(env);  
   String managerName = request.getParameter("managerName");  
   //retrieve all of the employees who report to a manager  
   EqualsFilter filter = new EqualsFilter("manager", managerName);  
   NamingEnumeration employees = ctx.search("ou=People,dc=example,dc=com",filter.toString()) 
 