<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های majidmc2</title>
        <link>https://virgool.io/feed/@majidmc2</link>
        <description>مجید ایرانپور هستم. از فعالیت هایی که دارم-بخصوص در زمینه IT-براتون می نویسم.</description>
        <language>fa</language>
        <pubDate>2026-06-17 02:19:00</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/149550/avatar/OOUPBQ.png?height=120&amp;width=120</url>
            <title>majidmc2</title>
            <link>https://virgool.io/@majidmc2</link>
        </image>

                    <item>
                <title>شرح آسیب پذیری CVE-2023-40459</title>
                <link>https://virgool.io/@majidmc2/%D8%B4%D8%B1%D8%AD-%D8%A2%D8%B3%DB%8C%D8%A8-%D9%BE%D8%B0%DB%8C%D8%B1%DB%8C-cve-2023-40459-s2dapnyx1ila</link>
                <description>سلام، من مجید هستم و توی این پست قصد دارم فرایند کشف آسیب پذیری CVE-2023-34194 رو شرح بدم. همین اول کار بگم که این Research همراه با دوست خوبم پویا انجام شد. نکته دیگه اینکه وقتی گزارش به وندور فرستاده شد متاسفانه قبل ما یه تیم به فاصله 10 روز، همین آسیب پذیری رو پیدا کرده بود. اما چون روش کشف برای ما تجربه جالبی بود ما هم این مقاله رو با اجازه ناشر نوشتیم.مقدمهداستان از این قراره که ما تصمیم گرفیتم روش های تحلیل فایل های باینری برای کشف آسیب پذیری رو روی یک تارگت واقعی شروع کنیم تا دستمون راه بیافته! برای اینکار هم Firmware های IOT رو انتخاب کردیم چون معمولا سازوکارهای Exploit Mitigation توی این دسته محصولات کمتر دیده شده. یه روز که در مورد روش های رمزگشایی فایل Firmware ها صحبت میکردیم، به این مقاله برخوردیم و بعد از مطالعه هم تصمیم گرفتیم که بشنیم و روی همین تارگت کار کنیم. حالا تارگت ما شد فریمور RV50 از محصولات شرکت Sierra Wireless. The AirLink® Raven RV50 is the industry’s lowest power LTE gateway. Simple to install and easy to manage, the Raven RV50 industrial gateway is designed to connect critical assets and infrastructure. Ideal for industrial-grade applications in energy, utilities and smart-city infrastructure, the Raven RV50 provides real-time remote connectivity for SCADA, distribution management systems and metering.شبیه سازیخوب اولین کاری که باید انجام میشد این بود که Firmware رو از سایت اصلی دانلود بشه. برای ما مهم بود که فایل های فایل سیستم دسترسی داشته باشیم، پس با ابزار binwalk اون رو استخراج کردیم و رسیدیم به فایل rootfs.sqfs.uboot.extracted این فایل رمز شده ی فایل سیستم بود (الگوریتم رمزگذاری AES و کلید رمزگشایی هم ورژن Firmware هست).حالا باید طبق مقاله رمزگشایی انجام میشد. این کار رو کردیم و با استخراج فایل بدست اومده توسط ابزار binwalk، رسید به فایل سیستم دستگاه :)کارمون تازه شروع شد. شروع به گشتن کریدم و اولین کارمون این شد که فایل اجرایی پنل وب رو پیدا کنیم. سیتم عامل دستگاه یه لینوکس برای سخت افزار ARM‌ بود و برای مدیریت سرویس ها هم از initng استفاده میکرد. توی سرویس های سیستم عامل، سرویس زیر محل فایل باینری رو به ما نشون داد$ cat /etc/initng/daemon/acemanager.iاطلاعاتی ک بدست اومد شد این موارد:· فایل اجرایی مدیریت پنل با نام ACEmanager و در مسیر sbin/ACEmanager/ قرار داره· فایل­های کلید خصوصی و عمومی پروتکل HTTPS در مسیر etc/ACEmanager/certs/ قرار داره· فایل­های استاتیک مربوط به پنل مدیریتی وب (شامل .html، .js و .cgi) در مسیر www/ قرار دارهکتابخانه ­های موردنیاز ACEmanager، در مسیر /lib/ قرار دارن که طبق دستور زیر بدست اومدن:$ readelf –d /sbin/ACEmanagerحالا نوبت شبیه سازی دستگاه شد. پس برای داشتن یک سیستم عامل با معماری ARM، از ابزارهای qemu-system-arm و Buildroot استفاده کردیم. Buildroot مجموعه‌ای از پیکربندی­ هاییه که فرآیند ساخت یک محیط لینوکس کامل و قابل بوت رو برای Embedded System ها ساده و خودکار میکنه و از ابزار QEMU استفاده کردیم تا بتونیم این محیط شبیه ساز رو اجرا کنیم.Buildroot is a set of Makefiles and patches that simplifies and automates the process of building a complete and bootable Linux environment for an embedded system, while using cross-compilation to allow building for multiple target platforms on a single Linux-based development systemQEMU is a free and open-source emulator. It emulates a computer&#x27;s processor through dynamic binary translation and provides a set of different hardware and device models for the machine, enabling it to run a variety of guest operating systems.توضیحات پیکربندی های Buildroot و QEMU رو دیگه رد میشم. نوع سخت افزاری که باید شبیه سازی میشد، armv7l GNU/Linux بود. بعد از اون باید فایل هایی که نیاز بود رو، از فایل سیستم رمزگشایی شده Firmware به فایل سیستم شبیه ساز انتقال میدادیم. پس این مراحل رو انجام دادیم:- ابتدا فایل سیستم شبیه‌ساز به یک پوشه با نام دلخواه (در اینجا try) Mount شد:$ mkdir try$ sudo mount squashfs-root try- بعدش کلیه کتابخانه­ ها، فایل­ های استاتیک پنل وب و گواهینامه ­ها به فایل سیستم شبیه­ ساز انتقال داده شد:$ sudo cp squashfs-root/sbin/ACEmanager try/sbin/$ sudo cp –r squashfs-root/lib/[LIBRARY-NAME].so* try/lib/$ sudo chmod 755 try/lib/[LIBRARY-NAME].so*$ sudo mkdir –p try/etc/ACEmanager/certs$ sudo cp –r squashfs-root/etc/ACEmanager/certs/server.crt try/etc/ACEmanager/certs/server.crt$ sudo cp –r squashfs-root/etc/ACEmanager/certs/server.key try/etc/ACEmanager/certs/server.keyحالا باید شبیه ساز اجرای میشد. با استفاده از اسکریپت start-qemu.sh، شبیه‌ساز اجرا شد:دستور اجرایی این فایل برای مشاهده پنل وب همون طور که قبلا نشون داده شد برابر دستور زیره:$ /sbin/ACEmanager -d &amp;quot/www&amp;quot -n -c &amp;quot/etc/ACEmanager/certs/server.crt&amp;quot -k &amp;quot/etc/ACEmanager/certs/server.key&amp;quotبا اجرای این دستور توسط برنامه Strace مشاهده شد که تعدادی از فایل‌های موردنیاز باید از فایل سیستم Frimware به فایل سیستم شبیه‌سازی‌شده انتقال داده بشه و توی پوشه tmp هم فایلی با نام swialeosdefs ایجاد بشه:$ sudo rsync -a --ignore-existing squashfs-root/ try/
