Thursday, August 25, 2016

Bash Parent/Child Pipe Inheritance Exploit

rdlnk=$(readlink /proc/$$/fd/0)
function get_input() {
 if grep -Eq "^pipe:|deleted" <<< "${rdlnk}" || [[ -p "${rdlnk}" ]]; then 
  while IFS= read -r piped_input || break; do 
  [[ -z "${ipaddr}" ]] && ipaddr="${piped_input}" && continue
  [[ -z "${user}" ]]   && user="${piped_input}"   && continue
  [[ -z "${passwd}" ]] && passwd="${piped_input}" && continue  
 echo "Got that IP address you gave me to work on: ${ipaddr}" 
 [[ -n "${user}" ]] && echo "[... and that user: ${user}]" 
 [[ -n "${user}" ]] && echo "[... and that users password: ${passwd}]" 
exit 0
Normally it's fine:
$> process_ip.bsh
Got that IP address you gave me to work on:

But, put the parent into a piped loop and watch out:
$ echo -en "\nroot\ntoor\n" | while read a; do echo "Parent loop, processing: ${a}"; grep -q '^[0-9]\{1,3\}.[0-9]\{1,3\}.[0-9]\{1,3\}.[0-9]\{1,3\}' <<< "${a}" && ./process_ip.bsh "$a"; done
Parent loop, processing:
Got that IP address you gave me to work on:
[... and that user: root]
[... and that users password: toor]

Ouch. The parent only wanted to provide the IP Address from its pipe to the child. Presuming that the parent must maintain an open pipe with sensitive data in it at the time of the fork to the child process. How can this be prevented? Unfortunately, inheriting a parents fd's is a POSIX standard that is not easily moved. The best way to handle this is to provide yet another pipe on fd0 from the parent, since the most recent will be the one dup'd. E.g. ./process_ip.bsh "$a" < /dev/null