2015-12-31

Ingress Hacking

Ingress 是利用 HTTP Request 方式將資料發送至伺服器
利用 HTTP Request 工具就可以模擬 Ingress App 發送 HTTP Request
但由於 Ingress 的 HTTP Request 經 SSL / TLS 進行加密,應如何解密 ?

在說明方法前,在下必須澄清,雖然本文提及 SSL / TLS 解密,但並非 SSL / TLS 指出已經不安全
而是在下利用 中間人攻擊 來側聽 在下與伺服器的資訊
關於 SSL / TLS 可以到 SSL / TLS @ Wiki 查閱

基於 Ingress 的 HTTP Request 經 SSL / TLS 的加密
使用 Wireshark 等 Packet Capture Tools 雖然能側聽到資訊,但由於資訊被加密,因此不能閱讀
若需要使用 Wireshark 將資訊解密,必須加入伺服器的 私鑰 (private key) ,但閣下不可能擁有伺服器的私鑰
因此要借用 代理伺服器 (Proxy Server) 進行 對稱私鑰加密

以在下使用 Linux Mint 為例

安裝 mitmproxy (mitm 就是 man in the middle 中間人 的縮寫)
在 Terminal 輸入
sudo apt-get install mitmproxy
或按此安裝

安裝後輸入
mitmproxy -p 8888
-p 8888 是指定 mitmproxy 使用 8888 port ,若不指定則是 8080 ,指定與否並不重要

見下文
mitmproxy 起動後, mitmproxy 會不斷監察通過 代理伺服器 時的資訊

先進行測試

見下文
開啟瀏覽器如 Firefox 到「偏好設定」

見下文
按「進階」>「網絡」>「設定」

見下文
選取「手動設定 Proxy」
在「HTTP Proxy」輸入 127.0.0.1 ,Port 為 8888 (與 mitmproxy 的 port 相同)
點選「所有通訊協定都使用此 Proxy 代理伺服器」
將「直接連線」清空
設定完成按「確定」

見下文
瀏覽具 HTTPS 的網頁進行測試如 https://www.google.com.hk/
由於經由 mitmproxy 連線至目標網頁,而且代理伺服器並未驗證,會出現「這個連線未受信任」導致不能瀏覽

見下文
到「偏好設定」
按「進階」>「憑證」>「檢視憑證清單」

見下文
到「憑證機構」分頁
按「匯入」

見下文
選取由 mitmproxy 產生的憑證 (.cer 格式),檔案位於 ~/.mitmproxy/mitmproxy-ca-cert.cer

見下文
選取後將點選
「信任此憑證機構以識別網站」
「信任此憑證機構以識別郵件用戶」
「信任此憑證機構以識別軟體製造商」
後按「確定」

見下文
匯入後會發現經由 mitmproxy 簽署的憑證

見下文
重新整理 HTTPS 網頁能瀏覽,並發現經 mitmproxy 驗證

見下文
回到 mitmproxy 介面會發現資訊已經被側聽

見下文
在 Terminal 輸入
ifconfig
尋找 代理伺服器 的 IP

見下文
使用 Android 裝置,前往「設定」>「Wi-Fi」

見下文
在已連線的 Wi-Fi 通訊,長按後,按「修改網絡」

見下文
按「進階選項」後
在「Proxy」選擇「手動」
並在「Proxy 主機名稱」輸入 代理伺服器的 IP (或 主機名稱)
及在「Proxy 通訊埠」輸入 代理伺服器 所使用的 port
其餘保留原設定
設定後按「儲存」

見下文
瀏覽具 HTTPS 的網頁進行測試時
會發生與剛才相同的情況而不能瀏覽網頁

見下文
前往「設定」>「安全性」

見下文
按「從儲存裝置安裝」

見下文
安裝由 mitmproxy 產生的憑證 (.cer 格式)
(可以借用 E-Mail 將由 mitmproxy 產生的憑證儲存至 Tablet 裝置,有更好的方法由閣下自行處理)

見下文
將憑證命名為「mitmproxy」後按「確定」

見下文
到「信任的憑證」

見下文
在「使用者」分頁中可查證 mitmproxy 的憑證已經安裝

見下文
點選憑證可以查看資訊

見下文
重新整理 HTTPS 網頁便可瀏覽

見下文
使用 iOS 裝置,前往「設定」>「Wi-Fi」
在已連線的 Wi-Fi 通訊,按「更多資訊」

見下文
將「HTTP 代理伺服器」選取為「手動」
並在「伺服器」輸入 代理伺服器的 IP (或 主機名稱)
及在「傳輸埠」輸入 代理伺服器 所使用的 port
其餘保留原設定
設定後按「儲存」