$ touch try/tmp/swialeosdefsدرنهایت برای دسترسی به پنل وب بر روی هاست اصلی باید پورت 80 شبیه‌ساز به هاست اصلی متصل میشد. برای این کار باید در فایل start-qemu.sh، مقدار شخص شده در شکل زیر اضافه بشه.حالا پنل وب فایل اجرایی از هاست اصلی و از طریق پورت 8888 در دسترس ماست.انجام Fuzz روی فایل ACEmanager حالا کارمون این شد که روی نقاط مختلف برنامه عملیات Fuzz انجام بدیم. ما سناریوهای مختلفی انجام دادیم و یکی از اون ها روی فرایند لاگین به پنل وب بود. ابزاری که برای Fuzz‌ کردن انتخاب کردیم Valgrind بود و جهت ایجاد TestCase از ابزار Radamsa استفاده شد. سناریویی که منجر به کشف خطا شد شامل اجرای عملیات Fuzz بر روی مقادیر نام کاربری و کلمه عبور درخواست­ های HTTP ارسالی بود. برای ارسال و دریافت داده بین سرور و رابط وب از XML استفاده میشه و درخواستی که برای ارسال نام کاربری و کلمه عبور بود هم این شکلی بود: پس از اجرای این سناریو بر روی مقدار تگ username و password در داده XML ارسالی یک Crash به دست اومد. اسکریپت توسعه داده‌شده برای انجام فاز در این مرحله مطابق شکل زیر بود.حالا ACEmanager رو توسط Valgrind با دستور زیر و کد تولید TestCase رو هم اجرا کردیم:$ valgrind /sbin/ACEmanager –d “/www” –n –c “/etc/ACEmanager/certs/server.crt”و این شد که به کرش رسیدیم :)پیلودی که منجر به Crash شد، مطابق زیر بود (مقدار خالی برای تگ password)تحلیل داینامیک برای بررسی Crash به‌دست‌ اومده، با تحلیل دینامیک، خروجی ابزار GDB رو روی ابزار Ghidra بررسی کردیم. ابتدا برنامه را در مد دیباگر اجرا می‌کنیم.برنامه بعد از لود شدن در GDBserver با دو سیگنال برخورد می‌کنه که روندی نرمال دارن و با دستور continue در GDB میشه از اون‌ها عبور کرد. در مرحله آخر GDB اعلام می‌کنه که در حال ادامه‌ی روند اجرای برنامه ست و فرایند لود کردن کتابخانه‌ها و اسکریپت‌های CGI به پایان رسیده و کنسول وب ACEmanager از طریق مرورگر قابل‌مشاهده شده. این یعنی برنامه با موفقیت اجراشده و وب سرور منتظر دریافت درخواست‌های HTTP از طریق رابط وبه. با ارسال یک درخواست احراز هویت، طبق خروجی GDB، برنامه برای بررسی نام کاربری و کلمه عبور ارسال‌شده به ماژول‌های امنیتی PAM رجوع میکنه و مقادیر Username و Password دریافتی رو چک می‌کنه. در ادامه‌ی روند  Fuzz، اسکریپت به ارسال درخواست‌ها ادامه میده تا جایی که Crash رخ بده.در این مرحله یک Request با ساختار غیرعادی توسط وب سرور دریافت شده و باعث رخ دادن خطا Segmentation Fault میشه. این مشکل در تابع ()ACEmanager::connect و در هنگام پردازش درخواست احراز هویت توسط وب سرور اتفاق افتاده. با بررسی بیشتر و تست کردن حالت‌های مختلف مشخص‌شده که عامل اون خالی بودن تگ  password در محتوای درخواست ارسال‌شده هست. به‌این‌ترتیب که اگر این تگ به شکل &lt;password&gt;&lt;/pasword&gt; و بدون مقدار به سمت سرور ارسال بشه، باعث Crash سرویس و خطای اون میشه.بررسی CVE 2021-42260 TinyXML Infinite Loop (DoS)آسیب‌پذیری CVE-2021-42260 در کتابخانه‌ی TinyXML و ماژول TiXmlParsingData::Stamp شناسایی‌شده که مربوط به عملیات پردازش درخواست‌های تحت وب و پیام‌های XML هست. این آسیب‌پذیری به دلیل تکرار بینهایت یک حلقه به وجود اومده که هیچ‌وقت به‌شرط موردنیاز برای خارج شد از اون نمی‌رسه. برای استفاده از این آسیب‌پذیری، مهاجم باید  یک XML Message با ساختار متناقض به وب سرور ارسال کنه تا برنامه وارد این حالت حلقه بی‌نهایت بشه.همان‌طور که اشاره شد، Crash کردن سرویس در تابع ()connect از ACEmanager اتفاق می‌افته. این تابع وظیفه‌ی دریافت Request و ارسال آن به توابع دیگر برای بررسی نوع درخواست و برقراری ارتباط استفاده می‌کنه. این تابع در اصل نقش تابع مادر برای پیاده‌سازی توابع XML Parser و PAM Authentication رو داره و در بین توابعی که از ()ACEManager::Connect فراخوانی میشن، تابع TiXmlParsingData::Stamp  دیده میشه. در سناریوی فعلی برای استفاده از این آسیب‌پذیری از یک HTTP Request که تگ password در اون خالیه استفاده شده چرا که پردازش XML توسط این کتابخانه در ACEmanager  انجام میشه.کشف آسیب‌پذیری DoS در سازوکار احراز هویت ACEmanagerحالا به بررسی تابع stamp از روش Dynamic Analysis با استفاده از ابزارهای gdbserver remote debugging و Ghidra پرداخته شد (آسیب پذیری در این تابع TinyXML گزارش شده). برای شروع ابتدا یک Breakpoint بر روی تابع main قرار دادیم. با این کار، کتابخانه‌ی TinyXML در پروسه‌ی جاری بارگذاری شده و میشه برای بررسی دقیق‌تر بر روی توابع اون Breakpoint گذاشت.در مرحله‌ی بعد، یک Breakpoint  روی تابع stamp گذاشتیم. در این حالت ACEmanager منتظر دریافت HTTP Request هست. با ارسال Request (که در آن تگ password خالی نیست) برنامه، به Breakpoint بعدی در تابع stamp می‌رسه و محل پارامترهای ارسال‌شده به تابع stamp شناسایی شد.همان‌طور که مشاهده میشه، تابع stamp درخواست XML را به‌عنوان پارامتر ورودی از تابع connect دریافت کرده. طبق مستندات رسمی کتابخانه‌ی TinyXML روند بررسی درخواست و خواندن پارامترهای احراز هویت کاربر به شکل زیره:در مرحله‌ی اول المان FirstChild کل محتویات تگ request را می‌خوانهدر مرحله‌ی دوم به‌صورت Recursive  وارد تگ connect شده و محتویات اون رو میخونهدر این مرحله برنامه هر یک از تگ‌های login و password را به‌طور جداگانه تجزیه می­کنه. از اونجا که تگ password برای ما اهمیت داره، پس به بررسی اون می‌پردازیم.در ادامه پسورد دریافت شده از Request به‌عنوان یکی از پارامترهای تابع بارگذاری شده و درصورتی‌که این تگ خالی نباشه پس از اجرای این تابع، برنامه به تابع caller که همان ()ACEManager::connect هست، برمی‌گرد‌ه.حالا مطابق شکل، همین سناریو را با تگ password خالی اجرا کردیم و فرایند قبلی را تکرار کردیم تا به تابع موردنظر رسیده تا محتویات Stack و پارامترهای تابع بررسی بشن:طبق مستندات آسیب‌پذیری، حالت Infinite Loop در این قسمت از کد و در هنگام تجزیه تگ اتفاق می‌افته. شکل زیر هم مقایسه‌ی کد تابع stamp با کد Disassembler در Ghidra ست.شکل زیر هم رسیدن برنامه به تابع stamp و حلقه‌ی While موجود در آن را نمایش می­ده. از اونجا که آسیب‌ پذیری در این حلقه اتفاق میافته، به بررسی دستورالعمل‌ها پرداخته‌ شد:همان‌طور که در شکل مشاهده شد، حلقه در دستورالعمل:cmp r10, #1به حالت Infinite میرسه و برنامه تا بی­نهایت به همون Breakpoint قبلی برمی‌گرده. این همون حالتیه که باعث می‌شه برنامه از تابع stamp خارج نشه و با ادامه‌ی Infinite Loop منجر به مصرف منابع سیستم و درنتیجه کرش کردن سرویس ACEManager بشه. به همین دلیل، اگر Breakpoint های قبلی را غیرفعال کنیم، پس از یک مدت‌زمان کوتاه و با افزایش میزان استفاده از منابع سیستم، برنامه با خطا سیستمی از تابع stamp به connect بازمی‌گرده و با سیگنال segmentation fault کرش می‌کنه.کد PoC‌ رو هم از اینجا در اختیار دارین.مرسی که تا آخرش بودی. راه ارتباطی با من در توییتر.</description>
                <category>majidmc2</category>
                <author>majidmc2</author>
                <pubDate>Tue, 06 Feb 2024 14:29:26 +0330</pubDate>
            </item>
                    <item>
                <title>تست نفوذ اندروید-بدقلق های پروکسی نرو!</title>
                <link>https://virgool.io/@majidmc2/%D8%AA%D8%B3%D8%AA-%D9%86%D9%81%D9%88%D8%B0-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-%D8%A8%D8%AF%D9%82%D9%84%D9%82-%D9%87%D8%A7%DB%8C-%D9%BE%D8%B1%D9%88%DA%A9%D8%B3%DB%8C-%D9%86%D8%B1%D9%88-siarhu4zf4t3</link>
                <description>سلام، من مجید هستم و توی این پست میخوام در مورد یکی از چالش هایی بنویسم که هنگام تست نفوذ یک برنامه اندرویدی که با Flutter نوشته شده بود، به اون برخوردم.مقدمهمن برای تست نفوذ از متودولوژی OWASP MASVS استفاده میکنم و داستان از این قراره که یکی از کارهایی که هنگام تست داینامیک باید انجام بدین، بررسی ترافیک های بین برنامه و سرور هست. معمولا برنامه های اندرویدی از پروتکل های HTTP و یا WebSocket برای این منظور استفاده میکنن و وظیفه ما هم بررسی ارتباط با Endpoint هاست.برای این کار من از ابزارهای زیر استفاده میکنم:Genymotion: شبیه ساز سیستم عامل اندرویدBurp Suite: ابزار پروکسی و بررسی ترافیکبرای‌ نصب Genymotion از این لینک دانلود و نصب کنید و برای Burp Suite  هم از این لینک. بعد از نصب کافیه یک مطابق شکل زیر یک سیستم عامل اندرویدی برای خودتون بسازید.این نکته رو بگم که من برای روشی که میخوام در ادامه بگم از اندروید 9 استفاده کردم و روی ورژن 6 و 12 هم جواب نگرفتم.سیستم عامل اندروید به طور پیشفرض Root شده است و بعد از اجرای اون نیازه که یه ARM-Translation رو روی شبیه ساز نصب کنید. برای ورژن های قبل از اندروید 9 از این لینک و برای ورژن های بعدی این لینک. خروجی این پروژه ها یک فایل zip هست که با درگ و دراپ روی شبیه ساز باید انتقال داده بشه و بعد از اون سیستم Flash شده و شما میتونید برنامه های ARM رو روی شبیه ساز نصب و استفاده کنید.اگر توی حوزه وب فعالیت دارین، میدونید که برای اینکه ارتباط بین مرورگر و سرور رو بخوایید با Burp Suite بررسی کنید نیازه که Cert مربوط به Burp Suite رو توی مرورگر وارد کنید. توی اندروید هم باید همین کار رو انجام بدیم ولی یکم قضیه فرق داره. برنامه های اندرویدی برای ارتباطاتی که امن هست و از TLS استفاده میکنه یکی از سه حالت زیر رو دارن:برنامه Cert مربوط به سرور رو چک نمیکنه (به طور پیشفرض غیر فعاله مگر اینکه برنامه نویس این کار رو کرده باشه!)برنامه به سیستم عامل اعتماد میکنه. یعنی میگه اگه سیستم عامل به این Cert اعتماد داره منم اوکیم.برنامه مقدار Cert سرور و یا Hash اون رو در کدش داره که موقع ارتباط TLS Handshake اعتبار سنجی انجام میده (به این سازوکار Certificate Pinning میگن)خوب توی این مرحله باید Cert ابزار Burp Suite رو به سیستم وارد کنیم. برای اینکار کلی مقاله وجود داره و من دیگه توضیحش نمیدم شما از طریق این مقاله برین جلو.حالا باید برای سیستم اندرویدی پروکسی ست کنید که از ترافیک اون از سیستم اصلی شما و ابزار Burp Suite رد بشه. پس سرور میشه IP سیستم اصلی و Port میشه Port ی که ابزار Burp Suite روی اون گوش میده. برای این کار به مسیر زیر در اندروید برین:Settings &gt; Network &amp; Internet &gt; Wi-Fi &gt; Advanced Options &gt; Proxy &gt; Manualخوب حالا اگه برنامه شما به Cert های سیستم عامل اعتماد میکنه شما ترافیک HTTP یا WS رو توی Burp Suite میبینید اما اگه سازوکار Certificate Pinning داره شما باید زحمت bypass رو بکشین. برای اینکار میتونید از ابزار Frida استفاده کنید. این ابزار حین تست داینامیک شما میتونه فانکشن هایی از برنامه که مد نظر دارین رو Hook کنه و کار دلخواه شما رو جایگزینش کنه. این مقاله هم معرفی میکنم که بخونید و اگه به این مشکل رسیدین بدون باید چیکار کنید. نکته اینکه کلی اسکریپت برای Bypass بوسیله Frida وجود داره که میتونید ازش استفاده کنید.اگه مراحل بالا رو برین جلو، حالا تسک شما میشه تست Endpoint ها و کشف آسیب پذیری.چرا یک سری برنامه ها بدقلق اند؟توی تست ها برای اولین باری که به یک برنامه Flutter ای برخوردم دیدم با اینکه Certificate Pinning فعال نیست و ترافیک سایر برنامه ها از Burp Suite رد میشه اما باز ترافیک این برنامه به پروکسی من محل نمیزاره!با سرچ فهمیدیم که طبق گفته ایشون، پیاده‌سازی فریمورک های مثل Flutter، Xamarin و Unity به این صورت هستش که خودشون مدیریت ارتباطات رو بر عهده دارن و به سیاست های سیستم (مثل قرار دادن پروکسی) محل نمیزارن :)Third party app frameworks will have their own low-level implementation for TLS and HTTP and default pinning bypass scripts won’t work. If the app is written in Flutter, Xamarin or Unity, you’ll need to do some manual reverse engineering.حالا باید چیکار کرد؟ برای اینکه از شر این وضع خلاص شد باید دو تا کار رو انجام داد:1- سیستم عامل اندروید شما Root باشه که به طور پیشفرض توی Genymotion این کار اوکیه2- برنامه ProxyDroid رو شبیه ساز نصب و فعال کنید (مطابق شکل زیر).با این روش نیاز به ست کردن پروکسی در تنظیمان گوشی نیست و میتونید ترافیک این برنامه ها رو روی Burp Suite مشاهده کنید.امیدورام این پست مفید بوده باشه براتون.راه ارتباطی با من در توییتر.</description>
                <category>majidmc2</category>
                <author>majidmc2</author>
                <pubDate>Tue, 30 Jan 2024 14:27:48 +0330</pubDate>
            </item>
                    <item>
                <title>چالش Hunting License از HackTheBox</title>
                <link>https://virgool.io/@majidmc2/%DA%86%D8%A7%D9%84%D8%B4-hunting-license-%D8%A7%D8%B2-hackthebox-u6igp2zyzpqh</link>
                <description>سلام، من مجید هستم و توی این پست میخوام یکی از چالش های بخش Reversing از HackTheBox بنام  Hunting License رو برای شما شرح بدم. پس بدون هیچ مقدمه بریم که شروع کنیم.اول از همه با ورود به پنل کاربری از بخش challenges و زیر بخش RETIRED CHALLENGES، این چالش قابل دسترسه که نیاز هست ابتدا فایل مربوطه رو دانلود کنیم(اسم فایل license هست). برای حل این چالش و گرفتن Flag یه سرور در اختیار ما قرار میگیره که باید به سوالات اون پاسخ بدیم و اگه همه سوالات به درستی پاسخ داده بشن، Flag رو دریافت میکنیم :)خوب برای شروع ابتدا به سروری که به ما داده متصل میشیم. برای اینکار من از Netcat استفاده کردم و این شد خروجی کار:$ nc [IP]  [Port]اولین سوال نوع فرمت اجرایی فایل رو پرسید. کافیه از دستور file استفاده کنیم تا مشخصات فایل اجرایی رو بکشیم بیرون:$ file licenseبرگردیم به سوالات. مشخص شد که نوع فایل اجرایی ELF است. پس وارد میکنیم و سوال دوم هم نوع معماری پردازنده که بر اساس اون فایل کامپایل شده رو از ما میخواد که جواب اون هم میشه x86-64. ایزی ایزی بریم سوال بعد.حالا از ما نام یکی از کتابخانه هایی که برای خوندن ورودی کابر هست رو میخواد که با راهنمایی که خودش کرده فقط کافیه که از دستور ldd استفاده کنیم:$ ldd licenseخیلی ساده جواب این سوال هم بدست اومد:در ادامه از ما آدرس شروع تابع main رو پرسیده که برای اینکار نیاز که تحلیل ایستای کد فایل license رو شروع کنیم. واسه همین من از ابزار Ghidra استفاده کردم و برنامه رو توی حالت CodeBrowser اجرا کردم. مطابق شکل تابع main در آدرس 0x4011172 شروع میشه.توی سوال بعدی تعداد تکرار تابع put در تابع main رو از ما میخواد. اگه به بخش Decompile ابزار Ghidra بریم میبینیم که 5 بار از این تابع استفاده شده. ایزی ایزی بریم سوال بعدی :)خوب خوب ماجرا داره تازه شورع میشه. در ادامه اولین پسورد رو از ما میخواد. اما قضیه چیه؟ بیاییم و فایل license رو یکبار اجرا کنیم.همونطور که میبینیم این فایل اول یه سوال میپرسه که باید y بزنیم و یه پسورد از ما میخواد. قطعا ورودی ما یجایی تو کد با  یک مقداری چک میشه پس برمیگردیم به Decompile و چرخ میزنیم توی کدها. توی main تابعی با نام exam فراخوانی میشه که اگه وارد اون بشیم میبینیم که بعد از اینکه خطوط شکل قبل نمایش داده شد، مقدار ورودی ما توی یه متغییر ذخیره شده و با یه مقداری توسط تابع strcmp مقایسه میشه. درست حدس زدید و این مقدار همون پسورد اول است :)خوب کار ادامه داره و پسورد دوم رو باید پیدا کنیم. مثل قبل برمیگردیم و میگردیم ببینیم که کجا ورودی ما داره با یه مقداری چک میشه. اگه به شکل زیر نگاه کنید میبینیم که مقدار t که توی بخش .data قرار داره ابتدا توسط تابع  reverse معکوس میشه و بعد از اون با ورودی ما مقایسه شده.حالا مقدار t چی هست؟ با کلیک روی t و مشاهده بخش Display bytes مقدار اون مشخص میشه. بله دیگه اگه این مقدار رو خودمون معکوس کنیم (با دستور rev) پس عملا پسورد دوم رو هم بدست آوردیم :)این چغر و بد بدن هنوز تموم نشده و پسورد سوم رو هم از ما میخواد. با همین تکنیک میریم جلو و میبینیم که این دفعه مقدار t2 با ورودی های 0x11 و 0x13 به تابع xor رفته و با ورودی کاربر مقایسه میشه. پس اگه بفهمیم که سر  t2 چه بلایی اومده عملا پسورد سوم رو هم یافتیم :)اگه وارد تابع xor بشیم میبینیم که یه حلقه for وجود داره که به اندازه 17 مرتبه اجرا میشه. چی شد؟ 17 از کجا اومد؟ توی شکل بالا مقدار 0x11 که معادل 17 هست و به عنوان ورودی سوم به تابع ارسال شده و با یکم دقت توی شکل زیر مشخصه که این تابع به اندازه param_3 تا اجرا میشه یعنی 17 بار!قبول دارین که param_1 هم یه آرایه هست و هر بار اجرای حلقه Index ای از اون پر میشه؟ و قبول دارین این حاصل ها از xor یکی از Index های param_2 (که t2 باشه) با مقدار 19 (معادل 0x13) هست؟ و قبول دارین param_1 که به صورت اشاره گر وارد تابع شده بود بعدا با وردی کاربر مقایسه میشه؟شک نکن و قبول کن. مقدار t2 توی شکل زیر مشخصه و همون طور که انتظار میره طول اون برابر 17 تا عدد هگز است. پس به زبان خیلی ساده هر عضو t2 با مقدار 19 عملیات xor رو انجام میدن و خروجی میشه پسورد سوم. برای راحتی کار میشه از کد پایتون زیر استفاده کرد تا این عملیات رو انجام بده و پسورد سوم رو بدست بیاریم :)خروجی هم شد این و پسورد سوم هم بدست اومد.خوب دیگه وقتشه که سوالات روی سرور رو هم پاسخ بدیم و Flag رو بدست بیاریم:امیدورام این پست مفید بوده باشه براتون.راه ارتباطی با من در توییتر.</description>
                <category>majidmc2</category>
                <author>majidmc2</author>
                <pubDate>Tue, 29 Aug 2023 17:22:57 +0330</pubDate>
            </item>
                    <item>
                <title>مدیریت تسک های زمان بر با Django-Q</title>
                <link>https://virgool.io/Rocket/%D9%85%D8%AF%DB%8C%D8%B1%DB%8C%D8%AA-%D8%AA%D8%B3%DA%A9-%D9%87%D8%A7%DB%8C-%D8%B2%D9%85%D8%A7%D9%86-%D8%A8%D8%B1-%D8%A8%D8%A7-django-q-hzoo2tio3x72</link>
                <description>فرض کنید نیازه یک View در پروژه Django خودتون تعریف کنید که کاری که باید انجام بده خیلی طولانی مدته، مثلا وظیفه داره یکسری محاسبات سنگینی انجام بده که حدود 30 دقیقه ای زمان می بره. آیا منطقیه که کاربر یک Request به مسیر مشخص شده  ارسال کنه و 30 دقیقه صبر کنه تا Response رو دریافت کنه؟سلام، من مجید هستم و میخوام در مورد چالش بالا بیشتر صحبت کنم.احتمالا در بیشتر موارد جواب شما به سوالی که پرسیدم نه باشه. خوب پس باید چه کار کنیم؟ در Django، وقتی تابع View شما اجرا میشه، همه ی کدهای اون در یک Thread اتفاق میافته. یعنی هر خط کد، یکی پس از دیگری اجرا میشه. ولی ما می خواهیم کد طولانی مدت مون رو در یک Thread متفاوت قرار دهیم تا کاربر مجبور نشه مدت زمان زیادی رو صرف کنه تا Response رو دریافت کنه. در واقع میخواییم یه همچین کاری رو انجام بدیم:# views.py

