Սկիզբ » Ուսումնական նյութեր » Ծրագրավորում » Ծրագրավորման լեզուներ » Python » Կոտրում ենք quadcopter֊ի ip camera-ն reverse engineering -ի մեթոդներով

Կոտրում ենք quadcopter֊ի ip camera-ն reverse engineering -ի մեթոդներով

| Ապրիլ 25, 2017 | Մեկնաբանված չէ |

Դրոնների թեման ինձ վաղուց էր հետաքրքրում ու քանի որ կային մի շարք մտքեր կապված դրանց հետ, որոշեցի վերջապես սկսել ինչ֊որ բան անել։ Գնեցի Overmax X-Bee drone 5.2, որը կարելի է կառավարել ինչպես rc֊ով, այնպես էլ android application-ով։ Բայց դա այն չէր ինչն ինձ պետք էր, իսկ ինձ պետք էր ստանալ video stream֊ն այնպես, որպեսզի հետագայում հնարավոր լիներ այն մշակել. ո՛չ rc -ն և ո՛չ էլ android application֊ը նման հնարավորություն չեն տալիս։

 

 

Առաջինը ինչից սկսեցի, դա արտադրողի դոկումենտացիայի ուսումնասիրությունն էր, բայց այնտեղից ոչ մի օգտակար բան չհաջողվեց պարզել․ այնտեղ տեխնիկական իրականացման վերաբերյալ ոչ մի ինֆորմացիա չկար ու պարզ չէր, թե ինչ պետք էր անել։ Մի լավ խոսք կա, ասում է “when in doubt, go old school”, կոնկրետ էս դեպքում դա նշանակում է reverse engineering: Պատկերավոր ասած, reverse engineering ֊ն այն է, երբ ունես սև արկղ և պետք է պարզես թե դրա ներսում ինչ կա, այսինքն եթե ինչ֊որ բան արտադրելիս առանձին դետալները կոնկրետ մեթոդներով և տեխնոլոգիաներով միացնում են իրար և ստանում են վերջնական արտադրանք, ապա այս դեպքում, պետք է վերջնական արտադրանքից ստանալ առանձին դետալները, մեթոդներն ու տեխնոլոգիաները։ Այս փուլում մեր խնդիրն է պարզել հնարավորինս շատ ինֆորմացիա, այսպես ասած գծել տեղանքի նախնական քարտեզն ու պարզել ուժերի բաշխվածությունը 😀

Դրա համար play market-ից քաշեցի drone֊ի LS_Model_v1.6_apkpure.com.apk ֆայլն ու decompile արեցի այն։

Դրա համար պետք  է․

1. cd /home
2. mkdir LS_Model_v1.6
3. unzip LS_Model_v1.6_apkpure.com.apk -d LS_Model_v1.6
4. cd LS_Model_v1.6
5. ~vardan/rev_eng/dex2jar-2.0/d2j-dex2jar.sh classes.dex

Էս հրամանից հետո ստանում ենք classes-dex2jar.jar ֆայլը, որն անհրաժեշտ է բացել jd-gui ծրագրով source֊երը տեսնելու համար։

sudo ~vardan/rev_eng/jd-gui-0.3.5.linux.i686\ \(1\)/jd-gui classes-dex2jar.jar 

Տեսնում ենք, որ source֊երում ոչ մի հետաքրքիր բան էլ չկա և պարզ է դառնում, որ պետք է այդ ինֆորմացիան փնտրել *.so ֆայլերի մեջ։ Դրա համար տեսնենք, թե ինչ ինֆորմատիվ տողեր կան դրանցում։
Դա կանենք հետևյալ հրամանով։

strings lib/armeabi/libmain.so > str 

Առաջին հերթին այսեղից մեզ հետաքրքրում է ip ֊ն, պորտի համարը և թե ինչ կոդեկ է օգտագործվում video streaming֊ի համար։
ip գտնելու համար grep ենք անում.

grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' str

և տեսնում ենք 172.16.10.1 ինչն էլ ամենայն հավանականությամբ drone ֊ի ստատիկ ip֊ն է։
Քանի֊որ video streaming֊ի համար առավել հաճախ օգտագործվում է h264 կոդեկը, ապա str ֊ի մեջ grep-ով փնտրում ենք h264 բառ պարունակող տողեր

grep "h264" str 

և տեսնում ենք, որ այդպիսի տողեր շատ կան, դա նշանակում է, որ մեծ հավանականությամբ հենց h264 ֊ն էլ օգտագործվում է։ Ինչպես տեսնում ենք մեր բախտը շատ բերեց․ հաջողվեց hard code տողեր գտնել, քանզի հակառակ դեպքում ստիպված էինք լինելու disassembly անել *․so֊ները, այնպես չէ որ չէինք կարող, ուղղակի դա ամենահաճելի զբաղմունքը չէր լինի։

Հիմա, ինչպես տեսանք մեզ հաջողվեց գտնել (այս փուլում ուղղակի համարենք) ip֊ն և codec֊ի տեսակը․ մեզ մնաց պարզել մեր device֊ի վրա եղած open port֊երը, դրա համար գործի մեջ ենք դնում իմ ամենասիրած tool֊երից մեկը nmap֊ը։

nmap -p 0-10000 172.16.10.1

Սյստեղ սկանավորում ենք 172.16.10.1 ip֊ի 0-10000 սահմանում open port֊երը և տեսնում ենք, որ 8888 պորտը բաց է։
Շատ լավ, հիմա նաև ունենք նաև port number֊ը:
Փորձենք telnet֊ով կպնել դրոնին, եթե հաջողվեց, ապա կկարողանանք remote հրամաներ կատարել և էլ ավելի շատ ինֆորմացիա հավաքել սարքի վերաբերյալ

telnet 176.16.10.1 8888

Տերմինալը մնում է կախված վիճակում, նույնն է նաև ssh֊ի դեպքում։ Սա նշանակում է, որ մենք չենք կարող անմիջապես սարքի վրա հրամաններ կատարել և պետք է wifi ցանցի միջոցով մտնել կոմունիկացիայի մեջ։
Այս պահին մենք գիտենք դրոնի ip֊ն, port number֊ը և video streaming֊ի codec֊ը։ Սարքը իր application֊ի հետ խոսում է wifi֊ի միջոցով և պետք է պարզել, արդո՞ք փոխանցվող ինֆորմացիան encrypt֊արվում է, թ՞ե ոչ։ Եթե encrypt է արվում, ապա ամենայն հավանականությամբ դա wep/wpa֊ով է արվում, որը կարող ենք կոտրել, ուղղակի լավ կլինի որ ստիպված չլինենք դա անել 😀 :

Դրա համար նախ ստանում ենք մեր wifi ընդունիչի անունը։

iwconfig

Հիմա անհրաժեշտ է այն switch անել monitor mode-ի, դա կանենք Aircrack-ng ծրագրային փաթեթի airodump tool֊ի միջոցով

airmon-ng start wlx30b5c2125754

Դրանից հետո նորից ենք անում՝

iwconfig

և ստանում ենք

Հիմա airodump-ng tool֊ով պարզում ենք՝ արդյո՞ք տվյալները encrypt եղած են փոխանցվում։

sudo airodump-ng mon0

