0x00 起因
前幾天朋友跟我說他的服務(wù)器最近老是爆炸,而且經(jīng)常是一到點就集體崩潰,別的服主也有類似的情況,他給服務(wù)器套上全局代理之后服務(wù)器就不崩潰了,然而給服務(wù)器開了代理客戶端也連不進來。一開始我猜測是BDS(Bedrock Dedicated Server,mcpe官方服務(wù)端)會與mojang服務(wù)器有連接,連不上就會觸發(fā)某個bug導(dǎo)致崩潰。

(圖片是windows服務(wù)器的內(nèi)存占用,服主windows和linux都有開)
報錯如下,基本上只能得知是內(nèi)存分配相關(guān)的問題,從報錯判斷不出什么。
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
[2020-03-15 15:09:41 INFO] Package: com.mojang.minecraft.dedicatedserver
Version: 1.14.32.1
OS: Linux
Server start: 2020-03-15 14:53:05 UTC
Dmp timestamp: 2020-03-15 15:09:41 UTC
Upload Date: 2020-03-15 15:09:41 UTC
Session ID: e24ac8b6-8e41-4d53-ba6c-949b7bbcde90
Commit hash:
Build id: development
CrashReporter Key: e29bac8d-dc1e-3938-8438-413e8e159bce
Crash
[2020-03-15 15:09:41 INFO] at gsignal (UnknownFile:?)
at abort (UnknownFile:?)
at __gnu_cxx::new_allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::allocate[unsigned long, void const*] (UnknownFile:?)
at std::allocator_traits<std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::allocate[std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, unsigned long] (UnknownFile:?)
at std::_Vector_base<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::_M_allocate[unsigned long] (UnknownFile:?)
at std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >* std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::_M_allocate_and_copy<std::move_iterator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*> >[unsigned long, std::move_iterator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*>, std::move_iterator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*>] (UnknownFile:?)
at std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::reserve[unsigned long] (UnknownFile:?)
at PurchaseReceiptPacket::read[ReadOnlyBinaryStream&] (UnknownFile:?)
at Packet::readNoHeader[ReadOnlyBinaryStream&, unsigned char const&] (UnknownFile:?)
at NetworkHandler::_sortAndPacketizeEvents[NetworkHandler::Connection&, std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l> > >] (UnknownFile:?)
at NetworkHandler::runEvents[bool] (UnknownFile:?)
at Minecraft::update[] (UnknownFile:?)
at ServerInstance::_update[] (UnknownFile:?)
at clone (UnknownFile:?)
0x01 抓包分析
為了驗證這個想法,我連朋友的服務(wù)器抓了幾次服務(wù)器崩潰時的包,抓包用的是tcpdump,服務(wù)器開在docker容器里面,大概方法如下:
# 獲取容器PID
docker inspect --format "{{.State.Pid}}" <container id/name>
# 切換到容器的網(wǎng)絡(luò)命名空間
nsenter -n -t <container root id>
tcpdump -i eth0 -w dump.cap
但是服務(wù)器在線人數(shù)比較多,從抓到的包里面也沒分析出什么關(guān)鍵信息。
0x02 問題排查
服務(wù)器還在一直崩潰,不過時間段好像變化了,沒那么固定了,有時候也只是卡死一段時間,服務(wù)器并沒有完全崩潰,此時除了懷疑MCPE服務(wù)器可能與mojang之間有連接之外,我慢慢地開始懷疑服主的群里面是不是有內(nèi)鬼,但是群里面那么多人,也不好找誰是內(nèi)鬼,于是我們準備使用ip白名單的方式來排查問題,也就是把部分信任的人的ip加入防火墻白名單,如果此時還會崩潰的話,那基本就可以排除服務(wù)器是被人攻擊了的猜想,開了白名單之后服務(wù)器維持了很長一段時間穩(wěn)定運行,但是后來還是炸了。我當時有點像放棄了(服主跑路算了,哈哈哈哈哈)。

