这篇文章主要以审计代码为主来分析每道题目中所存在的漏洞点:
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会自动将后面的截掉
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'] = '[email protected]'; } else { $data['to'] = $this->sanitize($data['to']); } if (!isset($data['from'])) { $data['from'] = '[email protected]'; } 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就会进行松散的检查。