下载工具NDM与cvefixes数据集的获取建议


起因是今天完善竞赛作品想整多语言的漏洞数据集,恰好找到了这个:cvefixes
感觉应该还可以,打算先试试手,但是11个G,下的也太慢了。
然后就想起来之前我看见过NDM这个下载软件,当时记得性能不错,今天一用,果真快了不少。

(一)NDM

1. 下载连接

NDM下载链接

2. 配置

因为我是下外面的东西,所以得科学上网,正好NDM有给配置代理的地方。
Settings --> Proxy/Socks 中设置一下就好,clash的端口号自己去clash看一下
配置代理

3. 资源嗅探

在Edge的扩展中下载NeatDownloadManager Extension,可以实现网站的资源嗅探,直接下载对应的视频等。
比较可惜的是对于m3u8格式的视频是无法成功提取的,只支持mp4,不过也很好了~

(二)cvefixes

之前尝试去获取这个数据集,在Windows系统下按照Readme文件操作,一直没成功。后面自己因为其他原因装了WSL,就又在这个Linux环境下试了一下,成功了。

1. 提取db文件

开始之前确保自己配置了linux环境,我这里直接以WSL作为示例了

(1)标准做法

运行:

(cvefixesEnv) G:\VulnerabilityDataset\CVEfixes\CVEfixes>wsl sh Code/create_CVEfixes_from_dump.sh

可能提示

Code/create_CVEfixes_from_dump.sh: 7: gzcat: not found
Code/create_CVEfixes_from_dump.sh: 7: sqlite3: not found

那就得下载对应的工具,执行:

sudo apt update
sudo apt install gzip sqlite3

再次运行.sh脚本即可

(2)我的做法

由于我安装了这些工具还是执行失败,问题出在gzcat命令的运行上而不是提取上,因此我选择:
create_CVEfixes_from_dump.sh 的内容替换如下:

DATA_PATH=Data/
sqlite3 $DATA_PATH/CVEfixes.db < $DATA_PATH/CVEfixes.sql

直接用Bandzip解压CVEfixes.sql.gz,解压出来的CVEfixes.sql存放在Data目录下。
再次运行.sh脚本,直接开始漫长的db文件提取

简而言之,数据集前期的工作就是从CVEfixes.sql.gz变为CVEfixes.sql,最终成为CVEfixes.db

2. 设置配置文件

在项目根目录(即本 INSTALL.md 文件所在位置)创建一个 .CVEfixes.ini 配置文件(仓库包含一个文件 example.CVEfixes.ini,复制改名即可)。
在 [CVEfixes] 部分定义以下变量以自定义路径:

  • database_path:应包含 CVEfixes 数据库文件(以及提取过程中的一些临时文件)的目录。
  • sample_limit: 要提取的样本数量,sample_limit = 0 被解释为无限数量的样本

3. 设置 GitHub 令牌

这一步是因为CVEFixes数据集在db文件中存的是Github提交url,可以下载DB Browser for Sqlite来看具体的数据库表结构~
因此,获取一个 GitHub 令牌并配置到 .CVEfixes.ini 配置文件,其中包含两个变量 user 和 token,分别填写你的 GitHub 用户名和访问令牌。
如何获取令牌就自行百度吧,很简单~

4. 提取源代码

以下是我整的一个脚本,记得替换输出目录。

import sqlite3
import pandas as pd
from pathlib import Path
import os

# --- 步骤 1: 定义路径 ---
BASE_PATH = Path(__file__).parent
DB_PATH = BASE_PATH / "Data" / "CVEfixes.db"

# 定义输出目录 - 按用户要求修改路径
VULNERABLE_DIR = Path("G:/VulnerabilityDataset/CVEfixes/vulnerability_dataset/vulnerable")
NON_VULNERABLE_DIR = Path("G:/VulnerabilityDataset/CVEfixes/vulnerability_dataset/non_vulnerable")