0x03 內(nèi)鬼自爆
高潮來了,開了白名單的那天晚上,內(nèi)鬼自爆了,這個人直接在群里面坦白說是他炸的服,并且揚言還要繼續(xù),不過當時他由于未知的原因沒有黑成功,被群友的嘲諷了一晚上(具體原因可能是那天我們把服務(wù)器換到了內(nèi)網(wǎng),用frp內(nèi)網(wǎng)穿透的方式開了服務(wù)器,目的是為了排除mcpe服務(wù)器的xbox驗證可能導(dǎo)致崩潰,由于網(wǎng)絡(luò)環(huán)境改變導(dǎo)致他的攻擊方式失效了)。

不過第二天服務(wù)器還是崩了,大概就可以確認是這個人搞崩的,服主提前找出了這個人在群里面的所有小號以及他的ip,并把他踢了出去,那天開了白名單后服務(wù)器還是崩潰了的原因是服主看白名單很穩(wěn)定,就放松了審核,不小心讓內(nèi)鬼就混了進去。在這之后服主開始了嚴格的ip白名單審核,服務(wù)器終于穩(wěn)定了下來。
0x04 重現(xiàn)bug
如果這么簡單結(jié)束了的話我是不會寫這篇文章的,在我得到了內(nèi)鬼的相關(guān)信息之后,我想知道他是怎么攻擊的。于是我又翻出了那天一開始抓的包,用服主得到的ip在包里面匹配,可是并沒有找到什么,應(yīng)該是換了ip了,然后我從ip歸屬地開始查,發(fā)現(xiàn)了一個跟內(nèi)鬼同一個歸屬地的ip。

理所當然地,我開始分析這個包的行為,發(fā)現(xiàn)他在服務(wù)器崩潰時刻發(fā)出了很多連接服務(wù)器的請求,每次的client GUID不一樣,我猜測服務(wù)端每發(fā)現(xiàn)一個客戶端連接時,不管它有沒有連進來都會給這個客戶端提前分配一段內(nèi)存,一次發(fā)送很多client GUID不一樣的包會讓服務(wù)端誤以為有很多客戶端在連接,于是內(nèi)存不夠分配服務(wù)器就崩潰了。

為了驗證這個想法,我把這段包提取出來,用tcpreplay重放,修改好網(wǎng)絡(luò)包的mac地址,ip和端口,向一個測試服務(wù)器快速重放這些可能會導(dǎo)致崩服的包,然而,持續(xù)發(fā)了好幾分鐘,服務(wù)器紋絲不動,內(nèi)存占用率是一條讓人尷尬的直線。
于是我開始找別的線索,抓的包里面與服務(wù)器有連接的也就十幾個ip,我挨個查了一下歸屬地,查完后我驚呆了,十幾個ip里面有6個ip是來自阿里云的,排除其中兩個是服主自己的服務(wù)器,還有4個,難道真正的攻擊者是內(nèi)鬼租的云服務(wù)器?我挨個看了一下那幾個阿里云服務(wù)器的行為,倒也看不出什么太大貓膩,我順手把那些包截取出來,稍作修改后開始對測試服發(fā)送,此時,測試服瞬間崩了,內(nèi)存占用,報錯信息和前幾天的一模一樣,然后我重新看了下這些包,

我猜是這樣發(fā)包才能騙過服務(wù)器有很多客戶端在與服務(wù)器建立連接,具體的原理已經(jīng)不太重要了,畢竟這個得去研究一下BDS的協(xié)議才能知道詳細信息,bug已經(jīng)復(fù)現(xiàn)了,向mojang提交bug才是正確方式。
0x05 后續(xù)
內(nèi)鬼被踢了之后服主的主頁被d了。?!,F(xiàn)在還是黑洞狀態(tài)
0x06
感謝sow village(老母豬村服務(wù)器)提供素材.
首發(fā)于我的個人博客