<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های پارسیا</title>
        <link>https://virgool.io/feed/@parsiya</link>
        <description>مهندس بیکار امنیت بازیهای کامپیوتری. نوشته‌های انگلیسی من در parsiya.net هستند.</description>
        <language>fa</language>
        <pubDate>2026-06-16 18:44:18</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/757212/avatar/567L36.jpeg?height=120&amp;width=120</url>
            <title>پارسیا</title>
            <link>https://virgool.io/@parsiya</link>
        </image>

                    <item>
                <title>همه سمینارها به بیمه عمر ختم می‌شوند</title>
                <link>https://virgool.io/@parsiya/life-insurance-epgpg1macds4</link>
                <description>در بدو ورود به کانادا یا آمریکا با تعداد زیادی از هموطنان مواجه می‌شوید که سعی در فروش بیمه عمر به شما دارند یا به شما پیشنهاد چنین شغلی می‌کنند.کپی این بلاگ را می‎‌توانید در بلاگ فارسی من هم بخوانید:https://parsiya.github.io/parsiya.fa/post/2022/insurance/خلاصه: در بدو ورود به کشور جدید، تصمیمات پرهزینه و بلندمدت نگیریدآیا بیمه عمر بد است؟در اینجا نمی‌خواهم در مورد خوب یا بد بودن بیمه عمر صحبت کنم. اکثر بیمه‌های عمری که به شما پیشنهاد می‌شوند در دسته permanent life insurance طبقه‌بندی می‌شوند که برای اکثر افراد مناسب نیستند. شما می‌توانید با جستجو در مورد permanent life insurance و term life insurance در مورد آنها بدانید. افراد زیادی در این مورد صحبت کرده اند. به عنوان مثال:https://www.whitecoatinvestor.com/debunking-the-myths-of-whole-life-insurance/https://www.reddit.com/r/personalfinance/wiki/insuranceاین نوع بیمه‌ها حق بیمه بالایی دارند. مخصوصا برای تازه‌واردین که درآمد بالایی ندارند فقط یک هزینه اضافی هستند. این بیمه‎‌ها کارمزد بسیار خوبی به فروشنده می‌دهند (معمولاً حدود یک سال از حق بیمه) چون برای شرکت صادرکننده بسیار سودآور هستند.سناریوهای ترسناکدوستانی که مشاور بیمه هستند معمولا سمینارهای رایگانی با عنوان &quot;اطلاعات مالی کانادا&quot; دارند. اکثر (به تجربه من &quot;همه&quot;) این سمینارها برای فروش بیمه عمر یا دیگر خدمات مالی پرهزینه طراحی شده‌اند (مثلاً ایجاد حساب سرمایه‌گذاری در فلان موسسه مالی با فاندهای پرهزینه).معمولاً با سناریوهای ترسناک (و معمولا مخلوطی از واقعیات و تخیلات) شروع می‌شوند. سپس بیمه عمر به عنوان راه چاره همه این مشکلات معرفی می‌شود.در سمیناری در مورد بیماریهای قلبی در کانادا شرکت کردم. ابتدا یک سری آمار و ارقام در مورد بیماریهای قلبی مطرح شد که البته درست هستند. در آمریکا و کانادا بیماریهای قلبی عوامل مرگ مهمی هستند (این بخش درست ماجرا). در دوسوم باقیمانده سمینار در مورد بیمه عمر بحث شد که چاره کار شماست.بعضی موارد این ترساندن‌ها به تخیلات هم می‌رسند. مثلا در همین سمینار بالا عنوان شد که وقتی شخصی فوت می‌کند، پلیس به در خانه میاید و می‌پرسد که آیا ایشان بیمه عمر داشته اند؟ اگر نداشته‌اند شروع به تخیله خانه می‌کنند (جدی می‌گویم چنین داستانی مطرح شد) که تخیلی بیش نیست. اینها برای ترساندن افراد تازه‌وارد طراحی شده‌اند.سمینار دیگر در مورد چالشهای خانم‌ها در کانادا بود. سمینار با این واقعیات شروع شد که خانم‌ها معمولاً درآمد کمتر و هزینه‌های بیشتری دارند. باز هم وقتی شرکت‌کنندگان خوب ترسیدند، اعلام می‌شود که &quot;خانم‌ها هم می‌توانند بیمه عمر بخرند و استقلال مالی داشته باشند.&quot;در سمینار دیگری در مورد افرادی که برای خود کار می‌کنند (نمی‌دانم ترجمه self-employed چه می‌شود) و شرکتهای خصوصی شرکت کردم. تبلیغ سمینار به این صورت بود که شما می‌توانید درآمد بدون مالیات از شرکت خود داشته باشید. روش این است که هر سال از درآمد شرکت تا سقف 50 هزار دلار برای خود بیمه عمر بخرید و سپس از سرمایه داخل بیمه عمر به خود همان مقدار وام بدهید (که مالیات ندارد) و وام را خرج زندگی کنید. وقتی که دارفانی را وداع کردید، بیمه عمر این وام را پرداخت می‌کند و شما درآمد بدون مالیات داشته اید. این تاکتیکی است که افراد ثروتمند استفاده می‌کنند. مثلا بجای فروش سهام خود و پرداخت مالیات، با استناد به آنها وام میگیرند که مالیات ندارد. اما این روش برای همه مفید نیست.بسیار تبلیغ شد که این بهترین روش است و شرکت بیمه دارد سرش کلاه می‌رود چون شما پول مجانی می‌گیرید. خوب، شرکت بیمه چرا باید چنین کاری کند؟ در مورد حق بیمه بالا، سود و هزینه‌های جانبی این وام (و بقیه درآمدهای شرکت بیمه) صحبت نشد و اینکه اگر شرکت شما دچار مشکل شد و یکسال درآمد کافی نداشتید و نتوانستید حق بیمه را پرداخت کنید، پدرتان درخواهد آمد.مثالهای بیشتری هم بودند که فقط اشاره می‌کنم: &quot;اینده مالی فرزندان.&quot; بیمه عمر بخرید تا فرزندانتان تامین باشند.&quot;بیمه مخصوص بیماریهای حاد.&quot; &quot;اشتباهات مالی مهاجرین ایرانی&quot; (درست حدس زدید که یکی از اشتباهات نخریدن بیمه عمر است).آیا با این افراد بحث کنیم؟در این موارد با مشاورین بحث نکنید. سعی نکنید تا ایشان و بقیه افراد سمینار را قانع کنید که این بیمه عمر برای اکثر افراد مناسب نیست. افرادی با فن بیان بسیار بهتر از من و شما برای همه این سناریوها جوابهایی طراحی کرده‌اند. مثلا اگر بگویید این بد است، شما را متهم می‌کنند که بیمه عمر مهم است (که البته هست ولی نه لزوماً این نوع بیمه عمر) و اینکه &quot;شما چرا به فکر فرزندانتان نیستید؟&quot;. درگیر مغالطه Motte-and-bailey یا تپه و حیاط می‌شوید.دعوت به همکاریممکن است دعوت به همکاری برای فروش چنین سرویسهایی شوید. مشکل این است که شما اول منبع درآمد و بعد کارمند هستید:شما باید در دوره‌هایی با پرداخت هزینه شرکت کنید تا لایسنس بگیرید. این خود یک درآمد برای شرکت و این افراد است (کلاس این دوره‌ها را هم برگزار می‌کنند). امتحان این دوره‌ها به زبان انگلیسی هستند و اکثر افراد بعد از گذراندن دوره به فارسی، متاسفانه در امتحان موفق نمی‌شوند.به عنوان کارمند شرکت باز همین بیمه ها را برای خود خریداری می‌کنید.باید این بیمه ها را به دوست و آشنا بفروشید و از آبرویتان مایه بگذارید.دوست و آشنا را به همکاری و فروش همین بیمه‌ها دعوت کنید.آیا این فقط مخصوص ایرانیان است؟نه. این دام برای همه تازه‌واردین وجود دارد. با جستجو درمی‌یابید که مشابه همین تاکتیک‌ها در گروههای مهاجرین کشورهای دیگر هم وجود دارند.پس سمینار نرویم؟اتفاقا برعکس، حتما شرکت کنید. اطلاعات مالی ابتدای سمینار و بخش واقعیات را یاد بگیرید. سپس با جستجوی بیشتر تصمیم بگیرید کدام روش سرمایه‌گذاری و کدام نوع بیمه برای شما بهتر است. هیچ لزومی ندارد در بدو ورود به کشور جدید بیمه عمر بلند مدت داشته باشید یا خانه خریداری کنید. اگر نگران بیمه عمر هستید term جوابگوی نیاز شما در چند سال اول خواهد بود.این منابع برای من در ابتدای مسیر بسیار مفید بودند: https://www.reddit.com/r/PersonalFinanceCanada/wiki/indexhttps://www.reddit.com/r/personalfinance/wiki/index ( معادل آمریکایی مورد بالا)</description>
                <category>پارسیا</category>
                <author>پارسیا</author>
                <pubDate>Sat, 27 Aug 2022 23:49:46 +0430</pubDate>
            </item>
                    <item>
                <title>قابلیت ترمیم خودکار Semgrep</title>
                <link>https://virgool.io/@parsiya/semgrep-autofix-kgmgycajf0se</link>
                <description>در این نوشتار می‌خواهم در مورد قابلیت ترمیمِ خودکار (autofix) کُد Semgrep صحبت کنم. این قابلیت آزمایشی به ما امکان می‌دهد که بعد از یافتن نتایج در فایلهای منبع، آنها را به صورت اتوماتیک دستکاری کنیم.مثل همیشه میتوانید کپی این نسخه را در بلاگ فارسی من بخوانید:https://parsiya.github.io/parsiya.fa/post/2022/semgrep-autofix/اگر علاقه به خواندن نسخه انگلیسی دارید:https://parsiya.net/blog/2021-10-25-a-hands-on-intro-to-semgreps-autofix/همه نمونه‌ها در Semgrep playground هستند ولی می‌توانید آنها را آفلاین نیز اجرا کنید:https://github.com/parsiya/Parsia-Code/tree/master/semgrep-autofixپیش‌نیازهای این بلاگبرای استفاده بهینه از این بلاگ، بهتر است این موارد را بدانید:استفاده از Semgrep و نوشتن rule (قانون؟).  چرا از Semgrep برای Static Analysis استفاده کنیم؟ را بخوانید.آشنایی سَرسَری با خواندن کدُ Java، Python و Go.آشنایی مختصر با بعضی مفاهیم امنیت مانند HttpOnly و XSS.نکته: ترمیمِ خودکار، یکی از قابلیت‌های آزمایشی Semgrep است. در زمان نگارش (آوریل 2022 برای نسخه فارسی و اکتبر 2021 برای نسخه انگلیسی) همه مثال‌ها درست هستند. اگر از آینده میایید، شاید بعضی چیزها متفاوت باشند.اجرای قوانینبرای اجرا و تست قوانین دو راه داریم: استفاده از Semgrep playground در آدرس https://semgrep.dev/playground. من بیشتر از این روش استفاده می‌کنم چون راحت و سریع می‏‌توانم قانون را عوض کنم و نتیجه را ببینم.اجرا در خطِ فرمان (ترجمه فارسی command line).بعد از نوشتن یک قانون می‌توانید درستی ساختار فایل yaml آن را تست کنید:semgrep-crule1.yaml--validate اگر یک قانون دارای بخش autofix باشد، هنگام اجرا فایل اصلی دستکاری نمی‌شود ولی می‌توانید تغییرات را ببینید. برای تغییر فایل اصلی از سویچ autofix--استفاده کنید. برای مشاهده تغییرات بدون تغییر فایل اصلی از سویچ dry-run-- استفاده کنید (حضور همزمان autofix و dry-run معادل نبودِ autofix است یعنی تغییرات فقط نشان داده می‌شوند):semgrep -c rule1.yaml example.java --autofix --dryrun استفاده از سویچ‌های مختلفروش‌های استفاده از autofixدو روش مختلف برای استفاده از autofix داریم:fixfix-regexفرمان Fixهر چیزی که قانون پیدا کرده است را با مقدار این فرمان جایگزین میکنیم. بهترین کاندیدها برای این قابلیت، توابع یا رشته (string) های ناامنی هستند که باید با معادل امن جایگزین شوند. چند مثال با این دستور ببینیم.Python - sys.exitاین مثال را از آموزش Semgrep در آدرس (https://semgrep.dev/s/R6g) قرض گرفته‌ام. در این قانون ما به دنبال تابع exit هستیم و می‌خواهیم آن را با sys.exit جایگزین کنیم. Semgrep تفاوت تابع exit با دیگر استفاده‌های این کلمه را در کُد می‌فهمد و می‎‌تواند راحت آن را جایگزین کنید. بعد از اجرای قانون در وب‌سایت بالا می بینید که دکمه Apply Fix فعال شده و می‌توانید به صورت خودکار کد برنامه را دستکاری کنید.تغییر اتوماتیک exit به sys.exitیکی از نکات جالب این است که می‌توانیم پارامتر تابع را توسط یک metavariable (در اینجا با نام X) در قانون ذخیره کنیم و در autofix استفاده کنیم. دیگر لازم نیست حتی نگران مقدار پارامتر باشیم.Java - CBC Padding Oracleبرای این مثال، قانون cbc-padding-oracle زبان جاوا را از رجیستری Semgrep دستکاری کرده‌ام تا راحت‌تر خوانده شود.# java-cbc-padding-oracle/cbc-padding-oracle.yaml
rules:
  - id: cbc-padding-oracle
    severity: WARNING
    message: Match found
    languages:
      - java
    pattern: $CIPHER.getInstance(&amp;quot=~/.*\/CBC\/PKCS5Padding/&amp;quot)
    fix: $CIPHER.getInstance(&amp;quotAES/GCM/NoPadding&amp;quot)این قانون به دنبال هر چیزی که شبیه object.getInstance(&quot;string&quot;)باشد می‌گردد و در صورتی که رشته داخل شامل CBC/PKCS5Paddingباشد، نتیجه را گزارش می‌دهد. این قانون از قابلیت قدیمی string matching استفاده می‌کند که دیگر پشتیبانی نمی‌شود. برای دست‌گرمی باید آن را با metavariable-regex جایگزین کنیم. این کار ساده است، اول یک metavariable به عنوان پارامتر تعریف می‌کنیم (در اینجاINS$) و بعد regex را روی آن اجرا می‌کنیم و نتیجه همان است:https://semgrep.dev/s/parsiya:java-cbc-padding-oracle-metavariable-regex# java-cbc-padding-oracle/cbc-padding-oracle-metavariable-regex.yaml
rules:
  - id: cbc-padding-oracle-metavariable-regex
    message: Match found
    languages:
      - java
    severity: WARNING
    patterns:
      - pattern: $CIPHER.getInstance($INS)
      - metavariable-regex:
          metavariable: $INS
          regex: .*\/CBC\/PKCS5Padding
    fix: $CIPHER.getInstance(&amp;quotAES/GCM/NoPadding&amp;quot)مقدار &quot;محاسبه&quot; قانون جدید در playground عدد بزرگتری بود و من خواستم آن را آزمایش کنم. قانون جدید خیلی پیچیده‌تر از قانون قدیمی نیست.$ multitime -q -n 50 ./cbc-padding-oracle.sh
===&gt; multitime results
1: -q ./cbc-padding-oracle.sh
            Mean        Std.Dev.    Min         Median      Max
real        0.781       0.006       0.773       0.780       0.806
user        0.501       0.041       0.406       0.500       0.609
sys         0.256       0.044       0.172       0.258       0.359$ multitime -q -n 50 ./cbc-padding-oracle-metavariable-regex.sh
===&gt; multitime results
1: -q ./cbc-padding-oracle-metavariable-regex.sh
            Mean        Std.Dev.    Min         Median      Max
