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 https://turkmenairlines.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 appstore and 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: 10+ 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://turkmenairlines.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.
- 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
appstore and 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 Apple
appstore and Google PlayStore but it is sad that Apple/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. My login is lecromee and my mail hosting of choice is
proton.me. I hope if you read these type of posts then you know how basic
concatenation works.
Source link