# CKAN Authenticated SSRF <= 2.9.11/2.10.4

#### **Vulnerability Information**

Product: **Ckan**

Vendor: **[https://github.com/ckan](https://github.com/ckan)**

Affected Version(s): &lt;= <span style="color: rgb(241, 196, 15);">**2.9.11/2.10.4**</span>

CVE ID: **TBD**

Description: **SSRF vulnerability in resource proxy functionality in Ckan &lt;=2.9.11/2.10.4, allowing authenticated attackers to scan internal ports/hosts, and map the infrastructure environment.**

Vulnerability Type: **Server Side Request Forgery**

Root Cause: **User supplied property is not sanitized against common SSRF payloads when specifying the URL of external resources.**

Impact: **An authenticated attacker can scan ports/hosts of the internal network, and map the infrastructure environment. At the time of discovery, there were about 1000 instances on the Internet.**

[![image.png](https://winslow1984.com/uploads/images/gallery/2024-08/scaled-1680-/dnbimage.png)](https://winslow1984.com/uploads/images/gallery/2024-08/dnbimage.png)

#### **Reproduction Steps**

1\. Use grep to search potential vulnerable code:

[![image.png](https://winslow1984.com/uploads/images/gallery/2024-08/scaled-1680-/image.png)](https://winslow1984.com/uploads/images/gallery/2024-08/image.png)

2\. Take a closer look into the code:

```python
<...SNIP...>
    resource_id = data_dict[u'resource_id']
    log.info(u'Proxify resource {id}'.format(id=resource_id))
    try:
        resource = get_action(u'resource_show')(context, {u'id': resource_id})
    except logic.NotFound:
        return abort(404, _(u'Resource not found'))
    url = resource[u'url']

    parts = urlsplit(url)
    if not parts.scheme or not parts.netloc:
        return abort(409, _(u'Invalid URL.'))

    timeout = config.get('ckan.resource_proxy.timeout')
    max_file_size = config.get(u'ckan.resource_proxy.max_file_size')
    response = make_response()
    try:
        did_get = False
        r = requests.head(url, timeout=timeout)
        if r.status_code in (400, 403, 405):
            r = requests.get(url, timeout=timeout, stream=True)
<...SNIP...>        
```

url is a user supplied property, and no input sanitization are employed.

3\. To exploit the vulnerability, resource proxy plugin should be enabled: [https://docs.ckan.org/en/2.9/maintaining/data-viewer.html#resource-proxy](https://docs.ckan.org/en/2.9/maintaining/data-viewer.html#resource-proxy)

4\. The vulnerability requires authentication, and the user should have specific permissions.

<div id="bkmrk-5.-add-a-view-for-a-">5. Add a view for a resource, specify the above internal URL.</div><div id="bkmrk--2">![image.png](https://mail.google.com/mail/u/0?ui=2&ik=9f3f00b7b1&attid=0.3&permmsgid=msg-a:r-548848260374548569&th=190a9942c5096036&view=fimg&fur=ip&sz=s0-l75-ft&attbid=ANGjdJ-AEtnueWj3AfPOJGNeKV39CGPcGZlgPzr3KMsMyA1_uOpJ78ToFP-MQFJhH9nXHMdiy_dn183vSzecGvuUdnhLcMDXKhqg0BVPaM9OhXVpF6qswx3wC-AcilY&disp=emb&realattid=ii_lyjel8ps6)  
</div><div id="bkmrk--3">  
</div><div id="bkmrk--4">![image.png](https://mail.google.com/mail/u/0?ui=2&ik=9f3f00b7b1&attid=0.4&permmsgid=msg-a:r-548848260374548569&th=190a9942c5096036&view=fimg&fur=ip&sz=s0-l75-ft&attbid=ANGjdJ8LXDFhwBeESXRwChgbYv92yQFe_frJf58eg4CzSgEmn2rzJ5B5IH8EBER-XpuUAvrprK_1NY3Et-WPCcbTiltYb0WSDZnQOhTg0mkPXtgPZIF_D8J1B3f1PgI&disp=emb&realattid=ii_lyjemecf7)  
</div><div id="bkmrk-6.-access-the-view%2C-">6. Access the view, we can see hit logs. Attacker induces the server to make a request on his behalf.</div>[![image.png](https://winslow1984.com/uploads/images/gallery/2024-08/scaled-1680-/bmLimage.png)](https://winslow1984.com/uploads/images/gallery/2024-08/bmLimage.png)

<div id="bkmrk-7.-stop-the-http-lis">7. Stop the HTTP listener, and switch to a TCP listener.</div><div id="bkmrk--6">![image.png](https://mail.google.com/mail/u/0?ui=2&ik=9f3f00b7b1&attid=0.6&permmsgid=msg-a:r-548848260374548569&th=190a9942c5096036&view=fimg&fur=ip&sz=s0-l75-ft&attbid=ANGjdJ_LRORiJkHlvEneIerfWPtcDr2YcBzjmcCqvhp49G6p0QW3BNNHUm_Q3EKHhMM6HfXTN04w5uKaqm9OOd3TuSjl8gKmacLruEhDV4BYgIOv2IlF898XK5Zarow&disp=emb&realattid=ii_lyjepr4m9)  
</div><div id="bkmrk--7"></div><div id="bkmrk-8.-preview-the-view-">8. Preview the view again, and the listener captures the access log against. </div><div id="bkmrk--8">![image.png](https://mail.google.com/mail/u/0?ui=2&ik=9f3f00b7b1&attid=0.7&permmsgid=msg-a:r-548848260374548569&th=190a9942c5096036&view=fimg&fur=ip&sz=s0-l75-ft&attbid=ANGjdJ-zLyTBNgaJVhjEoWKEdu6Jn5zKLLOspSDQEqrlbdrptz39ZTbSfX9tsXDf8mtcVa_qchSv_8HFDtFG0njxCCaGvIf3WeSwKKMa991VbozpUQzLHzAXBLP-M8E&disp=emb&realattid=ii_lyjeqesn10)  
</div><div id="bkmrk-interestingly%2C-since">Interestingly, since it is a non-http port, the preview keeps loading.</div><div id="bkmrk--9">![image.png](https://mail.google.com/mail/u/0?ui=2&ik=9f3f00b7b1&attid=0.8&permmsgid=msg-a:r-548848260374548569&th=190a9942c5096036&view=fimg&fur=ip&sz=s0-l75-ft&attbid=ANGjdJ93Dg-qNDUP0MlrcsJO6VrJS2PJZc3c8UoIO039XktDBWf-Q48NgJFLPJXw2njjW6y4vzrygzazWwZWYbQJvvSdCsXLVoqjiNMxdN9YqKeEiwJcc3RzeWkuISw&disp=emb&realattid=ii_lyjerne411)</div><div id="bkmrk-the-difference-in-re">The difference in response time can indicate whether a port is open, and whether the port is a http/https port. In this way, attackers can weaponize this vulnerability to scan internal network's hosts and ports.   
</div><div id="bkmrk--10">  
</div>