Consider the following Ruby script named open-uri.rb:
require ‘open-uri’
print open(ARGV[0]).read
|
The following command requests a web page:
# ruby open-uri.rb “https://ioactive.com”
|
And the following output is shown:
<!DOCTYPE HTML>
<!–[if lt IE 9]><html class=”ie”><![endif]–>
<!–[if !IE]><!–><html><!–<![endif]–><head>
<meta charset=”UTF-8″>
<title>IOActive is the global leader in cybersecurity, penetration testing, and computer services</title>
[…SNIP…]
|
Works as expected, right? Still, this command may be used to open a process that allows any command to be executed. If a similar Ruby script is used in a web application with weak input validation then you could just add a pipe and your favorite OS command in a remote request:
“|head /etc/passwd“
|
And the following output could be shown:
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin […SNIP…]
|
The difference between the two executions is just the pipe character at the beginning. The pipe character causes Ruby to stop using the function from open-uri, and use the native open() functionality that allows command execution[2].