Skip to content

Commit

Permalink
add urlencode_component & urldecode_component
Browse files Browse the repository at this point in the history
fix #145
  • Loading branch information
noraj committed Oct 17, 2023
1 parent dba7b52 commit 7d2b945
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 34 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ group :runtime, :cli do
end

group :runtime, :all do
gem 'cgi', '~> 0.3.3' # url decode / html escape
gem 'uri', '~> 0.12.2' # for argument parsing
end

Expand Down
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ GEM
specs:
ast (2.4.2)
base64 (0.1.1)
cgi (0.3.6)
commonmarker (0.23.10)
docopt (0.6.1)
json (2.6.3)
Expand Down Expand Up @@ -50,6 +51,7 @@ PLATFORMS

DEPENDENCIES
bundler (~> 2.1)
cgi (~> 0.3.3)
commonmarker (~> 0.23)
ctf-party!
docopt (~> 0.6)
Expand Down
10 changes: 6 additions & 4 deletions bin/ctf-party
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,12 @@ cmd_whitelist = {
to_hex: 'Encode a string into hexadecimal',
to_hexip: 'Encode a dotted decimal IPv4 into a hexadecimal one',
to_hexipv4: 'Encode a dotted decimal IPv4 into a hexadecimal one',
urldecode: 'URL-decode the string',
urldecode_component: 'URL-decode the URL component string',
urlencode: 'URL-encode the string',
urlencode_component: 'URL-encode the URL component string',
urldecode: 'URL-decode the string (RFC 2396)',
urldecode_component: 'URL-decode the URL component string (RFC 3986)',
urldecode_data: 'URL-decode the form data (application/x-www-form-urlencoded) string',
urlencode: 'URL-encode the string (RFC 2396)',
urlencode_component: 'URL-encode the URL component string (RFC 3986)',
urlencode_data: 'URL-encode form data (application/x-www-form-urlencoded) string',
# native string commands
bytesize: 'https://rubyapi.org/3.2/o/string#method-i-bytesize',
capitalize: 'https://rubyapi.org/3.2/o/string#method-i-capitalize',
Expand Down
3 changes: 3 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
- **Breaking changes**
- **Drop Ruby 2.7 support** because there is no `URI:WS` and `URI:WSS` used for `defang_uri` and anyway [official support has ended too](https://www.ruby-lang.org/en/downloads/branches/)
- `hex2bin` now returns even number of chars (pad with `0`) by default and add an option to disable it.
- `urlencode_component` & `urldecode_component` were renamed to `urlencode_data` & `urldecode_data`, `urlencode_component` & `urldecode_component` are now new functions
- Changes:
- Renamed `from_hexip` to `from_hexipv4` and created an aliases `from_hexip` for `from_hexipv4`. Same for `to_hexipv4` and bang methods.
- add options support for all decimal methods and aliases
- New methods:
- `from_hexipv6` and `from_hexipv6!`
- `bin2dec` and `dec2bin`
- `urlencode_component` (see **breaking change**, the old `urlencode_component` was renamed `urlencode_data`)
- `urldecode_component` (see **breaking change**, the old `urldecode_component` was renamed `urldecode_data`)
- Fix:
- bin2hex: fix odd byte cropping issue

Expand Down
68 changes: 48 additions & 20 deletions lib/ctf_party/cgi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
require 'uri'

class String
# URL-encode the URL string (RFC2396)
# URL-encode the URL string (RFC 2396)
# @return [String] the URL-encoded string
# @example
# 'http://vulnerable.site/search.aspx?txt="><script>alert(/Rubyfu/.source)</script>'.urlencode # => "http://vulnerable.site/search.aspx?txt=%22%3E%3Cscript%3Ealert(/Rubyfu/.source)%3C/script%3E"
# "'Stop!' said Fred" # => "'Stop!'%20said%20Fred"
# "'Stop!' said Fred".urlencode # => "'Stop!'%20said%20Fred"
def urlencode
URI::Parser.new.escape self
end
Expand All @@ -19,21 +19,21 @@ def urlencode!
replace(urlencode)
end

# URL-encode the URL component string
# @return [String] the URL-encoded string
# URL-encode form data (`application/x-www-form-urlencoded`) string
# @return [String] the URL-encoded data
# @example
# "'Stop!' said Fred".urlencode_component # => "%27Stop%21%27+said+Fred"
# 'http://vulnerable.site/search.aspx?txt="><script>alert(/Rubyfu/.source)</script>'.urlencode_component # => "http%3A%2F%2Fvulnerable.site%2Fsearch.aspx%3Ftxt%3D%22%3E%3Cscript%3Ealert%28%2FRubyfu%2F.source%29%3C%2Fscript%3E"
def urlencode_component
# "'Stop!' said Fred".urlencode_data # => "%27Stop%21%27+said+Fred"
# 'http://vulnerable.site/search.aspx?txt="><script>alert(/Rubyfu/.source)</script>'.urlencode_data # => "http%3A%2F%2Fvulnerable.site%2Fsearch.aspx%3Ftxt%3D%22%3E%3Cscript%3Ealert%28%2FRubyfu%2F.source%29%3C%2Fscript%3E"
def urlencode_data
CGI.escape self
end

# URL-encode the string in place as described for {String#urlencode_component}.
def urlencode_component!
replace(urlencode_component)
# URL-encode the data in place as described for {String#urlencode_data}.
def urlencode_data!
replace(urlencode_data)
end

# URL-decode the URL string (RFC2396)
# URL-decode the URL string (RFC 2396)
# @return [String] the URL-decoded string
# @example
# 'http://vulnerable.site/search.aspx?txt=%22%3E%3Cscript%3Ealert(/Rubyfu/.source)%3C/script%3E'.urldecode # => "http://vulnerable.site/search.aspx?txt=\"><script>alert(/Rubyfu/.source)</script>"
Expand All @@ -49,20 +49,20 @@ def urldecode!
replace(urldecode)
end

# URL-decode the URL component string
# URL-decode the form data (`application/x-www-form-urlencoded`) string
# @return [String] the URL-decoded string
# @example
# 'http://vulnerable.site/search.aspx?txt=%22%3E%3Cscript%3Ealert(/Rubyfu/.source)%3C/script%3E'.urldecode_component # => "http://vulnerable.site/search.aspx?txt=\"><script>alert(/Rubyfu/.source)</script>"
# 'http%3A%2F%2Fvulnerable.site%2Fsearch.aspx%3Ftxt%3D%22%3E%3Cscript%3Ealert%28%2FRubyfu%2F.source%29%3C%2Fscript%3E'.urldecode_component # => "http://vulnerable.site/search.aspx?txt=\"><script>alert(/Rubyfu/.source)</script>"
# "'Stop!'%20said%20Fred".urldecode_component => "'Stop!' said Fred"
# '%27Stop%21%27+said+Fred'.urldecode_component # => "'Stop!' said Fred"
def urldecode_component
# 'http://vulnerable.site/search.aspx?txt=%22%3E%3Cscript%3Ealert(/Rubyfu/.source)%3C/script%3E'.urldecode_data # => "http://vulnerable.site/search.aspx?txt=\"><script>alert(/Rubyfu/.source)</script>"
# 'http%3A%2F%2Fvulnerable.site%2Fsearch.aspx%3Ftxt%3D%22%3E%3Cscript%3Ealert%28%2FRubyfu%2F.source%29%3C%2Fscript%3E'.urldecode_data # => "http://vulnerable.site/search.aspx?txt=\"><script>alert(/Rubyfu/.source)</script>"
# "'Stop!'%20said%20Fred".urldecode_data => "'Stop!' said Fred"
# '%27Stop%21%27+said+Fred'.urldecode_data # => "'Stop!' said Fred"
def urldecode_data
CGI.unescape self
end

# URL-decode the string in place as described for {String#urldecode_component}.
def urldecode_component!
replace(urldecode_component)
# URL-decode the string in place as described for {String#urldecode_data}.
def urldecode_data!
replace(urldecode_data)
end

# HTML escape the string
Expand Down Expand Up @@ -90,4 +90,32 @@ def htmlunescape
def htmlunescape!
replace(htmlunescape)
end

# URL-encode the URL component string (RFC 3986)
# @return [String] URL-encoded component string
# @example
# 'http://vulnerable.site/search.aspx?txt="><script>alert(/Rubyfu/.source)</script>'.urlencode_component # => "http%3A%2F%2Fvulnerable.site%2Fsearch.aspx%3Ftxt%3D%22%3E%3Cscript%3Ealert%28%2FRubyfu%2F.source%29%3C%2Fscript%3E"
# "'Stop!' said Fred".urlencode_component # => "%27Stop%21%27%20said%20Fred"
def urlencode_component
CGI.escapeURIComponent self
end

# URL-encode the URL component string (RFC 3986) as described for {String#urlencode_component}.
def urlencode_component!
replace(urlencode_component)
end

# URL-decode the URL component string (RFC 3986)
# @return [String] URL-decoded component string
# @example
# 'http%3A%2F%2Fvulnerable.site%2Fsearch.aspx%3Ftxt%3D%22%3E%3Cscript%3Ealert%28%2FRubyfu%2F.source%29%3C%2Fscript%3E'.urldecode_component # => "http://vulnerable.site/search.aspx?txt=\"><script>alert(/Rubyfu/.source)</script>"
# '%27Stop%21%27%20said%20Fred'.urldecode_component # => "'Stop!' said Fred"
def urldecode_component
CGI.unescapeURIComponent self
end

# URL-decode the URL component string (RFC 3986) as described for {String#urldecode_component}.
def urldecode_component!
replace(urldecode_component)
end
end
42 changes: 32 additions & 10 deletions test/test_string_cgi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ def test_cgi_urlencode
# skip
end

def test_cgi_urlencode_component
def test_cgi_urlencode_data
my_url = 'http://vulnerable.site/search.aspx?txt="><script>alert(/Rubyfu/.source)</script>'
my_url_component = "'Stop!' said Fred"
assert_equal("http%3A%2F%2Fvulnerable.site%2Fsearch.aspx%3Ftxt%3D%22%3E%3Cscript%3Ealert%28%2FRubyfu%2F.source%29%3C%2Fscript%3E", my_url.urlencode_component)
assert_equal("%27Stop%21%27+said+Fred", my_url_component.urlencode_component)
assert_equal("http%3A%2F%2Fvulnerable.site%2Fsearch.aspx%3Ftxt%3D%22%3E%3Cscript%3Ealert%28%2FRubyfu%2F.source%29%3C%2Fscript%3E", my_url.urlencode_data)
assert_equal("%27Stop%21%27+said+Fred", my_url_component.urlencode_data)
end

skip def test_cgi_urlencode_component!
skip def test_cgi_urlencode_data!
# skip
end

Expand All @@ -42,18 +42,18 @@ def test_cgi_urldecode
# skip
end

def test_cgi_urldecode_component
def test_cgi_urldecode_data
my_url = 'http://vulnerable.site/search.aspx?txt=%22%3E%3Cscript%3Ealert(/Rubyfu/.source)%3C/script%3E'
my_url2 = 'http%3A%2F%2Fvulnerable.site%2Fsearch.aspx%3Ftxt%3D%22%3E%3Cscript%3Ealert%28%2FRubyfu%2F.source%29%3C%2Fscript%3E'
my_url_component = "'Stop!'%20said%20Fred"
my_url_component2 = '%27Stop%21%27+said+Fred'
assert_equal('http://vulnerable.site/search.aspx?txt="><script>alert(/Rubyfu/.source)</script>', my_url.urldecode_component)
assert_equal('http://vulnerable.site/search.aspx?txt="><script>alert(/Rubyfu/.source)</script>', my_url2.urldecode_component)
assert_equal("'Stop!' said Fred", my_url_component.urldecode_component)
assert_equal("'Stop!' said Fred", my_url_component2.urldecode_component)
assert_equal('http://vulnerable.site/search.aspx?txt="><script>alert(/Rubyfu/.source)</script>', my_url.urldecode_data)
assert_equal('http://vulnerable.site/search.aspx?txt="><script>alert(/Rubyfu/.source)</script>', my_url2.urldecode_data)
assert_equal("'Stop!' said Fred", my_url_component.urldecode_data)
assert_equal("'Stop!' said Fred", my_url_component2.urldecode_data)
end

skip def test_cgi_urldecode_component!
skip def test_cgi_urldecode_data!
# skip
end

Expand All @@ -74,4 +74,26 @@ def test_cgi_htmlunescape
skip def test_cgi_htmlunescape!
# skip
end

def test_cgi_urlencode_component
my_url = 'http://vulnerable.site/search.aspx?txt="><script>alert(/Rubyfu/.source)</script>'
my_data = "'Stop!' said Fred"
assert_equal('http%3A%2F%2Fvulnerable.site%2Fsearch.aspx%3Ftxt%3D%22%3E%3Cscript%3Ealert%28%2FRubyfu%2F.source%29%3C%2Fscript%3E', my_url.urlencode_component)
assert_equal('%27Stop%21%27%20said%20Fred', my_data.urlencode_component)
end

skip def test_cgi_urlencode_component!
# skip
end

def test_cgi_urldecode_component
my_url = 'http%3A%2F%2Fvulnerable.site%2Fsearch.aspx%3Ftxt%3D%22%3E%3Cscript%3Ealert%28%2FRubyfu%2F.source%29%3C%2Fscript%3E'
my_data = '%27Stop%21%27%20said%20Fred'
assert_equal('http://vulnerable.site/search.aspx?txt="><script>alert(/Rubyfu/.source)</script>', my_url.urldecode_component)
assert_equal("'Stop!' said Fred", my_data.urldecode_component)
end

skip def test_cgi_urldecode_component!
# skip
end
end

0 comments on commit 7d2b945

Please sign in to comment.