We didn't participate at this CTF (dear Mozilla fellows: next time please arrange the date somewhere in the weekend! thx :P) but some of us had a look to the challenges. One of them which got my attention was "Sharkpedia". Now it's offline but basically it was a PHP page with one input parameter used to select amongst three functions: "a", "b" and "c". Different "shark" images were shown (those ugly pets which David Litchfield likes so much }:-)) when any of former choices were selected and also the input was printed.
After some quick tests, I realized that:
- any other chars different from [A-Za-z_] could be entered but were ignored when looking for functions a, b or c (no exhaustive test done so forgive me if it may not be 100% accurate). So all of these are valid to select function "a":
- p=a [ https://challenge16.mozillactf.org/?p=a ]
- p=a$([
- p=$([a
- ...
- if any of a, b or c function matched, then the whole string was used inside PHP probably to build the function call to the appropiate function. Due to insufficient input sanitizing, it was possible to escape the string construction. For instance, I could concatenate strings, xoring, etc:
- p=a'.'
- p=a'^'
- ...
Our goal is to execute arbitrary PHP code. How could we get that?
Let's try to call phpinfo() function. My first attempt was:
p=a'.phpinfo().'
Guess what? Not possible because we need to match the "a" (or "b" or "c") function. PHP page would try to compare with "aphpinfo" function, which doesn't exist.
Second attempt: building "phpinfo" string without using [A-Za-z_]. I used a simple xor construction:
p=a'.(%8F%97%8F%96%91%99%90^%FF%FF%FF%FF%FF%FF%FF)().'
It didn't work because function name obtained by xoring was not taken as string type. I couldn't figure out how to cast into string given the filter limitations :-/
Third attempt: we get a PHP error stating that %ff (its ascii char, not the % representation) function didn't exist if we entered:
p=a'.%FF().'
So I was very near. But still insufficient. Shit!
I decided to use PHP variables (which imply nice type-conversions :-)). I built a custom .php for making some tests and uploaded to my test web server. My tests showed that it was perfectly possible to execute code by injecting:
p=a'.$var=phpinfo.$var().'
Former sentence creates a variable containing the command to run and finally invokes the function given by that name. Simple...
Or not so simple... Remember we cannot use [A-Za-z_] chars (well, we could use "$a" for instance, but then we would need another "$a" for invoking the function; and that's two "a" letters: not permitted). Time to RTFM! PHP manual states that a variable name follows this regexp syntax:
'[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'
Mistery solved: we can use $\xde\xad or $\xca\xfe (e.g.) as variable names. For the sake of simplicity, I'll call my variable: $\xfe (in url-encoding format: $%fe).
Coming back to the real challenge and trying to applying what we had learned above we entered:
A nice phpinfo screen appears!!! Hurray!
Now in order to get a directory listing, let's run a simple PHP passthru("ls"):
Oh, there's a file called "very_secret_fil3_pls_read_content.txt". Let's run "cat very_secret_fil3_pls_read_content.txt" (and this is the final solution):
We got the flag:
GaoxMpTbGFFD
Funny challenge :)
No comments:
Post a Comment