1. 程式人生 > >校園黑客,python突破校園飲水機餘額限制!

校園黑客,python突破校園飲水機餘額限制!

校園黑客,python突破校園飲水機餘額限制!

Python 和放大鏡的二進位制程式碼

0x00 目錄

0x01 前言

0x02 利用fd分析與實戰

0x03 Python+burp簡易搭建代理伺服器

0x04 實現自動化exp

0x05 結束語

0x01 前言 本文只是對某校園熱水服務app做個測試,其實本人並沒有做大壞事,並未傳播相關技術,文章以下內容的敏感部分會打碼,並且相關廠商已經正在進行漏洞修復,大家看看就好。文章後會提供“Python簡易搭建代理伺服器”的關鍵程式碼,程式碼簡單而且開源,我自己也加了點註釋。最後的exp只針對本app,感興趣的朋友可以看看。以下內容包含個人見解,輕噴。若有誤導懇請指出。

0x02 利用fd分析與實戰

要對這app做測試,首先了解下app的運作流程。

登入後,app主介面如下

校園黑客,python突破校園飲水機餘額限制!

 

邏輯簡單,步驟如下:

1.app使用藍芽連線水錶。

2.先扣你10塊餘額,轉到預扣款裡(不夠10元扣除所有)

3.水錶上顯示10塊錢,也就是你的預扣款(我只有6元所有會顯示6元),水錶出水

4.用水,水錶上的金額隨著用水量而減少

5.停止用水,水錶上顯示的金額就是餘額,將返還給餘額

這樣分析還不夠,我們利用fiddler看看app向伺服器的HTTP請求內容

怎麼抓手機包看這,講的比我好我就不多說了:如何用Fiddler對Android應用進行抓包

app啟動時的HTTP資料請求截圖:

校園黑客,python突破校園飲水機餘額限制!

 

一共請求了5次,沒發現什麼地方有問題。要想知道這些請求都是做什麼的,可以看看請求的get的內容以及post的內容,還可以看看網站的響應內容。從截圖中fiddler右下角的“Message=未發現版本”就可以猜想這個http請求可能是檢查更新的請求。

我們用的是“fiddler”,大家都知道的,許多利用都是改金額,現在還沒用水,還沒發生金額的變化,咱們現在用水試試。

點選“點選開始用水”按鈕,看看app截圖以及fiddler的http請求

校園黑客,python突破校園飲水機餘額限制!

 

校園黑客,python突破校園飲水機餘額限制!

 

app扣除了6塊,轉到了預扣款裡,水錶上顯示6.00元,<img>假裝有水錶照片.jpg</img>

看fiddler截圖,一共有4個http請求,注意紅框,“00A3AAAF”是本次用水的訂單號,之後會用到。

看了下這些http請求,發現並未和伺服器發生有關金額的資訊互動。

我們進行下個步驟,停止用水讓它退還餘額。

app截圖,以及fiddler抓取到的金額資料截圖:

校園黑客,python突破校園飲水機餘額限制!

 

校園黑客,python突破校園飲水機餘額限制!

 

可以看到之前紅框框起來的訂單號在結賬返還金額的時候用到了,不用改。bal的值明顯就是退還金額,將他改為6,也就是我的預扣款試試。成功退還所有預扣款!(這app有兩次http請求返回的餘額,內容都相同,都需要改為6,另一次就不貼截圖了)

校園黑客,python突破校園飲水機餘額限制!

 

點選確認結賬就餘額就能變回6元了,這個“確認結賬”按鈕實際上是個重新整理命令。

0x03 Python+burp簡易搭建代理伺服器

之前已經用fd實現漏洞利用,但是每次都需要手動改,如果寫個指令碼會比較快一些。正巧我在某同性交友網看到了“Python搭建代理伺服器”的程式碼,就想試試能不能通過這個程式碼稍加更改實現自動化Exp。

貼出原始碼:

#coding:utf-8
import socket
import thread
import urlparse
import select
 
BUFLEN = 8192
 
 
 
class Proxy(object):
 def __init__(self, conn, addr):
 self.source = conn
 self.request = ""
 self.headers = {}
 self.destnation = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 self.run()
 
#用來構造header
 def get_headers(self):
 header = ''
 while True:
 header += self.source.recv(BUFLEN)
 index = header.find('
')
 if index > 0:
 break
 # firstLine,self.request=header.split('
',1)
 firstLine = header[:index]
 self.request = header[index + 1:]
 self.headers['method'], self.headers['path'], self.headers['protocol'] = firstLine.split()
 
#用來發送請求
 def conn_destnation(self):
 url = urlparse.urlparse(self.headers['path'])
 hostname = url[1]
 port = "80"
 if hostname.find(':') > 0:
 addr, port = hostname.split(':')
 else:
 addr = hostname
 port = int(port)
 ip = socket.gethostbyname(addr)
 print ip, port
 self.destnation.connect(('127.0.0.1', 8080)) #可以填burpsuite的代理
 data = "%s %s %s
" % (self.headers['method'], self.headers['path'], self.headers['protocol'])
 self.destnation.send(data + self.request) #傳送請求
 print data + self.request
 
#傳送響應的結果
 def renderto(self):
 readsocket = [self.destnation]
 while True:
 data = ''
 (rlist, wlist, elist) = select.select(readsocket, [], [], 3)
 if rlist:
 data = rlist[0].recv(BUFLEN)
 if len(data) > 0:
 self.source.send(data)#傳送響應的結果
 else:
 break
 # readsocket[0].close();
 
 def run(self):
 self.get_headers()
 self.conn_destnation()
 self.renderto()
 
 
class Server(object):
 
 def __init__(self, host, port, handler=Proxy):
 self.host = host
 self.port = port
 self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
 self.server.bind((host, port))
 self.server.listen(5)
 self.handler = handler
 
 def start(self):
 while True:
 try:
 conn, addr = self.server.accept()
 thread.start_new_thread(self.handler, (conn, addr))
 except:
 pass
 
 
if __name__ == '__main__':
 s = Server('127.0.0.1', 6666) #這裡寫本地ip,監聽的埠。
 s.start()

關鍵部分我寫了註釋,還有程式碼不清楚格式是否會亂,我在文後以附件的形式貼出來吧

這次配合burpsuite來使用,使用方法:第90行(倒數第二行)寫入之前用fiddler改包時手機wifi設定的代理,以及埠號,用來監聽手機發出的http請求。第44行寫burpsuite監聽的地址,從手機上獲取的http請求都會轉發給burpsuite,burpsuite設定我也貼出來吧:

校園黑客,python突破校園飲水機餘額限制!

 

校園黑客,python突破校園飲水機餘額限制!

 

設定好後,只要執行程式碼,就可以實現代理服務。雖然想要代理直接連burp就好,但是這提供了一個可以使用PY程式碼進行一定程度的中間人操作的環境。

0x04 實現自動化exp

PS:看到這裡就可以不看了,因無法提供app與藍芽水錶,以下內容多半無法看明白。。

之前實現了代理,那麼現在就要開始改程式碼了,將程式碼改成漏洞app的漏洞利用工具。

因為這個不是通用型漏洞,漏洞利用工具也只能針對這個app,所以以下內容不存在乾貨,感興趣的可以看下去。

思路:通過這個代理,將停止用水後“結賬”請求中返還的金額替換為預扣款的金額,即返還所有金額。

還有個:對app的http請求分析的越透徹,exp就可能寫的越簡單思路越清晰。

漏洞利用程式方法眾多,以下將按我自己的思路

從之前的fd測試可以知道,“用水”與“結賬返還金額”是兩個獨立的http請求部分,根據常識“結賬”肯定要在“用水”之後,那我們可以在app執行“用水”之後就馬上向伺服器請求偽造的“結賬”http請求,因偽造的“結賬”請求只是PC機跳過app與伺服器互動,所以執行結賬後不會影響藍芽水錶的供水。這種思路有個前提,就是能成功偽造“結賬”請求,如果無法偽造,也可以在“結賬”請求發出時攔截並改包,這樣理論上是不會出問題的。

偽造“結賬”需要在“用水”之後,那怎麼判斷“用水”請求?

用 if 判斷資料的特徵,簡單明瞭。因為只是判斷,不是攔截,所以只需要在conn_destnation函式的結尾,也就是destnation.send() 執行後,新增 if 判斷即可,如果是“用水”便開始偽造“結賬”。因為結賬需要訂單號,所以可以用re模組正則表示式匹配“用水”請求的特徵時順帶取出訂單號,見截圖:

校園黑客,python突破校園飲水機餘額限制!

 

訂單號正好包含在URL中,真方便。

用if判斷不為空就可以剛剛獲取的訂單號進行偽造的“結賬”了

偽造“結賬”請求需要類似cookies的憑證,憑證存在header裡,可以直接使用“用水”請求的header。

可是!!我發現用水、結賬、查餘額等一系列操作是使用的header中的憑證永不過期,若重登會給予新的憑證,但舊憑證依舊可以使用!所以就可以偷懶直接貼一份header使用。

校園黑客,python突破校園飲水機餘額限制!

 

有了憑證就可以為所欲為了,偽造“結賬”請求除了訂單號還需要知道預扣款,前面提到過,預扣款一般為10元,但有時候餘額不足預扣款就不足10元,所以為了程式相容性,還需要獲取下預扣款。既然有了憑證為所欲為,那麼可以再偽造下一個能讓伺服器返回預扣款的請求即可。

校園黑客,python突破校園飲水機餘額限制!

 

見上圖:有了憑證,並且正好伺服器返回的是json形式的,直接用Python 的 eval,再獲取對應鍵值就行。

然後就是執行偽造的“結賬”請求:

校園黑客,python突破校園飲水機餘額限制!

 

0x05 結束語

終於結束了,感謝看我這篇文章的人,更感謝從頭到尾看完的人,不枉我寫這篇文章,畢竟對於你們來說是沒見過的app,這太抽象了,並且文章內容無聊,而且讀程式碼遠比寫程式碼困難,遺憾的是不能提供實驗環境。要是有人看完我會很開心,謝謝啦QAQ

校園黑客,python突破校園飲水機餘額限制!