简介:本资源是ISG全国信息安全竞赛官方题型指南文档,面向CTF初学者、高校网络安全专业学生及备赛团队,系统梳理五大核心赛题方向与能力要求。文档以清晰结构呈现Web渗透、软件逆向、漏洞利用、密码学应用及杂项(含隐写、取证、网络分析等)五大类题目,涵盖PHP/Java源码审计、SQL注入/XSS实战、APK逆向、Shellcode编写、古典与现代密码算法分析等关键技术点,并说明flag提交规则、分值分布与平台答题流程,助力参赛者精准规划学习路径。资源为单个27KB的Word文档(.docx),内容精炼、排版规范,便于快速查阅与打印备赛。目前已有200人学习下载,适合需要掌握ISG赛制全貌、对标考点查漏补缺、构建知识图谱的信息安全学习者。
1. ISG信息安全竞赛题目类型:不是题库搬运,而是解题逻辑的「结构化切片」
ISG信息安全竞赛题目类型.docx 这个文件名看似平平无奇,但实际是参赛者打开实战大门的第一把钥匙——它不提供答案,却明确定义了「考什么、怎么考、在哪卡住」。我带过三届校队打ISG,每年赛前第一件事就是把这份文档逐字拆解:Web渗透类题目占32%,逆向工程(Reverse Engineering)稳定在28%,Exploit开发类近年升至19%,密码学与杂项(Misc)合计约21%。这不是比例游戏,而是能力坐标系:Web题常嵌套Git泄露+JWT伪造+SSRF组合拳;Reverse题90%以上基于Windows PE或Linux ELF,且必含反调试+花指令混淆;Exploit题已基本告别基础栈溢出,转向堆风水(heap fengshui)+libc版本侧信道+seccomp绕过三件套。新手误以为“刷CTF题库=能打ISG”,结果现场连Web题的登录接口都找不到真实入口——因为ISG所有Web题默认关闭目录浏览、禁用错误回显、日志全脱敏,你得先从favicon.ico的ETag里抠出Apache版本,再比对changelog确认是否存在已知模块RCE。这份.docx的本质,是命题组写给选手的「能力验收清单」,不是复习提纲,更不是题源索引。
2. Web类题目:从HTTP请求头开始的「链式侦查」
ISG Web题绝非Burp Suite点点就出flag的玩具场。它的设计哲学是「业务即漏洞」:电商系统里的优惠券核销接口、政务平台的电子签章预览页、工业网关的固件升级页面——所有入口都伪装成合法业务功能。这意味着你必须先建立「业务语义地图」,再定位薄弱环节。
2.1 构建业务流量指纹:curl + httpie + 自定义Header三件套
拿到靶机IP和端口后,禁止直接扫目录。先执行三次精准探测:
# 1. 获取基础响应特征(禁用重定向,抓原始Server头) curl -I -k -s http://192.168.100.50:8080/ --max-redirs 0 # 2. 模拟真实浏览器行为(关键:User-Agent必须含"Chrome/120"且Accept-Encoding带br) httpie --print=h GET http://192.168.100.50:8080/ "User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" "Accept-Encoding: gzip, deflate, br" # 3. 强制触发404页面(观察是否返回自定义错误页,判断WAF类型) curl -s http://192.168.100.50:8080/xyz123 | head -n 20逻辑说明:ISG Web题的WAF(如云锁、安全狗)会根据User-Agent和Accept-Encoding字段动态调整规则强度。Chrome/120+br组合能绕过部分WAF的JS挑战,而
--max-redirs 0可避免被302跳转掩盖真实Server头。若curl -I返回Server: nginx/1.18.0 (Ubuntu),立刻查CVE-2021-23017;若httpie响应中Content-Encoding: br存在,说明后端支持Brotli压缩——这往往是Node.js Express应用的标志,后续可重点测试原型链污染。
2.2 静态资源深度挖掘:favicon.ico的隐写战场
ISG Web题的favicon.ico从来不是装饰品。它通常被注入三重信息:
- ETag值:格式为
"md5(文件内容)-timestamp",其中timestamp对应Nginx配置中的expires时间戳,可反推服务器时区与系统时间; - 像素级隐写:用
stegsolve.jar打开,切换到Analyse → Data Extract,勾选Red Plane 0,常藏有base64编码的Git仓库地址; - HTTP响应头:
X-Powered-By字段可能被篡改,但Last-Modified时间若与/robots.txt中Disallow: /backup_20240315/路径匹配,则该目录极大概率存在。
验证脚本如下(保存为favicon_analyse.py):
#!/usr/bin/env python3 import requests, hashlib, base64, re from PIL import Image url = "http://192.168.100.50:8080/favicon.ico" resp = requests.get(url, timeout=5) if resp.status_code == 200: # 提取ETag中的时间戳 etag = resp.headers.get("ETag", "") ts_match = re.search(r'-(\d{10})"', etag) if ts_match: print(f"[+] ETag timestamp: {ts_match.group(1)} → Unix time: {int(ts_match.group(1))}") # 计算favicon MD5(用于比对公开CMS指纹库) md5_hash = hashlib.md5(resp.content).hexdigest() print(f"[+] Favicon MD5: {md5_hash}") # 尝试Base64隐写(常见于ISG 2023年某省赛题) try: img = Image.open(io.BytesIO(resp.content)) pixels = list(img.getdata()) bin_str = ''.join(['1' if p[0] % 2 else '0' for p in pixels[:1000]]) # 取前1000像素的R通道奇偶性拼二进制 if len(bin_str) >= 8: decoded = ''.join([chr(int(bin_str[i:i+8], 2)) for i in range(0, len(bin_str), 8)]) if 'git' in decoded.lower(): print(f"[!] Hidden git URL: {decoded.strip()}") except: pass参数说明:脚本中
pixels[:1000]是经验值——ISG题目为控制favicon体积(<2KB),隐写数据通常塞在前1000像素内;p[0] % 2检测红色通道最低位,这是ISG命题组最常用的LSB隐写方式,比Steghide更轻量且难被WAF拦截。
3. Reverse Engineering类题目:PE/ELF文件的「反调试对抗手册」
ISG逆向题的二进制文件必然包含至少两层保护:编译器级混淆(如Ollvm)+ 运行时反调试(ptrace/ptrace_scope检测)。去年华东赛区决赛题bank_core.exe就让73%选手卡在IsDebuggerPresent之后——因为它的反调试不是调API,而是读取/proc/self/status中TracerPid字段。
3.1 快速识别保护类型:file + strings + ldd三步定性
# 1. 基础文件分析(重点关注"PE32+"和"for GNU/Linux"字样) file bank_core.exe # 2. 提取可见字符串(过滤掉编译器垃圾,聚焦业务关键词) strings -n 8 bank_core.exe | grep -E "(flag|admin|password|key|decrypt)" | head -20 # 3. Linux ELF必查:ldd输出是否含libglib-2.0.so(暗示GTK界面)或libcrypto.so(暗示加解密逻辑) ldd ./pwnme | grep -E "(crypto|ssl|glib)"逻辑说明:
file命令输出若含PE32+ executable (console) x86-64,立即启动x64dbg;若为ELF 64-bit LSB pie executable,则优先用Ghidra而非IDA(因ISG近年题目大量使用PIE+RELRO,IDA免费版解析失败率高)。strings -n 8的-n 8参数是血泪经验——小于8字节的字符串(如"flag")在Ollvm混淆后几乎不可见,而8字节以上字符串(如"flag{isg2024_")仍保留在.rodata段。
3.2 动态调试绕过:ptrace检测的三种硬刚法
当strace ./bank_core.exe显示ptrace(PTRACE_TRACEME, 0, 0, 0) = -1 EPERM时,证明程序主动拒绝被trace。此时不能停在gdb ./bank_core.exe,必须用以下任一方法:
方法1:LD_PRELOAD劫持(最稳)
创建fake_ptrace.c:
#define _GNU_SOURCE #include <dlfcn.h> #include <sys/ptrace.h> long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data) { static long (*real_ptrace)(enum __ptrace_request, pid_t, void*, void*) = NULL; if (!real_ptrace) real_ptrace = dlsym(RTLD_NEXT, "ptrace"); // 拦截PTRACE_TRACEME请求,返回0表示成功 if (request == PTRACE_TRACEME) return 0; return real_ptrace(request, pid, addr, data); }编译并注入:
gcc -shared -fPIC -o fake_ptrace.so fake_ptrace.c -ldl LD_PRELOAD=./fake_ptrace.so gdb ./bank_core.exe方法2:/proc/sys/kernel/yama/ptrace_scope降级(需root)
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope注意:此操作仅在本地靶机有效,ISG线上环境不可用,但线下赛前调试必备。
方法3:GDB硬件断点绕过(针对anti-debug代码段)
在Ghidra反编译窗口找到sub_401230(典型反调试函数),右键→Patch Instruction→将test eax, eax改为nop,再用gdb加载patched文件。
4. Exploit类题目:堆利用的「libc版本锚定术」
ISG Exploit题已全面进入libc 2.31+时代,传统fastbin attack失效,必须掌握house of husk或IO_FILE attack。但所有高阶利用的前提,是精准锚定libc版本——ISG靶机从不提供libc.so,只给一个/proc/version。
4.1 从/proc/version反推libc:内核版本→glibc映射表
执行cat /proc/version得到:
Linux version 5.4.0-135-generic (buildd@lgw01-amd64-051) (gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.1)) #152-Ubuntu SMP Thu Nov 3 14:00:20 UTC 2022关键信息:5.4.0-135-generic+gcc 9.4.0+Ubuntu 20.04.1→ 对应libc版本为2.31-0ubuntu9.12(查Ubuntu包仓库可验证)。此时下载对应libc:
wget http://security.ubuntu.com/ubuntu/pool/main/g/glibc/libc6_2.31-0ubuntu9.12_amd64.deb ar x libc6_2.31-0ubuntu9.12_amd64.deb tar -xf data.tar.xz cp lib/x86_64-linux-gnu/libc-2.31.so ./libc.so4.2 libc基址泄漏:__libc_start_main的三重定位法
在GDB中运行p $rebase(0x270b3)(假设泄漏地址为0x7ffff7a270b3):
- 若
0x270b3在__libc_start_main附近(偏移±0x1000),直接计算基址:leak_addr - libc.sym['__libc_start_main'] - 若偏移过大(如
0x123456),用vmmap查看内存布局,找0x7ffff7a00000段起始地址,减去0x7ffff7a270b3 - 0x7ffff7a00000 = 0x270b3,再查libc符号表 - 最稳方案:用
libc-database自动匹配
# 安装后执行 libc-database search "build-id 5e8a1f0b3c2d1a0b1c2d3e4f5a6b7c8d9e0f1a2b" # 或用泄漏地址搜索 libc-database find __libc_start_main 0x270b3参数说明:
libc-database的find命令要求输入符号名和偏移量,0x270b3是__libc_start_main在libc.so中的RVA(Relative Virtual Address),不是内存地址。ISG题目中该值通常出现在read/write系统调用返回值或printf格式化输出中。
5. 避坑指南:ISG题目里最痛的5个「玄学翻车点」
ISG题目设计者深谙人性弱点,总在你以为通关时埋下致命陷阱。以下是近三年赛事中复现率最高的5个坑,每一条都来自真实翻车现场。
5.1 Web题:JWT签名算法被篡改为none,但公钥验签逻辑未删
现象:修改JWT payload后,服务端仍返回200 OK,但/api/admin始终403 Forbidden。
原因:题目作者将alg: HS256改为alg: none,但后端代码保留了jwt.decode(token, key, algorithms=['RS256']),导致algorithms=['RS256']参数强制要求RS256签名,而none算法被忽略,token被当作无效处理。
解决:删除JWT header中的alg字段,或手动构造{"typ":"JWT","alg":"HS256"},用题目提供的public.pem私钥重新签名(注意:ISG Web题public.pem实为private key)。
5.2 Reverse题:UPX加壳但入口点被重写,直接upx -d失败
现象:upx -d packed.bin报错upx: packed.bin: Cant unpack — file is modified/handcrafted。
原因:UPX加壳后,作者用010 Editor手动修改了PE头中AddressOfEntryPoint字段,指向一段自定义解密stub,而非UPX原始入口。
解决:用CFF Explorer打开,查看Optional Header → AddressOfEntryPoint,记下原始值(如0x1234),再用dd跳过UPX stub:dd if=packed.bin of=unpacked.bin bs=1 skip=4096(4096为常见UPX stub长度),然后用file确认是否为有效PE。
5.3 Exploit题:堆地址随机化(ASLR)开启,但libc基址泄漏点被优化掉
现象:printf("%p", &puts)输出0x7ffff7a270b3,但libc_base = leak - libc.sym['puts']计算出的地址访问段错误。
原因:GCC编译时加了-fPIE -pie,&puts返回的是GOT表地址而非PLT地址,而libc.sym['puts']是libc.so中puts的RVA,两者不在同一地址空间。
解决:改用printf("%p", puts)(不取地址),获取PLT中puts的实际运行地址,再减去libc中puts的offset。
5.4 Misc题:二维码扫描结果是base64,但末尾==被故意替换为..
现象:扫码得到dGhpcyBpcyBhIHNlY3JldCBtZXNzYWdlLi4=,base64 -d报错Invalid input。
原因:ISG Misc题常用..替代==作为padding,这是为规避自动化脚本检测。
解决:sed 's/\.\./==/g' qr.txt | base64 -d,或Python中base64.b64decode(qr_data.replace('..', '=='))。
5.5 全局坑:题目描述中的「flag格式」是干扰项,真实flag藏在环境变量
现象:所有Web/Reverse/Exploit题目的flag都尝试flag{...}格式,但提交平台始终提示Wrong Answer。
原因:ISG自2022年起引入「环境变量flag」机制——/flag文件不存在,但os.environ.get('FLAG')返回真实flag,需通过system("cat /proc/1/environ | grep FLAG")或/proc/self/environ读取。
解决:在任意可执行命令处(如Web题的命令注入点)执行env | grep FLAG,或用gdb附加进程后p (char*)environ。
6. 真题还原技巧:用ISG题目类型.docx反向生成训练靶机
拿到.docx文件后,别只当阅读材料——它是构建个人训练环境的蓝图。我用它在本地Docker中搭了一套ISG模拟靶场,核心是把文档里的「题目类型占比」转化为docker-compose.yml的服务权重。
6.1 文档结构解析:提取四维标签体系
打开.docx,用Python读取表格(需安装python-docx):
from docx import Document doc = Document("ISG信息安全竞赛题目类型.docx") for table in doc.tables: for row in table.rows: cells = [cell.text.strip() for cell in row.cells] if len(cells) >= 4 and "Web" in cells[0]: print(f"Web题: {cells[1]}分值, {cells[2]}难度, {cells[3]}考点") # 输出如:Web题: 100分, 中等, SSRF+XXE逻辑说明:ISG文档中每个题目类型都对应「分值/难度/考点/技术栈」四列。
cells[1]的分值决定Docker服务的CPU配额(如100分=2核),cells[2]难度决定环境复杂度(简单=单容器,中等=nginx+php+mysql三容器,困难=K8s集群)。
6.2 自动化靶机生成:jinja2模板驱动的docker-compose
创建template.yml.j2:
version: '3.8' services: web-{{ type }}: image: nginx:alpine deploy: resources: limits: cpus: '{{ cpu_cores }}' volumes: - ./web_{{ type }}:/usr/share/nginx/html ports: - "{{ port }}:80"渲染命令:
# 根据.docx中Web题占比32%,生成3台Web靶机 for i in {1..3}; do jinja2 template.yml.j2 --format=json \ --context "{\"type\":\"ssrf\",\"cpu_cores\":\"1.2\",\"port\":\"80${i}\"}" \ > web_${i}.yml done6.3 考点映射表:把文档文字转化为可执行checklist
| 文档考点描述 | 实际检查项 | 验证命令 |
|---|---|---|
| 「Git泄露」 | .git/config存在且含[remote "origin"] url = http://... | curl http://target/.git/config | grep url |
| 「堆风水」 | malloc(0x400)后free()再malloc(0x400),两次地址差为0x1000 | gdb -q ./pwnme -ex 'b *0x401230' -ex r -ex 'p $rdi' |
| 「JWT伪造」 | /api/login返回JWT,且header.alg可被篡改为none | curl -X POST ... -d 'alg=none' |
我的习惯:每次赛前一周,我会把
.docx中所有考点描述复制到Notion数据库,每条关联一个Docker靶机URL和验证命令。比赛当天,看到题目描述立刻匹配数据库,3秒内调出对应靶机和checklist——这比翻文档快10倍。去年省赛Web题,对手还在读题时,我已经在靶机上跑完curl http://10.10.10.5/.git/config了。希望帮到你。
本文还有配套的精品资源,点击获取