Swing VPN app is a DDOS botnet
tldr: Swing VPN is using its user base to DDOS sites using its users as a an attack botnet.
Introduction
It all started with a friend of mine complaining that his phone was doing a request to a specific app every few seconds. Initial assumption was that the phone was infected with a virus but a 2 minute investigation showed that all requests went from ‘Swing VPN’ app which were legitimately installed on the phone as VPN service. It was making requests to specific website that my friend never used and had specific data inside request payload indicating its intent send requests to an endpoint that would be heavily demanding on resources of that site.
The site that was targeted on my friends phone and later on my phones was https://turkmenistanairlines.tm. Request was sent about every 10 seconds and was sent specifically to this search endpoint:
https://turkmenistanairlines.tm/tm/flights/search?_token=J8SxUX2Qwzltw4LiHsRHTCtfthgBYxf4hyI8oNly&search_type=internal&departPort=TAZ&arrivalPort=CRZ&tripType=rt&departDate=4%2F22%2F2023&arrivalDate=5%2F4%2F2023&adult=1&child=0&infant=0&is_cship=on
The specificity of this URL clearly indicates that this is not a mistake nor is it method to ping a site to check for errors with internet connection. Later in this document I will show and hopefully prove malicious intent of the creator of this application by inspecting how it all works and infrastructure behind it.
Requests
Let’s start with examining requests and see what exactly is happening when we run Swing VPN on our phone. I am using a physical phone connected to a computer using a usb wire and a program named ‘scrcpy’ to mirror screen of my phone to the screen of my computer. This is done just simplify screenshot taking and is not required for the analysis.
First let’s start with simple inspection and verification that the request made to airlines website is done by the ‘Swing VPN’ app. For this I will use an android app pcapdroid to capture all requests by the apps and see who is responsible for which request. There is no need for additional plugins or apps to see the details about the requests as I will use different tools for those tasks. Current goal is to link each request with specific app. I want to mention that this phone have only standard android apps and swing. In this video pcapdroid has been just installed and I waited some time for google play to finish with all of its statics and other request so that they will be less non related requests in the log.
From the video we can clearly see that this ‘Swing VPN’ app does some type of request to the site turkmenistanairlines.tm. From it we cannot clearly conclude that the app does something malicious but this is left for later analysis. For now the proof that the request are originated from the app that I am inspecting is good enough. Now we can safely proceed to a deeper dive into functionality of the app.
The next step is to figure out what exactly Swing VPN is trying to do by sending these requests. For these I will use mitmproxy to capture all data sent and see what the purpose of those requests.
In this video ‘Swing VPN’ is just freshly installed from the Play Store and being monitored by mitmproxy. After app startup, language selection and acceptance of privacy policy the app starts to figure out ‘real IP address’ by doing a request to both google and bing with query “what+is+my+ip”. My guess is that the app just parses the returned HTML and figures IP from those responses.
These ip request needed, as we will see later, to figure out which config files to load. The app loads different configs and does different actions based on not only country or region of the user but also on the internet provider within the region.
After the required config type is identified in this video the Swing VPN does a couple of requests to 2 different config files stored in personal google drive account of the app creator. The config files are requested from specific personal servers, a few github repositories or a couple google drive accounts. My guess is that config file location could be determined by daytime but I have not spent any time to verify that as it is not important. As soon as configs are retrieved the app connects to ad network to load ads. This concludes the app initialization process. After this app stores data into a local cache and proceeds to DDOS a site returned from the config.
And this is how the app behaves over time after being close. Hint it still tries to do it DDOS even though it is not being used.
From this log we can see that the app is requesting a specific endpoint of ’tm/flights/search’. Since flight search is quite intensive tasks that requires a lot of databases and server resources then it is clear that that the goal is to stress server out of resources so that normal users won’t be able to acess it when needed. And even though 1 request per 10 seconds might seem that it does not doing DDOS the problem is in amount of install base. Currently in the beginning of June 2023 it has over 5 million install base on android and even if you split it by 10 it has a potention of 500k RPS. Which is quite impressive to be able to handle for a small site written probably in PHP.
Sidenote: The app does not respect privacy
While doing this little investigation I found out that the app does not care about privacy. It probably added the button ‘I Accept the privacy policy’ just to make playstore accept the app but in reality it is just a button that does not do anything. In the video above I installed a fresh version of Swing VPN from playstore and then instead of pressing ‘I Accept the privacy policy’ button I pressed which leads to ‘Privacy Policy’ screen. And while I was skimming though the policy the app already started sending my data to ad network. At the same time it was downloading configurations with information about which site to DDOS and started executing the DDOS routine while I as reading the ‘Privacy Policy’. After I was done reading I just pressed back a couple time thus informing the app that I am not agreeing to the term but it is already late. The act of opening the app is enough for it start it’s DDOS actions.
The functionality of the configurations
So we just went through outer look of how the app app does it actions related to DDOS’ing other sites. But I could have installed some other app in the background maybe with similar icon which did all the nasty stuff just to fool you. So now let’s dive deeper inside the app and the actual configurations stored in the app which you can do yourself to verify that it is indeed the ‘Swing VPN - Fast VPN Proxy’ that is responsible for all this actions.
Some general information about android apk:
VERSION USED: swing-vpn-1-8-4.apk
APK SIZE: 32.5 MiB
INSTALL BASE ON PLAY STORE: 5+ million users
LINK TO PLAY STORE: https://play.google.com/store/apps/details?id=com.switchvpn.app&hl=en_US
ANDROID APP CREATOR: Limestone Software Solutions
LAUNCH DATE: 2020-10-06
The app uses 2 custom native libraries to just obfuscate it’s function and complicate the reverse engineering process. This files are libnativelib.so and libbony.so. We will use libnativelib.so as it will be enough to decrypt and deobfuscate the data.
Configuration is downloaded from github, google drive or a custom host. In my research I checked only github and google drive since it was enough to check the hypothesis.
Github
Let’s start with github. First of all there are at least 2 different github accounts used to store the configurations for the app. I cloned both the repositories just in case somebody needs the historical data if they are modified or deleted. It looks like both repositories are about 6 month old so it won’t be something unexpected if new repositories are created soon. These repositories are:
https://github.com/Javaidakhtar576/swinglite_new
https://github.com/githubfunc/cocomo
The general format of the message is some encoded string surrounded by curly braces. You could have seen one example of these in the second video. Here is how it looks like.
And here is a the text version of one of the configs requested during startup.
{{{30766d755274445150474d656e6770435276786e6f15631c6056373b4f673c5935726c225378450752474d666d65704850707a6a6e48634f6355373d483b3a5631736e23527b425b54434b606a6a761955257f3a6f48624d6006303e4c6f3a5536716b715774475451444c616865754954767e3a6947664f6454306c4c693f5630756d25562f420754424e616d36724d507f7b3d6f46631a650132394c673a55367f6b7756784157554c4a34686b754e55747d6e6d13634b6051353f486e395334736e7556294257544248346837764255777e3b6b1667186656336c4c6e3a0232276f245328465751134c346c66744955277d6d6912644d6403306b4c3c3c0030746f75547a425554164a326862764c54257f366b4567496006363648683f5832276e7953284352554d48656865744855207c3d6a1166486407303a4e3b3d5630276f78577d4601514d4e616d62724d51727b3d6b47674e645530384c3a3a55362268795778435b554149676c6670185177783a6d13624d6051303a4d3f3c0030746f24567d410754174a376862754c55737f3e6b46674b6006363648683f5933226e77537d4754554d49306960754855227d3d6a1166486407303a4e6e3d5630766b735328460151444f636c65724351277e3d6b16661c6454323e4d6e3e0333746e775229475451444c616862751d54247d3c6911651b6456313d4d6a3d0331736b735328460151464e616c6b724d54277f3a6a11671f6452323e48683f5232276f755328475a511349606961751955237d38681367486051356e486e380434736b22527b425b54434b606b63764a54247e3b6f48624d6006363c48683e5432276b76572b4254554d4866686a771955277c3b6813664e655130364c3d3d5834736a20527b475b50454e346c65761855717e3b6a49661c6454323848683f5232276f745328475a511348626860744e57717d69681466406451306c4c693d0032776f78577b430255434e616d36724d507e7b3d6f46631a640333384d69380536776b7657294354554448666860764d55707c3b6947664e6457343d4966390235716b735275460154434b616866774855227e3d69496748640433394e3a3b0536226a785574430155164861683175485571793b6c4462186153343d483b390230756f78577a420254114a326832764a55247e3b6915674e640333694c3c3a0434226a2057294354554448666860714f507f793b6c1562186004343d4d6f3c0330276f2556784301551749606864774d55227f3a6b44651b6455333d4c683a5436226a715328460551134d636c66711a51777c3b69126741645c313d4d683e0530726e73567c4200541648666832764e55277f6c6b1667186006363648683f5832276e7953284200554749666960744855777d3c6b1466496452306a486e385534736b735275460155434a66686b764a55207e3d6b12674a6601336d4c6b3a5632276f245328475451444c616831751d54737d3c691466496452313b486e385534736f79577d430755474b606d36721951717f3b6b16674a645433694c3a3b0736226a7657794357544c4c3268677542552379366d13624d6051303a4c383d0730236f22527b475050454e616c6b724d54257f3a6b46671b645c323e4c6b3a5532276f245328475451444c616963751e55747c3d681466406553313f486e385534736b735275460154414a626864764a55277f696b45674c6006363648683e0332726e7757784301541049676865754a54777d38694362186106343d486e395334736e75577e425355434b676862774d51277a6e6f48631a6057373e4d6e3a5136756b71577e430651134d696c66714f5120793b694866406401303a4f6f3d0331736e77567c430156104a336964774b51277a6e6f48621f6006376948683a07367f6a2757744055554d49616962754854777f6e6947671b6557333f486e385534736a70527b465650454a656866761d55227c3c6b16661a655d33394d68385436776b765675405656114c616d37714f5074793b6d4262186455303e4c673d0333726f74577b430554424b616a6b761f54247e3b6811641c6701373e493b3e03337e6e77537d4754551748626830754856767d3c6813671c6456313d4e3b3d5631726e75557f405357474e616d36724d507e7b3d6f46631a645d333d4c383a0235246a7056284250554d49616a31751d54767c3d6b4965416051356e486e380434736b22527b4206544349606862774d54237f3a6a48661d6006363648683f5935206a72522b4306564248656966754f55777e6c6846644f6506353c4e6e3e5735706f7756784150514649666b667748567e7c3d6e49654e6101323f4f6c380032276e7953284351554c4b606861744f54737d3c6813671b6757333f486e385534736a7054784250554448326a65764954777f6e6e16671f6501316a4c673a593620697752284105574c49646a30774956277f3f6c47664b645731394f683d5832276e74527b465650454a646863754c55227e3d6a13671b6506323f4f6a395832276f2453284657504c4d616860771e56747e3f6914654e6651306b4d68380532726e72552f405b574d4f306960751e50777a3f6b16621b610430384c6e3950357f6876567b425451134c346c66754a55717e3a691267186555303a4d6e3c0533716c71557a4601514d4e616d66734b57227e376840621a670430364e663b5236756a73557d415356424b606961751951237e3b694565496551306c493f3d5132726c77557a4006544c4a666a31724d51727b3d6b146718670133394d683b0736226b77562b405057414b636c667018517778386a16664a650631384f6e3c5533776d77567c4153541148346d667749567e7c6e6a4267496107333b4c673f0535716973542e4157544048626b37754f5624783a6d13624d605130384c683e0530746e73577f420055454b606a60754f51277a6e6f48621f6701326d4c6c3a5137236a23542b400055144a616963771d55277f6e68476518665735374c6e3e0235716d23567f425055174f616861724255727d3c6a4866406006376948683a043676697657744254541748666966744e5177786c6d136418615133694d6f390234246b73567e425257444a666965774955227e3d6a4964186700373e493b3e0334276f77547e425554114c616c31714f55727d6a6a14661d655131394c693c0231726c7155794601514d4e616a65734d56717e3c6a11661c6006376948683a043676697657744254541748666966744e56757e396a1462186106343d4e6e3802337e6e725779435a55444e616c6b724d55207f376849671b6506323a4c6f3b03372469735578405651134d696c66774f50777e366814671c6403313f486e395334736f76562e410254424b616961764a54277e3c6914641c600636364868380333276923562b435154114c616c31714f54707c39691166406557303a486e385531256b73567c425454464a61686b764a55257b3d6e40631a6100373e48663e0337226b7557754357544c48666b62754854777c3a6947664e645d326a4c6d3d5230746b735328460150454e346c65774a547e7f3b6b1266186407313a4c3c3b0336246a7057754155554748676861714f507f793b6d13624d6051313a4d6c3d0030706e75567c405b54454a356962774b51277a6e6f48631a6057373e4d6f3b5836256a7456754353574548336966744f55257c3b6c1662186106343d486e395334736e745779420754464b676862744255777e3d6a4867486506363e48683f5232276e77567c475a511349666966751a5476793b6c44674a6051303a4c3d3d0730736f22567c420750454f696c65734e51277b6c6f48674a6452336b4f6e3a5136736a705328460551134d626d64714f5120793b694366406500333b4c3c3d5230746b735328460151464f636c65724351277e3d6b1267496404313f4c3a3e0333746e775229475451444c616961744f55207f6e6947671b6557343d49663e5431256b73577c430154104e616d36724d55767e3b6a15661c65013636483c3e5737256b705628430655454866686a751d54767c3d6916664f645230364d6e3d5330236f24567c430250164b67686a721954257f6b6f4567416457336e4c6d3a5037256b76537e4255554d48626966754e552478366a41671a645c306d4c693d5135276d20532e4102551449666b30734d567f7e386a40674b6504323b496e385436776822562b405457404b676a67744955737c3d6946661f665133364d3f3d5935756f795729405351144a356a32764354777b396a49671b6403323e4c693a5035716b7156784256554d4d376836754354717d3c6813664f6452306c486a3d0030746e7156784301554349636831774d54257a6b6815651f6751373a4c6b3b0337276a25562c435755444b63686b744f5471786d6b146518670634394d683c0230236e71557d435355474a666d6a774d54257b396b15671b6500333d4d683b0534256a745675435350454d676c61704f5773783b6c13621d61513239496e380435736a72527f425b55454b6168377749557f7f6c6915671f6504333949673f0232226f77552c4652514d4d616a62704f5075783b6c14621c6452303b4d693d5331756a255378460554444a306837764355257a6b6e1163416452336b4c6c3a5936706b71527c4656511748336967764255767c3a694666486553356b4c3a3d5134736b22527b425754424b676830761955257b3d6e40631a665c31394f6e3e0337736e79567a4754544d49616831714f507f793b6946671a6557313f4d6f3855347e6b27577d430055454a68686a764a55707f366a4966186403336b4c6b3a5137276a7957784301554d49606c6a7449552379366811664c605c30394c3b3d5630766f79577d430250114b606862764e54277f3c6b426248675432384c3c3a5336226a20527c410550404b60693576485624783b6a16671f6506306c4d683c5835756d2256294052554449616a30754b57247e3b6b1366186453333b4e68395137766a735275430754414a336d35754257227d6e6847621c6550303a4c6d3c0230726f79552f430755174b636862734255777f6a6a15671b6506336b4c6b3a5432236a7157744256551649616960764d55257c3b6811634c6757323e4f66395930706e73577b425355414a62686b754f55717e3d6a15624a6601303e4f3b3e0737256b7757784256564c49336964754850237c3b6811621c6457303a4d6c3d0731736e75547d425b55434a666d6a734b51227a3d6913621a610637394968380733276f7552284655511748626966744f55277c3f6916664d6657303e4d683d0335276a74527c470156414f676c62734d57237a3d6e11621a6101373a4c6b3a0537226a795675465b50164c656867751e55277d6e6911634c615334394c3c3d5130776f70562c430751134f636c61761f54247c696b49661d6453336e4d6a3f5536716a205328475a511348376861744955247d36691162186106343d4e6b3f0333756b7357744656554c4e616962774d55727b3d6e40631a645332384d6e3b5837246f24537e4702544c49666966751f55237d3c694066486550313b4c6d3d5130706f78577b425654174a326862774c51707e3b6b4763486504336a483c3a0736726a25572f4307544c49606c6b744e55707d386813661b640035694f3a3c00307e6f23567c4254511348696d30754c54767c3a6842621a6703323b4d3b3a5437256b725275415a55414a306967764f57247e3d6b14671a6455313b4c3f3d5832736c78572e420551434a306937741f50767f696944674b6552373a4d693a02367f6b77572b4307564749676936744d5570786d6947664f6557303a4d6e3d5130706f22527f420754424b636866774d54257c3f6b45661a6504366a4f6e385935746e7357294254541348336962754c55207e39694167186557356b4e6f3e0233226b77577d430154174b636b63771f547e7f3a6e47661a6504373a4c6e3a02377e6a7456284252574c4862696075485023783d6d1263186655353d496e390335736d77537b475a51454f606c61764e54277e3d6b436641640333694e6e3a5937256a70527c4653514d4d616a6270495170783b6b4863186153353d496f395930706f75577c425655434f376d66724955247f376b43674b6404366a496a3e0736776a20572c4357554649676d32704d51737d696814654e6450313c4c3f3d5631716a25562f425450454e346c65764255227e3b6b4267486404373e493b3e03342068705475475454454b376c31714f54707d386b4266486550313b486e385533256b7354744255554d4a33686b7643557f7b696e1663496100373c483d390436776a2057754302541449606c647743567179396c166341605d353f4967390433766f78562c470551434f686c67771850237a3b6f43631c6603323c4d6a3a54362269725774435457434833696071425070783a6c49624f61503539486c395732256d79557d405756104e346c67764355777f6d6b16631c665c33394c693a5336716e25532e415555404961686b7519557079366c1663406152346a496c395135716b245379465a57444a626861764e54277f366f45621b6101363b483f3f0033236e77537d4754574548356937751d55207d6e6916624e6156346a496c390434206c765629425454434a356960774c517e7d6a6815631c6103363c483f3f5833756e75542f410256144d656d60711d51757f38681567416404303a4f6b3d0330736d235629430750114f666d64734851707a3c6e13631c605331374e3d390534736879537d4756554448336830754851757f3e6912661b64013069483c390432726f79577b425554134a666c31734e507f7a3e6f44621c6055363c483f3f58327e69765729435055164961683671425070783a6c49624f61503539486e395334736d25562f
435054174a34686b764e51717a3a6f44621c6000376d4f6d3a5136706a71577e425154104c636a6a7649517578386c15624f61533436486c3f0731716e715675420057404a666865741d55777e3b6f45621b6101363b483f3f0033236e755379410657404b676a32771a51207939694266486401303a486c3f5830746f72562b425550174e636a64761854277f696b47671b6054363d496b3f5932706f75537f465651464d636c64764e55747d3f69166718640334694969380535766b24537a470550454e346c65744255717e6e6b43674b6457333d483c3f0232706f75532e470757444833686a74485424786b6d156440645d303b4d6e3d5030236f755279475b51474e336c67744e547e7e3f6b46671b675c33394c68385336776b71537e465350104d646c6a704e507379396d46644a6600333b4e383f5334246b7156754253544c4a666c67744855227f3c6b4167486052373c4e693a5037276a23577c435351474d626d65704c512278396d40631d61563539496f395135706a70537f465a56134a356865761f55727f3a6f11641d6403333a4c6b3b0336776e235274465550144c326d67704b51777e6d6843674c}}}
The decoding code is located in the native libs directory with the name libnativelib.so. I reverse engineered the decoding algorithm and wrote is the python code that does the reversing. You can download it here: decode.py
In order to decode that message store it into a file, let’s say ‘data.txt’ and just run that file on it like this:
python decode.py data.txt
The decoding string string will be put into stdout of the terminal and you if you want to save it to a file just redirect the output to the output file. For example:
python decode.py data.txt > data.decoded.txt
If we run this decoder on the encoded message provided above the output of it will be:
{
"adsMode": "Remote",
"adsSingleIdMode": "1",
"summaryAdLocal": "0",
"timeLimitedMode": "1",
"timeLimitedConnection": "0",
"defaultTimeLimit": "5",
"minTimeLimit": "3",
"extendTimeSmall": "15",
"extendTimeBig": "30",
"report": "1",
"fixedServer": "1",
"repair": "0",
"summary": "0",
"adsTest": "0",
"screenMirroring": "1",
"hotspot": "1",
"adsDisabledFirst": "0",
"adsDisabledPeriod": "0",
"drawerCodeItemEnabled": "0",
"disconnectDialogEnabled": "0",
"summaryScreenEnabled": "0",
"reportScreenEnabled": "0",
"youtubeChan": "",
"telegramChan": "",
"livechat": "https://demolivechat.com/",
"email": "",
"telegram": "",
"whatsapp": "",
"facebook": "",
"instagram": "",
"twitter": "",
"tiktok": "",
"fakeServerList": "1",
"fakeServerListP": "1",
"fakeServerListPP": "1",
"fakeServerListPPS": "0",
"fakeServerListVIP": "0",
"fakeServerListGP": "0",
"gdServers": "1Wg3kZfrbbZxNz3BX1faZ1UQwPR3I3sVC",
"gdServersTP": "1AjsNBfyj5asMmagR2JDwKDYF9jdvTgMu",
"gdServersPP": "142dHQVc_Bmt3Cs_AZ8wZ90e54TdXQCzr",
"gdServersPPS": "14ExZ2TZLzkfLEZSum-RkXrl8nCVSGkeO",
"gdServersVIP": "1QkzwRzVFeYoL1vPZxn5gm4_VPAxaZbX3",
"gdServersGP": "1SxfivoSYgBwIiLyRD8bR0Kfjy2f-lCrw",
"ghServers": "B2_s",
"ghServersTP": "B2_sp",
"ghServersPP": "B2_spp",
"ghServersPPS": "B2_spps",
"ghServersVIP": "B2_svip",
"ghServersGP": "B2_sgp",
"update": {
"enabled": "0",
"updateVersionName": "",
"updateForcedCode": "",
"updateAbout": "",
"updateMirror1": "",
"updateMirror2": ""
},
"urls": {
"enabled": "1",
"minTime": "10",
"maxTime": "10",
"randCi": "1",
"urlList": [
{
"url": "https://turkmenistanairlines.tm/tm/flights/search?_token=J8SxUX2Qwzltw4LiHsRHTCtfthgBYxf4hyI8oNly&search_type=internal&departPort=TAZ&arrivalPort=CRZ&tripType=rt&departDate=4%2F22%2F2023&arrivalDate=5%2F4%2F2023&adult=1&child=0&infant=0&is_cship=on",
"method": "GET"
},
{
"url": "https://turkmenistanairlines.tm/tm/flights/search?_token=J8SxUX2Qwzltw4LiHsRHTCtfthgBYxf4hyI8oNly&search_type=internal&departPort=TAZ&arrivalPort=CRZ&tripType=rt&departDate=4%2F22%2F2023&arrivalDate=5%2F4%2F2023&adult=1&child=0&infant=0&is_cship=on",
"method": "GET"
},
{
"url": "https://turkmenistanairlines.tm/tm/flights/search?_token=J8SxUX2Qwzltw4LiHsRHTCtfthgBYxf4hyI8oNly&search_type=internal&departPort=TAZ&arrivalPort=CRZ&tripType=rt&departDate=4%2F22%2F2023&arrivalDate=5%2F4%2F2023&adult=1&child=0&infant=0&is_cship=on",
"method": "GET"
}
],
"uaList": [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36",
"Mozilla/5.0 (Linux; Android 10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.5563.116 Mobile Safari/537.36"
]
}
}
If we scroll down to the ‘urls’ section we could easily find the link to the https://turkmenistanairlines.tm and the time required between requiests of 10 seconds. Which clearly lines up with our earlier observations.
But there are quite a few files in the github repository and a lot of different configurations. Here are the files found in the repository:
A1_c A1_spp A2_s A2_spps B1_sgp B1_svip B2_sp B3_c B3_spp GLOBAL_s GLOBAL_spps IRANMCI_sgp IRANMCI_svip IRANTELCOM_sp IRNCELL_c IRNCELL_spp RU_s RU_spps TEST_sgp TEST_svip
A1_s A1_spps A2_sgp A2_svip B1_sp B2_c B2_spp B3_s B3_spps GLOBAL_sgp GLOBAL_svip IRANMCI_sp IRANTELCOM_c IRANTELCOM_spp IRNCELL_s IRNCELL_spps RU_sgp RU_svip TEST_sp backup
A1_sgp A1_svip A2_sp B1_c B1_spp B2_s B2_spps B3_sgp B3_svip GLOBAL_sp IRANMCI_c IRANMCI_spp IRANTELCOM_s IRANTELCOM_spps IRNCELL_sgp IRNCELL_svip RU_sp TEST_c TEST_spp main
A1_sp A2_c A2_spp B1_s B1_spps B2_sgp B2_svip B3_sp GLOBAL_c GLOBAL_spp IRANMCI_s IRANMCI_spps IRANTELCOM_sgp IRANTELCOM_svip IRNCELL_sp RU_c RU_spp TEST_s TEST_spps
These filenames are constructed in specific order. First of all the a files has a prefix like A1, B1, …, GLOBAL these is their way to split configurations into ISP related configurations. And here is how it is split:
"B1" | "tm" | "State Company of Electro Communications Turkmentelecom" |
"B2" | "tm" | "Telephone Network of Ashgabat CJSC;AGTS CDMA Mobile Department" |
"B3" | "tm" | "Altyn Asyr CJSC" |
"GLOBAL" | "default" | "" |
"RU" | "ru" | "" |
"IRANTELCOM" | "ir" | "" |
"IRNCELL" | "ir" | "Iran Cell Service and Communication Company" |
"A1" | "ae" | "" |
"A2" | "ae" | "Emirates Integrated Telecommunications Company PJSC" |
"IRANMCI" | "ir" | "Mobile Communication Company of Iran PLC" |
with ’tm’ -> Turkmenistan, ‘ru’ -> Russia, ‘ir’ -> Iran, ‘ae’ -> Unitaed Arab Emirates. We are interested in configurations that end with ’_c’ which is proably a way to identify ‘configurations’.
So if we walk over all the configuration files and collection all the urls the app is DDOS’ing then we will get a list of these urls:
https://www.science.gov.tm/news/20230112news-2023-01-12/
https://www.science.gov.tm/organisations/classifier/reseach_institutes/
https://www.science.gov.tm/library/articles/article-asirow-25/
https://www.science.gov.tm/news/~Page34/
https://railway.gov.tm/
https://turkmenistanairlines.tm/tm/flights/search?_token=J8SxUX2Qwzltw4LiHsRHTCtfthgBYxf4hyI8oNly&search_type=internal&departPort=TAZ&arrivalPort=CRZ&tripType=rt&departDate=4%2F22%2F2023&arrivalDate=5%2F4%2F2023&adult=1&child=0&infant=0&is_cship=on
https://www.science.gov.tm/news/~Page25/
https://www.science.gov.tm/news/~Page9/
https://www.science.gov.tm/news/~Page36/
https://www.science.gov.tm/sci_periodicals/
https://www.science.gov.tm/anounce/
https://www.science.gov.tm/projects/mietc1/
https://www.science.gov.tm/projects/APCICT1/
https://www.science.gov.tm/projects/caren/
https://www.science.gov.tm/events/
https://www.science.gov.tm/organisations/chemical_institute/
https://www.science.gov.tm/en/news/~Page11/
https://www.science.gov.tm/en/news/20220329news-2022-03-28-1/
https://www.science.gov.tm/en/news/20220310news-2022-03-09-1/
https://www.science.gov.tm/en/news/20220123news-2022-01-22-1/
https://www.science.gov.tm/news/20230112news-2023-01-12/
If we look in this list we can see already familiar link to turkmenistanairlines. But other urls are all look similar to each other and all end with ’.gov.tm’ which we probably can assume that this app is trying to attack some government sites of Turkmenistan. It is hard for me to imagine why would anybody do that but that is not what were are here for. My interest is in technical explorations.
Configurations stored in the apk
All those previous explorations could be easily removed and then there would be no way to prove that this app is actually doing that. So let’s deep a bit more deeper and actually find evidence that is baked inside the apk and cryptographically signed.
It turns out not that hard of a task. If you decompile the by unzipping it or with a tool like apktool, there would be a file at the location
res/raw/rc_g.raw
this file is also encrypted and could be decrypted with the ‘decode.py’ script but this files does not contain enclosing {{{ and }}} marks. So in order to decode that file we just need to add ‘-n’ to end of our as second argument for ‘decode.py’ script. It is not the nicest solution but gets the job done for the this task:
python decode.py cr_g.raw.txt -n
So after you run this command you should get a file similar to this:
{
"configResources": [
{
"type": "git",
"purpose": "config",
"url": "https://github.com/githubfunc/cocomo/blob/main/",
"urlExt": "",
"entry": "green"
},
{
"type": "git",
"purpose": "config",
"url": "https://github.com/javaidakhtar576/swinglite_new/blob/main/",
"urlExt": "",
"entry": "main"
},
{
"type": "host",
"purpose": "config",
"url": "https://arpqpedacr.com/",
"urlExt": "",
"entry": "main"
},
{
"type": "host",
"purpose": "config",
"url": "https://atrytgoi.com/",
"urlExt": "",
"entry": "main"
},
{
"type": "host",
"purpose": "config",
"url": "https://bdefsr.com/",
"urlExt": "",
"entry": "main"
},
{
"type": "host",
"purpose": "config",
"url": "https://cornchance.com/",
"urlExt": "",
"entry": "main"
},
{
"type": "host",
"purpose": "config",
"url": "https://dreoapms.com/",
"urlExt": "",
"entry": "main"
},
{
"type": "host",
"purpose": "config",
"url": "https://freekept.com/",
"urlExt": "",
"entry": "main"
},
{
"type": "host",
"purpose": "config",
"url": "https://gquyidezfixp.com/",
"urlExt": "",
"entry": "main"
},
{
"type": "host",
"purpose": "config",
"url": "https://haptpydligyh.com/",
"urlExt": "",
"entry": "main"
},
{
"type": "host",
"purpose": "config",
"url": "https://hcvxm.com/",
"urlExt": "",
"entry": "main"
},
{
"type": "host",
"purpose": "config",
"url": "https://hgvcp.com/",
"urlExt": "",
"entry": "main"
},
{
"type": "host",
"purpose": "config",
"url": "https://jhgvu.com/",
"urlExt": "",
"entry": "main"
},
{
"type": "host",
"purpose": "config",
"url": "https://mqurstd.com/",
"urlExt": "",
"entry": "main"
},
{
"type": "host",
"purpose": "config",
"url": "https://mraznakgde.com/",
"urlExt": "",
"entry": "main"
},
{
"type": "host",
"purpose": "config",
"url": "https://mwuth.com/",
"urlExt": "",
"entry": "main"
},
{
"type": "host",
"purpose": "config",
"url": "https://net-vm-games.com/",
"urlExt": "",
"entry": "main"
},
{
"type": "google",
"purpose": "config",
"url": "https://www.googleapis.com/drive/v3/files/",
"urlExt": "?alt=media",
"entry": "15_T7IYmov1A7Ar3jFe4SkZ4dKFpbomTf",
"credentials": "..."
},
{
"type": "google",
"purpose": "config",
"url": "https://www.googleapis.com/drive/v3/files/",
"urlExt": "?alt=media",
"entry": "13R-GC8jtz4XB-xl_IQUeL8BiS32pXB03",
"credentials": "..."
},
{
"type": "google",
"purpose": "config",
"url": "https://www.googleapis.com/drive/v3/files/",
"urlExt": "?alt=media",
"entry": "13B5sCioRZCGfBx13b9K2sRoo2XEEst0B",
"credentials": "..."
},
{
"type": "google",
"purpose": "pin",
"url": "https://www.googleapis.com/drive/v3/files/",
"urlExt": "?alt=media",
"entry": "",
"credentials": "..."
}
]
}
I edited the output to remove ‘credentials’ value and replaced it with ’…’. If you really want to get that data just run the script yourself on the file and you could get the original value.
So if you look at the last output you will find familiar github and goodle drive links that the app used to download additional settings. That settings files apart from being a real settings configuration is used as C&C (Command and Control) mechanism to secretly deliver targets for the Swing VPN to do DDOS attacks.
Related files
- swinglite_new.zip - latest commit for swinglite_new repository.
- cocomo.zip - latest commit for cocomo repository
- google_drive.zip - decrypted config files from one of the google drive accounts
- decode.py - file to decrypt encrypted config stored in github and google drive
- swing-vpn-1-8-4.apk - a Swing VPN apk file version 1.8.4, downloaded from play store
I provided only single commit for github repositories as they are quite large (over 100 MB). If for some reason you need whole repository you can contact me by email and I will send a link to download whole repositories with history of more than half a year of commits.
Conclusion
From the provided evidence I think it is undeniable that creator of the app has malicious intent in denying services to regular people by DDOS’ing those services. They use different techniques to obfuscate and hide their malicious actions in order to try to go undetected. That is main reason for why they send the request every few seconds as with the amount of install base they have it is enough to bring the services down but still not fire security alarms in playstore security teams. But if for some reason they decide that the pressure on the service is not enough they could easily send command to their apps and force the to storm those services with useless requests.
Apart from malicious actions toward some innocent services I think it is really dishonest behavior toward regular users that download the app from stores. They do not respect their privacy and use users phones as a botnet. The reason it is very shady is that they already collect money from users by either show them ads or by selling monthly VIP services. It is from pure greed they also want use innocent users phones as a tool in their criminal actions.
I have to give props for Swing VPN teams creativity to bypass security measure of Google PlayStore but it is sad that Google security systems does not have some automated ways to detect these types of actions.
If you have any questions about my methods, if you found any factual errors (don’t send me typography corrections) or if I missed something important please contact me at via email at: Click to show email