def my_view(request):
    run_offline(long_running_task) # different thread
    # ...
    return HttpResponse(&amp;quotYour will task be finished soon!&amp;quot) یکی از روش ها اینه که طوری View مد نظرمون رو بنویسیم که وقتی Request کاربر رو دریافت کرد، همون موقع یه Response به کاربر بفرسته و بگه &quot;کار شما به زودی تموم میشه&quot; و در Background محاسبات سنگین رور انجام بده.در Django از روش های مختلفی میشه برای پیاده سازی این قابلیت استفاده کرد. استفاده از Celery یاDjango Redis Queue و Django Q از مشهورترین روش ها هستند. برای اکثر پروژه ها، به دلایلی که در ادامه  این پست اشاره میکنم، استفاده از Django Q را توصیه می کنم.وقتی توی اینترنت شروع به جست و جو کنید، اکثرا استفاده از Celery رو به شما پیشنهاد میدن.درواقع  Celery یک صف کار/صف کار ناهمزمان بر اساس ارسال پیام توزیع شده است. بر روی عملیات بلادرنگ متمرکز است، اما از زمان‌بندی نیز پشتیبانی می‌کند.چی شد؟ ناهمزمانی؟ توزیع شده؟ پیچیده به نظر میاد. آیا من به اینا نیاز دارم؟ Celery برای مبتدیا میتونه ترسناک باشه. من معتقدم که استفاده از Celery برای اکثر پروژه ها زیاده رویه.یکی از دغدغه ها اینه که Celery نیاز داره که نوعی کارگزار رو راه اندازی کنید(برنامه ای که تمام کارهایی را که باید انجام بشه رو پیگیری کنه). برای اجرای Celery باید برنامه های مثل Redis یا RabbitMQ رو نصب و اجرا کنید، که شروع کار رو پیچیده تر می کنه و زیرساخت های بیشتری را برای نگرانی در اختیار شما قرار می ده.پیشنهاد من استفاده از Django Q ست که راه‌اندازی و اجرای اون ساده‌تر از Celery هست، و برای سرویس های متوسط رو به پایین کاملاً مناسبه. Django Q می تونه فقط از پایگاه داده موجود شما به عنوان کارگزار استفاده کنه (از طریق ORM خود Django)، به این معنی که شما نیازی به راه اندازی زیرساخت جدیدی ندارید. اگر هم بعداً متوجه شدید که باید از یک کارگزار دیگری (مثل Redis) استفاده کنید، می توانید پایگاه داده را با چیز دیگری تعویض کنید. خیلی هم عالی.توی این بخش میخواهیم ببینیم که این Django Q چطوری راه اندازی میشه (البته که اگه سراغ داکیومنت اصلی برین بهتره). در اولین گام پکیج مربوطه رو نصب می کنیم:pip install django-qسپس باید تنظیمات Django را طوری تنظیم کنیم که پروژه بدونه که باید از برنامه Django Q استفاده کنه. همچنین باید Django Q را پیکربندی کنیم تا از پایگاه داده ی ما به عنوان کارگزار استفاده کنه.# my_project/settings.py

