Post

FEAT:🚩 Daily-AlpacaHack 「Guess IP」Easy

ブロードキャストアドレスの特性を利用したIPフィルタバイパス

FEAT:🚩 Daily-AlpacaHack 「Guess IP」Easy

20260608-daily_alpaca-misc-easy-guess-ip

Summary

本問は,ネットワークの予約済みIP (ブロードキャストアドレス) の特性を利用した問題です.

  • Category: Misc
  • Description: 10.0.0.1から10.255.255.254の中からIPアドレスを当ててみて!
  • Tools & TechStack:
    • Python
  • Release: 2026/06/08

階層構造

1
2
3
4
5
6
7
8
9
10
.
├── app
│   ├── app.py
│   └── Dockerfile
├── compose.yaml
└── server
    ├── Dockerfile
    └── server.py

3 directories, 5 files

ソースコードの調査

compose.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
services:
  app:
    build: ./app
    restart: unless-stopped
    ports:
      - "${PORT:-1337}:1337"
    networks:
      ctfnet: {}

  server:
    build: ./server
    restart: unless-stopped
    environment:
      FLAG: "Alpaca{REDACTED}"
    networks:
      ctfnet:
        ipv4_address: 10.99.99.99 # REDACTED. Different on remote. Can you guess the IP?

networks:
  ctfnet:
    driver: bridge
    ipam:
      config:
        - subnet: 10.0.0.0/8

まず,10.0.0.1 から 10.255.255.254 を総当たりすることは不可能かつ,1度の試行で接続が切れます. もし総当たりするとすれば,sock.settimeout(1.0) のため少なくとも1つのリクエストに1秒はかかります. 最悪の場合は以下のようになり,$16,777,214 \text{ 秒}$ $\approx$ 約194日 かかる計算になるため現実的ではありません.

\[16,777,216 - 2 = 16,777,214 \text{ 通り}\]

sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) という記載から,このソケットでブロードキャストパケットの送信を許可する設定がされていることも分かりました.

app/app.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import ipaddress
import socket

print("Example: 10.123.45.67")
ip = input("Enter IP> ").strip()

try:
    ipaddress.IPv4Address(ip)
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.settimeout(1.0)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

    sock.sendto(b"hello", (ip, 1234))

    try:
        data, _ = sock.recvfrom(4096)
        print(data.decode())
    except socket.timeout:
        print("no response")

except Exception as e:
    print(f"Error: {e}")

server.py では,sock.bind(("0.0.0.0", 1234)) で,全NICのUDPポートでなんらかのデータを受信した瞬間に,Flag文字列とアドレスをレスポンスする処理が記載されています. app.py で,sock.sendto(b"hello", (ip, 1234)) が使用されているため,正しいIPを入力できれば server.py にパケットが届き,FLAG が返ってくるはずです.

総当たりはできないため,有効なIPを指定する方法を考えていると,制限付きブロードキャストアドレスを思いつきました.

server/server.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import os
import psutil
import socket

FLAG = os.environ.get("FLAG", "Alpaca{REDACTED}")

message = (
    f"Hello from {psutil.net_if_addrs()['eth0'][0].address}\n"
    f"Here is your flag: {FLAG}"
)

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(("0.0.0.0", 1234))

while True:
    data, addr = sock.recvfrom(4096)
    sock.sendto(message.encode(), addr)

制限付きブロードキャストアドレス

255.255.255.2551 は,予約済みIPであり,標準的なパブリック・プライベートIPとして割り当てられていません. このIPは,ブロードキャスト通信を行いブロードキャストパケットを使用します. ブロードキャストパケットは,他のサブネットにはルーティングされないため,送信元と同じネットワークセグメント内に存在するすべてのホスト に対してパケットを届けます.

この問題設定でも,serverapp は同一のサブネットに属しているはずなので,このアドレスを使用することで FLAG が返ってくるはずです.

1
2
3
4
5
$ nc 34.170.146.252 32918
Example: 10.123.45.67
Enter IP> 255.255.255.255
Hello from xx.xxx.xxx.xx
Here is your flag: Alpaca{REDACTED}

Post-Mortem & Dead ends

  • SO_BROADCAST: そのソケットでブロードキャストパケットの送信を許可する設定

References

This post is licensed under CC BY 4.0 by the author.