Նկարից տեսնում ենք, որ տվյալները կոդավորված չեն (ENC ֊ի տակ գրված է OPN, այսինքն open), դա մեզ ազատում է ավելորդ գլխացավանքից։
Բայց հիմա մի ուրիշ խնդիր ունենք․ պետք է պարզել ինչ protocol֊ով են տվյալները փոխանցվում tcp թե udp?: Դրա համար մեզ պետք է sniff անել դրոնի և android application֊ի կոմունիկացիան։ Դրա համար մեզ պետք կգա root արված android os ֊ով հեռախոս, որի վրա տեղադրված են busybox ֊ն ու android terminal emulator֊ը։ Հեռախոսը root անելու, busybox և android terminal emulator install անելու վերաբերյալ 10T ինֆորմացիա կարելի է գտնել համացանցից 🙂
Միացնում ենք drone֊ը, android application֊ը (այնպես, որ հեռախոսի էկրանին տեսնենք դրոնի տեսախցիկից ուղարկված վիդեոն) և android terminal emulator֊ում կատարում ենք հետևյալ հրմանաը

tcpdump -vv -s 0 -w /sdcard/tcap.cap 


Սպասում ենք 3-4 րոպե և ընդհատում ենք tcpdump֊ը volume down & c ֊ով։
Հիմա դրոնի և application֊ի միջև ողջ կոմունիկացիան raw ձևով ունենք tcap.cap ֆայլում, մնում է դրանից բան հասկանալ ։)
Այդ tcap․cap ֆայլը բացելու համար խաղի մեջ ենք մտցնում մեր ծանր հրետանին՝ Wireshark֊ը։
Բացում ենք Wireshark -ը

sudo wireshark

Տալիս ենք File->Open և ընտրում ենք մեր tcap.cap ֆայլը։

Այս նկարից տեսնում ենք, որ application֊ը դրոնի հետ կոմունիկացիայի մեջ է մտնում 4 անգամ՝ տարբեր պորտերով.

Source ip,         source port      packet type   direction       destination ip,   destination port

172.16.72.109      53383              SYN             ->          172.16.10.1       8888                
172.16.72.109      53383              SYN, ACK        <-          172.16.10.1       8888
172.16.72.109      53383              ACK             ->          172.16.10.1       8888
172.16.72.109      53383              PSH, ACK        ->          172.16.10.1       8888
172.16.72.109      53383              PSH, ACK        <-          172.16.10.1       8888
172.16.72.109      53383              ACK             ->          172.16.10.1       8888
Source ip,         source port      packet type   direction       destination ip,   destination port

172.16.72.109      39159              SYN             ->          172.16.10.1       8888                
172.16.72.109      39159              SYN, ACK        <-          172.16.10.1       8888
172.16.72.109      39159              ACK             ->          172.16.10.1       8888
172.16.72.109      39159              PSH, ACK        ->          172.16.10.1       8888
172.16.72.109      39159              PSH, ACK        <-          172.16.10.1       8888
172.16.72.109      39159              ACK             ->          172.16.10.1       8888
Source ip,         source port      packet type   direction       destination ip,   destination port

172.16.72.109      59472              SYN             ->          172.16.10.1       8888                
172.16.72.109      59472              SYN, ACK        <-          172.16.10.1       8888
172.16.72.109      59472              ACK             ->          172.16.10.1       8888
172.16.72.109      59472              PSH, ACK        ->          172.16.10.1       8888
172.16.72.109      59472              PSH, ACK        <-          172.16.10.1       8888
172.16.72.109      59472              ACK             ->          172.16.10.1       8888
Source ip,         source port      packet type   direction       destination ip,   destination port

172.16.72.109      41942              SYN             ->          172.16.10.1       8888                
172.16.72.109      41942              SYN, ACK        <-          172.16.10.1       8888
172.16.72.109      41942              ACK             ->          172.16.10.1       8888
172.16.72.109      41942              PSH, ACK        ->          172.16.10.1       8888
172.16.72.109      41942              PSH, ACK        <-          172.16.10.1       8888
172.16.72.109      41942              ACK             ->          172.16.10.1       8888