# Add Django Q to your installed apps.
INSTALLED_APPS = [
    # ...
    &#039;django_q&#039;
]

# Configure your Q cluster
Q_CLUSTER = {
    &amp;quotname&amp;quot: &amp;quotTest&amp;quot,
    &amp;quotorm&amp;quot: &amp;quotdefault&amp;quot,  # Use Django&#039;s ORM + database for broker
}حالا باید جداول Django Q رو بسازیم پس:python manage.py migrateحالا فرض کنید جدولی از یکسری کالا برای هر کاربر داریم که میخوایم وقتی کاربر به مسیر مشخص شده درخواستی میزنه، قیمت های هر رکورد (هر کالا)  از یک سرویس دیگه ای دریافت و بروز رسانی بشن. پس Model ما یه چیزی شبیه به اینه:# my_app/models.py

class Stock(models.Model):
    code = models.CharField(max_length=16)
    price = models.DecimalField(decimal_places=2, max_digits=7)
    user = models.ForeignKey(User, on_delete=models.CASCADE)خب برای اینکه کدی که قراره عملیات طولانی مدتی رو انجام بده رو بنویسیم (در اینجا درخواست برای دریافت قیمت از یک سرویس دیگه)، یک فایل به اسم tasks.py در پوشه Application مون ایجاد میکنیم و کدش رو مینویسیم مثلا:# my_app/task.py