# --- 步骤 2: 创建输出目录 ---
print("正在创建源代码数据集输出目录...")
VULNERABLE_DIR.mkdir(parents=True, exist_ok=True)
NON_VULNERABLE_DIR.mkdir(parents=True, exist_ok=True)
print(f"修复版本将保存到: {VULNERABLE_DIR}")
print(f"未修复版本将保存到: {NON_VULNERABLE_DIR}")

# --- 步骤 3: 连接数据库并查询数据 ---
try:
    conn = sqlite3.connect(DB_PATH)
    print(f"\n成功连接到数据库: {DB_PATH}")
except sqlite3.Error as e:
    print(f"数据库连接失败: {e}")
    exit()

# 编写 SQL 查询语句 - 修复查询逻辑,获取文件级别的代码和CWE信息
query = """
SELECT DISTINCT 
    f.file_change_id,
    f.filename,
    f.code_before,
    f.code_after,
    f.programming_language,
    cc.cwe_id,
    cv.cve_id
FROM file_change f
JOIN commits c ON f.hash = c.hash
JOIN fixes fx ON c.hash = fx.hash
JOIN cve cv ON fx.cve_id = cv.cve_id
JOIN cwe_classification cc ON cv.cve_id = cc.cve_id
WHERE f.programming_language IN ('C', 'C++', 'C/C++') 
    AND f.code_before IS NOT NULL 
    AND f.code_after IS NOT NULL
    AND f.code_before != ''
    AND f.code_after != ''
ORDER BY f.file_change_id
"""

print("正在从数据库查询源代码数据...")
df = pd.read_sql_query(query, conn)
conn.close()
print(f"查询完毕!共找到 {len(df)} 条源代码变更记录。")

# --- 步骤 4: 遍历数据并保存文件 ---
if df.empty:
    print("未查询到任何源代码数据,请检查数据库。")
else:
    print("\n开始处理并保存文件...")
    total_files = len(df)
    processed_count = 0
    
    for index, row in df.iterrows():
        try:
            # 获取原始文件的后缀名
            original_filename = row['filename']
            extension = Path(original_filename).suffix
            if not extension:
                # 根据编程语言设置默认后缀
                if row['programming_language'] == 'C':
                    extension = ".c"
                elif row['programming_language'] in ['C++', 'C/C++']:
                    extension = ".cpp"
                else:
                    extension = ".txt"

            # 构造新的文件名:CWE-ID_CVE-ID_文件变更ID.后缀
            cwe_id_sanitized = str(row['cwe_id']).replace(':', '_').replace('/', '_')
            cve_id_sanitized = str(row['cve_id']).replace('-', '_')
            file_change_id = str(row['file_change_id'])
            
            new_filename = f"{cwe_id_sanitized}_{cve_id_sanitized}_{file_change_id}{extension}"

            # 获取修复前和修复后的代码
            code_before = row['code_before']
            code_after = row['code_after']

            # 保存未修复版本 (vulnerable) - 修复前的代码
            if code_before and isinstance(code_before, str) and code_before.strip():
                vulnerable_path = NON_VULNERABLE_DIR / new_filename
                with open(vulnerable_path, 'w', encoding='utf-8') as f:
                    f.write(code_before)

            # 保存已修复版本 (non_vulnerable) - 修复后的代码
            if code_after and isinstance(code_after, str) and code_after.strip():
                fixed_path = VULNERABLE_DIR / new_filename
                with open(fixed_path, 'w', encoding='utf-8') as f:
                    f.write(code_after)
            
            processed_count += 1
            if processed_count % 100 == 0:
                print(f"  已处理 {processed_count}/{total_files} 个文件...")

        except Exception as e:
            print(f"处理第 {index + 1} 行时出错: {e} - 文件名: {row.get('filename', 'N/A')}")
            continue

    print(f"\n所有文件处理完毕!成功处理了 {processed_count} 个文件。")
    print(f"修复版本保存在: {VULNERABLE_DIR}")
    print(f"未修复版本保存在: {NON_VULNERABLE_DIR}")

文章作者: Fetyloi
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Fetyloi !
  目录