ի՞նչ է այստեղ տեղի ունենում։ Սա TCP 3-way handshaking֊ն է։ Սկզբում մեր android application֊ը (կլիենտ) ուղարկում է կոմունիկացիայի հաստատման SYN packet դրոնին (սերվեր), որին սերվերը պատասխանում է SYN, ACK packet֊ով, հետո կլինետը ACK packet֊ով տեղեկացնում է սերվերին, որ ստացել է դրա կողմից ուղարկված պատասխանը։ Դրանից հետո կլիենտը PSH, ACK packet֊ով ուղարկում է ինչ֊որ data, սերվերը պատասխանում է PSH, ACK packet-ով և դրան ի պատասխան կլիենտը ուղարկում է ACK packet֊ը։ Եվ նույնը արվում է մնացած բոլոր 3 կոմունիկացիաներում էլ։
Այստեղ մնացածից բացի կան նաև երկու շատ կարևոր թվեր․ դրանք ենք seq (sequence number) և ack (acknowledgment number)։ Երբ կլիենտը SYN packet֊ով initiate֊է անում կոմունիկացիա սերվերի հետ, այն (կլիենտը) գեներացնում է seq = 0 և ack = 0 թվերը (իրականում դրանք պատահական գեներացված թվեր են, որոնք սկզբում պայմանականորեն համարում ենք 0)։
Սերվերը դրան պատասխանում է SYN, ACK packet֊ով, որտեղ seq ֊ը նույնպես 0 ֊է (պայմանական 0, իրականում 0 ֊ 4,294,967,295 միջակայքից պատահական թիվ), իսկ ահա ack֊ն հավասար է նախորդ packet֊ի seq + 1 (կլիենտից սերվերին ուղարկված packet֊ի մասին է խոսքը)։ Դրանից հետո կլիենտը սերվերին է ուղարկում ACK packet֊ը, որտեղ seq -ը հավասար է նախորդ packet֊ի ack֊ին, իսկ ack֊ն հավասար է packet֊ի seq + 1: Դրանից հետո նորից է կլիենտը PSH, ACK packet ուղարկում սերվերին, բայց այս անգամ այն ունի payload, այսինքն օգտակար, ինֆորմատիվ տվյալներ, այս դեպքում seq֊ն ու ack֊ն համապատասխանաբար հավասար են նախորդ packet ֊ի համապատասխան թվերին (նախորդ packet ֊ում նույնպես կլիենտն էր սերվերին packet ուղարկել)։ Սրան սերվերը պատասխանում է PSH, ACK packet֊ով, որտեղ seq֊ը հավասար է նախորդ packet֊ի (կլիենտից սերվերին ուղարկված packet-ի) ack-ին, իսկ ack֊ն հավասար է նախորդ packet ֊ի seq + length of payload data և այսպես շարունակ։ Այսինքն սա միջոց է հանդիսանում կլիենտի և սերվերի միջև համոզվելու, որ ոչ մի ուղարկված packet չի կորել ճանապարհին։
Փաստորեն տեսնում ենք, որ video streaming֊ը initiate է արվում 4 հատ կոմունիկացիաների միջոցով, որոնցում app֊ն ու drone֊ը փոխանակվում են ինչ֊որ data֊ով, այստեղ data ասելով պետք է հասկանալ PSH,ACK packet֊ներով փոխանակումը, քանի որ մնացած SYN, SYN ACK և ACK packet֊ները ընդամենը սինխրոնիզացիայի համար են։ Այսինքն հերիք է մեզ պարզել, թե դրանք ինչ data֊ներ են, բացել 4 հատ socket և վերջ 🙂
Բացում ենք wireshark֊ը, open tcap.cap file, նշում ենք application֊ից դրոն գնացող 160 երկարությամբ packet֊ը, ներքևի պատուհանում քլիք ենք անում data ֊ի վրա, հիմա աջ քլիք և ընտրում ենք “Show Packet Bytes …

Բացված պատուհանի ներքևի “Shown as” դաշտում ընտրում ենք “raw” և copy ենք անում data֊ն (նշված է նկարում կապույտով) և այդպես բոլոր 4 կոմունիկացիաների համար։