def refresh_stocks_task(stock_ids):
    stocks = Stocks.objects.filter(id__in=stock_ids).all()
    for stock in stocks:
        stock.price = some_api.fetch_price(stock.code)
        stock.save() حالا بریم سراغ کد View:# my_app/views.py

from django_q.tasks import async_task
from .tasks import refresh_stocks_task

def refresh_stocks_view(request):
    stocks = Stocks.objects.filter(user=request.user)
    stock_ids = stocks.values_list(&#039;id&#039;, flat=True)
    
    # Dispatch task to Django Q
    async_task(refresh_stocks_task, stock_ids)

    return render(request, &#039;stocks.html&#039;, {&#039;stocks&#039;: stocks})همونطور که مشاهده میکنید باید از تابع async_task برای فراخوانی تابع refresh_socks_task استفاده بشه تا این تابع در یک thread مجزا اجرا بشه و سریعا ادامه کد که نمایش صفحه socks.html هست، انجام بشه. (نوشتن url برای refresh_socks_view و migrate پایگاه داده دیگه با خودتون)کار ما تموم شده تقریبا، فقط یادتون باشه که باید فرآیند Django Q را مستقل اجرا کنیم. هنگام استفاده از Django، معمولاً یک پردازش دارید که مسئول ارائه درخواست‌های وب است و یک پردازش جداگانه که وظایف Django Q را بر عهده دارد. این دو فرآیند عبارتند از: درخواست های وب:python manage.py runserverوظایف Django Q:python manage.py qclusterبنابراین اگر فرمان مدیریت qcluster را اجرا نکنید، Task های مد نظر هرگز اجرا نمیشن.امیدورام این پست مفید بوده باشه براتون.راه ارتباطی با من در توییتر.برگرفته شده از.</description>
                <category>majidmc2</category>
                <author>majidmc2</author>
                <pubDate>Sat, 23 Apr 2022 18:06:01 +0430</pubDate>
            </item>
            </channel>
</rss>