real        0.788       0.007       0.778       0.786       0.813
user        0.516       0.047       0.406       0.516       0.609
sys         0.247       0.048       0.156       0.250       0.359 این مقدار محاسبه و عددی که در playground نشان داده می‌شود بحثی است که بعدا باید به آن بپردازم. خلاصه بگم، معمولاً نباید نگران عملکرد قانون خود باشید. مقدار زیادی از وقت Semgrep صرف خواندن و پردازش فایل‌ها و سپس درست کردن Abstract Syntax Tree (AST) کُد می‌شود. خیلی regex های پیچیده ننویسید اما دیگر نگران ذره ذره مسائل هم نباشید. برای دیدن زمانی که صرف هر بخش شده از سوییچ time--استفاده کنید.Java - HttpOnly Cookiesمی‌خواهیم چک کنیم که آیا کوکی ما دارای خصوصیت HttpOnlyاست و اگر نیست آن را درست کنیم. من قانون cookie-missing-httponly جاوا را خلاصه کرده‌ام:# java-httponly/httponly-practice.yaml
rules:
- id: cookie-missing-httponly
  message: Match found
  severity: WARNING
  languages: [java]
  patterns:
  - pattern-not-inside: $COOKIE.setValue(&amp;quot&amp;quot); ...
  - pattern-either:
    - pattern: $COOKIE.setHttpOnly(false);
    - patterns:
      - pattern-not-inside: $COOKIE.setHttpOnly(...); ...
      - pattern: $RESPONSE.addCookie($COOKIE);این قانون (https://semgrep.dev/s/parsiya:java-httponly-practice) چک می‌کند که آیا:ما به صورت دستی مقدار HttpOnly را false کرده‌ایم. در این صورت باید مقدار false را به true تغییر دهیم.یک کوکی به response (پاسخ؟) اضافه کرده‌ایم ولی HttpOnly را سِت نکرده‌ایم. در این صورت باید مقدار HttpOnly را به true تغییر دهیمبرای رفع این مشکل باید این قانون را به این دو بخش بشکانیم و دو قانون مجزا درست کنیم زیرا بخش fix برای همه قوانین اجرا می‌شود ولی ما دو نوع ترمیم مختلف داریم.ترمیم HttpOnly اولدر این ترمیم تنها باید مقدار false در ;COOKIE.setHttpOnly(false)$را با true جایگزین کنیم (برای تمرین از https://semgrep.dev/s/parsiya:java-httponly-practice-1 استفاده کنید):# java-httponly/httponly-practice-1.yaml
rules:
- id: cookie-missing-httponly-1
  message: Match found
  severity: WARNING
  languages: [java]
  patterns:
  - pattern-not-inside: $COOKIE.setValue(&amp;quot&amp;quot); ...
  - pattern: $COOKIE.setHttpOnly(false);
  fix: $COOKIE.setHttpOnly(true);semgrep -c httponly-practice-1.yaml httponly.javaترمیم HttpOnly دومدر این بخش ما ;RESPONSE.addCookie($COOKIE)$را می‌بینیم اما خبری از setHttpOnlyنیست. باید آن را اضافه کنیم. این قانون (https://semgrep.dev/s/parsiya:java-httponly-practice-2) این کار را انجام می‌دهد اما کد اضافه شده &quot;خوشگل&quot; نیست (برای جاوا فاصله و غیره مهم نیستند و شاید بگویید که این قانون برای من کافی است زیرا ابزارهای دیگری اتوماتیک کُد شما را فُرمَت می‎‌کنند).کُدِ زشتما می‌توانیم این مشکل را با فرمان fix-regex حل کنیم.فرمان fix-regexهمانطور که دیدیم برای جابجایی‌های ساده (مثلا تغییر badFuncبه goodFunc) فرمان fix کافی است. اما fix-regex به ما قدرت مانور بیشتری می‌دهد.https://semgrep.dev/docs/experiments/overview/#autofix-with-regular-expression-replacementاین فرمان سه بخش دارد: بخش regex که regular فارسیش واقعا چی میشه؟ اصلاً معادل داره؟) را روی بخشی از کد که توسط قانون پیدا شده است، اجرا می‌کند.بخش replacement: چیزی که باید با بخش بالا جایگزین شود.بخش count: تعداد جایگزینی‌ها.نکته: در حال حاضر (آوریل 2022) Semgrep از metavariable در fix-regex پشتیبانی نمی‌کند.با استفاده از fix-regex می‌توانیم قانون قبلی را دوباره بنویسیم. برای این کار اول باید ببینیم که چه چیزی capture می‌شود. این قانون را می‌توانید در https://semgrep.dev/s/parsiya:java-httponly-fix-regex-practice اجرا کنید.# java-httponly/httponly-fix-regex-practice.yaml
rules:
  - id: cookie-missing-httponly-fix-regex-practice
    message: Match found
    severity: WARNING
    languages:
      - java
    patterns:
      - pattern-not-inside: $COOKIE.setValue(&amp;quot&amp;quot); ...
      - pattern-not-inside: $COOKIE.setHttpOnly(...); ...
      - pattern: $RESPONSE.addCookie($COOKIE);
    fix-regex:
      regex: (.*)
      replacement: //\1نتیجه اجرای قانون بالادر جواب، //را دو بار می‌بینیم. چون regex ما greedy (حریص) است. برای این کار باید از فیلد count با مقدار یک استفاده کنیم که فقط اولین جایگزینی انجام شود.اجرای قانون با count برابر یکولی هنوز کُدِ خوشگل نداریم. برای این کار در بخش regex باید فاصله بین ابتدای خط تا اول کُد را capture کنیم. بعد در بخش replacement اول فاصله را جایگزین کنیم (1\) و بعد // و در انتها خود کُد (2\).    fix-regex:
      regex: (\s*)(.*)
      replacement: \1// \2
      count: 1حالا باید در خط جدید، کُدِ درست را وارد کنیم. اگر می‌توانستیم از metavariable ها استفاده کنیم کار ما خیلی راحت‌تر بود اما ترمیم پایین درست اجرا نمی‌شود. این را در https://semgrep.dev/s/parsiya:java-httponly-fix-regex-practice-2 می‌توانید امتحان کنید.# java-httponly/httponly-fix-regex-practice-2.yaml
    fix-regex:
      regex: (\s*)(.*)
      replacement: |
        \1$COOKIE.setHttpOnly(true);
        \1\2
      count: 1مقدار COOKIE$ در ترمیم جایگزین نشده استبرای این کار باید از قانون زیر استفاده کنیم (واقعا حوصله توضیح دوباره آن را ندارم ?):# java-httponly/httponly-fix-regex-practice-final.yaml
rules:
  - id: cookie-missing-httponly-fix-regex-practice-final
    message: Match found
    severity: WARNING
    languages:
      - java
    patterns:
      - pattern-not-inside: $COOKIE.setValue(&amp;quot&amp;quot); ...
      - pattern-not-inside: $COOKIE.setHttpOnly(...); ...
      - pattern: $RESPONSE.addCookie($COOKIE);
    fix-regex:
      regex: (\s*)(.*addCookie\((.*)\).*)
      replacement: |
        \1\3.setHttpOnly(true);
        \1\2
      count: 1بقیه بلاگ دیگر چیز جدیدی به شما یاد نمی‎‌دهد. اما می‌توانید در بلاگ انگلیسی بخوانید.چه یاد گرفتم؟قابلیت ترمیم خودکار Semgrep بسیار جالب است. من از آن برای اضافه کردن comment به کد استفاده می‌کنم تا هنگام مرور آن بدانم هر بخش چه مشکلی دارد.</description>
                <category>پارسیا</category>
                <author>پارسیا</author>
                <pubDate>Sun, 24 Apr 2022 00:06:22 +0430</pubDate>
            </item>
                    <item>
                <title>چرا از Semgrep برای Static Analysis استفاده کنیم؟</title>
                <link>https://virgool.io/@parsiya/semgrep-1-eunz6j8fxjib</link>
                <description>در static analysis ما برنامه را اجرا نمی‌کنیم و معمولاً فقط کد (یا کد decompile یا disassemble شده) آن را بررسی می‌کنیم. توضیح این روش از حوصله این مقاله خارج است (خودمونیش این میشه که گوگل کنید).طبق معمول همیشه یک کپی از این بلاگ را می‌توانید در بلاگ فارسی من در آدرس زیر ببینید:https://parsiya.github.io/parsiya.fa/post/2021/semgrep-1/چرا static analysis؟من یک مهندس امنیت محصول (ترجمه product security engineer) هستم و معمولا به کد محصولات دسترسی دارم. بررسی کد یکی از مهمترین بخشهای کار من است. محصولات نرم‌افزاری مدرن (و به خصوص بازیهای کامپیوتری) ملغمه ای از چند هزار کتابخانه و فریمورک هستند و بررسی دستی کد آنها غیرممکن است. به عنوان مثال یک بازی کامپیوتری حداقل چندین میلیون خط کد دارد: کد client بازی که روی کامپیوتر و یا کنسول اجرا می‌شود (معمولاً ++C).کد سرورهای مختلف مانند login, lobby, matchmaking و غیره که می‌تواند به هر زبانی باشد.کد برنامه موبایل همراه بازی مانند FIFA 21 Mobile companion app. زبان برنامه نویسی معمولاً جاوا (اندروید) و swift (برای iOS) است.کد integration با سرویسهای دیگر مانند market place و یا Steam.کد زیرساخت ابری (منظور اینجا infrastructure-as-code مثل Terraform است که فارسیش نمی‌دونم چیِ).برای بررسی این همه کد باید به چندین زبان برنامه‌نویسی و فریمورک عمومی و خصوصی (ترجمه آزاد proprietary) مختلف مسلط بود (که تقریبا امکان ندارد) و از ابزارهای مختلف استفاده کرد.استفاده از grepمهمترین اسلحه من برای بررسی کد، grep است. معمولاً به دنبال کلمات کلیدی در کد می‌گردم تا قسمت‌های مهم را پیدا کنم. مثلاً  grep -ir password در تمامی فایلهای دایرکتوری حاضر (و فرزندانش) به دنبال کلمه password (صرفنظر از حروف کوچک و بزرگ) می‌گردد. در چند سال اخیر از برنامه ripgrep که با زبان برنامه‌نویسی Rust نوشته شده است، استفاده می‌کنم. به عنوان یک gopher سابق همیشه به شوخی می‌گویم که بالاخره Rust هم یک فایده‌ای داشت.تا یک سال قبل شاید 90 درصد باگ‌های امنیتی در کد را با grep پیدا کرده بودم. بعد از مدتی سروکله زدن با فریمورک‌ها و زبانهای برنامه‌نویسی مختلف لیستی از کلمات مهم درست می‌کنید و به دنبال آنها می‌گردید.نقطه ضعف grepبزرگترین مشکل grep برای تحلیل کد، ندانستن مفهوم کلمات است. grep برای جستجوی متن طراحی شده و برایش مهم نیست که این کلمه در آن زبان برنامه‌نویسی چه تایپی دارد (مثلاً تابع یا کامنت یا غیره). اگر به دنبال کلمه password در کد Go زیر بگردیم چهار نتیجه مختلف داریم:// nem.go
package main
func main() {
    // کلمه پسورد اینجا بخشی از کامنت است
    // Hardcoded passwords are bad.

    // کلمه پسورد در اینجا نام متغیر است
    password := &amp;quothunter2&amp;quot

    // کلمه پسورد در اینجا بخشی از یک استرینگ است
    errorMsg := &amp;quotIncorrect password&amp;quot
}

// کلمه پسورد در اینجا بخشی از نامِ تابع است
func validatePassword(p string) bool {
    // Do something
    return true
}grep -in passwordفرض کنیم هدف من توابعی است که در نام خود کلمه پسورد را دارند. در اینجا با استفاده از grep باید چهار نتیجه را بررسی کنم تا به جواب برسم. شاید بگویید که این مشکلی نیست ولی، در یک برنامه واقعی با میلیونها خط کد، هر جستجو صدها نتیجه بی‌ربط (false positive) دارد.یک تکنیک من برای حل این مشکل جستجوی پرانتز به همراه نام تابع بود.grep -in &quot;password(&quot;این تا حدی کمک می‌کند ولی مواردی که فاصله یا whitespace بین پرانتز و کلمه پسورد وجود دارد را پیدا نمی‌کند. می‌توانم با استفاده از regular expression جستجوی خود را بهتر کنم ولی در انتها راهی وجود ندارد که به grep بفهمانم که فقط به دنبال نام تابع بگردد.ورود Semgrepروز آشنایی با Semgrep یکی از بهترین روزهای زندگی شغلی من بود. با استفاده از Semgrep می‌توانم چند پله بالاتر از grep عمل کنم و به برنامه بفهمانم که فقط در یک تایپ خاص به دنبال کلمات بگردد. نمی‌خواهم این پست را به &quot;آموزش Semgrep&quot; تبدیل کنم. برای این کار از https://semgrep.dev/learn شروع کنید. ولی، چند مثال کوتاه را توضیح می‌دهم.https://semgrep.dev/learn/2می‌خواهیم در کد Python زیر همه مواردی که تابع logging.info با پارامتر تابع get_user فراخوانی شده را پیدا کنیم.import logging as lg

def get_user(uid):
    d = {1: &amp;quotharry&amp;quot, 2: &amp;quotron&amp;quot, 3: &amp;quothermione&amp;quot}
    return d[uid]

# Match both of these using an ellipsis.
logging.info(get_user(1)
    + &amp;quot logged in&amp;quot)
lg.info(get_user(2)
    + &amp;quot logged in&amp;quot)اگر از grep استفاده کنیم:grep -in &quot;logging.info(.*get_user.*&quot;اینجا مورد اول پیدا شد و مورد دوم نه. چرا؟ چون grep نمی‌داند که lg در اینجا معادل logging است. با Semgrep  این مشکل را نداریم چون می‌داند که اینجا lg و logging یکی هستند. ... هم همان غیره خودمان است که با همه چیز match می‌شود (توضیح بیشترش را در خود آموزش بخوانید).https://semgrep.dev/learn/6اینجا به بحث شیرین metavariable می‌رسیم که می‌تواند جایگزین هر آیتم باشند. اگر بخواهیم همه توابع را در Python پیدا کنیم:def $FUNC(...):
    ...پیداکردن همه توابع در Pythonحالا می‌توانیم داخل این توابع جستجو کنیم. در اینجا فقط یک جستجوی ساده انجام می‌دهیم. می‌خواهیم که ببنیم آیا تابع با یک مِتُد از requests تمام می‌شود؟حالا فرض کنید بخواهیم یک rule برای امنیت بنویسیم. می‌خواهیم چک کنیم که آیا ورودی تابع در پارامترهای مِتُدِ requests وجود دارد؟ چرا این کار ناامن است؟ فرض می‌کنیم که ورودی تابع مستقیماً از ورودی کاربر است و اگر به کاربر اجازه دهیم تا هر URL را دریافت کند ممکن است به مشکل SSRF بربخوریم. rule ما به این صورت است.def $FUNC($USERINPUT):
    ...
    requests.$METHOD(...,$USERINPUT,...)در خط اول یک metavariable تعریف کرده‌ام که به جای ورودی تابع است. سپس، چک می‌کنیم که ورودی به مِتُد می‌رسد یا خیر. یک مِتُد امن هم به کد اضافه کرده‌ام که نباید در نتایج باشد.با metavariable ها کارهای عجیب غریبی می‌توانیم انجام بدهیم. مشابه همین کاری که کردیم را در بخش 8 آموزش می‌بینیم.https://semgrep.dev/learn/8اگر در Python یک فایل را برای خواندن باز کرده باشیم دیگر نباید به آن بنویسیم. در اینجا metavariable متغیر حاوی هَندِلِ فایل است. سپس می‌توانیم چک کنیم که آیا متد write را برای آن فراخوانی کرده‌ایم. پس rule ما این شکل می‌شود:https://semgrep.dev/learn/13درس 13 جالب است. می‌توانیم توسط pattern-inside بخشهایی که می‌خواهیم را جدا کنیم و سپس داخل آنها را با pattern بگردیم. اینجا می‌خواهیم که داخل توابع این کُدِ Go:آیا پارامتر ورودی از نوع http.ResponseWriter هست؟آیا مِتُدِ Write روی آن فراخوانی شده است؟در ابتدا rule به این صورت است. اول همه توابع توسط pattern-inside انتخاب می‌شوند و بعد در داخل آنها به دنبال متد Write می‌گردد.باید pattern-inside را دستکاری کنیم تا تنها توابعی را پیدا کند که یکی از پارامترهای ورودیشان از نوع http.ResponseWriter است. با گذاشتن ... قبل و بعد پارامتر به Semgrep می‌گوییم که این پارامتر می‌تواند هرجا باشد.- pattern-inside: |
    func $FUNC(..., $WRITER http.ResponseWriter, ...) {
      ...
    }حالا می‌توانیم توسط pattern چک کنیم که آیا مِتُدِ Write روی این ورودی فراخوانی شده یا خیر.حل مساله اولحتماً کل آموزش را تا انتها ادامه دهید ولی حل تک تک آنها در این پست فایده‌ای ندارد. بجای آن می‌خواهم مشکلی که در اول داشتیم را حل کنم. مشکل ما این بود که میخواستیم توابعی که در نام آنها کلمه password وجود دارد را پیدا کنیم. می‌توانید به صورت عملی راه‌حلهای خودتان را در این آدرس امتحان کنید https://semgrep.dev/s/WODo.در مرحله اول یک pattern می‌نویسیم تا همه توابع را پیدا کند. این کار را قبلا انجام داده‌ایم و چیز عجیبی نیست.جواب جستجو هر دو تابع را پیدا کرد. دقت کنید که الان نام تابع در metavariable به نام FUNC ذخیره شده. حالا، می‌توانیم از قابلیت metavariable-regex استفاده کنیم و یک regex را روی آن اجرا کنیم.rules:
  - id: password-in-func-name
    languages:
      - go
    message: Find functions that have password in their name.
    patterns:
      - pattern: |
          func $FUNC(...) {
            ...
          }
      - metavariable-regex:
          metavariable: $FUNC
          regex: .*password.*
    severity: ERRORولی باز هم کار نمی‌کند چون regex به صورت case-sensitive اجرا می‌شود. برای اجرای آن به صورت case-insensitive می‌توانیم از inline flag استفاده کنیم.regex: (?i).*password.*و جوابمان را گرفتیم.چی یاد گرفتیم؟یاد گرفتیم که با استفاده از Semgrep راحت‌تر داخل کد جستجو کنیم. با Semgrep کارهای خیلی عجیب غریبی کرده‌ام که خودم هم باورم نمی‌شود. شما هم می‌توانید از این ابزار مجانی در کار خود استفاده کنید و به قولی sky is the limit.نقشه من برای بلاگ بعدی:چرا  از Semgrep (مثلا به جای CodeQL) استفاده می‌کنم.چگونه از Semgrep در CI/CD استفاده می‌کنم.</description>
                <category>پارسیا</category>
                <author>پارسیا</author>
                <pubDate>Sun, 04 Jul 2021 11:41:48 +0430</pubDate>
            </item>
                    <item>
                <title>دستکاری سِیو بازی Car Mechanic Simulator 2015</title>
                <link>https://virgool.io/@parsiya/car-mechanic-simulator-2015-save-korlzhkvayjm</link>
                <description>این کار &quot;هک&quot; نیست و با کاری که من در محل کارم انجام می‌دهم خیلی متفاوت است. ولی، دستکاری save این بازی فرصت خوبی است تا با یکسری از مفاهیم امنیت بازیهای کامپیوتری آشنا شویم.اصل این نوشته را می‌توانید در بلاگ انگلیسی من بخوانید و مانند همیشه یک کپی از این نوشته در بلاگ فارسی من در https://parsiya.github.io/parsiya.fa/post/game-hacking-1 در دسترس است.پیش زمینهدستکاری سِیو، یکی از قدیمی‌ترین و ساده‌ترین روشها برای تقلب در بازیهای کامپیوتری است. تقلب در بازی یکی از عوامل اصلی آشنایی افراد با مقوله امنیت است. خیلی از افراد از جمله من از اینجا شروع کردیم و اولین قدمهای خود را با مهندسی معکوس ساختار سِیوهای بازی برداشتیم.هیچ وقت فکر نمی‌کردم که حقوق بگیرم که بازی کامپیوتری هک کنم.هدف مادر این بازی ما یک مکانیک هستیم که باید قطعات مختلف اتومبیل را عوض کند. دو مشخصه داریم:پول.تجربه یا experience.هدف ما دستکاری سِیو بازی و تغییر این مقادیر است. سِیوهای بازی(نگارش Steam) در ویندوز در آدرس زیر ذخیره می‌شوند:%AppData%\LocalLow\Red Dot Games\Car Mechanic Simulator 2015\در اینجا چند دایرکتوری داریم که هر کدام مخصوص یک پروفایل در بازی هستند و نام آنها profile0 و غیره است.اولین قدم: جستجوی اعداد در فایلاولین قدم همیشه تبدیل مقداری که می‌خواهیم عوض کنیم به مبنای 16 یا hex و جستجوی آن در فایل است. این کاری است که در اکثر بازیهای قدیمی جواب می‌دهد. مثلاً اولین دستکاری سِیو من در بازی Heroes of Might and Magic بود. فرض کنید در این بازی می‌خواستم تعداد Unicorn هایم را اضافه کنم. دو گروه 13 عددی تشکیل می‌دادم و بعد در فایل سِیو به دنبال 0D می‌گشتم. اگر دو مقدار نزدیک به هم پیدا می‌کردم آنها را به FF (یا 255) تغییر می‌دادم. اگر درست بود، که چه خوب وگرنه دوباره جستجو می‌کردم.در بازی SimCity 2000 هم مقدار پول در مبنای 16 در فایل سِیو ذخیره میشد. نکته‌ای که در سِیو این بازی وجود داشت این بود که تعداد بایتها با افزایش عدد افزایش پیدا می‌کرد. مثلاً مقدار 10000 به صورت 0x2710 در دو بایت ذخیره میشد. برای افزایش پول اگر این دو بایت را به FF FF تغییر می‌دادم به 65535 می‌رسیدم که پول زیادی نبود. اما اگر خودم یک بایت به فایل اضافه می‌کردم دیگر فایل قابل بارگذاری نبود. این به احتمال زیاد برای این بود که offset قسمتهای مختلف فایل به هم می‌ریخت.برای حل این مشکل اول مقدار پول خود را به 65535 تغییر می‌دادم. سپس با انتشارjunk bond (چیزی شبیه اوراق مشارکت) مقدار پول خودم را اضافه می‌کردم تا نیاز به بایتهای بیشتری برای ذخیره آن باشد و سه بایت شود. سپس آن را به FF FF FF و یا 16 میلیون و خرده‌ای تغییر می‌دادم. با این کار دیگر احتیاجی به مهندسی معکوس بقیه فایل نبود و سریع به هدفم رسیدم.مقدار پول و تجربه من در ابتدادر اینجا هم به دنبال 0x07D0 (معادل 2000 در مبنای 16) و کلمه money در کل فایلهای دایرکتوری یک پروفایل گشتم:$ grep -arb $&#039;\xd0\x07&#039;
global:631:▒▒▒▒{~gameVer▒▒▒▒▒1.1.6.0{~date▒▒▒▒▒2017-11-28 22:56:20{
$ grep -arb money
global:610:▒▒▒{~moneyاین مقادیر در فایلی به نام global پیدا شدند:تجربه و پول در فایل globalحدس آگاهانه یا educated guess  یکی از مهمترین تواناییها در مهندسی معکوس حدس زدن آگاهانه است (فکر کنم ترجمه فارسی educated guess). یعنی با داشتن اطلاعاتی محدود و معمولاً بر اساس تجربه حدس می‌زنیم. سپس این حدس را امتحان می‌کنیم و اگر درست بود زمان معمولاً زیادی صرفه‌جویی شده است. اگر غلط بود حدسمان را با نتیجه آزمایش تغییر می‌دهیم و دوباره آزمایش می‌کنیم.مثلاً بعد از دیدن فایل با این فرمت من مطمئن هستم که این یک فایلِ serialize شده است. بعد از دیکامپایل کردن بازی و جستجو در کد، فهمیدم که از کتابخانه Easy Save 2 استفاده شده است.این دو عدد به صورت little-endian در چهار بایت ذخیره شده اند. حدس من این است که این مقادیر در یک متغیر از نوع int 32 ذخیره شده‌اند. برای آزمایش حدس این مقادیر را به FF FF FF FF تغییر دادم.دستکاری فایل global و تغییر پول و تجربهو بازی را شروع کردم اما نتیجه آن چیزی که می‌خواستم نبود.مقدار پول و تجربه منفی استاین یعنی چه؟ این یعنی مقدارها در یک متغیر از نوع signed int 32 ذخیره می‌شوند. در یک متغیر signed اولین بیتِ بزرگترین بایت (یعنی بایت چهارم) مخصوص علامت عدد است (اگر صفر باشد مثبت است و اگر یک باشد منفی). اگر عدد منفی باشد بقیه عدد به صورت two&amp;amp;#x27;s complement (فارسیش واقعاً نمی‌دانم چه می‌شود) ذخیره می‌شود. برای بدست آوردن این مقدار همه بیت‌ها را تغییر می‌دهیم (اگر صفر بود یک می‌شود و برعکس) و سپس با یک جمع می‌کنیم. برای همین است که FF FF FF FF در واقع منفی یک است.برای داشتن بزرگترین عدد ممکن در یک signed int 32 باید عدد 7F FF FF FF را وارد کنیم.بزرگترین مقدار ممکن پول و تجربهمشکل جدید و integer overflowاینجا فکر کردم کار من تمام شده و حواسم به integer overflow نبود. بعد از شروع بازی و کمی تجربه کسب کردن، تجربه‌ام دوباره منفی شد.تجربه منفیچرا؟ چون مقدار در یک signed int 32 ذخیره می‌شود و ما بزرگترین عدد ممکن (max int) را در تجربه داشتیم. اضافه کردن یک به چنین عددی باعث می‌شود که integer overflow داشته باشیم و تبدیل به کوچکترین عدد ممکن شود. اضافه کردن 1 به 7F FF FF FF مقدار 00 00 00 80 را به ما می‌دهد که معادل min int است. بازی هم کنترلی برای چِک کردن این حالت ندارد چون در داخل بازی هیچ‌وقت به چنین مقدار پول یا تجربه‌ای نمی‌رسیم.برای حل این مشکل باید عددی کوچکتر وارد کنیم. مثلاً من مقدار 7F 00 00 00 را وارد کردم.مکانیک با تجربه!!آیا این یک مشکل امنیتی است؟معمولاً دستکاری سِیو یک مشکل امنیتی (security issue) نیست. اکثر سِیوها برای بازیهای تک نفره (single player) هستند و مشکل امنیتی این بازیها بسیار محدود است. اگر بشود با چنین سِیو در یک بازی چند نفره (multiplayer) بازی کرد آن وقت مشکل داشتیم. مثلاً اگر این بازی یک حالت چند نفره داشت و همه با هم در یک تعمیرگاه کار می‌کردند آن وقت مشکل داشتیم.اکثر مشکلات بازیهای تک نفره امنیتی نیستند. مثلاً یکی از بازیهای تک نفره ما Jedi: Fallen Order است. اگر شما بتوانید در این بازی تقلب کنید تاثیری در بازی بقیه کاربران ندارد. هنگام تست امنیتی چنین بازی این مسائل برایم مهم نیست.تنها حالتی که ممکن است دستکاری سِیو یک بازی فقط تک نفره مشکل امنیتی باشد وقتی است که باز کردن این سِیو در یک کامپیوتر دیگر باعث remote code execution یا دستکاری فایلهای کامپیوتر مقصد شود.این مشکل در بازی Untitled Goose Game وجود داشت. این بازی هم با موتور Unity تولید شده است و سِیوهای این بازی هم serialize شده هستند و هنگام بارگذاری آن و deserialize کردن کنترلی ندارد. اطلاعات بیشتر را در لینک زیر می‌توانید بخوانید. چیز عجیبی نیست یک insecure deserialization کلاسیک  دات‌نت است.https://pulsesecurity.co.nz/advisories/untitled-goose-game-deserializationچی یاد گرفتیم؟دستکاری سِیو این بازی بسیار ساده است اما ما را با مفاهیمی مانند serialization، معندسی معکوس فایل و int 32 آشنا کرد و دستگرمی خوبی است.</description>
                <category>پارسیا</category>
                <author>پارسیا</author>
                <pubDate>Sun, 16 May 2021 07:07:24 +0430</pubDate>
            </item>
                    <item>
                <title>در اهمیت زبان انگلیسی</title>
                <link>https://virgool.io/@parsiya/write-in-english-qsmyxxuhixnc</link>
                <description>یازده سال پیش برای پر کردن رزومه در دانشگاه آزاد چند ترم درس دادم. یکی از درس‌هایم &quot;زبان تخصصی کامپیوتر&quot; بود. همیشه به بچه‌ها می‎‌گفتم که مهمترین درسی که در دانشگاه یاد می‌گیرید همین است. هنوز هم روی حرفم هستم. ساختمان داده و برنامه‌نویسی و غیره مهم نیست، زبان بخوانید.پس زبان انگلیسی خیلی خوب است؟نه، کلی مزخرف هم به زبان انگلیسی چاپ شده است. ولی، زبان انگلیسی زبان علمی جهان است. تحقیقات دست اول به این زبان تولید و منتشر می‌شوند. کنفرانس‌های بین‌المللی به این زبان هستند. زبان همه شرکت‌های چندملیتی (مثل کارفرمای خودم) همین است. نوشتن به زبان انگلیسی به شما کمک می‌کند تا در مورد دانش خود صحبت کنید و مقاله بنویسید.هر زبان دیگری همین فواید را داشت باید همان را یاد می‌گرفتیم. زمان ابن‌سینا باید عربی می‌خواندیم، زمان سقراط یونانی، و زمان سینوهه هم خط هیروگلیف مصری.خوب ترجمه اش را می‌خوانماول باید صبر کنید یک نفر وقت بگذارد و ترجمه کند. بعد باید به آن ترجمه اعتماد کنید. خدابیامرز آقای ذبیح الله منصوری مشهور به این بودند که خودشان به ترجمه اضافه می‌کردند. این کار حتی در کتاب‌های غیرعلمی مشکل ایجاد می‌کند چه برسد به متن تخصصی.ترجمه های قشنگانگیزه اصلی من برای خواندن زبان، کتاب‌های خدابیامرز دیگر آیزاک آسیموف در ژانر علمی-تخیلی بود. انتشاراتی به نام شقایق اکثر کتاب‌هایش را ترجمه می‌کرد و اکثر جلدهایش به همین شکل بود. تقریباً هر چه پول داشتم خرج این کتاب‌ها می‌کردم. این جلد را بیشتر از همه دوست داشتم.عنوان اصلی کتاب &quot;بنیاد دوم&quot;این کتاب جلد سوم از سه گانه بنیاد آسیموف است. سه گانه بنیاد سه کتاب دارد که به ترتیب &quot;بنیاد&quot;، &quot;بنیاد و امپراطوری&quot; و &quot;بنیاد دوم&quot; نام دارند. این سه کتاب به نام‌های &quot;ظهور/جنگ/سقوط امپراطوری کهکشان‌ها&quot; در ایران منتشر شدند. حتی جلد کتاب بالا هم دزدی است. این اثری به نام Visions of Cassandra از Michael Whelan و برای کتاب دیگری است. حالا حساب کنید که کتابی که اسم و جلدش عوض شده چقدر به متن اصلی‌اش نزدیک است؟یادم هست کتاب دیگری داشتم که مجموعه ای از داستان‌های کوتاه آرتور سی کلارک بود. اسم اصلی کتاب Tales from the White Hart است ولی ترجمه اسم دیگری داشت که یادم نیست (جلدش قرمز بود). یک جمله از آن هنوز یادم هست. در تشبیه یک ساختمان نوشته بود &quot;شبیه یکی از زاده‌های فرانک اِل وان اوید رایتی بود&quot;. وقت خواندن این جمله تنها شانسی که آوردم این بود که خواهرم معماری خوانده بود و من نام فرانک لوید رایت را شنیده بودم. حالا چرا Lloyd تبدیل شده به &quot;اِل وان اوید&quot;؟ به دلیل اینکه در ماشین تحریر‌های قدیمی دکمه شماره یک وجود نداشت و از حرف L کوچک بجای آن استفاده می‌شد. طرف هم فکر کرده L1oyd  و نه Lloyd است. چقدر اشتباه بزرگی است که من هنوز بعد از 25 سال یادم هست. حالا کسی که اسم را نتوانسته ترجمه کند بقیه را چه کرده؟جعفرنژاد قمی هم که معرف حضور همه کامپیوتری‌ها هست. ایشان هر چه کتاب کامپیوتر بود ترجمه می‌کردند. چقدر ایشان دخل و تصرف کرده اند معلوم نیست.و این لیست ادامه دارد… .چرا انگلیسی بنویسیم؟چون مخاطب بیشتری خواهیم داشت. مخاطب بیشتر یعنی افراد بیشتری می‌دانند شما وجود دارید. یک روز در مورد این قضیه به مفصل خواهم نوشت. با نوشتن و تمرین بهتر می‌شوید.بلاگ من دلیل اصلی شغل حاضرم است. مدیر تیم، بلاگ من را خوانده بود و کسی را دنبال من فرستاده بود. زمان مصاحبه هم بیشتر با هم در مورد کار صحبت کردیم چون با خواندن نوشته‌های من به این نتیجه رسیده بود که به درد تیم می‌خورم. از طریق همین بلاگ در توییتر با افراد دیگر صنعت خودم آشنا شده ام که وقتی بخواهم کارم را عوض کنم به من کمک می‌کند. همین افراد اشکالات نوشته‌هایم را به من گوشزد کرده‌اند و سوال پرسیده‌اند. حتی بعضی مواقع گفته‌اند فلان متن مشابه را هم بخوان، به حل این مشکل کمک می‌کند.یک مثال از خودم در مورد تمرین و بهتر شدن بزنم. من از سال 2013 و بعد از شروع به کار در آمریکا شروع به نوشتن کردم. تا قبل از آن فکر می‏‎‌کردم زبانم خیلی خوب است. ناسلامتی تافل 113/120 داشتم و دو سال هم به انگلیسی درس خوانده بودم. ولی خیلی خبری نبود.مثلاً این پست را درسال 2013 و با نام Snow Crash and Malware نوشتم.So I finished &quot;Snow Crash&quot; and it was quite nice. The concept of linguistic malware was interesting and ahead of its time. I noticed that the term &quot;Virus&quot; was used correctly in the book as the malware was not propagating between people (then it would become a worm). Although I suspect it was due to the fact that most people (read almost everyone) calls any malware a &quot;virus&quot;. Nevertheless, it was a very enjoyable read.چقدر بد می‌نوشتم. شاید اگر بخواهم دوباره بنویسم این شود که هنوز هم در حد شکسپیر نیست اما برای ساعت یک نیمه شب خوب است:Finished the book &quot;Snow Crash.&quot; One of the classics. Linguistic malware is such a fascinating concept. Fortunately, Neal Stephenson used the term &quot;virus&quot; correctly in the book which is a pet peeve of mine. To the public, any computer malware is a virus.از نظر خودم نوشتن‌ام وقتی خوب شد که دیگر به فارسی فکر نکردم و کلمات را در ذهنم ترجمه نکردم.کجا بنویسیم؟هرجا که دوست داشتید. این روزها نوشتن نیازی به هزینه اضافی ندارد. اگر دامنه خاص نخواهید می‌توانید یک بلاگ مجانی در صفحات گیت‌هاب داشته باشید که در پست قبلی درباره آن نوشته‌ام.بعد از نوشتن ممکن است بقیه شما را مسخره کنند. مهم نیست. قبول دارم ترسناک است و آدم ناراحت می‌شود ولی باید پیه‌اش را به تنمان بمالیم. خوشبختانه حداقل در جامعه امنیت دنیا افرادی که انگلیسی زبان اولشان نیست مورد تمسخر زیادی قرار نمی‌گیرند. مثلاً دیگر مهم نیست که فلان سخنران با لهجه خاصی انگلیسی صحبت می‌کند.یکی از سریعترین راه‌ها برای بهترشدن نوشته‌، استفاده از سرویس‌هایی مانند Grammarly است. متن خود را در نگارش مجانی این سرویس تست کنید. به دو نکته دقت کنید: فقط طوطی‌وار مشکلات را اصلاح نکنید بلکه ببینید چرا غلط داشتید و درستش چیست. کم کم یاد می‌گیرید که چگونه بنویسید. ولی، به آن وابسته نشوید.متون سِرّی را به این سرویس‌ها ندهید. مثلاً من فقط بلاگ‌های عمومی خودم را قبل از انتشار تصحیح می‌کنم و نه باگی که در محل کارم پیدا کرده‌ام.سوال و جوابنمیشه فقط فیلم ببینم؟ نه!پس بقیه مثل خواندن و شنیدن و صحبت چه شد؟ همه مقداری خواندن را در مدرسه یاد گرفته‌ایم. فرض بر این است که می‌توانید کجدار و مریز بخوانید و بنویسید.اگر حوصله خواندن زبان نداشته باشم چه؟ نخوانید.اگر زبانم بد بود و خجالت کشیدم چه؟ مگر همه در خانواده با زبان انگلیسی بزرگ شدیم؟ همه باید از یکجا شروع کنیم و چه وقتی بهتر از الان.چرا فارسی ننویسیم؟ هم فارسی بنویسید و هم انگلیسی.حتما باید نوشته‌هایم را منتشر کنم؟ نه. اجباری نیست ولی بدون انتشار کسی نمی‌داند شما چقدر بلد هستید.آخر من چیزی بلد نیستم؟ چرا بلد نیستید؟ خوب هم بلدید. بالاخره یک چیزی هست که در مورد آن بدانید. در همان مورد بنویسید. این خود بهانه‌ای می‌شود که در مورد آن تحقیق کنید و بیشتر یاد بگیرید.آیا نوشتن پست‌های تخصصی با دانش ابتدایی مشکلی ندارد؟ نخیر که ندارد. کسی علامه به دنیا نیامده است. نوشتن پست تخصصی در مورد موضوعات ابتدایی خیلی هم خوب است. چند صد بلاگ در مورد Cross-Site Scripting نوشته شده‌اند. هر نوشته جدید یک نگاه جدید است و ممکن است خواننده از آن چیز جدیدی یاد بگیرد.نمیشه فارسی بنویسیم و یکی ترجمه کند؟ بیخود!حالا فیلم ببینم نمیشه؟ ای بابا!</description>
                <category>پارسیا</category>
                <author>پارسیا</author>
                <pubDate>Fri, 30 Apr 2021 19:35:55 +0430</pubDate>
            </item>
                    <item>
                <title>توسعه و میزبانی سایت روی صفحات گیت‌هاب</title>
                <link>https://virgool.io/@parsiya/farsi-blog-github-pages-tb8lglazafvx</link>
                <description>در این پست تجربه خودم در راه‌اندازی یک بلاگ فارسی بر پایه Hugo روی صفحات گیت‌هاب (Github Pages) را می‌نویسم. نوشتن این تجربیات به من کمک می‌کند که اگر در آینده خواستم کاری را تکرار کنم چرخ را دوباره اختراع نکنم. همین نوشته را در سایت فارسی من (که با همین روش ایجاد شده است) در لینک زیر ببیند:https://parsiya.github.io/parsiya.fa/post/github-actions-farsi-site/نگارش انگلیسی این نوشته (با کمی تغییر) را در لینک زیر می‎‌توانید ببینید:https://parsiya.net/blog/2021-02-17-automagically-deploying-websites-with-custom-domains-to-github-pages/چرا گیت‌هاب؟در سایت انگلیسی من نمی‌توان فارسی نوشت چون قالب سایت از راست-به-چپ پشتیبانی نمی‌کند. سایت اصلی من بر روی AWS قرار دارد که متاسفانه استفاده از این سرویس‌ها در ایران امکانپذیر نیست. اما صفحات گیت‌هاب علاوه بر مجانی بودن دیگر شامل تحریم نیستند. گیت‌هاب پس از دو سال سر و کله زدن توانسته مجوز مربوطه را بگیرد.چرا Hugo؟ صفحات گیت‌هاب به صورت native از Jekyll پشتیبانی می‌کنند ولی کار با Hugo برای من راحت‌تر است. تقریباً تمام سایتهای من توسط Hugo تولید شده‌اند. اکثر این static website generator ها (مولّد سایت استاتیک؟) روش کاری یکسانی دارند. شما مطالب را با فرمت markdown می‌نویسید و بقیه کار را به آنها می‌سپارید.لزومی ندارد حتماً از هوگو و یا جِکیل استفاده کنید، هر مولّدی که با آن راحت‌تر هستید را انتخاب کنید. به احتمال زیاد راهنمای استفاده از آن برای صفحات گیت‌هاب وجود دارد. خوشبختانه دیگر نیازی به اجرای دستی بسیاری از مراحل نیست و Github actions به کمک ما می‌آیند.روش استفاده کل سایت در یک repository (مخزن؟) گیت در گیت‌هاب ذخیره می‌شود.مطالب را به فرمت markdown می‌نویسید و در یک یا چند کامیت به مخزن اضافه می‌کنید.پس از هر کامیت یک Github action سایت را تولید می‌کند.سایت تولید شده در یک branch (شاخه؟) مجزا ذخیره می‌شود.گیت‌هاب این شاخه را به عنوان یک سایت، serve می‌کند (فارسیش چی میشه؟).دانش پیشینبرای این پست شما باید یکسری موارد را بدانید:آشنایی با Hugo (اگر از مولّد سایت دیگری استفاده می‌کنید می‌توانید بخشهای مربوط به Hugo را سرسری رد شوید).آشنایی ابتدایی با گیت. در حد اینکه کامیت و شاخه چه هستند.انواع صفحات گیت‌هاببر روی گیت‌هاب می‌توانیم سه نوع سایت مختلف داشته باشیم:سایت کاربر یا user site: هر نام کاربری می‌تواند یک سایت در آدرس username.github.io داشته باشد.سایت سازمان یا organization site: مشابه صفحه کاربر است. مثلاٌ  https://microsoft.github.io.سایت پروژه یا project site: هر پروژه می‌تواند یک سایت مجزا داشته باشد. آدرس سایت پروژه وابسته به نام کاربری یا سازمانی است که صاحب اکانت است.با استفاده از سایت‎های پروژه شما می‌توانید تعداد نامحدود سایت در صفحات گیت‌هاب داشته باشید.من از سایت فارسی خودم برای مثال استفاده می‌کنم که یک سایت پروژه است:آدرس سایت: https://parsiya.github.io/parsiya.faآدرس مخزن سایت: https://github.com/parsiya/parsiya.faقالب با متن راست-به-چپقالب سایت من قابلیت راست-به-چپ ندارد. آن را خودم از Octopress به Hugo منتقل کرده‌ام و از css چیز زیادی نمی‌دانم. بنابراین تصمیم گرفتم از قالب دیگری استفاده کنم. بعد از چند انتخاب به قالب hugo-PaperMod رسیدم. Hugo از زبانهای مختلف در سایت پشتیبانی می‌کند. معمولاً این برای انتشار نسخه‌های یک صفحه (یا سایت) به چند زبان استفاده می‌شود. شما یک صفحه را به انگلیسی و فارسی می‌نویسید و Hugo بقیه کار را انجام می‌دهد.من تنها می‌خواهم به فارسی بنویسم پس نیازی به استفاده از چند زبان ندارم. این موارد را به config.yml سایتم اضافه کردم:languageCode: fa
defaultContentLanguage: fa

languages:
  fa:
    languagedirection: rtl
    weight: 1استفاده از فونت وزیرکار دیگر استفاده از فونت فارسی وزیر بود. ویرگول هم از این فونت استفاده می‌کند. خوشبختانه این فونت یک مجوز باز برای استفاده دارد.مرحله اول دانلود فونت وزیر و قراردادن آن در دایرکتوری static سایت بود. در Hugo هر چیزی که در static باشد عیناً به root خود سایت اضافه می‌شود. فونت وزیر دو بخش دارد یکی خود فایل‌های فونت و دیگر css. اینها را در دایرکتوری‎‌های جداگانه قرار دادم (این کار لزومی ندارد ولی خوشگل‌تر است).مرحله دوم اضافه کردن css فونت به قالب بود. در Hugo برای شخصی‌سازی قالب نیازی به دستکاری مستقیم آن نیست. برای اضافه کردن css باید فایل مربوط به بخش head هر صفحه قالب را دستکاری می‌کردم. در این قالب برای دستکاری این بخش می‌توان از فایل extend-head.html استفاده کرد.یک کپی از این فایل را در خود سایت ایجاد کردم که در https://github.com/parsiya/parsiya.fa/blob/main/layouts/partials/extend_head.html است. هنگام تولید سایت محتویات این فایل مستقیما به تگ head هر صفحه اضافه می‌شود.استفاده از چنین فایل‌هایی یکی از روش‌های خوب قالب‌ها برای شخصی‌سازی است. اگر چنین فایلی نبود باید کل  layout/partials/head.html قالب را کپی و دستکاری می‌کردم (که البته آخر دنیا هم نبود). تا قبل از نوشتن این مقاله از همین روش استفاده کرده بودم.ایجاد workflowاکنون وقت ایجاد Github action است. برای تولید یک سایت توسط Hugo از راهنمای زیر استفاده کردم (که اشتباهات کوچکی هم داشت):https://gohugo.io/hosting-and-deployment/hosting-on-github/#build-hugo-with-github-actionنیازی به دستکاری این فایل نبود و عیناً آن را در مخزن سایت کپی کردم.https://github.com/parsiya/parsiya.fa/blob/main/.github/workflows/gh-pages.ymlبه طور خلاصه، هر کامیت در شاخه main باعث شروع action می‌شود و سایت را تولید و سپس در شاخه gh-pages ذخیره می‌کند.یک نمونه از اجرای این action را می‌توانید در این لینک ببینید. با push کردن کامیتی که حاوی پست جدید (همین پست در بلاگ فارسی است، این action آن را منتشر کرده). روی هر کدام از مراحل مانند Setup Hugo یا Deploy کلیک کنید تا جزئیات را ببینید.تنظیمات صفحه گیت‌هابداخل هر مخزن در بخش settings/pages می‌توان شاخه‌ای که دارای صفحات سایت است را مشخص کرد. این کار را باید بعد از ایجاد شاخه در مخزن انجام دهید چون شاخه‌ای که وجود ندارد را نمی‌توانید انتخاب کنید.تنظیمات صفحه گیت‌هاب برای سایت مندامنه شخصیکار من در اینجا تمام شد امّا هر کدام از این سایتها می‌توانند دامنه مخصوص به خود را داشته باشند. مثلاً یکی از سایتهای من به اسم begbounty.com یک سایت پروژه در مخزن https://github.com/parsiya/begbounty.com است. راهنماهای زیادی برای استفاده از دامنه شخصی برای سایتهای کاربران و سازمان‌ها بود ولی تنظیمات برای سایتهای پروژه نتایج جستجوی زیادی نداشت.برای این کار باید به تنظیمات DNS دامنه خود دسترسی داشته باشید. چند تا از دامنه‌های من در namecheap هستند و این قابلیت را دارند. همه رکوردهای DNS دامنه خود را پاک کردم.اول چهار A Record اضافه کردم. host این رکوردها @ و مقدار آنها IP های زیر است:185.199.108.153185.199.109.153185.199.110.153185.199.111.153سپس یک رکورد CNAME با host با مقدار زیر (نقطه اضافی در آخر مقدار را فراموش نکنید):parsiya.github.io.نکته امنیتی: از wildcard در این رکورد CNAME استفاده نکنید. مثلاً ننویسید:*.whatever.comاگر چنین تنظیمی داشته باشید هر اکانت گیت‌هاب می‌تواند یک سایت را در subdomain های سایت شما هاست (همون host که نمی‌دونم فارسیش چی میشه) کُنَد. انگلیسی این اخطار را در این صفحه بخوانید.کار بعدی رفتن داخل تنظیمات صفحه در گیت‌هاب بود. در بخش Custom Domain دامنه را وارد کردم.تنظیمات صفحه گیت‌هاب begbounty.comاین کار یک کامیت جدید تولید می‌کند. این کامیت یک فایل به نام CNAME را به مخزن اضافه می‌کند. مقدار این فایل همان دامنه‌ای است که در بخش قبل استفاده کردیم. صفحات گیت‌هاب از این فایل برای تشخیص دامنه شخصی استفاده می‌کند.اگر راهنمای Hugo برای صفحات گیت‌هاب را دنبال کرده باشید یک فایل مشابه در دایرکتوری static مخزن دارید. واقعاً نمی‌دانم هر دوی این فایلها لازم هستند و یا خیر. ولی وقتی سایت کار می‌‎‌کند دستکاری آن فایده‌ای ندارد.مشکلاتیک مشکل بزرگ عدم پشتیبانی Visual Studio Code از راست-به-چپ است. تقریباً همه نوشته‌های من در این ادیتور است. این کار سرعت من را پایین آورد چون مجبور شدم از ادیتور Notepad++ استفاده کنم. در VS Code من تعداد زیادی snippet و shortcut دارم که سرعتم را زیاد می‌کنند.مشکل بعدی انتخاب محدود قالب است. قالبهایی که از راست-به-چپ پشتیبانی می‌کنند کم هستند. علاقه زیادی به PaperMod ندارم (قالب خوبی است ولی من دوست ندارم) اما از بقیه بهتر بود.بزرگترین مشکل هم نوشتن به فارسی است که زبانم (دستم؟) نمی‌چرخد. همین معادلسازی یا نیم‌فاصله (ctrl+shift+2) پدر من را درآورده اند ?.چی یاد گرفتم؟این بخشی است که من در تقریباً همه مقاله‌هایم می‌نویسم.یادگرفتم که اگر خواستم بلاگ فارسی بر پایه Hugo در صفحه گیت‌هاب (و با دامنه مخصوص) داشته باشم چکار کنم.</description>
                <category>پارسیا</category>
                <author>پارسیا</author>
                <pubDate>Mon, 12 Apr 2021 01:28:36 +0430</pubDate>
            </item>
                    <item>
                <title>آسیب پذیری Remote Code Execution در PlayStation Now</title>
                <link>https://virgool.io/@parsiya/psnow-rce-cwiitwj7wjti</link>
                <description>این اولین بانتیِ PlayStation من و اولین متن فارسیِ من درباره امنیت است. متون فارسی در سایت خودم به دلیل راست به چپ بودن درست نمایش داده نمی‌شدند، این شد که به ویرگول روی آوردم. دستشون درد نکنه که اکانت من را تایید کردند.نوشتن در مورد امنیت برای من به زبان فارسی سختِ. &quot;خارجی&quot; نشدم (البته فامیل نظرشان متفاوت است) ولی امنیت و اصطلاحاتش را به زبان انگلیسی یاد گرفته ام و زبانِ کار روزمره ام هست. در مقابل مثلاً  در زمینه &quot;کلیله و دمنه&quot; به انگلیسی نمی‌توانم صحبت کنم.این گزارش مربوط به &quot;هک کنسول بازی پلی استیشن&quot; نیست. این گزارش در مورد برنامه ویندوز PlayStation Now یا psnow است که برای استریم بازیهای پلی استیشن استفاده می‌شود.این مقاله ترجمه آزادی از گزارش من در Hacker One به پلی استیشن در https://hackerone.com/reports/873614 است. پیشنهاد می‌کنم آن را بخوانید.باگ در Hacker One‌مقدماتاین گزارش ترکیبی از سه باگ منطقی مختلف است. هر کدام از این باگ ها در یک محدوده تحقیقاتی مختلف قرار دارند. برای یادگرفتن این باگ ها شاید لازم باشد که موارد زیر را بدانید. در خیلی از موارد توضیحات مفصلی ندادم چون نمی‌شود همه چیز را در گزارش توضیح داد. متاسفانه تمام این لینک ها به زبان انگلیسی هستند (انگلیسی آش کشکِ خاله است، آخرش باید یاد بگیرید?).نزدیک یک سال قبل من ارائه ای در مورد این باگ ها (این باگ هنوز disclose نشده بود) در Appsec village کنفرانس DEF CON 2020 داشتم. در آن یکی از باگ های مشابه خودم برای برنامه Attack Surface Analyzer مایکروسافت را بررسی کردم. ویدئو و اسلاید این ارائه:https://parsiya.net/blog/2020-08-13-localghost-escaping-the-browser-sandbox-without-0-days/اطلاعات مربوط به هک برنامه های فریمورک الکترونhttps://github.com/doyensec/awesome-electronjs-hackingپیدا کردن سرورهای localhost و ترافیک برنامه های ویندوزhttps://parsiya.net/blog/2015-08-01-network-traffic-attribution-on-windowsباگ های Tavis Ormandy از Google Project Zero درباره سرورهای localhosthttps://bugs.chromium.org/p/project-zero/issues/list?q=owner%3Ataviso%40google.com%20localhost&amp;amp;amp;amp;amp;amp;amp;can=1خلاصهبرنامه PlayStation Now نگارش 11.0.2 دارای آسیب پذیری &quot;اجرای کد از راه دور&quot; یا Remote Code Execution یا RCE است. هر وب سایتی که در کامپیوتری که برنامه را اجرا می‌کند باز شود می‌تواند از طریق یک websocket روی آن ماشین کد اجرا کند.سرور websocket که روی پورت 1235 اجرا می‌شود هدر origin ریکوئست ها را چک نمی‌کند. این به وب سایتهایی که روی ماشین باز شده‌اند اجازه می‌دهد که مستقیم به این سرور متصل شوند و داده بفرستند. websocket ها توسط Same-Origin Policy کنترل نمی‌شوند. یک وب سایت باز شده در مرورگر می‌تواند یک ارتباط websocket با هر سرور در دسترس ایجاد کند.برنامه psnow یک برنامه Electron به نام AGL را اجرا می‌کند. با فرستادن داده به سرور websocket می‌توان به AGL دستور داد تا هر URL که بخواهیم را باز کند. در نتیجه، هر وب سایت باز شده در ماشین می‌تواند چنین کاری انجام دهد. همچنین می‌توان توسط دستور setUrlDefaultBrowser به AGL دستور داد که یک executable را اجرا کند (مثلاً calc).در برنامه AGL فیلد nodeIntegration فعال است. یعنی کد جاواسکریپت وب سایت باز شده در AGL میتواند از کتابخانه‌های Node استفاده کند و مثلاً process جدید ایجاد کند.با سر هم کردن این سه باگ میتوانیم به RCE برسیم.اصل ماجرابرنامه PlayStation Now یک برنامه برای استریم بازیهای پلی استیشن روی ویندوز است (البته این برنامه روی کنسول PS4 هم وجود دارد اما اینجا در مورد آن صحبت نمی‌کنیم). این برنامه دو بخش اصلی دارد. QAS و AGL.برنامه QASاین برنامه اصلی بر پایه فریمورک Qt5 (کیوت یا cute تلفظ می‌شود). اسم اصلی این برنامه psnowlauncher.exe است. بعد از اجرا دو کار انجام می‌دهد: برنامه دیگری به نام AGL.exe را اجرا می‌کند.یک سرور websocket روی localhost:1235 می‌سازد.برنامه AGLبرنامه AGL بر پایه فریمورک Electron است. این برنامه توسط QAS و به صورت زیر با یک سوییچ url اجرا می‌شود.&amp;quotC:\Program Files (x86)\PlayStationNow\agl\agl.exe&amp;quot
    --url=https://psnow.playstation.com/app/1.10.43/105/00d3603f8/بعد از اجرای برنامه، وب سایتی که با سوییچ url مشخص شده در برنامه باز می‌شود.فریمورک Electronهم Qt و هم Electron از فریمورک های پرطرفدار ساخت برنامه های دسکتاپ هستند. فریمورک الکترون بر پایه مرورگر متن باز Chromium ساخته شده است. مرورگرهای مشهوری مانند Google Chrome, Microsoft Edge و Brave هم از Chromium استفاده می‌کنند. در واقع هر صفحه یک برنامه الکترون یک تب مرورگر است که در آن یک وب سایت نشان داده می‌شود.یکی از اصلی ترین نکات هنگام بررسی یک برنامه الکترون بررسی فیلد nodeIntegration است. در صورت فعال بودن (به صورت پیش فرض غیرفعال است) کد جاوااسکریپت داخل مرورگر می‌تواند از کتابخانه‌های Node استفاده کند. من از دو روش برای چک کردن این فیلد استفاده می‌کنم:بازکردن کد برنامه و static analysis: کد جاوااسکریپت برنامه Electron معمولاً در یک فایل به نام app.asar است که میتوان آن را به راحتی باز و مشاهده کرد. بعد از دسترسی به کد برنامه سرچ کنید nodeIntegration و ببینید که آیا به مقدار true سِت شده است یا خیر.بازکردن یک وب سایت در برنامه که مثلاً برنامه ماشین حساب را اجرا می‌کند.برای اطلاعات بیشتر به این رفرنس که در قسمت مقدمات معرفی کردم مراجعه کنید.مشکل اول: nodeIntegrationبرای تست این فیلد من از روش دوم استفاده کردم چون خیلی راحت‌تر بود. یک صفحه با کد زیر را در یک s3 bucket (سطل؟) ذخیره کردم. این کد ماشین حساب ویندوز را از طریق ماژول child_process اجرا میکند. کدباکس ویرگول تگ های script را فیلتر می‌کند، برای همین از عکس استفاده کرده‌ام:popping calc with Nodeسپس برنامه را دستی با سویچ url اجرا کردم.&amp;quotC:\Program Files (x86)\PlayStationNow\agl\agl.exe&amp;quot
    --url=https://[redacted].s3.us-east-1.amazonaws.com/node.htmlماشین حساب ویندوز اجرا شد و من فهمیدم که مقدار آن فیلد سِت شده است.تا اینجا کار خارق العاده ای انجام ندادم، روی کامپیوتر خودم دستی کد اجرا کرده‌ام. به قول این بلاگ، هنوز در سمت دیگر &quot;دریچه&quot; (یعنی روی کامپیوتر خودم) هستم. https://devblogs.microsoft.com/oldnewthing/20060508-22/?p=31283مشکل دوم: سرور websocketهمانطور که بالا دیدیم برنامه AGL روی 1235 یک سرور websocket می‌سازد. قدم بعدی پراکسی کردن برنامه توسط Burp بود. برنامه های بر پایه مرورگر Chromium معمولاً از تنظیمات پراکسی ویندوز استفاده می‌کنند.پراکسی کردن ترافیک برنامه های دسکتاپپراکسی این بحث مفصلی است و من تابحال 18 بلاگ درباره آن نوشته‌ام و هنوز جا برای تحقیق زیاد دارد:https://parsiya.net/categories/thick-client-proxying/بعد از پراکسی کردن این برنامه ها ترافیک زیادی در Burp دیدم. یکی از مشکلات پراکسی کردن با تنظیمات ویندوز این است که بسیاری از برنامه های دیگر و سرویس های ویندوز نیز ترافیک خود را به پراکسی می‌فرستند. برای این کار می‌توانید دامنه‌های بی‌ربط را به TLS Passthrough اضافه کنید تا Burp آنها را پراکسی نکند. برای اطلاعات بیشتر در این زمینه بلاگ زیر را بخوانید:https://parsiya.net/blog/2020-05-01-towards-a-quieter-burp-history/ترافیک برنامه‌ها را توسط user-Agent شان تشخیص دادم. هر دو برنامه کلمه gkApollo را در user-agent داشتند. پس بقیه ترافیک به درد من نمی‌خورد. برای تشخیص ترافیک این دو برنامه از هم به کلمات دیگر در user-agent دقت کردم:ترافیک برنامه QAS که بر پایه Qt است این کلمه دارد QtWebEngine/5.5.1.ترافیک برنامه AGL که بر پایه الکترون است این دو را دارد Electron/1.4.16 و playstation-now/0.0.0.توسط یک افزونه به نام Request Highlighter در Burp، ترافیک این دو برنامه را زرد و آبی کردم که تشخیص آنها از هم راحت‌تر باشد. پروتکل پیام های websocketپس از پراکسی کردن در Burp ترافیک سرور websocket را می‌بینیم. پیام‌های پروتکل این سرور بسیار ساده بودند و به نظر می‌رسید توسط JSON.stringify جاوااسکریپت ایجاد شده‌اند. پیام ها به این شکل بودند:{
  &amp;quotcommand&amp;quot: &amp;quotisMicConnected&amp;quot,
  &amp;quotparams&amp;quot: {},
  &amp;quotsource&amp;quot: &amp;quotAGL&amp;quot,
  &amp;quottarget&amp;quot: &amp;quotQAS&amp;quot
} بخش اول فرمان یا command است که می‌گوید این دستور باید چه کاری انجام دهد.بخش دوم پارامترهای دستور است.بخشهای سوم و چهارم مبدا و مقصد پیام هستند. در واقع مبدا پیام مهم نیست و فقط مقصد مهم است.برای دیدن اینکه چه دستورهایی در برنامه وجود دارند دو کار کردم:برنامه را اجرا کردم و چند کار داخل برنامه انجام دادم سپس ترافیک داخل Burp را دیدم.کد برنامه الکترون را باز کردم و اسم چند دستور که در Burp دیده بودم را سرچ کردم تا به بخش commandHandler رسیدم. در این بخش همه دستورات سرور وجود داشتند.دو دستور مهم هستند: setUrl و setUrlDefaultBrowser. دستور setUrl به برنامه می‌گوید که کدام وب سایت را باز کند. پیام این دستور به این شکل است:{
  &amp;quotcommand&amp;quot: &amp;quotsetUrl&amp;quot,
  &amp;quotparams&amp;quot: {
    &amp;quoturl&amp;quot: &amp;quothttps://psnow.playstation.com/app/1.10.43/105/00d3603f8/&amp;quot
  },
  &amp;quotsource&amp;quot: &amp;quotAGL&amp;quot,
  &amp;quottarget&amp;quot: &amp;quotQAS&amp;quot
}دستور setUrlDefaultBrowser یک فایل را به کمک سیستم عامل باز می‌کند. مثلاَ اگر ورودی آن یک آدرس وب سایت باشد، آن را در مرورگر باز می‌کند و یک فایل ورد در برنامه آفیس (اگر نصب شده باشد) باز می‌شود. چند روز بعد از گزارش باگ به من به یاد یکی از باگ های Tavis Ormandy افتادم که با استفاده از این دستور به RCE دست یافته بود.https://bugs.chromium.org/p/project-zero/issues/detail?id=693اگر یک فایل اجرایی را با این دستور باز کنیم، ویندوز خود آن فایل را اجرا می‌کند. پس دستور زیر ماشین حساب ویندوز را اجرا می‌کند.{
  &amp;quotcommand&amp;quot: &amp;quotsetUrl&amp;quot,
  &amp;quotparams&amp;quot: {
    &amp;quoturl&amp;quot: &amp;quotfile:///c:/windows/system32/calc.exe&amp;quot
  },
  &amp;quotsource&amp;quot: &amp;quotAGL&amp;quot,
  &amp;quottarget&amp;quot: &amp;quotQAS&amp;quot
}با استفاده از این دستور دیگر نیاز به nodeIntegration هم نداریم. اما این دستور یک محدودیت بزرگ دارد. فقط می‌توانیم فایل اجرا کنیم و نمی‌توانیم به فایل اجرایی پارامتر و یا سوییچ بفرستیم.مشکل سوم: اجرای کد روی ماشین توسط دستورات websocketدر اینجا برنامه AGL (الکترون) به QAS می‌گوید که یک وب سایت را باز کند. در ابتدا من به مبدا و مقصد دقت نکردم و بی‌خیال باگ شدم چون بازکردن سایت در QAS فایده‌ای برای من نداشت. اما چند ساعت بعد وقتی کار دیگری انجام می‌دادم یادم آمد که چرا مقصد را AGL (برنامه الکترون) نگذارم؟ با فرستادن پیام پایین وب سایتی که در بخش اول ساخته بودم (ماشین حساب ویندوز را اجرا میکرد) در برنامه الکترون باز کردم و ماشین حساب ویندوز اجرا شد.{
  &amp;quotcommand&amp;quot: &amp;quotsetUrl&amp;quot,
  &amp;quotparams&amp;quot: {
    &amp;quoturl&amp;quot: &amp;quothttps://example.net&amp;quot
  },
  &amp;quotsource&amp;quot: &amp;quotAGL&amp;quot,
  &amp;quottarget&amp;quot: &amp;quotQAS&amp;quot
}بعد از این کد یک برنامه چت بر پایه websocket را دستکاری کردم و در یک سطل (؟) s3 دیگری قرار دادم. بعد از باز کردن این وب سایت در مرورگر روی کامپیوتری که برنامه psnow در حال اجرا بود می‌توانستم با سرور websocket برنامه صحبت کنم و به آن دستور بفرستم.امنیت websocketاولین مرحله در ایجاد ارتباط با یک سرور websocket، فرستادن یک ریکوئست HTTP با تعدادی header خاص است. در حالت عادی Same-Origin Policy یا SOP مرورگر به اسکریپت های یک اریجین اجازه نمیدهد تا با اریجین دیگر ارتباط برقرار کنند (بحث SOP هم مفصل است ولی حتما در مورد آن بخوانید چون یکی از مهمترین بخشهای امنیت مرورگر و وب است). websocket ها شامل SOP نمیشوند. یعنی هر وب سایت میتواند با هر سرور websocket ارتباط برقرار کند.حل این مشکلاتتا اینجا سه باگ را بررسی کردیم و فهمیدیم که اگر برنامه PlayStation Now را اجرا کنیم. وب سایتی که در مرورگر کامپیوتر ما باز شده است می‌تواند روی ماشین ما کد اجرا کند. این اصلاً خوب نیست.یکی از مهمترین وظایف من به عنوان یک مهندس امنیت نرم افزار، حل مشکلات امنیتی است.راحت‌ترین راه حل این مشکل چک کردن هِدِر origin در اولین بخش ایجاد ارتباط websocket است. این هدر فقط توسط مرورگر می‌تواند اضافه شود (به این هدرها Forbidden Header Name گفته می‌شود). اولین ریکوئست ایجاد یک websocket شکلی مشابه زیر دارد:GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== - مقدار این هدر معمولاً مهم نیست
Sec-WebSocket-Version: 13
Origin: whatever.comچون نمیتوان به مکانیزم SOP برای فیلتر کردن درخواست های websocket اتکا کرد باید به صورت دستی هدر origin را بررسی کنیم و مواردی که نمی‌خواهیم (مثلاً هر چه که از playstation.com نیست) را رد کنیم.دومین مشکل این است که سرور روی همه IP های دستگاه در حال شنیدن است. به عبارت دیگر روی 0.0.0.0 بایند شده. این یعنی هر کسی که بتواند به پورت 1235 دستگاه از خارج دسترسی داشته باشد می‌تواند به آن وصل شود. در دنیای واقعی این مشکل آنقدر ترسناک نیست زیرا اکثر مودم و روترها تنها اجازه دسترسی به پورت را در شبکه داخلی می‌دهند.برای حل این مشکل باید سرور روی localhost بایند شود.چی یاد گرفتیم؟متاسفانه در این باگ مرزهای علم را جابجا نکردم و دانش جدیدی تولید نشد. خودم هم چیز جدیدی یاد نگرفتم. اما امیدوارم خواننده چند نکته یادگرفته باشد. اگر بازخورد یا پیشنهادی دارید، پیدا کردن من در اینترنت بسیار راحت است.</description>
                <category>پارسیا</category>
                <author>پارسیا</author>
                <pubDate>Tue, 30 Mar 2021 22:22:17 +0430</pubDate>
            </item>
            </channel>
</rss>