見下文
以 Safari 瀏覽使用 HTTPS 的網頁同樣不能瀏覽

見下文
取得 mitmproxy 的 .cer 憑證

見下文
按「安裝」

見下文
輸入解鎖密碼

見下文
按「安裝」

見下文
按「安裝」確認安裝

見下文
完成安裝 mitmproxy 憑證

見下文
可以檢視 mitmproxy 的憑證資訊

見下文
更多 mitmproxy 的憑證資訊

見下文
重新整理 HTTPS 網頁便可瀏覽

見下文
開啟 Ingress

見下文
mitmproxy 側聽到資訊

見下文
https://m-dot-betaspike.appspot.com/rpc/gameplay/getPaginatedPlexts 為例
選取後按 ENTER 可以查看資訊
其中
HTTP Request header 的 Cookie, Content-Type, X-XsrfToken
及 HTTP Request body 的 JSON 中的 clientBlob
為關鍵資訊
Cookie 中有一個稱為 SACSID 的資料,並以 ~AJKiYc 為開頭的長字串 (1.92.1 之前為 AJKiYc ,沒有「蛇線」)
Content-Type 必定為 application/json; charset=UTF-8
X-XsrfToken 為一個 41長度的字串,分開2部分
第一部分為 27長度的字串,第二部分為13長度的 Unix Timestamp MS 字串,兩部分中間有一個「:」分隔
Request header 及 JSON 的資料是區分大小寫

見下文
按 TAB 可以切換 Request 及 Response
Response 都是 JSON

見下文
複製剛才的 HTTP Request header 及 HTTP Request body 的關鍵資訊
再使用如 CURL 的 HTTP Request Tools 發送 HTTP Request

見下文
便可以不經 Ingress App 向 Ingress 的伺服器發送 HTTP Request

經過資料搜集後檢查到 Ingress 的 HTTP Request URL

Host 暫時必定是 m-dot-betaspike.appspot.com 並以 HTTPS 為通訊協定
  • very-long-string 是故名思義就是一組非常長的字串,是由 Ingress 產生,但暫時未知產生方法
    因此 clientBlob 的資料仍然需要由 Ingress App 協助
  • 在 Ingress 中,任何物件都有稱為 guid 的特殊編號,包括 Agent, Portal, Link, Field 都有
    guid 的格式為「^[0-9a-z]{32}\.[0-9a-z]{2}$」
    執行對應操作涉及 Ingress 的物件都要遞交 guid
  • location 或 playerLocation 需要提供 Agent 身處的經度及緯度
    經度及緯度格式均為 「^[0-9a-f]{8}$」即 8位的16進制數值,不足8位,必須補 0
    經度及緯度之間有「,」分隔而不存在空格
    location 或 playerLocation 必須定屬性名稱不能互換
    估計是已經發佈後,再修改需要花時間進行重構,所以沒有統一名稱
/rpc/gameplay/addMod
安裝 Mod
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "modableGuid": "portal-guid",
        "modResourceGuid": "mod-guid",
        "playerLocation": "00000000,00000000",
        "index": 0
    }
}
index 為 portal 可安裝 Mod 的位置,為 0 至 3
/rpc/gameplay/collectItemsFromPortalWithGlyphResponse
Glyph Hack
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "portalGuid": "portal-guid",
        "location": "00000000,00000000",
        "glyphGameRequested": false,
        "userInputGlyphSequence": {
            "bypassed": false,
            "glyphSequence": [
                {
                    "glyphOrder": "order-0"
                },
                {
                    "glyphOrder": "order-1"
                },
                {
                    "glyphOrder": "order-2"
                }
            ],
            "inputTimeMs": 0
        }
    }
}
bypassed 為 false 表示不略過 Glyph Hack
glyphOrder 為進行 Glyph 時的畫圖次序的字串
/rpc/gameplay/collectItemsOrGlyphsFromPortal
Hack
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "portalGuid": "portal-guid",
        "location": "00000000,00000000",
        "glyphGameRequested": false
    }
}
glyphGameRequested 為 false 表示不使用 Glyph Hack ,但 Glyph Hack 本身亦有另一種 HTTP Request
/rpc/gameplay/collectItemsOrGlyphsFromPortal
Hack No Key
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "portalGuid": "portal-guid",
        "location": "00000000,00000000",
        "glyphGameRequested": false,
        "spewInfluenceGlyphSequence": {
            "bypassed": false,
            "glyphSequence": [
                {
                    "glyphOrder": "NOKEY"
                }
            ],
            "inputTimeMs": 0
        }
    }
}
與 Glyph Hack 的 JSON 相似
分別是 userInputGlyphSequence 改成 spewInfluenceGlyphSequence
而 glyphOrder 指定為 NOKEY
/rpc/gameplay/collectItemsFromPortalWithGlyphResponse
Request Glyph
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "portalGuid": "portal-guid",
        "location": "00000000,00000000",
        "glyphGameRequested": true
    }
}
/rpc/gameplay/completePassphraseObjective
進行任務時,進行輸入 Passphrase 操作
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "missionGuid": "portal-guid",
        "location": "00000000,00000000",
        "waypointIndex": 0,
        "passphraseAnswer": "passphrase"
    }
}
passphraseAnswer 為填寫問題的答案字串
/rpc/gameplay/createLink
建立 Link
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "originPortalGuid": "from-portal-guid",
        "destinationPortalGuid": "to-portal-guid",
        "linkKeyGuid": "portal-key-guid",
        "playerLocation": "00000000,00000000"
    }
}
/rpc/gameplay/deployResonatorV2
部署 Resonator
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "itemGuids": [
            "resonator-guid"
        ],
        "portalGuid": "from-portal-guid",
        "location": "00000000,00000000",
        "preferredSlot": 0
    }
}
preferredSlot 為 -1 或 0 至 7
當設定為 -1 時,Resonator 會部署在與 Agent 對應的方向
當設定 0 至 7 時,為指定方向
  1. 東北
  2. 西北
  3. 西
  4. 西南
  5. 東南
