Friday, March 1, 2024
Google search engine
HomeUncategorizedSwing VPN app is a DDoS botnet

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.

new: Some people wrote me saying that the DDOS is not happening on ios
devices. Just did a quick check and you guys are right. iOS app is using
different way to do VPN and also does not do anything suspicious. I should
appologize to you and to Appstore team for my lazy extrapolation without
actually checking it. Unfortunately I don’t have much time to fix the article
right now, so please just ignore anything ios related below this line.

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.

Android install base of Swing VPN

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.

Requests over some time for Swing VPN

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: 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.

Android install base of Swing VPN

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.

Read More

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments