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