/rpc/gameplay/dischargePowerCube
使用 PowerCube
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "itemGuid": "power-cube-guid",
        "playerLocation": "00000000,00000000"
    }
}
/rpc/gameplay/dropItem
掉下物品
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "itemGuid": "inventory-guid",
        "playerLocation": "00000000,00000000"
    }
}
/rpc/gameplay/fieldTripCardViewed
進行任務時,進行觀看 Portal 操作
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "missionGuid": "mission-guid",
        "location": "00000000,00000000",
        "fieldTripCardGuid": "trip-guid"
    }
}
/rpc/gameplay/fireUntargetedRadialWeaponV2
使用 XMP Burster 或 Ultra Striker 攻擊
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "encodedBoost": "unknown-encoded-hex-value",
        "itemGuid": "weapon-guid",
        "playerLocation": "00000000,00000000"
    }
}
encodedBoost 只在使使用 XMP Burster 或 Ultra Striker 攻擊時產生
暫時未知如何計算產生需要依靠 Ingress App
/rpc/gameplay/flipPortal
使用 Ada Refactor 或 JARVIS Virus
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "portalGuid": "owned-portal-guid",
        "resourceGuid": "flip-card-guid",
        "location": "00000000,00000000"
    }
}
/rpc/gameplay/getMissionDetails
檢視任務資訊
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "value": "mission-guid",
        "playerLocation": "00000000,00000000"
    }
}
/rpc/gameplay/getModifiedEntitiesByGuid
檢視 Portal 資訊
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "guids": [
            "portal-guid"
        ],
        "location": "00000000,00000000",
        "timestampsMs": [
            0
        ]
    }
}
/rpc/gameplay/getNearbyMissions
列出附近任務
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "location": "00000000,00000000"
    }
}
/rpc/gameplay/getTopMissionsForPortal
列出 Portal 的任務
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "value": "portal-guid",
        "playerLocation": "00000000,00000000"
    }
}
/rpc/gameplay/pickUp
拾取物品
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "itemGuid": "inventory-guid",
        "playerLocation": "00000000,00000000"
    }
}
/rpc/gameplay/rateMission
評價任務
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "missionGuid": "mission-guid",
        "location": "00000000,00000000",
        "rating": 1000000
    }
}
rating 為 1000000 表示「是」,為 0 表示「否」
/rpc/gameplay/rechargeResonatorsV2
補充 Resonator 能量
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "isBoostRecharge": false,
        "location": "00000000,00000000",
        "portalGuid": "mission-guid",
        "resonatorSlots": [
            0,
            1,
            2,
            3,
            4,
            5,
            6,
            7
        ]
    }
}
resonatorSlots 指定對應方向,可不全選全部 Resonator
/rpc/gameplay/recycleItemsBulk
回收物品
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "itemGuids": [
            "inventory-0-guid",
            "inventory-1-guid",
            "inventory-2-guid"
        ],
        "playerLocation": "00000000,00000000"
    }
}
/rpc/gameplay/remoteRechargeResonatorsV2
遙距補充 Resonator 能量
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "isBoostRecharge": false,
        "location": "00000000,00000000",
        "portalKeyGuid": "portal-guid",
        "resonatorSlots": [
            0,
            1,
            2,
            3,
            4,
            5,
            6,
            7
        ]
    }
}
/rpc/gameplay/startMission
開始任務
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "value": "mission-guid",
        "playerLocation": "00000000,00000000"
    }
}
/rpc/gameplay/updateContainer
載入 或 卸載 物品
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "containerGuid": "capsule-guid",
        "inventoryGuidsToLoad": [
            "inventory-0-guid",
            "inventory-1-guid",
            "inventory-2-guid"
        ],
        "containerGuidsToUnload": [
            "inventory-0-guid-in-specific-capsule",
            "inventory-1-guid-in-specific-capsule",
            "inventory-2-guid-in-specific-capsule"
        ],
        "playerLocation": "00000000,00000000"
    }
}
/rpc/gameplay/upgradeResonatorV2
升級 Resonator
JSON 範例
{
    "params": {
        "clientBasket": {
            "clientBlob": "very-long-string"
        },
        "emitterGuid": "resonator-guid",
        "portalGuid": "portal-guid",
        "location": "00000000,00000000",
        "resonatorSlotToUpgrade": 0
    }
}
resonatorSlotToUpgrade 與 resonatorSlots 對應的位置數值相同
/rpc/geoInfo/getPortalImages
列出 Portal 的圖片
JSON 範例
{
    "params": {
        "portalGuid": "portal-guid",
        "maxItemsPerPage": 10
    }
}
maxItemsPerPage 最大數值為 10
/rpc/player/say
發送 Comm 訊息
JSON 範例
{
    "params": {
        "factionOnly": true,
        "message": "message"
    }
}
factionOnly 為 true 表示只有與自己相同陣形的 Agent 才能查看,false 表示不同陣形的 Agent 亦可查看
message 為傳送的訊息
/rpc/playerUndecorated/getGameScore
顯示全球分數
JSON 範例
{
    "params": [
    ]
}
/rpc/playerUndecorated/getInventory
列出物品
JSON 範例
{
    "params": {
        "lastQueryTimestamp": 0
    }
}
lastQueryTimestamp 為 unix timestamp 準確至毫秒,該時間後所獲得的物品,當為 0 時表示全部物品
/rpc/playerUndecorated/getInviteInfo
列出邀請資訊
JSON 範例
{
    "params": [
    ]
}
/rpc/playerUndecorated/getNickNamesFromPlayerIds
以 GUID 取回 Agent 代號
JSON 範例
{
    "params": [
        [
            "agent-guid"
        ]
    ]
}
/rpc/playerUndecorated/getPaginatedMissionBadges
載入更多任務徽章
JSON 範例
{
    "params": [
        {
            "continuationToken": "continuation-token"
        }
    ]
}
首個 continuationToken 需於 /rpc/playerUndecorated/getAgentProfile 創建,列出往後最多 10個 任務徽章
之後的 continuationToken 便能透過自身創建
/rpc/playerUndecorated/getPlayerProfile
顯示 Agent 資訊
JSON 範例
{
    "params": [
        "agent-code"
    ]
}
agent-code 為 Agent 代號,例如在下的 HKGoldenMrA
/rpc/playerUndecorated/getRegionScoreByLocation
顯示地區分數
JSON 範例
{
    "params": {
        "location": "00000000,00000000"
    }
}
/rpc/playerUndecorated/inviteViaEmail
發送邀請 E-Mail
JSON 範例
{
    "params": {
        "inviteeEmailAddress": "email",
        "customMessage": "message"
    }
}
inviteeEmailAddress 為收件者的 E-Mail ,必須透過邀請 E-Mail 進行安裝 Ingress App 的新玩家才計算 Recruiter 成就
/rpc/playerUndecorated/redeemReward
兌換獎勵
JSON 範例
{
    "params": [
        "passcode"
    ]
}
passcode 為兌換獎勵的兌換碼
/rpc/playerUndecorated/setNotificationSettings
設定語言、是否顯示通知、促銷、其他 Agent 通訊、Portal 被攻擊、邀請、最新消息資訊
JSON 範例
{
    "params": [
        {
            "clientBasket": {
            },
            "notificationSettings": {
                "locale": "en_US",
                "shouldSendEmail": true,
                "maySendPromoEmail": true,
                "shouldPushNotifyForAtPlayer": true,
                "shouldPushNotifyForPortalAttacks": true,
                "shouldPushNotifyForInvitesAndFactionInfo": true,
                "shouldPushNotifyForNewsOfTheDay": true
            }
        }
    ]
}
locale 為設定語言
shouldSendEmail 為設定是否顯示通知資訊
maySendPromoEmail 為設定是否顯示促銷資訊
shouldPushNotifyForAtPlayer 為設定是否顯示其他 Agent 通訊資訊
shouldPushNotifyForPortalAttacks 為設定是否顯示Portal 被攻擊資訊
shouldPushNotifyForInvitesAndFactionInfo 為設定是否顯示邀請資訊
shouldPushNotifyForNewsOfTheDay 為設定是否顯示最新消息資訊
/rpc/playerUndecorated/setPortalDetailsForCuration
更新 Portal 資訊
JSON 範例
{
    "params": [
        {
            "curationType": "PLAYER_EDIT",
            "portalGuid": "portal-guid",
            "title": "title",
            "description": "description"
        }
    ]
}
curationType 暫時必須為 PLAYER_EDIT
title 為 Portal 的顯示名稱
description 為 Portal 的顯示描述資料
title 及 description 不能為空字串,最少必須使用其中一種屬性,不使用的屬性為保持原來資料
/rpc/playerUndecorated/setProfileSettings
設定是否顯示詳細 Agent 的資訊
JSON 範例
{
    "params": [
        {
            "areMetricsPublic": true
        }
    ]
}
areMetricsPublic 為設定能否讓其他 Agent 查看數據
true 為可以查看,false 為不能

