Oscar Tesniere

OSCAR TESNIERE

Profile Picture

Email: oscar.tesniere@mail.mcgill.ca

Website: About Me

Another way to see the comp 206 homework

Motivations

Our assignment consisted of a very poorly written C code (voluntarily done as so of course), to deleguate basic calculator operations to bash with arithmetic substitution (syntax : $((operation))). The program then returns the result to the user. The program was structured as a client-server web app.

The key lesson from this assignment was that anyone could run a command by adding a simple command substitution (syntax : $(command)). We would expect the arithmetic substitution to throw an error but recall that command substitution returns the exit status of the command being run.

Combining it together, we are able to execute a command on the remote server and will usually get a 0 as return. But what if we push this vulnerability further and try to reverse the connection to the server to extract data?

Some useful commands

The intuition is to read from a file, generate a large int from the bytes and send the result over. Usually arithmetic expansion will throw an error beyond the 64 bits limit, or wrap around and start from the negatives.

So we’re limited to a maximum of 8 bytes per request, and each UTF-8 character is encoded in 8 byte so 8 characters maximum.

dd command

dd command : converts and copy a file parameters : bs=BYTES : read and write up to BYTES bytes at a time.
if=FILE : read from file instead of stdin. count=N : how many bytes to read

xxd command converts binary data into a hex dump

1 byte can be represented by 2 HEX digits

The command

Take an offset of k bytes, and read the next 8 bytes

dd if=[server.cgi] bs=1 skip=k count=8 | od -An -t u8
# prints 8 bytes starting at k and converts the stream into a large integer

The reverse operation can be done with

printf "%08X" "$your_int" | xxd -r -p 
# chunks of 8 bytes

Try for yourself ! Create a file called calc.cgi with the following code :

#!/bin/bash

function urldecode() {
       	: "${*//+/ }"
	echo -e "${_//%/\\x}"
}

decoded="$(urldecode "$(cut -d= -f2- <<< "$QUERY_STRING")")"
result="$(eval "echo \$(($decoded))" 2>&1)"
printf "content-type: text/plain\r\n"
printf "content-length: \$\{#result\}\\r\\n"
printf "\r\n"
printf "$result"

To avoid having to serve an html form, simply set the following environment variables to set the input to the CGI script :

export QUERY_STRING="expr=[YOUR EXPRESSION]"
export REQUEST_METHOD="GET"