---
# System prepended metadata

title: Keynote - A New Era of SSRF - Exploiting URL Parser in Trending Programming Languages!

---

# Keynote - A New Era of SSRF - Exploiting URL Parser in Trending Programming Languages!

### [R0]Keynote - A New Era of SSRF - Exploiting URL Parser in Trending Programming Languages! ###  

[slide](https://www.blackhat.com/docs/us-17/thursday/us-17-Tsai-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages.pdf)
[Case Study - How I Chained 4 vulnerabilities on GitHub Enterprise, From SSRF Execution Chain to RCE!](http://blog.orange.tw/2017/07/how-i-chained-4-vulnerabilities-on.html)


SSRF網頁安全的攻擊手法
* 2008被提出
* 因XXE(Attack through XML)而繁榮

SSRF漏洞一再出現在臉書和google中
- 預覽功能
- 網址上傳圖片（內網網址->無視防火牆保護去抓圖）
    - http://orange/logo.gif (normal)
    - http://10.0.56.254/logo.gif (abnormal)

熟悉SSRF新的攻擊手法很重要，讓SSRF重返榮耀
SSRF漏洞：繞過防火牆碰觸到內網資源，企業內網越大，攻擊力越強
如何進一步利用SSRF？(很吃基本功：對**網路架構**的了解)
SSRF仍然常見，所以了解是必要的
SSRF可繞過防火牆去取得內網資源，內網資源越多，SSRF的觸碰面越多，被攻擊面也越多



從一些有趣的案例來介紹
* SSRF bypass 
* protocol smuggling
 


## What Is SSRF
Server Side Request Forgery
* 繞過防火牆，碰觸到內網資源
* 被戲稱為專打有錢人的漏洞, 因為有錢人的內網比較大(SSRF攻擊力道愈大)
* XSPA (Cross Site Port Attack, 概念似 side channel attack) attack:based on 時間差可知哪些port 有開，可作port scan -> 有開哪些services
    * http://10.0.56.254:80          -OK
    * http://10.0..56.254:81         -Timeout
    * http://10.0.56.254:82          -Timeout
* ![內網中的服務使用的不同的lib，可能會有不同的解讀](https://i.imgur.com/zhwF8q5.png)
例如：python 抓某網址之內容時，不同之內建http lib的解析會不同。

## SSRF Digging
- 常見參數？url,link, src, target, u, imageURL, host
- 從網址上傳？
- 資源 import/文章中網址？
- URL 預覽; 分享連結(since tittle or meta data needs server-side information)
- 有無存取 web server (Tool: Skull security)
- DNS 有無來存取 (Tool: Dnslogger)
- Special XML insert
    - schemaLocation
    - noNamespeaceSchemaLocation
    - Xlnclude
- XML External Entity (XXE): XML 中，定義變數
- 特殊 SSRF 的地方(下敘為弱點)
    - Oracle UTL_HTTP：?id=1 and 1=1
    - ImageTragick：SSRF.gif(.mvg)
    - FFMPEG：SSRF.m3u8(加字幕功能)
    - HTTPoxy：HTTP request header 會被取代成環境變數 incording to CGI spec
        - HTTP lib 將環境變數 http_proxy 當作 proxy 使用 e.g. CURL
    - SVG to SSRF：SVG Parser implement 抓取外部資源


## Protocol Smuggling in SSRF
* Make SSRF more powerful
* HTTP based protocol: Elastic, CouchDB, MongoDB, Docker（可被攻擊的內網服務）
* Text-based protocol: FTP, SMTP
* 在原有的協議中走私其他的協議
* SMTP 的 protocol 是 line by line 
    * 利用 CR-LF injection 將 payload 插到 HTTP protocol 中
* 現在的SMTP Server 會阻止HTTP connection
    * if SMTP connection 第一行有 HTTP pattern then close connection
    * GOPHER(a protocol (?))


### HTTPS 中偽造 SMTP(:25/)
HTTPS Protocol 所有訊息都會在SSL中被加密，那如何在HTTPS中偽造SMTP? ->思考有哪些東西在SSL/HTTPS中不會被加密？->SNI(Server Name Indication)(?)

#### 對攻擊目標之:25/送 HTTPS connection -> bypass

![](https://i.imgur.com/OgaleLo.png)

> 將攻擊payload 放在SSL SNI中
hello message 中 sni 的 extension 
如果我們能在 hostname 插一些奇怪的字元
在這個例子中黃色框框是一個空白
這個空白非常重要，因為能讓我們有機會塞一些奇怪的東西，但他還是能正常連上
這邊用到的 trick 在 linux 的 glibc 中 （//先記住，晚點說）

剛剛是用 16 進位的方式來看封包
現在用人類方式來看(?)
![](https://i.imgur.com/KlFqxjq.png)


## Make SSRF Great Again: 4 methods
URL Parsing Issues: URL parser and requester 對同一個網址有不同解釋
    * checking URL is defficult because WHATWG的RFC3986 只有定義規格無定義實作。以人魚為例，spec 是半人半魚，但不知道哪一半是人哪一半是魚啊！實作成品會出乎意料之外。
    ![URL Components (RFC3968)](https://i.imgur.com/5lJi8vc.png)
        - Scheme: SSRF 攻擊面
        - Authority: 是否可以SSRF攻擊
        - Path: SSRF 攻擊深度
### SSRF 利用
**Local**
- Ruby's open(parans[:url])
    - url: /etc/passwd
    - http:/../../etc/passwd: Because there is not http://, therefore, if there is an folder named http, the url will be seems file route note url.

**Remote**
- 可使用的協議
    - Gopher (萬用協議-可偽造任意TCP封包)
        - 限制：需要Handshake/加密/認證，則無法利用
    - Jar: 在目標伺服器製造可控的暫存檔案
        - DOS
        - LFY
    - FTP / SMB: pwd BruteForece
    - UNC Path
        - Pass the Hash
- 可擁有的服務
    - 攻擊內網常見的 HTTP/HTTPS service
        - Struts2: Java framework
        - ElasticSearch - Port 9200
        - Docker - Port 2375
        - Neo4j, CouchDB, MongoBD: 直接訪問API 可透過修改設定甚至導致ROC
        - HeartBleed
        - Tomcat Port 8005
        - Zabbix Port 10050
        - Radis Port 6379
            - SAVE write shell
            - .. SSH Key
            - .. Cribtab
            - SET modify value for 二次利用
        - SMTP Port 25
            - 內部主機寄信：test.smtp.org/
                - test/smtp.org/log 記錄攻擊是否成功
            - Memcached Port 11211
                - SET modify value for 二次利用
                - Memcached + Rails: Memcahed & Dalli lib 會經過 Marshal
            - FastCGI Port 9000

#### 演練
Q1:
https://blog.ephrain.net/wp-content/uploads/2015/08/1439478873-964214684.png

http://127.0.0.1/

file://../etc/passwd


![今天會涵蓋的漏洞列表](https://i.imgur.com/M7fdgMC.png)

這段 php code 只有 7 行
![A php code for read a file](https://i.imgur.com/GmupdP4.png)

programmers use parse_url(php內建的) method to check port & host are legal or not; However, RFC 只定義冒號(分隔 port&host) spec，但有的 parser 會從帽號前面來解釋，有的 parser 會從冒號後面來解釋
![Example1: Different parseres have different result](https://i.imgur.com/SujkMSw.png)

![Example2: Different parseres have different result](https://i.imgur.com/M0fptNm.png)
// PHP parse_url讀前面 PHP readfile讀後面


**How about CURL(?)**

Curl(A lib) 很大量的人用，用於抓取資源。內建 http lib很爛，故幾乎都改用 Curl，但給 Curl 更新之後，後續用一個空白一樣可以打穿這個弱點。
開發團隊回覆：無法過濾來源網址，請程式設計師自行檢查，只能用文件提醒大家… ((誰會看文件啊 XD

![Example3: Different parseres have different result](https://i.imgur.com/Ugjbf5q.png)

![Example4: Different parseres have different result](https://i.imgur.com/AQfkuDA.png)


##### Attack NodeJS by Unicode
![A Nodejs code](https://i.imgur.com/A2Oeviw.png)

- 使用者同名目錄當成加目錄，會檢查..以外的字（為了防止什麼攻擊？）-> 無法存取sandbox 以外的目錄：
- 假設現在有個密碼檔在根目錄下，如何繞過此限制存取到該檔案？-> 用 Unicode 全型字母 N。

**JavaScript 內部使用UCS2實作來處理全型字母**

- UCS2 處理全型字串->轉為十六進位->N = \xFF\x2E

(Differences between UCS-2 and UTF-16: https://mathiasbynens.be/notes/javascript-encoding)

![JavaScript UCS2 處理全型字母前之URL](https://i.imgur.com/wP1IZPM.png)
![JavaScript UCS2 處理全型字母後之URL1](https://i.imgur.com/IobWtQn.png)

Moreover, NodeJs(C++實作，以byte為單位) bufferString will discard the fist byte when encoding conversion.
![JavaScript UCS2 處理全型字母後之URL2](https://i.imgur.com/tGoQDLK.png)

. = \x2E

![JavaScript UCS2 處理全型字母後之URL3](https://i.imgur.com/ctxoqn6.png)


**若插換行呢？**
可以用剛剛這個 unicode 的特性 U+FF0D, U+FF0A 繞過這個保護(when BufferString, FF會被拿掉->變換行符號)

#### GLibc NSS 的特性
![GLibc sourcecode](https://i.imgur.com/y4WZAyA.png)

- RFC1035: DNS 支援十進位的轉換。

        or\097nge = orange

- 反斜線後面若非數字，會把反斜線直接拿掉->用一堆反斜線來混淆host name域名。(python@linux). For example, \o\r\a\n\g\e.\o\r\g

- Getaddressinfo(): 合法IP address+空白字元後面的東西給過濾掉![linux'll return 127.0.0.1](https://i.imgur.com/Cy7qyYN.png)

      \o\r\a\n\g\e.\o\r\g = orange.org

#### 攻擊URL parsing (\t encoding 問題)32:40

![](https://i.imgur.com/s23miFF.png)

![](https://i.imgur.com/LS0qDHF.png)

換行 & 可以用相同的 Host 塞奇怪的東西進來，以"換行"參雜其他協定。(繞過相同的Host，傳送至其他的Request)


**Attacks by Glibc NSS feature**
- HTTP 1.1 要求 a Host header; 網址 host name will put in request host header. 34:00
- .......(?)
![參雜radis protocol(?)](https://i.imgur.com/kfBmOGw.png)

SET foo 0 60 5\r\n:443/
![\t](https://i.imgur.com/gra14xi.png)

![\t URL encode](https://i.imgur.com/Om6rYdS.png)

![\t URL double encode](https://i.imgur.com/sbVARLt.png)

感謝 Redis 跟 memcached
用前面的空白去繞過亦可。 (用於多一個空白，可用於最新版本的python)


#### Attack IDNA

- IDNA => 定義Unicode的標準 //複雜的排版上是否為合法之類的標準
- IDNA standars 目前常用的標準有兩個 2003, 2008  過渡期：2003+UTS46->如果 URL 的 parser 跟 url requester 用不同標準就會有問題
![](https://i.imgur.com/o48d5nr.png)

- 拉丁字母 ß (德母的字母沒有相對應的大寫字母，就會轉成兩個大寫s) However, ss!=ß; 但如果用瀏覽器去開啟，會有可以繞過黑名單的洞。For example, WordPreß = WordPress -> 目前還沒修 XD

繞過 IIS 的方式：找出標準中的不一致，就可以達到繞過的方式。

### SSRF Bypass
- DNS Bypass
    - 方便的host name反解提供商
        - xip.io
    - DNS Rebinging
        - Round-Robin DNS: 使某DNS記錄可對應到哪個IP
        - TTL = 1
            - attack.com 第一次解析 1.2.3.4
            - attack.com 第二次解析 127.0.0.1
- 網址 Bypass
    - 127.0.0.1
        - localhost
        - 127.0.1
        - 127.1
        - 0.0.0.0
        - 0.0
        - 0
    - IP 表達形式
        - ping 127.2.3.4
        - ping 0x7f.0x0.0x0.0x1
        - ping 0177.01.01.01
        - ping 0x7f000001
        - .........
        - IPv6 可接 interface(IP....%1, %後接的是interface)
    - WordPress SSRF
        - 各種 localhost 的不同表達方式

- 雜項
    - 302 Rederection
    - Fingerprinting: intranet 有哪些services


**檢查要檢查什麼？**
Scheme
Host
Port


### Case study: 3個繞過的方法
1. Time-of-check to time-of-use(TOCTTOU) problem
![三者對SSRF的防禦方法](https://i.imgur.com/YNeEavM.png)
- URL parser: 檢查網址是否在白名單內
- DNS checker:確保IP不再黑名單內
- URL requstster:存取網址(此時會再產生一次DNS query)並抓回內容

BUT!!!!若檢查時狀態與使用時狀態不同！！
![TOCTTOU問題之精髓（？）41:00](https://i.imgur.com/E2c3lVr.png)

2. 對 IDNA 標準支援的差異
CURL 支援 Unicode 域名自動轉換但PHP之gethostbyname()不支援-> SSRF bypass

3. URL parser and URL requester 的解讀不一致-> bypass


即使 curl 7.54, PHP 後來修復了 SSRF 的問題，但是大多數專案(ex. Ubuntu 17.0.1?的 curl)沒有跟上
**空白的弱點**，curl 永遠不會修復XD

#### SSRF Execution Chain: 4個漏洞串成RCE (?)44:00

GitHub WebHuck 用了一個Ruby gem 作為黑名單保護，然而
可以用 0 輕鬆繞過。**在 linux 中 0 = localhost**->有一個SSRF

但，此SSRF有以下限制導致無法利用此漏洞做事情：
1. 只能用http/https 的 skeme&沒有302重導向跳轉(?)可以轉換成其他skeme(第一次第二次沒檢查header可能被插入location 轉去其他地方)
2. 無法控制POST header&其他內容
3. 前面介紹的CR LF injection(?)在這邊都無法做到
-> 無法做到 protocol smuggling

那，內網中的http服務中有什麼可以做利用咧？
localhost:8000 有個服務會抓GET()參數並訪問->第二個SSRF->用兩個 SSRF 結合成Chain，偽造 protocol


&url=127.0.0.1:6379/%0D%0ASET...
一個假造協定，一個假造目標（？）


為什麼Github 能存下 ruby object (？)
用marshal(?)的方式包起來

![完全不懂（？）](https://i.imgur.com/igtt4Qj.png)

#### Prevent(Mitigation)

1. Software(Application): 唯一IP(不用再問一次DNS Server) and hostname(一個IP可能會有多個網站)，不要reuse使用者提供的IP
2. Network: firewall/network policy 阻擋intranet traffics(不可以做192.168.../172.20...等內網的請求) Some library you can use like SafeCurl or Advocate