Սկզբնական pin-աչի (փորձարարական) կոդեր գրելու համար բավական է python ֊ը 😀

import pdb
import select
import socket
import sys

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
s3 = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s1.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s2.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s3.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

s.connect(('172.16.10.1', 8888))
s1.connect(('172.16.10.1', 8888))
s2.connect(('172.16.10.1', 8888))
s3.connect(('172.16.10.1', 8888))
socks = [s, s1, s2, s3]

magic_word='4954640000005200000005a7a90fb36ecd3fa2ca7ec48ca36004acef63f77157ab2f53e3f768ecd9e18547b8c22e21d01bfb6b3de325a27b8fb3acef63f77157ab2f53e3f768ecd9e185b7330fb7c95782fc3d67e7c3a66728dad8b59848c7670c94b29b54d2379e2e7a'.decode('hex')

magic_word1 = "495464000000520000007298c0389bc372a71a174bd1b514b3adacef63f77157ab2f53e3f768ecd9e18547b8c22e21d01bfb6b3de325a27b8fb3acef63f77157ab2f53e3f768ecd9e185b7330fb7c95782fc3d67e7c3a66728dad8b59848c7670c94b29b54d2379e2e7a".decode('hex')

magic_word2 = "4954640000005200000021e0c477c77394e85d66a98c2c922cc5acef63f77157ab2f53e3f768ecd9e18547b8c22e21d01bfb6b3de325a27b8fb3acef63f77157ab2f53e3f768ecd9e185b7330fb7c95782fc3d67e7c3a66728dad8b59848c7670c94b29b54d2379e2e7a".decode('hex')

magic_word3 = "495464000000580000009bf89049c926884d4f922b3b33ba7eceacef63f77157ab2f53e3f768ecd9e18547b8c22e21d01bfb6b3de325a27b8fb3acef63f77157ab2f53e3f768ecd9e185eb20be383aab05a8c2a71f2c906d93f72a85e7356effe1b8f5af097f9147f87e".decode('hex')

s.send(magic_word)
data = s.recv(106) 
sys.stdout.write(data)

s1.send(magic_word1)
data = s1.recv(300) 
sys.stdout.write(data)


s2.send(magic_word2)
data = s2.recv(300) 
sys.stdout.write(data)


s3.send(magic_word3)
sys.stdout.write(data)

try:
   while True:
      data = s3.recv(300) 
      sys.stdout.write(data)
except KeyboardInterrupt:
   s.close()
   s1.close()
   s2.close()
   s3.close()
sys.exit(0)

Կոդը թողարկում ենք հետևյալ կերպ․

sudo python get_stream.py > video_stream.raw

Արդյունքում ստանում ենք video_stream.raw վիդեո file֊ը, որը կարող ենք բացել ffplay ֊ով․

ffplay -f h264 video_stream.raw

Մնում է կատարել վերջին քայլը․ կոդերը պորտ անել C++ (հետագայում պետք է, որ կոդը շատ ավելի արագ աշխատի), գտնել real-time play անելու միջոց։
Ինչպես տեսնում ենք h264 codec֊ի հարցում չէինք սխալվել։

Իսկ դրսում մութ էր և համարյա ոչինչ չէր երևում, բայց կարևորն ամենևին էլ դա չէր 🙂

Կոտրում ենք quadcopter֊ի ip camera-ն reverse engineering -ի մեթոդներով, 10.0 out of 10 based on 4 ratings

Նշագրեր: , , , ,

Բաժին: Python, Ժեշտ, Ինֆորմացիոն Անվտանգություն, Ծրագրավորում

Կիսվել , տարածել , պահպանել

VN:F [1.9.20_1166]
Rating: 10.0/10 (4 votes cast)

Մեկնաբանեք

Կհաստատվեն միայն մեսրոպատառ հայերենով գրած մեկնաբանությունները

328