不同的錯誤代號及對應的錯誤訊息
錯誤代號錯誤訊息
CONTAINED_WITHIN_CAPTURED_REGIONPortal is within existing field
CROSSES_EXISTING_LINKLink crosses an existing link
DESTINATION_MUST_BE_FULLPortal missing Resonators
DESTINATION_UNOWNEDNeutral destination Portal
DESTINATION_WRONG_TEAMEnemy Portal
EDGE_ALREADY_EXISTSLink already exists
INDEX_OUT_OF_BOUNDSINDEX_OUT_OF_BOUNDS
INVENTORY_FULLToo many items in Inventory. Your Inventory can have no more than 2000 items
ITEM_DOES_NOT_EXISTItem does not exist
MISSION_DOES_NOT_EXISTMISSION_DOES_NOT_EXIST
NEED_MORE_ENERGYYou don't have enough XM
NO_MISSION_ACTIVENO_MISSION_ACTIVE
ORIGIN_LINK_CAPACITY_REACHEDPortal can't support more Links
OUT_OF_RANGEPortal is out of range
PLAYER_LIMIT_REACHEDPLAYER_LIMIT_REACHED
PORTAL_AT_MAX_RESONATORSPortal has all resonators
PORTAL_BELONGS_TO_ENEMYEnemy Portal
PORTAL_OUT_OF_RANGEPortal out of range
SERVER_ERRORServer error
RESONATORS_FULLY_CHARGEDFully charged
TOO_MANY_RESONATORS_FOR_LEVEL_BY_USERToo many resonators with same level by you
TOO_OFTENPortal burned out! It may take significant time for the Portal to reset
TOO_SOON_5_SECSPortal running hot! Unsafe to acquire items. Estimated time to cooldown: 5 seconds
TOO_SOON_10_SECSPortal running hot! Unsafe to acquire items. Estimated time to cooldown: 10 seconds
TOO_SOON_20_SECSPortal running hot! Unsafe to acquire items. Estimated time to cooldown: 20 seconds
TOO_SOON_30_SECSPortal running hot! Unsafe to acquire items. Estimated time to cooldown: 30 seconds
TOO_SOON_60_SECSPortal running hot! Unsafe to acquire items. Estimated time to cooldown: 60 seconds
TOO_SOON_120_SECSPortal running hot! Unsafe to acquire items. Estimated time to cooldown: 120 seconds
TOO_SOON_180_SECSPortal running hot! Unsafe to acquire items. Estimated time to cooldown: 180 seconds
TOO_SOON_240_SECSPortal running hot! Unsafe to acquire items. Estimated time to cooldown: 240 seconds
TOO_SOON_BIGPortal running hot! Unsafe to acquire items. Estimated time to cooldown: 300 seconds

在下以 Java 編寫了一個仍未算完全的工具,有興趣可以參與及改進
https://bitbucket.org/hkgoldenmra/google-api-for-java
可以使用 git 下載
git clone https://bitbucket.org/hkgoldenmra/google-api-for-java.git

雖然這種遊戲方法相信不是 Ingress 期望玩家的遊玩方法,但這種技術令在下學習更多知識

1 則留言 :