# **Middle Road 中間道** 當兩邊都不行的時候,你應該試試中庸之道。從字面上看。 Attachment: [middle-road_e5e04f86fca99ad4d6bd959137562820.zip](https://file.hkcert22.pwnable.hk/middle-road_e5e04f86fca99ad4d6bd959137562820.zip) ## Analyze --------------------------------------- Unzip apk. Get classes.dex. Use dex2jar to convert classes.dex to classes.jar. Use jd-gui to de-compile classes.jar. ![](https://i.imgur.com/dw9qAIO.png) We found that some string are encrypted, so we need to call the **DecryptString.decryptString()** to decrypt. So we finally got the code. ![](https://i.imgur.com/LKmo6PB.png) We start to analysis the code and the work flow. First, get the RSA key parameters from the **/getKey** api. ![](https://i.imgur.com/6RueFmg.png) It seems to encrypt the AES key with the RSA and send to api **/getFlag**. ![](https://i.imgur.com/X66Qr0h.png) It seems to create the RSA public key based on information got from the **/getKey** api. --------------------------------------- Let's try the app.<br> ![](https://i.imgur.com/3smI3WE.png) ![](https://i.imgur.com/xtg00U4.png) First connect to the mitm proxy and install the decrypt CA on android phone. ![](https://i.imgur.com/lnZklva.png) Press the Get Flag key button.<br> Then we can see the https traffic from the app.<br> First, get the RSA key parameters from the **/getKey** api. ``` POST https://middle-road.hkcert22.pwnable.hk:4433/getKey HTTP/1.1 Content-Type: application/x-www-form-urlencoded Content-Length: 13 Host: middle-road.hkcert22.pwnable.hk:4433 Connection: Keep-Alive Accept-Encoding: gzip User-Agent: okhttp/4.10.0 code=32933185 ``` ``` HTTP/1.1 200 OK Content-Type: application/json Content-Length: 1262 {"rsa_e":"65537","rsa_n":"630791816259958205673016318224240858751136661280471188438412165447232723393914969097252787347626988321917000774733737322494449818919125260958648800263996495910600551815631575048264209421462043584096144705567721409215513579478663560574161504773513061565180193507862861434089810710400523178487707581275521520577795243670305564926506609230306209563205662716453787880405129570055856427308236053212836347739247466071945057090182041305420394821265067125791719709125731551049817247167239327835167637907528587926920743330992051512069741151473403496874341619954964058090710784149252382410520680830775602521185581289313125400239124506053645292697781762946657933842988207613736173565401062037912720334806569630800708139852384275452749639040442985616234470227456393754010233488011575792824583072056560579111260482563707424996590173055927167750726725710388553693042649995924410781689294007749036207493130036597566481094607536687014042687135417672264358144088925155507117340622725123068145705074122591740835971852863145356002433770919362756255797144813740238108754874435077344162655866048790680086970052985926804608808427216687157188698375760724339352425399301906941294728294761952114211421984549491710888098698226680830192527065831968050134441967"} ``` Second, send the encrypted AES key to the **/getFlag** api. ``` POST https://middle-road.hkcert22.pwnable.hk:4433/getFlag HTTP/1.1 Content-Type: application/x-www-form-urlencoded Content-Length: 781 Host: middle-road.hkcert22.pwnable.hk:4433 Connection: Keep-Alive Accept-Encoding: gzip User-Agent: okhttp/4.10.0 key=Z4Qhb9q9prV6ibvXMtSbS%2BivRVf8dI%2BJK1WTbHPph0ApYmfku4nw8M%2FDQ49qjyysuWJIDUZtoBA4%0AXaFFCUh5teB42eSjo4ngrC%2BIxV%2FvlE%2BUmVEPN8FAnpkicpl6OrYXy%2FRsqABGVc1F32Cfn%2FwS1Yhv%0AXsHCNj4RwUs731CvxCckfVWZQfsgfBe%2FAJxKIlAdgb2%2BF6SuQTlqFDzN3wfAPQOGFeP5hDQ%2FwaSM%0AF53WyandV0qigD3ciM50zufBBr6LX7WZ%2FY1rXuVIKZ%2BaZPhZF88pbX%2FSfEXT2nRrau31149p%2FnrG%0A9Jkqji4IRIDF578hIqGLcmh7r%2BXzwgjBPoandqW2bG%2BROh3XWCIMz0L0WvV6cYU94iYR0LcuAVvg%0AwyZ2VJ1nlfecX%2FAMJvsfO1lQlvejxkwLDZi9choBzmRbAiwpOq7O7ToUHyC%2FfDn2c0HhO15SVLNZ%0At%2BJVwSGAlvSK9E7kJ9cWozFuRoh%2FGZ5hrhP3J3mOnH0N3vrQ2lF3w9I9tYDetRWMlPzmST8JjtZL%0A2Pg6NcSiDwjrHWvZZPiqjCOmY6A9vhIV2pxeVvQqNAXKD33k1b4shxpchnvQs3Aaz2NzTKef3i%2B7%0Ap%2FE1SlD4FjD5uKMBqbaqDPt7rhdzWceXbni4y3vAJz2Ro93dyIwvXf%2FOcOCTVjC2TV%2FZ4ioCQx4%3D%0A&code=22011917 ``` ``` HTTP/1.1 200 OK Content-Type: application/json Content-Length: 164 {"aes_cbc_iv":"XOsBZtM06DHFiIUgrwvNmw==","enc_flag":"Oi0nLfie+Hu8ZYzoAgwSbIvsWzByAT34J4GI+r08zyyPZkTUcSkKmUxX8Iv/EHDE0hNtEfockTG3ZUfu0amSFIwbWgWpsmRBwbu+MP3KNNE="} ``` Finally, server will return the IV and encrypted flag. Solution ================ We can perform the **M**an-**I**n-**T**he-**M**iddle attack to control the encryption key. ### Step 1: Generate RSA public key Server will return the RSA public key parameters, we can use the following code to generate the RSA public key. ```java Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding"); BigInteger rsa_n = new BigInteger("630791816259958205673016318224240858751136661280471188438412165447232723393914969097252787347626988321917000774733737322494449818919125260958648800263996495910600551815631575048264209421462043584096144705567721409215513579478663560574161504773513061565180193507862861434089810710400523178487707581275521520577795243670305564926506609230306209563205662716453787880405129570055856427308236053212836347739247466071945057090182041305420394821265067125791719709125731551049817247167239327835167637907528587926920743330992051512069741151473403496874341619954964058090710784149252382410520680830775602521185581289313125400239124506053645292697781762946657933842988207613736173565401062037912720334806569630800708139852384275452749639040442985616234470227456393754010233488011575792824583072056560579111260482563707424996590173055927167750726725710388553693042649995924410781689294007749036207493130036597566481094607536687014042687135417672264358144088925155507117340622725123068145705074122591740835971852863145356002433770919362756255797144813740238108754874435077344162655866048790680086970052985926804608808427216687157188698375760724339352425399301906941294728294761952114211421984549491710888098698226680830192527065831968050134441967"); BigInteger rsa_e = new BigInteger("65537");//e KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPublicKeySpec rSAPublicKeySpec = new RSAPublicKeySpec(rsa_n, rsa_e); cipher.init(1, kf.generatePublic(rSAPublicKeySpec)); ``` ### Step 2: Generate AES key ```java byte[] keyBytes= keyGenerator.generateKey().getEncoded(); System.out.println("AES Key(Hex): " + bytesToHex(keyBytes)); ``` ``` AES Key(Hex): 956036706E73E3DC33FE38F02FEE92211D880EEC688A88402BDE4B50EED25CCD ``` ### Step 3: Encrypt AES key with RSA public key ```java BASE64Encoder encoder = new BASE64Encoder(); byte[] arrayOfByte = cipher.doFinal(keyBytes); System.out.println("Encrypted AES Key(Base64): " + encoder.encode(arrayOfByte)); ``` ``` Encrypted AES Key(Base64): QR8BoTJEFV05ZSpzpP1J57j4iQ4bFE46Hv/5lhP9VWsWvaoLs8jjpjfYwn0LeAXDKLRF+/RmxMTi GuAat2TeYuLlELy8socD93u5MEzXGDGVOQxqDJrLL4pYAO2Ry0pzHeEpIr1PhwnFoSlSvr0EjSPz mMREWoMTXpiW+4GDZbAL6RDb4aqkhXmR84F1jFxaiY6BuTXQt9n5GciMom5YWnyss1sFqPwNY8NM MBXeDHsm4IAA0anmy1rFIzdAZyPDfTzeG7F9FNG88uxn2KoUzE/FVXFZivQaZf/uIPifmLhUnMLb t7WXvy0qOuz/VkSZ+utUCorPFJcFFA+wYgKuzNZCTjyhD5g5GhjUsB0xZnpa+OQYyOaemVxnxR4I zES43+scsILXJMLrnqR3gIfuna086zhag3kcuP+uy9LGoINbgHwOZX7Q/bNb3iBXpnS/0k2eOq/X ADfIzM9G9EVOG8XdSrpBpxUmmJPQW/oYkXJzbl1SZfqcDKhzatXDL+uW4/wBaZ9rxjjE7aGIW5Yk gaDOebMVu6Av4/xTyRZYzKlGrMYOGv+qKqFOEMFUlVvXVdCwt8NkzfTvLZVzZ61CrlfbZQb/OJMY oJDJaobjbRO2aXzutbc2N1iv7VNYvdy1Xh2ui9iteqk4/HR0Lv52KMStBXopOLHKvSB5sAU6pSI= ``` ### Step 4: Send encrypted AES key to server #### Intercept the request and replace the encrypted AES key with the one we generated. The server is also validate the TOTP code and the TOTP code is valid for 30 seconds only, so we need to ~~generate the TOTP code and replace it with the one we generated~~. As I already been single for many years, I can edit the packet and replace the data within a second. :P ![](https://i.imgur.com/8NA4c12.png) ``` POST https://middle-road.hkcert22.pwnable.hk:4433/getFlag HTTP/1.1 Content-Type: application/x-www-form-urlencoded Content-Length: 796 Host: middle-road.hkcert22.pwnable.hk:4433 Connection: Keep-Alive Accept-Encoding: gzip User-Agent: okhttp/4.10.0 key=QR8BoTJEFV05ZSpzpP1J57j4iQ4bFE46Hv%2F5lhP9VWsWvaoLs8jjpjfYwn0LeAXDKLRF%2B%2FRmxMTi%0D%0AGuAat2TeYuLlELy8socD93u5MEzXGDGVOQxqDJrLL4pYAO2Ry0pzHeEpIr1PhwnFoSlSvr0EjSPz%0D%0AmMREWoMTXpiW%2B4GDZbAL6RDb4aqkhXmR84F1jFxaiY6BuTXQt9n5GciMom5YWnyss1sFqPwNY8NM%0D%0AMBXeDHsm4IAA0anmy1rFIzdAZyPDfTzeG7F9FNG88uxn2KoUzE%2FFVXFZivQaZf%2FuIPifmLhUnMLb%0D%0At7WXvy0qOuz%2FVkSZ%2ButUCorPFJcFFA%2BwYgKuzNZCTjyhD5g5GhjUsB0xZnpa%2BOQYyOaemVxnxR4I%0D%0AzES43%2BscsILXJMLrnqR3gIfuna086zhag3kcuP%2Buy9LGoINbgHwOZX7Q%2FbNb3iBXpnS%2F0k2eOq%2FX%0D%0AADfIzM9G9EVOG8XdSrpBpxUmmJPQW%2FoYkXJzbl1SZfqcDKhzatXDL%2BuW4%2FwBaZ9rxjjE7aGIW5Yk%0D%0AgaDOebMVu6Av4%2FxTyRZYzKlGrMYOGv%2BqKqFOEMFUlVvXVdCwt8NkzfTvLZVzZ61CrlfbZQb%2FOJMY%0D%0AoJDJaobjbRO2aXzutbc2N1iv7VNYvdy1Xh2ui9iteqk4%2FHR0Lv52KMStBXopOLHKvSB5sAU6pSI%3D&code=70690328 ``` ``` HTTP/1.1 200 OK Content-Type: application/json Content-Length: 164 {"aes_cbc_iv":"emkizYvQp+CrvuWwsWuY7A==","enc_flag":"On2zwMGWGmKhDXNxCWBAYuuARVd39Pl7wAVEW1zSFrMTQhoXrqBH3Exxlj6ZNWzJ52z7n7I8DNFRe8G3iRQ3N8y2edaY7Dyce++PRMf2+fE="} ``` ### Step 5: Decrypt encrypted flag with AES key We can decrypt the encrypted flag with the AES key we generated. The encryption method is AES-256-CBC. | | | | ----------- | ----------- | | AES Key | 956036706E73E3DC33FE38F02FEE92211D880EEC688A88402BDE4B50EED25CCD | | IV | emkizYvQp+CrvuWwsWuY7A== | | Encrypted_flag | On2zwMGWGmKhDXNxCWBAYuuARVd39Pl7wAVEW1zSFrMTQhoXrqBH3Exxlj6ZNWzJ52z7n7I8DNFRe8G3iRQ3N8y2edaY7Dyce++PRMf2+fE= | ![](https://i.imgur.com/mMesham.png) ### Step 6: Got the flag >hkcert22{CLi3NT_can_B3_reverSE_EnGIN33red_by_0ne_W4y_or_aNoTh3r}