-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathnotes.txt
174 lines (152 loc) · 15.2 KB
/
notes.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
Steps Taken
===========
* Download and unzip and decompile source from apk ripped from phone
----Didn't find anything useful in source code, but found some keys and cloudfront URLs in non-source files
* Turn on bluetooth traffic capture on phone (output to wireshark format)
* Indirectly retrieve bluetooth traffic capture from phone using adb bugreport workaround
----LG stores the bluetooth traffic capture in the system dir where normal users cannot access it!
* Root old Nexus 5 and install Sony Headphones app on it
* Use rooted Nexus 5 (first time) to capture network traffic from SOny Headphones app (this network capture required rooting)
* Analyze network traffic, calls to cloudfront, then what appears to be downloads from an S3 bucket
* "Spoof" DNS server by setting phone to talk to laptop and using "dnsspoof" program with dnsspoof.conf file, redirect all cloudfront traffic back to the laptop
----dnschef is a way better application, it's up and running
--------dnschef proxies requests by default to google and selectively "cooks" the dns lookups for other domains
* There appears to be an issue establishing the SSL connection. The app says "no internet connection" when trying to connect to my laptop
----UPDATE: This wound up being crappy SSL code on my side it seems, the cert needed the domain names in SAN format.
----Use wireshark to sniff those packets and see what's up!
--------TLS session establishment fails, from some reading at the URL below it appears that the application is using certificate pinning
------------https://blog.securityevaluators.com/how-to-view-tls-traffic-in-androids-logs-6a42ca7a6e55
--------Might be server name identification issues instead.....
------------https://en.m.wikipedia.org/wiki/Server_Name_Indication
------------https://stephanheijl.com/rustls_sni.html
* Defeat certificate pinning
----UPDATE: Certificate pinning was never a thing
----I've found an RSA cert key in the extracted apk (using apktool with the full command below). The cert is (apparently) in pkcs7 format in binary encoding (using DER). It was a pain in the ass to figure this out.
----Cert location
--------"/home/egaebel/Programs/sony-headphones-hack/base-apk--apktool-output/original/META-INF/CERT.RSA"
------------UPDATE: This cert seems to just be what was used to sign the apk.
----apktool command
--------apktool d base.apk -o base-apk--apktool-output/
----Guide to identify apk file location for an app
--------https://gist.github.com/ctrl-freak/24ac0e61b7cf550a6945
----openssl command to convert pkcs7 cert from der to ascii
--------openssl pkcs7 -inform der -in CERT.RSA -text
----openssl command to test secure connection with server
--------openssl s_client -CAfile ../../../keys-and-certs/authority/server.crt -connect 192.168.1.64:443
----Next step (I think?) replace the pinned certificate in the APK with my own, repackage the app, self-sign the app, upload to nexus 5 and try again.
* Create mitm server (in rust) to also run on laptop, print out requests/responses
----UPDATE: No decryption needed, TLS libs do this by default of course
----Some decryption will be necessary, but using which keys?
--------The keys are ones that I set up. I create new key-certificate pairs for SSL spoofing and install the certs on my phone
* Add a self-signed certificate for my rust mitm server to actually execute the mitm attack
* Figure out request/response format and add this to the mitm server
----First just replay and listen
* Verify the whole system works end to end with no tampering
----Snoop on everything and ensure I can see it all working end-to-end
Steps To Take
==============
* Figure out audio file format!
----The audio section of the file has almost maximum entropy. It's probably encrypted (fucking why?) or maybe compressed? IDK how high entropy typically goes for compression algorithms though.
* Start tampering
----Swap out the shitty audio files from Sony with better ones (use a language besides english for this)
--------Make sure the new audio files aren't longer than the originals (shouldn't be hard, that's the goal anyway) there might be some buffer overflows that can happen in the headphones firmware
* Polish things up and make sure the headphones have the new audio loaded
* Be happier :D
Notes
=====
* https://en.m.wikipedia.org/wiki/Server_Name_Indication
* Using SAN with RusTLS: https://github.com/ctz/rustls/issues/331
* Looks like there might be a static IP for akamai CDN to serve the audio files?
----If so, I'll have to change some router settings.....
* My issues may all have stemmed from using a cert that only had a single domain name attached to it.
I can now make SAN certs and am serving bdcore and music-center traffic from my mitm server!
* Everything works with my server sitting in the middle now! I have grabbed the audio file, I need to reverse engineer its encoding.
* Big info dump on the binary audio file format
----There are 3 headers, separated by 0xFFs
----The audio portion is presumably the last part (it's huge and has no more 0xFF chains)
----The audio portion is DEFINITELY encrypted
--------This was initially shown by using the entropy measurement tool binwalk
--------This was backed up VERY heavily by looking through the decompiled apk file
------------Relevant files are under the package: com.sony.songpal.automagic in the files InformationHeader.java, l.java, and a.java (yes, they're obfuscated, but legible enough). Look in InformationHeader for the most info. It's possible to send unencrypted files. Otherwise the files are encrypted with DES3 (wtf?) or AES. (Where are the keys for that!?)
----It appears that the headers should be utf-8 encoded based on reading through the code in the decompiled java files referenced above, but reading them in that format isn't really panning out, so I'm not sure what's up there.
----Writing a small Java program to read the file might be in order.
----Spying on bluetooth traffic again might be a good idea.
----DEFINITELY look more closely at the mitm server responses to see what the specific format is before it's saved off. (Maybe something got changed when I saved the file?)
openssl req -new -addext "subjectAltName = DNS:bdcore-apr-lb.bda.ndmdhs.com,DNS:musiccenter-cdn.meta.ndmdhs.com,DNS:api.iac.meta.ndmdhs.com,DNS:mds.csx.sony.com,DNS:hc01.prc.sonydna.com,DNS:info.update.sony.net" -key server.key -out server-2.csr
openssl x509 -req -extfile <(printf "subjectAltName = DNS:bdcore-apr-lb.bda.ndmdhs.com,DNS:musiccenter-cdn.meta.ndmdhs.com,DNS:api.iac.meta.ndmdhs.com,DNS:mds.csx.sony.com,DNS:hc01.prc.sonydna.com,DNS:info.update.sony.net") -in server-2.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server-2.crt -days 9999 -sha256
* the info.xml files are what contain the encryption and decryption instructions. The info.xml file is NOT encrypted, it is zipped up for sending over the network. To read an example file you can run:
---- zcat saved-responses/1624652413984--https:----info.update.sony.net--HP002--MDRID294300--info--info.xml.binary
----Example output header:
zcat saved-responses/1624652413984--https:----info.update.sony.net--HP002--MDRID294300--info--info.xml.binary
eaid:ENC0003
daid:HAS0003
digest:c12fe043bbb38b8a8f93d8db7b452f6a28845103
<followed by a bunch of binary stuff that I may or may not care about.>
----The above example means that the binary file (presumably, right? Maybe just the rest of the info.xml file though) is encyrpted with AES (ENC0003) and the digest is computed with SHA-1 (HAS0003).
* The biggest thing here is that I've been trying to apply the code that reads info.xml to the audio binary files, which is completely wrong. I *think* that the encryption type and digest applies to the binary file. I guess I can potentially check the digest by computing the SHA-1, but I'm not sure if it's on the .bin file that I receive or a decrypted version, etc.
* It seems that updates are triggered/controlled via "package com.sony.songpal.mdr.j2objc.application.update.mtk.MtkUpdateController"
* This guide lays out what the Sony App *might* be doing
----https://medium.com/mindorks/how-to-pass-large-data-between-server-and-client-android-securely-345fed551651
----Basically, ship public key with app (store private key on server), generate symmetric key in-app, encrypt symmetric key with public key, send to server.
* From the certs headphones domain the app downloads a certificate!!
----https://certs-headphonesconnect-cfgdst-ore-pro.bda.ndmdhs.com/certificates
* Looking at where we actually parse what I think is the audio file:
----com.sony.songpal.automagic.a line 44, with a call to n.a(<bytes>)
* There are two possible paths forward:
----Figure out how to parse the audio binary file via 44:a: n.a(bytes) (noted above) or figure out how to decrypt the info.xml file.
* I think the above line 44 n.a call is a dead-end, it might just be parsing the disclaimer.....
* com.sony.songpal.mdr.j2objc.application.update.common.automagic.a appears to contain an AsyncTask that downloads a file.
* The AES cipher is initialized at: base-dex2jar.jar.src--files/com/sony/songpal/automagic/e.java
* A brief summary of what's going on:
----The info.xml files are encrypted. They appear to use AES with a hash verification (which will help me be sure I decrypted properly)
--------ENcryption cipher initialized at: /home/egaebel/workspace2/Programs/sony-headphones-hack/base-dex2jar.jar.src--files/com/sony/songpal/automagic/e.java
--------They use SecretKeySpec: https://developer.android.com/reference/javax/crypto/spec/SecretKeySpec
--------THEY HARDCODED THE KEY IN THE CONSTANT INT ARRAY 'c' IN THE ABOVE FILE!!!
private static final byte[] c = new byte[] {
79, -94, 121, -103, -1, -48, -117, 31, -28, -46,
96, -43, 123, 109, 60, 23 };
----I think the actual .*.bin audio files are unencrypted (they might be encrypted with the same key as the info.xml file though)
* info.xml comes from: https://info.update.sony.net/HP002/MDRID294300/info/info.xml
* The MAIN AUDIO UPDATING CONTROL POINT
----base-dex2jar.jar.src--files/com/sony/songpal/mdr/j2objc/application/update/mtk/MtkUpdateController.java
----Controls firmware updating and language updating!
* Call pattern working backwards starting from where the URI key is used:
----Starting. -- file k: class k.b method a line 479 return new k.a((String)param1HashMap.get("Version"), (String)param1HashMap.get("URI"), (String)param1HashMap.get("MAC"), (String)param1HashMap.get("ClientVersion"), bool);
----Class k.b retrieved from method k.a. -- file a: class a method a line 17 k.b b = k.a(paramString3, paramString4, paramString5, paramString6, paramString7);
----Method k.a returning instance of class k.b -- file k: class k method a line 352 public b a(String paramString1, String paramString2, String paramString3, String paramString4, String paramString5) {
----Method k.a calling methods a(a(...)) -- file k: class k method a line 353 Map<String, Object> map = a(a(paramString1, paramString2, paramString5));
----Method k.a called from OTHER(above) method k.a -- file k: class k method a line 36 private static Map<String, String> a(String paramString1, String paramString2, String paramString3) {
----Method k.a called from OTHER(2 above) method k.a with param from OTHER(1 above) k.a ---- file k: class k method a line 357 public Map<String, Object> a(Map<String, String> paramMap) {
----The audio object appears to be wrapped/returned here -- file a: class a method a line 26 return new b(AutoMagicClientErrorCode.OK, true, b.a(paramLangCode), paramString3, str, list);
----Class b in file b which is a value class that gets returned in the above call. -- file b: class b method constructor line 22 public b(AutoMagicClientErrorCode paramAutoMagicClientErrorCode, boolean paramBoolean, String paramString1, String paramString2, String paramString3, List<c> paramList) {
----Usage of class b (this.l is an instance of automagic.b) (not sure if it's key or not yet). -- file MtkUpdateController class MtkUpdateController method a line 756 ((b)l.a(this.l)).a(paramMdrLanguage);
----Following usage of class b, there's something that appears to be downloading. -- file file MtkUpdateController class MtkUpdateController method a line 779 this.k.a(paramArrayOfbyte, paramInt, A());
----UpdateCapability class/enum of interest. -- file UpdateCapability: class UpdateCapability.Target method <enum definition> line 78 public enum Target {
----Voice Guidance usage to create CsrUpdateController for voice guidance update. -- file com.sony.songpal.mdr.application.update.csr.a: class a method b line 25 return new CsrUpdateController(paramContext, paramc, UpdateCapability.Target.VOICE_GUIDANCE);
----CLass field k set in CsrUpdateController (similar to MtkUpdateController.....) construtor. Field k is type: com.sony.songpal.mdr.j2objc.application.update.common.automagic.a -- file CsrUpdateController class CsrUpdateController method construtor line 75 this.k = new com.sony.songpal.mdr.j2objc.application.update.common.automagic.a((b)new c());
----SHA1 digest comparison for downloaded audio file (I think this one is the audio one.....). -- file com.sony.songpal.mdr.j2objc.application.update.common.automagic.a class a method a line 83 if (str1.equals(DigestType.SHA1)) {
----
----
----
----Acquisition of an objet of type com.sony.songpal.mdr.j2objc.tandem.c in CsrUpdateController based on the UpdateCapability.Target type (VOICE_GUIDANCE is ordinal 2 I think). -- file: CsrUpdateController class CsrUpdateController method constructor line 67 this.f = (c)new a(paramc.O().G());
----
----
----
----Mention of "failing to 'generate' update file". Seems like a potential lead. -- file com/sony/songpal/mdr/application/update/csr.d class d method e line 305 d.a(this.b, new h(param1ArrayOfbyte));
----Construction of 'h' objet from line above(1 above). -- file com/sony/songpal/mdr/application/update/csr.d class h method constructor line 25 h(byte[] paramArrayOfbyte) {
* Brief summary of findings from above trace
----CsrUpdateController with UpdateCapability.Target.VOICE_GUIDANCE as a parameter is how the update is done.
----UpdateCapability.Target is under the "tandem" package, a brief search for "audio" uncovered the "Codec" class which is ALSO in tandem. Tandem appears to handle a lot of audio processing, so it is likely involved in decoding the audio blob I get.
----
* NOTE: The audio is DEFINITELY transformed somehow from the language .*.bin file before it is transmitted to the headphones. A bluetooth packet sniff shows that certain byte patterns are completely missing.
Current Focus (Where I left off)
================================
* Found encryption and response reading files located under:
----/base-dex2jar.jar.src--files/com/sony/songpal
* Much of the key files appear to be under:
----/base-dex2jar.jar.src--files/com/sony/songpal/automagic
----In particular, InformationHeader.java and base-dex2jar.jar.src--files/com/sony/songpal/automagic/l.java (that's a lowercase L)
* There is AES, DES3, and NONE for encryption types.
----They're using AES in ECB mode with no padding, this is indicated at the top of the info.xml file. THe info.xml has the xml portions encrypted.
* It seems like maybe the responses aren't being read properly in Rust since they're Java objects?
----Wrote ResponseReader java program to try and resolve this. Had to instal XmlPuller to get the Java code working. Used https://github.com/stefanhaustein/kxml2/issues/5 for reference to get it working with maven.