PHP SECURITY CALENDAR 2017 学习总结-更新中
这篇文章主要以审计代码为主来分析每道题目中所存在的漏洞点,记录一下自己的学习:
1.Day 1 - Wish List
class Challenge {
const UPLOAD_DIRECTORY = './solutions/';
private $file;
private $whitelist; public function __construct($file) {
$this->file = $file;
$this->whitelist = range(1, 24);
} public function __destruct() {
if (in_array($this->file['name'], $this->whitelist)) {
move_uploaded_file(
$this->file['tmp'],
self::UPLOAD_DIRECTORY . $this->file['name']
);
}
}
} $challenge = new Challenge($_FILES['solution']);
这道题主要是php的弱类型绕过导致的文件上传漏洞,inarray在比较的时候,比如“5aaaa”==“5”的,因为php会自动将后面的截掉
这部分有道练习题,漏洞点在:
select * from user where id=$id;
即在$id处可以进行报错注入,updatexml()型注入,或者使用extractvalue()型注入。
updatexml函数是从特殊字符、字母后面开始截取的,我们就需要在我们想要的数据前面拼接上特殊字符。
extractvalue() :对XML文档进行查询的函数
语法:extractvalue(目标xml文档,xml路径) updatexml()函数与extractvalue()类似,是更新xml文档的函数。
语法updatexml(目标xml文档,xml路径,更新的内容)
我们要使它报错的点在xml路径处,默认/xxx/xx是正确的路径,常见payload如下:
select username from security.user where id= and (extractvalue(‘anything’,concat(‘~’,(select database()))))
select username from security.user where id=1 and (updatexml(‘anything’,concat(‘~’,(select database())),’anything’))
其中concat为连接字符串的函数,页面会为我们返回错误,其中错误的信息中就包含了我们想要查询的敏感数据。
如果concat用不了,可以考虑其他的字符串连接函数,比如make_set()函数,常见payload如下:
select updatexml(,make_set(,'~',(select user())),); //3对应011,那么就会将第一位与第二位拼接
我们还可以找到类似的函数:lpad()、reverse()、repeat()、export_set()(lpad()、reverse()、repeat()这三个函数使用的前提是所查询的值中,必须至少含有一个特殊字符,否则会漏掉一些数据)。
有一点需要注意,extractvalue()能查询字符串的最大长度为32,就是说如果我们想要的结果超过32,就需要用substring()函数截取,一次查看32位
这里查询前5位示意:
select username from security.user where id= and (extractvalue(‘anything’,concat(‘#’,substring(hex((select database())),,))))
https://www.jb51.net/article/87120.htm 这个连接是mysql的字符串函数参考
2.Day 2 - Twig
// composer require "twig/twig"
require 'vendor/autoload.php'; class Template {
private $twig; public function __construct() {
$indexTemplate = '<img ' .
'src="https://loremflickr.com/320/240">' .
'<a href="{{link|escape}}">Next slide »</a>'; // Default twig setup, simulate loading
// index.html file from disk
$loader = new Twig\Loader\ArrayLoader([
'index.html' => $indexTemplate
]);
$this->twig = new Twig\Environment($loader);
} public function getNexSlideUrl() {
$nextSlide = $_GET['nextSlide'];
return filter_var($nextSlide, FILTER_VALIDATE_URL);
} public function render() {
echo $this->twig->render(
'index.html',
['link' => $this->getNexSlideUrl()]
);
}
} (new Template())->render();
twig是php的模板语言,就像jinjia2是flask的模板语言,都是起到了渲染的作用,在这段代码中用户可以控制的是$nextSlide变量,然后经过filter_var函数进行一个过滤,验证其是不是正确的url,然后再将过滤后的url经过escape过滤后让{{}}来渲染,那么肯定要了解这两个过滤函数是不是能够绕过?看起来它的确只是验证是否是以://分割的字符串
接下来看twig的escape函数:
twig的中文官方文档上说:
Internally, ``escape`` uses the PHP native `htmlspecialchars`_ function for the HTML escaping strategy.
escape的过滤策略和htmlspecialchars的过滤规则一样,就是和htmlspecialchars($link, ENT_QUOTES, 'UTF-8')一样,设置了ENT_QUOTES以后,就会将单引号和双引号进行编码。
所以首先利用javascript://comment来绕过filter的过滤,然后因为//是javascript的注释符号,所以真正的payload可以放在下一行,也就是可以使用%0a或者%250a来构造一个\n换行符,
所以完整的payload可以为:
javascript://comment%0aalert(1),就会触发xss漏洞。
PHP7.0.25 绕过filter_var可以使用0://
file_get_contents()结合data协议进行xss
相关链接 https://www.anquanke.com/post/id/101058
day3-snow flake
function __autoload($className) {
include $className;
} $controllerName = $_GET['c'];
$data = $_GET['d']; if (class_exists($controllerName)) {
$controller = new $controllerName($data);
$controller->render();
} else {
echo 'There is no page with this name';
} class HomeController {
private $data; public function __construct($data) {
$this->data = $data;
} public function render() {
if ($this->data['new']) {
echo 'controller rendering new response';
} else {
echo 'controller rendering old response';
}
}
}
漏洞点在class_exist()函数判断类存不存在的时候会自动调用__autoload函数,如果__autoload函数有读写文件或可以包含文件,那么就有可能产生危险,在php小于5.4中
都有效,php的目前版本是7.3.2。
这道题又让我想到了file_exist()函数检查文件存在时会进行反序列化,还是不能够完全信任用户的数据,需要对数据进行消毒。
Day 4 - False Beard
class Login {
public function __construct($user, $pass) {
$this->loginViaXml($user, $pass);
} public function loginViaXml($user, $pass) {
if (
(!strpos($user, '<') || !strpos($user, '>')) &&
(!strpos($pass, '<') || !strpos($pass, '>'))
) {
$format = '<xml><user="%s"/><pass="%s"/></xml>';
$xml = sprintf($format, $user, $pass);
$xmlElement = new SimpleXMLElement($xml);
// Perform the actual login.
$this->login($xmlElement);
}
}
} new Login($_POST['username'], $_POST['password']);
这道题主要是strpos的trick,0==false,那么出现在字符串第一位也会返回为0,那么就能绕过。
Day 5 - Postcard
class Mailer {
private function sanitize($email) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
return '';
} return escapeshellarg($email);
} public function send($data) {
if (!isset($data['to'])) {
$data['to'] = 'none@vsplate.com';
} else {
$data['to'] = $this->sanitize($data['to']);
} if (!isset($data['from'])) {
$data['from'] = 'none@vsplate.com';
} else {
$data['from'] = $this->sanitize($data['from']);
} if (!isset($data['subject'])) {
$data['subject'] = 'No Subject';
} if (!isset($data['message'])) {
$data['message'] = '';
} mail($data['to'], $data['subject'], $data['message'],
'', "-f" . $data['from']);
}
} $mailer = new Mailer();
$mailer->send($_POST)
在这个题目中主要学会了escapeshellcmd和escapeshellarg同时使用时会出发漏洞
escapeshellcmd
escapeshellcmd() 对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义。 此函数保证用户输入的数据在传送到 exec() 或 system() 函数,或者 执行操作符 之前进行转义。 反斜线(\)会在以下字符之前插入: &#;`|*?~<>^()[]{}$\, \x0A 和 \xFF。 ' 和 " 仅在不配对儿的时候被转义。 在 Windows 平台上,所有这些字符以及 % 和 ! 字符都会被空格代替。
escapeshellarg
escapeshellarg() 将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,并且还是确保安全的。对于用户输入的部分参数就应该使用这个函数。shell 函数包含 exec(), system() 执行运算符 。
从上面的两次过滤中可以看到可以成功执行curl,对应的题目漏洞的CVE是https://github.com/opsxcq/exploit-CVE-2016-10033,主要利用了mail函数没有对第五个参数进行严格检查,导致可以附加恶意参数,并且要求php没有安装PCRE,没有开始safe_mode,这样对mail的address就会进行松散的检查。
Day 6 - Frost Pattern
class TokenStorage {
public function performAction($action, $data) {
switch ($action) {
case 'create':
$this->createToken($data);
break;
case 'delete':
$this->clearToken($data);
break;
default:
throw new Exception('Unknown action');
}
} public function createToken($seed) {
$token = md5($seed);
file_put_contents('/tmp/tokens/' . $token, '...data');
} public function clearToken($token) {
$file = preg_replace("/[^a-z.-_]/", "", $token);
unlink('/tmp/tokens/' . $file);
}
} $storage = new TokenStorage();
$storage->performAction($_GET['action'], $_GET['data']);
这道题主要考察对preg_replace函数的正则匹配规则熟悉不熟悉,这里存在unlink函数,其中$file变量是经过正则匹配替换以后的,即$token变量,这段正则匹配的是除a-z和.-_之间的所有字符,那么表达的是一个区间,而我们想防止目录遍历的话这里
需要过滤.(点号),即需要对-进行转义。
Day 7 - Bells
function getUser($id) {
global $config, $db;
if (!is_resource($db)) {
$db = new MySQLi(
$config['dbhost'],
$config['dbuser'],
$config['dbpass'],
$config['dbname']
);
}
$sql = "SELECT username FROM users WHERE id = ?";
$stmt = $db->prepare($sql);
$stmt->bind_param('i', $id);
$stmt->bind_result($name);
$stmt->execute();
$stmt->fetch();
return $name;
} $var = parse_url($_SERVER['HTTP_REFERER']);
parse_str($var['query']);
$currentUser = getUser($id);
echo '<h1>'.htmlspecialchars($currentUser).'</h1>';
parse_str 功能 :parse_str的作用就是解析字符串并且注册成变量,它在注册变量之前不会验证当前变量是否存在,所以会直接覆盖掉当前作用域中原有的变量。 定义 :void parse_str( string $encoded_string [, array &$result ] ) 如果 encoded_string 是 URL 传入的查询字符串(query string),则将它解析为变量并设置到当前作用域(如果提供了 result 则会设置到该数组里 )。
因为parse_str不会检查要注册的变量是否已经存在,所以会直接对变量进行覆盖,这里可以覆盖config变量从而连接任何我们想要连接的数据库及数据表。
Day 8 - Candle
header("Content-Type: text/plain"); function complexStrtolower($regex, $value) {
return preg_replace(
'/(' . $regex . ')/ei',
'strtolower("\\1")',
$value
);
} foreach ($_GET as $regex => $value) {
echo complexStrtolower($regex, $value) . "\n";
}
这段代码里面我们可以提供正则表达式,和需要进行匹配的字符串,其中需要知道正则中的自匹配,\1就是匹配到的结果,preg_replace中的/e模式会将匹配到的字符串当作命令执行函数的参数进行执行,所以${phpinfo()}可以由正则匹配到,从而进行执行,
\e是在替换完字符串以后再用eval函数检测替换后的字符串。
php中在用${}包裹变量时,其中会把花括号中的字符串首先当作变量名进行解析,在解析的过程中如果该括号包含的是函数,则会首先对函数进行执行,如果是变量则会首先取变量的值,然后结合外面的${}生成新的变量,以值作为键名,也就是php里面的
动态变量。
class LanguageManager
{
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(array('../','./'),"",$str),那么.....///就能绕过
PHP SECURITY CALENDAR 2017 学习总结-更新中的更多相关文章
- C++11 学习 间隔更新中
1.*this 返回执行它的的对象的引用,this返回的是地址,这涉及C++对象模式有可能是对象的首地址,有可能是首地址加上虚表的长度, 一般是*this ,有不同意见的可以提出来讨论 2.初始化列表 ...
- JVM调优学习 【更新中】
JVM调优(jdk1.8) 老生常谈,面试吹牛的的最佳谈资,在接下来的几天里,我找了点资料来对其进行一波学习: 本地环境是不需要对我们的虚拟机进行优化的,一般在生产环境下,也就是Linux下才有对JV ...
- ROS学习(更新中~)
1.一次把ROS环境变量都自动配置好(即添加到bash会话中)echo "source /opt/ros/indigo/setup.bash" >> ~/.bashrc ...
- Python3学习笔记-更新中
1.Python概况 2.Anaconda安装及使用 3.Pycharm安装及使用 4.Hello World!!! 5.数据类型及类型转换 6.分支结构 7.循环语句 8.异常
- Linux 系统化学习系列文章总目录(持续更新中)
本页内容都是本人系统化学习Linux 时整理出来的.这些文章中,绝大多数命令类内容都是翻译.整理man或info文档总结出来的,所以相对都比较完整. 本人的写作方式.风格也可能会让朋友一看就恶心到直接 ...
- java 学习必备的软件,持续更新中
小编会持续更新在学习Java过程中需要的软件以及各种文件: 话不多说,看行动! 一:JDK (1)JDK1.8(*64): 链接:https://pan.baidu.com/s/1vM0jNXn2CT ...
- Kotlin教程——史上最全面、最详细的学习教程,持续更新中....
关于这个系列教程,我是从最基础的开发环境搭建到项目进阶到后面的项目开发这个过程来写的.我一直秉承从实际项目开发以及源码解析的角度去写好这个教程,并让从未接触过编程的朋友能学好kotlin这门语言.所以 ...
- 痞子衡嵌入式:史上最强i.MX RT学习资源汇总(持续更新中...)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MX RT学习资源. 类别 资源 简介 官方汇总 i.MXRT产品主页 恩智浦官方i.MXRT产品主页,最权威的资料都在这里,参考手 ...
- PHP中非常好玩的Calendar扩展学习
为什么说这个 Calendar 扩展很好玩呢?因为你基本用不到它!这个扩展是一套关于日期历法的扩展,但是对于我们来说,它没有农历的相关操作,所以对于我们中国人来说这个扩展并没有什么实际的作用.不过这并 ...
随机推荐
- MVC 路由调试工具-RouteDebugger
MVC 路由调试工具-RouteDebugger 方案一: 在程序包控制台中执行命令 PM> Install-Package routedebugger 自动会在你的项目webconfig中& ...
- 数组中 reduce累计运算
let arr = [1,2,3,4]; let sum = (a, b) => a + b; arr.reduce(sum, 0); 最后输出10
- 灯塔AOI简易实现
首先我们来讨论下游戏开发中的几个坐标系,为了方便解释,我截取了灯塔AOI DEMO当NPC数目为0时候的样子(代码地址觉得有帮助的童鞋记得给我代码点个星^_^) 先对这张图简单说明下: 蓝色的坐标轴表 ...
- python字符串常用方法、分割字符串等
一.字符串的常用方法 1.str.capitalize() 字符串首字母大写 2.str.center() 把字符串居中 3.str.isalnum() 判断字符串是否含有英文.数字,若有英文和数 ...
- 【bzoj4869】[Shoi2017]相逢是问候 线段树+扩展欧拉定理
Description Informatikverbindetdichundmich. 信息将你我连结.B君希望以维护一个长度为n的数组,这个数组的下标为从1到n的正整数.一共有m个操作,可以 分为两 ...
- loj #2508. 「AHOI / HNOI2018」游戏
#2508. 「AHOI / HNOI2018」游戏 题目描述 一次小 G 和小 H 在玩寻宝游戏,有 nnn 个房间排成一列,编号为 1,2,…,n,相邻房间之间都有 111 道门.其中一部分门上有 ...
- 从HDU1004来看C++<map>
最近做题有点浮躁~于是从HDU第一题开始刷,刷到1004题的时候突发奇想来复习一发很久没有用到过的map 题意是给你n个气球,每个气球有一种颜色,让你求出数量最多的气球颜色 因为颜色是气球数量的识别关 ...
- 通用动态树(Link-Cut Tree)模板
一个没有维护任何东西的动态树模板 忘了怎么写可以直接来粘 int ch[300010][2], fa[300010], st[300010]; bool lazy[300010]; bool nroo ...
- composer 创建自己包
服务器环境下创建自己的项目文件 初始化composer 打开cmd 窗口,cd 到 backrestore 执行 composer init 命令 D:\phpStudy\WWW\backrestor ...
- 【算法笔记】B1047 编程团体赛
1047 编程团体赛 (20 分) 编程团体赛的规则为:每个参赛队由若干队员组成:所有队员独立比赛:参赛队的成绩为所有队员的成绩和:成绩最高的队获胜. 现给定所有队员的比赛成绩,请你编写程序找出冠军队 ...