<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های نوید شیرمحمدی</title>
        <link>https://virgool.io/feed/@nashi</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-04-15 04:36:35</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/1715378/avatar/nczTP9.png?height=120&amp;width=120</url>
            <title>نوید شیرمحمدی</title>
            <link>https://virgool.io/@nashi</link>
        </image>

                    <item>
                <title>معرفی بک‌تست اسکریپت!</title>
                <link>https://virgool.io/@nashi/%D9%85%D8%B9%D8%B1%D9%81%DB%8C-%D8%A8%DA%A9-%D8%AA%D8%B3%D8%AA-%D8%A7%D8%B3%DA%A9%D8%B1%DB%8C%D9%BE%D8%AA-pb5hjfyigxux</link>
                <description>لوگو بسیار جذاب و با مفهوم سایتم 😅😙سلام به همگی! امروز می‌خوام اولین اطلاعیه عمومی از پروژ‌ه‌ای که روش کار می‌کنم را باهاتون به اشتراک بذارم. پروژه‌ای که روش کار می‌کنم یه زبان خاص دامنه (DSL - Domain-Specific Language) هست که مخصوصاً برای کاربران فارسی‌زبان طراحی شده تا بتونن به راحتی استراتژی‌های معاملاتی خودشون رو بدون نیاز به یادگیری زبان‌های برنامه‌نویسی و درگیر شدن با کتابخونه های مختلف تعریف کنن و ازش بک‌تست بگیرن. این زبان به شکلی طراحی شده که ساده و قابل فهم باشه و بتونه پیچیدگی‌های برنامه‌نویسی رو از سر راه کاربران برداره. در فاز اولیه پروژه مواردی که سعی می‌کنم رعایت بشن به این صورتن:تعریف استراتژی معاملاتی به ساده‌ترین شکل ممکن انجام بشه و یک کاربر جدید که یکم از اندیکاتور و اکسل سر در میاره و زبان هم بلد نیست، بدون آموزش بتونه استراتژی را بخونه و متوجه بشه. با چند دقیقه آموزش هم بتونه استراتژی خودشو بنویسه 🦘تمام محاسبات سمت کاربر و روی مرورگر 🌐 انجام بگیرن و صرفا داده از سمت سرور ارسال بشه.یادگیری ماشین، رمزنگاری سمت کاربر و ... میمونه برای فازهای بعد!پیشرفت پروژهدر حال حاضر پروژه در مرحله MVP قرار داره و بخش‌های مهمی از کار رو پیش بردم. دامنه backtestscript.com رو تهیه کردم و بیشتر صفحه فرود (landing page) سایت هم آماده شده. البته برای بخش پایگاه داده که فعلاً برای جمع‌آوری ایمیل کاربران نیاز دارم، یکم از برنامه عقب افتادم (چون اولین بارم بود با NextJS دارم کد میزنم😅)، ولی مطمئنم این هفته جمع می‌شه.جمع‌آوری دادهیکی از مهم‌ترین قسمت‌های پروژه، جمع‌آوری داده‌هاست. تا الان تمرکزم روی داده‌های بورس تهران بوده و تونستم ورکر (با پایتون🐉) لازم برای جمع‌آوری این داده‌ها رو بنویسم و داده‌ها رو در پایگاه داده QuestDB ذخیره کنم. هدفم اینه که کل پروژه رو با استفاده از فریمورک NextJS پیاده‌سازی کنم، بنابراین توی یکی دو روز آینده کدهایی که نوشتم رو باید برای NextJS بازنویسی می‌کنم. البته در آینده داده‌های مربوط به بازارهای دیگه مثل رمز ارزها، بورس آمریکا و حتی آپلود دستی فایل کاربر رو هم اضافه می‌کنم، ولی فعلاً تمرکزم روی چند تا نماد از بورس تهران بود. طراحی زبان خاص دامنهیکی از چالش‌های اصلی  در طراحی زبان، این بود که بتونم یک زبان برنامه نویسی که به‌طور کامل از زبان فارسی پشتیبانی کنه و در عین حال ساده و قابل درک باشه رو ارائه بدم. برای این کار، سرور زبان رو با جاوا و antlr نوشتم برای تست اولیه. با چالش‌هایی مثل پشتیبانی از متن راست‌به‌چپ (RTL) در ادیتور روبرو شدم. در ابتدا از Monaco Editor استفاده کردم، ولی با توجه به مشکلاتش در پشتیبانی از RTL، تصمیم گرفتم به جای اون از CodeMirror استفاده کنم. با اینکه CodeMirror امکانات کمتری داره، ولی سبک‌تره (برنامه خیلی سریعتر الان اجرا میشه 💯)  و پشتیبانی خوبی از RTL ارائه می‌ده. الان دارم سرور زبان رو با TypeScript بازنویسی می‌کنم تا بتونم اون رو در مرورگر کاربر اجرا کنم. امروز بخش خوبی را منتقل کردم ولی دوباره باید lexer را مثل پست «مینی پایتون ...» اینجا هم بنویسم 😮‍💨.نگاهی به زبان استراتژی‌نویسیبرای اینکه یه ایده‌ای از این زبان به دست بیارید، می‌خوام یه snippet کوتاه از نحوه تعریف استراتژی در این زبان رو باهاتون به اشتراک بذارم. البته این فقط یک بخش کوچیک از امکانات زبانه و خیلی بیشتر از این‌ها رو می‌تونید باهاش انجام بدید.متغیر ورودی کاپپا را با مقدار 1 در نظر بگیررابطه فرآیند_هاکس را با ورودی‌های ستون هدف و عدد کاپپا به این صورت تعریف کن:    بررسی کن که کاپپا بزرگتر از 0 باشد    متغیر آلفا را با مقدار توان(- کاپپا) در نظر بگیر    1 ردیف قبلی خود * آلفا + هدف را برگردانیا مثلاسیگنال هاکس_ویلیامز را با ورودی‌های ستون بسته و ستون هاکس و ستون درصد_دامنه_ویلیامز به این صورت تعریف کن    اگر بسته کمتر از هاکس بود و درصد_دامنه_ویلیامز کمتر از -0.8 بود، بخر    اگر بسته بیشتر از هاکس بود و درصد_دامنه_ویلیامز بیشتر از -0.2 بود، بفروشبه نماد وبملت ستون هاکس را با رابطه فرآیند_هاکس اضافه کنبه نماد وبملت ستون درصد_دامنه_ویلیامز را با رابطه درصد_دامنه_ویلیامز با پنجره_زمانی 14 اضافه کنبه نماد وبملت ستون سیگنال_هاکس_ویلیامز را با سیگنال هاکس_ویلیامز اضافه کنهمونطور که می‌بینید، با استفاده از این زبان می‌تونید به راحتی استراتژی‌های پیچیده رو به زبانی ساده و قابل فهم تعریف کنید. اگر هنوز یکم مبهم بنظرتون میرسه، به شکل زیر توجه کنین. صرفا با وارد کردن دستور یکسری رابطه را روی داده‌های نماد محاسبه میکنیم و ستون اضافه میکنیم، درست مثل اکسل ولی به فارسی!جزئیات بیشتر را موقعی که سایت بالا اومد روی بخش داکیومنت میتونید ببینین!برنامه‌های آیندهبرنامه‌م اینه که تا آخر این هفته یه داشبورد ساده برای تعریف استراتژی روی چند نماد خاص و انجام بک‌تست رو آماده کنم. البته بنا به تجربه اطمینان میدم که ممکنه این یک هفته بشه دو هفته و فراتر از آن 😁. با پیشرفت بیشتر پروژه، دوباره پست میذاریم ولی فعلا کد زدن اولویت اوله. ممنون که تا اینجا همراه من بودید! منتظر آپدیت‌های بعدی باشید!</description>
                <category>نوید شیرمحمدی</category>
                <author>نوید شیرمحمدی</author>
                <pubDate>Sun, 04 Aug 2024 21:29:24 +0330</pubDate>
            </item>
                    <item>
                <title>مینی پایتون با ANTLR4</title>
                <link>https://virgool.io/@nashi/%D9%85%DB%8C%D9%86%DB%8C-%D9%BE%D8%A7%DB%8C%D8%AA%D9%88%D9%86-%D8%A8%D8%A7-antlr4-kkxm4blkw1no</link>
                <description>مقدمهاگه یه روزی به سرت زد که یه زبان برنامهنویسی بنویسی و انقدر هم تو هپروت نبودی که بخوای با regex جمعش کنی، احتمالا اسم ANTLR4 را شنیدی (شاید باور نکنی ولی گزینههات برای این کار نسبتا زیادن). اگه نه، خیلی ساده بخوام توضیح بدم، با ANTLR4 میتونی یه دستور زبان ایجاد کنی، مثل یه زبان برنامهنویسی شبیه پایتون یا C++ یا هر زبان دیگه. از دیدگاه یک دانشجوی زجر کشیده کامپیوتر، اراجیف درس نظریه زبان و ماشین را با ANTLR4 میتونی پیادهسازی کنی و عذاب بکشی.ماجرا از اینجا جالب میشه که بدونی پیادهسازی زبانهایی مثل C++ و Java و JSON خیلی راحته و در مقابل پیادهسازی زبانی مثل پایتون یا YAML دهن سرویسکنترین کاره! یعنی برای اینکه یه زبانی داشته باشی که نخواد ملت هعی مثل حیوون آکولاد و کروشه و پرانتز بذارند، نویسنده دستور زبان به چوخ میره. من هم چندسالی بود که میخواستم این چالش را انجام بدم و میدونید چی شد؟ انجامش دادم....یهیهیهی....البته باید تشکر ویژه کنم از نویسندگان این شاخه از ریپو که گرامر کامل پایتون را با ANTLR4 نوشتن و من صرفا قسمتایی از کدشون را که نیاز داشتم استفاده کردم: grammars-v4/python/python3_12_1 at master · antlr/grammars-v4 (github.com)در این پست توضیح میدم که یه مینی گرامر شبیه پایتون چطور پیادهسازی میشه. منظورم از مینی گرامر اینه که یه گرامر خیلی ریز که صرفا بتونه تشخیص بده بدنه یه تابع کجاست. بدیهتا خواننده عاقل و کمی آشنا با نوشتن دستور زبان متوجه میشه که حلقه و هندل کردن بقیه statement ها مطلقا اینجا اهمیتی نداره و هر کسی با باز کردن یه کتاب مثل ANTL4 Mega Book و دو ساعت خوندنش میتونه اینا را هندل کنه. توی این پست مه دقیقا تمرکز را روی همین میذارم.خلاصه این که گرامر زیر را قراره پارس کنیم و Abstract Syntax Tree شو بگیریم (بله، اون Enter های اول و آخر فایل هم باید هندل بشن. در بدنه تابع از تب استفاده شده نه space):

pass
pass;
pass; pass
pass; pass;

def func:
	pass

تعریف دستور زبانخب، در اولین مرحله باید دستور زبان را تعریف کنیم. برای اینکار یه فایل به اسم Indented.g4 ساختم که از اول قسمت به قسمت میگم چیه (خیلی یه بلوک بزرگ کد را خوب نمیشه توضیح داد وقتی شماره خط نداریم 😢)اول اسم دستور زبان را مشخص میکنیم که باید با اسم فایل یکی باشه.بعد دو تا توکن با نامهای INDENT و DEDENT تعریف میشن. نکته اینجاست که این دو تا توکن توسط Lexer ای که خودکار ANTLR تولید میکنه با هیچ کاراکتری match نمیشن و باید داخل کد هندلشون کنیم. نکته دوم هم اینکه این توکنها دقیقا کار آکولاد باز و بسته در تعریف یک بلوک را قراره انجام بدن و هیچ ربطی به اینکه بلوک کد چندتا تب قبلشه نداره. یعنی الان یه کد Java یا C++ بذار جلوت و فرض کن بجای آکولاد نوشته شده INDENT و DEDENT، به اینکه چند تا تب یا فاصله داریم کاری نداشته باش.grammar Indented;
tokens {
	INDENT, DEDENT
}چند تا توکن ساده دیگه هم تعریف میکنیم که با کاراکترای داخل فایل match میشن.برای تشخیص کردن اسامی (مثلا اسم متغیر یا تابع) -&gt; Name  برای تشخیص خط جدید -&gt; NEWLINEبرای دور ریختن کاراکتر فاصله -&gt; SPACEبرای ریختن کاراکتر تب توی یه کانال بنام کانال HIDDEN (روی کد میبینی چرا) -&gt; WSNAME: [a-zA-Z]+;
NEWLINE: &#039;\r&#039;?&#039;\n&#039;;
SPACE: [ ] -&gt; skip;
WS: [\t]+ -&gt; channel(HIDDEN);بعد میریم قوانین پارسر را تعریف میکنیم.اول یه قانون به اسم file نوشتم که میگه در فایل ممکنه statements باشه یا نباشه ولی حتما با EOF (مخفف End Of File) تموم میشه.در قانون دوم میگم که statements خودش از تعدادی مثبت statement تشکیل شده.قانون سوم میگه که یک statement یا simple_stmts هست یا compunt_stmts.قانون چهارم میگه که یک simple_stmts از یک یا تعدادی simple_stmt تشکیل شده که بینشون نقطه-کاما داریم و در پایان حتما یک توکن NEWLINE.قانون بعد هم میگه که یک simple_stmt معادل عبارت pass هست. یعنی هرجا pass دیدی یه simple_stmt داریم. بدیهتا اگه return و break د اینجو چیزا را داشتیم اینجا باید تعریف کنیم.در قانون ششم گفته شده که یک counpunt_stmts معادل یک func_def هست. بدیهتا اگه while و for هم داشتیم اینجا باید اضافه کنیم.در قانون هفتم میگی که یک func_def چه شکلیه. طبق چیزی که اینجاست، اول def میاد، بعد یک NAME، بعدش یه دو نقطه و در آخر یک block.مهمترین قانون هم قانون هشتمه که یک block را تعریف میکنه. اینجا از توکنهای INDENT و DEDENT استفاده میکنیم و میگیم که یک بوک با NEWLINE و سپس یه INDENT، سپس statements و در آخر یه DEDENT شناسایی میشه. در حال دوم هم یه simple_statments هست. file: statements? EOF;
statements: statement+;
statement: compound_stmt  | simple_stmts;
simple_stmts: simple_stmt (&#039;;&#039; simple_stmt)* &#039;;&#039;? NEWLINE;
simple_stmt: &#039;pass&#039;;
compound_stmt: function_def;
function_def: function_def_raw;
function_def_raw: &#039;def&#039; NAME &#039;:&#039; block;
block
    : NEWLINE INDENT statements DEDENT
    | simple_stmts
    ;نکته مهم دستور زبان بالا اینجاست که هیچ جا مشخص نکردیم توکنهای INDENT و DEDENT چطور مشخص میشن. پس منطقا نمیتونیم block (بدنه تابع) را در این مرحله تشخیص بدیم. باید این مورد را در کد هندل کنیم.بیلد گرامرقبل از نوشتم کد، باید دستور زبان بالا را بیلد کنیم تا پارسر و Lexer خود ANTLR4 را بگیریم، تا بشه روشون کد زد. برای بیلد یه justfile نوشتم ولی چون احتمالا خیلیها نمیدونن چیه درگیرش نمیشم. صرفا این کدها را بزنین تا فایلهای لازم برای Java ایجاد بشن. برای بقیه زبانها هم کافیه یه یگ Dlanguage بعد از antlt4 استفاده کنین. ربطی به کار من نداره. اینم اضافه کنم که چند تا پکیج گرامر مختلف دارم و justfile هم کف پروژه است، پس خودتون با توجه به ساختار پروژتون دستورات را تطابق بدین.export BASE_PATH=&amp;quot./src/main/java/info/navidlabs&amp;quot
export PROJECT_PACKAGE=&amp;quotinfo.navidlabs&amp;quot
export GRAMMAR_PACKAGE=&amp;quotP01Indented&amp;quot
export GRAMMAR_NAME=&amp;quotIndented&amp;quot
antlr4 {{BASE_PATH}}/{{GRAMMAR_PACKAGE}}/{{GRAMMAR_NAME}}.g4 -package {{PROJECT_PACKAGE}}.{{GRAMMAR_PACKAGE}}.gen -o {{BASE_PATH}}/{{GRAMMAR_PACKAGE}}/genبعد از اجرای دستورات یه پوشه به اسم gen ایجاد میشه که شبیه تصویر زیره. خیلی درگیر نامگذاریم نشین، اگه فایلها را گرفتیم حله، اگه نه زور بزنین تا بگیرینشون. به موقعیت اون justfile هم یه نگاه بندازین بد نیست.نوشتن Lexerو اما بریم سر کد. قسمت بامزه کار اینه که باید Lexer تولید شده توسط ANTLR را توسعه بدیم تا بتونه INDENT و DEDENT را به دنباله توکنها اضافه کنه. برای اینکار، یه فایل بنام MyLexer.java نوشتم. اینو هم اضافه کنم که برای زبانهای دیگه اگه خواستین کافیه به همون ریپو بالا یه سر بزنین.با هم تیکه تیکه کدشو بررسی میکنیم. اول توی فایل pom.xml این نیازمندی را اضافه میکنیم که antlr را دانلود کنه:&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.antlr&lt;/groupId&gt;
        &lt;artifactId&gt;antlr4&lt;/artifactId&gt;
        &lt;version&gt;4.13.1&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt; بعد توی فایل MyLexer.java اسم پکیج و ایمپورتها را داریم که توضیح خاصی نداره. فقط بجای antlr.v4 اشتباهی antlr خالی استفاده نکنین.package info.navidlabs.P01Indented;

import info.navidlabs.P01Indented.gen.IndentedLexer;
import info.navidlabs.P01Indented.gen.IndentedParser;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CommonToken;
import org.antlr.v4.runtime.Token;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.LinkedList;کلاس، متغیرهایی داخلی و کانستراکتور را اینجا تعریف کردیم. به ترتیب:یه لیست double ended برای نگهداری تعداد indent های کد داریم.یه لینک لیست برای نگهداری توکنهایی که هنوز پردازش نشدن.یه عدد برای نگهداری نوع توکن قبلی که هنوز پردازش نشده (به هر توکن به عدد خود ANTLR نسبت میده)یه عدد دیگه برای نگهداری نوع توکنی که از کانال پیشفرض (و نه کانال HIDDEN) اومده.یه متغیر بنام curToken برای نگهداری توکن در حال پردازش (فعلی)یه متغیر بنام ffgToken برای نگهداری توکن بعدی (هنوز پردازش نشده)در کانستراکتور هم تابع init را صدا زدیم.public class MyLexer extends IndentedLexer {
    private Deque&lt;Integer&gt; indentLengthStack;
    private LinkedList&lt;Token&gt; pendingTokens;
    private int previousPendingTokenType;
    private int lastPendingTokenTypeFromDefaultChannel;
    private CommonToken curToken;
    private Token ffgToken;

    protected MyLexer(CharStream input) {
       super(input);
       this.init();
    }تابع init صرفا متغیرهایی را که بالا تعریف کردیم را مقداردهی اولیه میکنه (با صفر و Null و چیزای دیگه)private void init() {
    this.indentLengthStack = new ArrayDeque&lt;&gt;();
    this.pendingTokens = new LinkedList&lt;&gt;();
    this.previousPendingTokenType = 0;
    this.lastPendingTokenTypeFromDefaultChannel = 0;
    this.curToken = null;
    this.ffgToken = null;
}در گام بعد تابع nextToken کلاس IndentedLexer را بازنویسی میکنیم. کلا ANTLR هر توکنی که دید این کلاسو صدا میزنه. ما با بازنویسی ایم کلاس کاری میکنیم که Lexer طبق قوانین ما توکنها را پردازش کنه. در اینجا میگیم هر توکنی اومد اول متود checkNextToken را صدا بزن، بعد هم از لینک لیست توکنهای در انتظر بررسی (pendingTokens) اولین عضو را برگردون.توی پرانتز: منطق کاری Lexer اینه که یه رشته از توکنها برمیگردونه و پارسر AST را میسازه.@Override
public Token nextToken() {
    this.checkNextToken();
    return this.pendingTokens.pollFirst();
}حالا در checkNextToken بررسی میکنیم چی اومده. اگه به ته فایل (EOF) نرسیدیم، تابع setCurrentAndFollowingTokens را صدا میزنیم تا توکن فعلی (curToken) و بعدی (ffgToken) را آپدیت کنه. اگه داخل بدنه یه بلوک هم نبودیم (با indentLengthStack اینو میشه چک کرد)، یه تابع بنام handleStartOfInput را صدا میزنیم که اون اراجیف اول فایل (فاصله و NEWLINEهای الکی) که در بلوک کد اول پست دیدیم را هندل کنه.بعد از این کارا نوع توکنی که الان داره بررسی میشه را چک میکنیم. اگه NEWLINE بود تابع handleNEWLINEtoken را صدا میزنیم که خودش چک میکنه داخل یه block رفتیم یا نه.اگه EOF بود یعنی فایل تموم شده و handleEOFtoken را اجرا میکنیم.مگر نه addPendingToken را صدا میزنیم تا توکن فعلی را به دنباله توکنها اضافه کنه (که میره برای پارسر).دقت کنین که تب را ریختیم توی کانال HIDDEN و الان داریم کانال DEFAULT را بررسی میکنیم. پس در case ها INDENT و DEDENT نداریم.private void checkNextToken() {
    if (this.previousPendingTokenType != Token.EOF) {
       this.setCurrentAndFollowingTokens();
       if (this.indentLengthStack.isEmpty()) {
          this.handleStartOfInput();
       }

       switch (this.curToken.getType()) {
          case IndentedParser.NEWLINE:
             this.handleNEWLINEtoken();
             break;
          case Token.EOF:
             this.handleEOFtoken();
             break;
          default:
             this.addPendingToken(this.curToken);
       }
    }
}در متود setCurrentAndFollowingTokens چک میکنیم که آیا توکن بعدی (ffgToken) وجود داره یا نه. اگه وجود داشت توکن فعلی (curToken) را میذاریم ffgToken، مگرنه با صدا زدن super.nextToken مقدار دهیش میکنیم. این تابع super.nextToken اگه ته فایل باشیم EOF برمیگردونه!به صورت مشابه، چک میکنیی به تع فایل رسیدیم یا نه و اگه رسیدیم، ffgToken هم EOF میذاریم، مگرنه توکن بعدی را با super.nextToken میگریم میریزیم توش (یه واحد جلوتر از curToken میشه چون هربار super.nextToken را صدا بزنی خودکار یکی میره جلو).private void setCurrentAndFollowingTokens() {
    this.curToken = this.ffgToken == null ?
          new CommonToken(super.nextToken()) :
          new CommonToken(this.ffgToken);

    this.ffgToken = this.curToken.getType() == Token.EOF ?
          this.curToken :
          super.nextToken();
}متود بعدیمون، handleStartOfInput هست که هدفش خلاص شدن از تبها و خطهای اضافی اول فایله. برای اینکار، اول یه صفر میندازه سر indentLengthStack که یعنی در بلوکی نیستیم (بدیهتا هیچ فایل پایتونی با تب و دستور شروع نمیشه طبق دستور زبان).بعد توی یه حلقه، چک میکنیم که آخر فایل هم نباشیم (فایل خالی مثل __init__ هم باید هندل بشه). اینجا چک میشه آیا داخل کانال DEFAULT هستیم یا کانال HIDDEN. یادآوری میکنم که کانال HIDDEN برامون تب را هندل میکرد.اگه داخل کانال DEFAULT بودیم، چک میکنیم که توکنی فعلی NEWLINE هست یا نه. اگه آره، hideAndAddPendingToken را صدا میزنیم، مگر نه بیخیال میشیم و برمیگردیم. اگه هم کانال HIDDEN بودیم، addPendingToken را صدا میزنیم. بعد setCurrentAndFollowingTokens را اجرا میکنیم که توکنهای curToken و ffgToken آپدیت بشن و تا ته فایل را پیمایش کنیم.private void handleStartOfInput() {
    this.indentLengthStack.push(0);
    while (this.curToken.getType() != Token.EOF) {
       if (this.curToken.getChannel() == Token.DEFAULT_CHANNEL) {
          if (this.curToken.getType() == IndentedParser.NEWLINE) {
             this.hideAndAddPendingToken(this.curToken);
          } else {
             return;
          }
       } else {
          this.addPendingToken(this.curToken);
       }
       this.setCurrentAndFollowingTokens();
    }
}تا اینجا فراخوانی متودها این شکلیه (خودمم نمیدونم چه نموداری کشیدم، ولی مفهومو میرسونه...احتمالا):بخش خیلی مهم کار اینه که باید یجوری INDENT و DEDENT را به استریم توکنها اضافه کنیم تا شروع و پایان هر block مشخص بشه. این کار را در handleNEWLINEtoken انجام میدیم. اول توکن فعلی که NEWLINE هست را در nlToken ذخیره میکنیم. بعد چک میکنیم که توکن بعدی تب هست یا نه (در گرامر گفتیم WS با تب Match بشه)، اگه بود، isLookingAhead را True قرار میدیم، مگرنه False.حالا اگه isLookingAhead درست بود، setCurrentAndFollowingTokens را صدا میزنیم تا یه واحد توکنهای curToken و ffgToken برن جلو. اگه ffgToken توکن NEWLINE بود که یعنی یه خط در بدنه block همینطوری هست و هیچی توش تایپ نشده، پس نقش خاصی هم در AST نداره و میدیم hideAndAddPendingToken تا هندلش کنه. اگه داخل بدنه یه block بودیم (با isLookingAhead چک میکنیم)، توکن curToken را به addPendingToken میدیم تا بذاره توی stream خروجی Lexer.اگه ffgToken توکن NEWLINE نبود، توکن nlToken که اول ذخیره کردیمش (کاراکتر NEWLINE هم هست) را به addPendingToken میدیم تا بره تو استریم خروجی، اگه isLookingAhead درست نبود، insertIndentOrDedentToken را با پارامتر صفر صدا میزنیم تا بگیم توی بلوک نیستیم. اگه هم isLookingAhead  درست بود (داخل یه بلوک جدید رفتیم/توکن ffgToken تب بود)، getIndentationLength را صدا میزنیم تا تعداد تب را از اول خط را بهمون بده. بعد مقداری که گرفتیم را به insertIndentOrDedentToken  میدیم تا کاراکتر INDENT یا DEDENT را با توجه به اینکه داریم وارد بلوک میشیم یا ازش بیرون میایم اضافه کنه.private void handleNEWLINEtoken() {
    CommonToken nlToken = new CommonToken(this.curToken);
    final boolean isLookingAhead = this.ffgToken.getType() == IndentedParser.WS;
    if (isLookingAhead) {
       this.setCurrentAndFollowingTokens();
    }

    switch (this.ffgToken.getType()) {
       case IndentedParser.NEWLINE:
          this.hideAndAddPendingToken(nlToken);
          if (isLookingAhead) {
             this.addPendingToken(this.curToken);
          }
          break;
       default:
          this.addPendingToken(nlToken);
          if (isLookingAhead) {
             final int indentationLength = this.ffgToken.getType() == Token.EOF ?
                   0 :
                   this.getIndentationLength(this.curToken.getText());
             this.addPendingToken(this.curToken);
             this.insertIndentOrDedentToken(indentationLength);
          } else {
             this.insertIndentOrDedentToken(0);
          }
    }
} خب، میرسیم سر وقت insertIndentOrDedentToken. این تابع از indentLengthStack استفاده میکنه تا ببینه چند Level بلوک تو در تو داریم و الان کجاییم. اول یه دید میزنه سر indentLengthStack که ببینه چند لول رفتیم داخل (چیزی از indentLengthStack برداشته نمیشه چون peek را صدا زدیم). اگه دید یه لول اضافه شده، یعنی یه block داره تشکیل میشه و با صدا زدن  createAndAddPendingToken یه توکن INDENT به استریم خروجی Lexer اضافه میشه. indentLengthStack هم آپدیت میکنیم.اگه هم نه، دیدیم indentLengthStack کم شده، میریم داخل یه لوپ تا ببینیم چند تا بلوک دارن بسته میشن. به اضای بسته شدن هر بیوک یه بار createAndAddPendingToken را صدا میزنیم تا یه DEDENT اضافه بشه.private void insertIndentOrDedentToken(final int indentLength) {
    int prevIndentLength = this.indentLengthStack.peek();
    if (indentLength &gt; prevIndentLength) {
       this.createAndAddPendingToken(IndentedParser.INDENT, Token.DEFAULT_CHANNEL, null, this.ffgToken);
       this.indentLengthStack.push(indentLength);
    } else {
       while (indentLength &lt; prevIndentLength) {
          this.indentLengthStack.pop();
          prevIndentLength = this.indentLengthStack.peek();
          this.createAndAddPendingToken(IndentedParser.DEDENT, Token.DEFAULT_CHANNEL, null, this.ffgToken);
       }
    }
}تابع بعدی insertTrailingTokens هست. نقشش اینه که اگه آخر فایلمون NEWLINE نبود، اضافه کنه. چرا؟ چون گفتیم بعد هر simple_stmt باید NEWLINE باشه و بعد از compound_stmt باید DEDENT باشه. ولی ممکنه کاربر عشقش نکشه اون Enter آخر را بزنه که در نتیجه موارد بالا اضافه نمیشن.private void insertTrailingTokens() {
    switch (this.lastPendingTokenTypeFromDefaultChannel) {
       case IndentedParser.NEWLINE:
       case IndentedParser.DEDENT:
          break;
       default:
          this.createAndAddPendingToken(IndentedParser.NEWLINE, Token.DEFAULT_CHANNEL, null, this.ffgToken);
    }
    this.insertIndentOrDedentToken(0);
}تابع بعدی هم صرفا اگه دید رسیدیم ته فایل (EOF دید)، تابع بالا را صدا میزنه.private void handleEOFtoken() {
    if (this.lastPendingTokenTypeFromDefaultChannel &gt; 0) {
       this.insertTrailingTokens();
    }
    this.addPendingToken(this.curToken);
}تابع بعدیمون هم وقتی صدا زده بشه،  توکن دریافتی را میریزه توی کانال HIDDEN (اول کانال را عوض میکنه و بعد addPendingToken را صدا میزنه). دو جایی که بالا این تابع را صدا زدیم، وقتی بود که یه NEWLINE میدیدم (متودهای handleStartOfInput و handleNEWLINEtoken را ببین).private void hideAndAddPendingToken(CommonToken cToken) {
    cToken.setChannel(Token.HIDDEN_CHANNEL);
    this.addPendingToken(cToken);
}تابع بعد، که تا حالا چندبار هم ازش استفاده کردیم، createAndAddPendingToken هست. کلا کار این تابع اینه که یه توکن را بریزه توی یه کانال دلخواه، یه اسم هم در پارامتر text میگیره که کمک میکنه موقع parse یه اسم با معنی برای توکنها داشته باشیم. بعد هم توکن را میدیم به addPendingToken. از baseToken هم (که مقدارش ffgToken هست) استفاده میکنیم که مشخص کنیم توکن فعلی کجا تموم میشه (ایندکسش در فایل ورودی از کجا تا کجاست).private void createAndAddPendingToken(final int type, final int channel, final String text, Token baseToken) {
    CommonToken cToken = new CommonToken(baseToken);
    cToken.setType(type);
    cToken.setChannel(channel);
    cToken.setStopIndex(baseToken.getStartIndex() - 1);
    cToken.setText(text == null
          ? &amp;quot&lt;&amp;quot + this.getVocabulary().getSymbolicName(type) + &amp;quot&gt;&amp;quot
          : text);

    this.addPendingToken(cToken);
}تابع بعدی صرفا توکن را میگیره، چک میکنه روی کانال DEFAULT هست یا نه. اگه بود lastPendingTokenTypeFromDefaultChannel را آپدیت میکنه. همینطور، بدون توجه با کانال توکن، previousPendingTokenType را آپدیت میکنه و میذارتش ته pendingTokens.private void addPendingToken(final Token token) {
    this.previousPendingTokenType = token.getType();
    if (token.getChannel() == Token.DEFAULT_CHANNEL) {
       this.lastPendingTokenTypeFromDefaultChannel = this.previousPendingTokenType;
    }
    this.pendingTokens.addLast(token);
}تابع بعدی کمکمون میکنه تعداد تب از اول خطی که توکن داخل آرگومان گرفته را مشخص کنیم. اینکه اون TAB_LENGTH نقشی داره یا نه، بستگی به ادیتورتون داره 🤔. اگه تنظیم شده که بجای تب، space بزنه، این کد اوکیه. اگه هم tab میذاره بمونه، بازم اوکیه. ولی اگه تعداد دیگهای space زد باید این تنظیم بشه. بازم ربطی به کار من نداره، راحت هم میشه تست کرد اوضاع چطوره.private int getIndentationLength(final String textWS) {
    final int TAB_LENGTH = 4;
    int length = 0;
    for (char ch : textWS.toCharArray()) {
       length += TAB_LENGTH - (length % TAB_LENGTH);
    }
    return length;
}در پایان هم متود reset را override میکنیم که کار که تموم شد، همه متغیرهایی که برای state برنامه ازشون استفاده کردیم به مقدار اولیه برگردن.@Override
public void reset() {
    this.init();
    super.reset();
}خروجیکد بالا را با تکه کد زیر اجرا کردمinputFile = classloader.getResource(&amp;quottest-files/p01-t01.txt&amp;quot).getPath();
info.navidlabs.P01Indented.TestGrammar gp01t01 =
        new info.navidlabs.P01Indented.TestGrammar();
try{ gp01t01.test01(inputFile); }
catch (Exception e) { return; }
break;نتیجه شد این، بدون هیچ اروری 😁. میبینید که به زیبایی هر چه تمام تر بدنه تابع شناسایی شده. البته این رو باید اضافه کنم که در این پست خیلی درگیر کنترل خطا هم نشدم. چند تا متود هم برای نمایش پیام خطا و اضافه کردن توکن مناسب برای نمایش اون در گرامر و کد ریپو اصلی هست. خواستین یه نگاه بندازین.(file
  &#40;statements
    (statement (simple_stmts (simple_stmt pass&#41; \r\n))
    (statement (simple_stmts (simple_stmt pass) ; \r\n))
    (statement (simple_stmts (simple_stmt pass) ; (simple_stmt pass) \r\n)) 
    (statement (simple_stmts (simple_stmt pass) ; (simple_stmt pass) ; \r\n)) 
    (statement (compound_stmt 
      (function_def 
        (function_def_raw def func : 
          (block \r\n &lt;null&gt; 
            (statements 
              (statement (simple_stmts (simple_stmt pass) \r\n))) &lt;null&gt;))))))
&lt;EOF&gt;)سخن پایانیاولا تبریک میگم اگه نشستی این پست را خوندی! میدونم خیلی فرد شاخص و انسان خفنی هستم 😆 (سه روز وقتم سر راه انداختن این کد و خوندن ANTLR4 Mega Book رفت...)انصافا این کارای دستور زبانی مصیبته. تازه تا اینجا صرفا Abstract Syntax Tree را ساختیم. در فاز بعد باید پارسر را بنویسیم (بهتره بگم Listener ها را پیادهسازی کنیم) تا بشه با AST یه کاری کرد. مثلا فایل JSON ساخت یا این جور کارا. در مجموع قسمت سخت کار همین Lexer بود، بقیش مثل هر زبان دیگست...دقیقا توی پروژم از این جنایت علیه بشریت قراره استفاده کنم تا یه زبان برای back testing بورس بزنم. فالوم کن تا قبل از بقیه بتونی پروژه را تست کنی!</description>
                <category>نوید شیرمحمدی</category>
                <author>نوید شیرمحمدی</author>
                <pubDate>Sun, 28 Jul 2024 12:05:16 +0330</pubDate>
            </item>
                    <item>
                <title>معاملات الگوریتمی و یادگیری ماشینی (فصل اول)</title>
                <link>https://virgool.io/@nashi/%D9%85%D8%B9%D8%A7%D9%85%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%DA%AF%D9%88%D8%B1%DB%8C%D8%AA%D9%85%DB%8C-%D9%88-%DB%8C%D8%A7%D8%AF%DA%AF%DB%8C%D8%B1%DB%8C-%D9%85%D8%A7%D8%B4%DB%8C%D9%86%DB%8C-%D9%81%D8%B5%D9%84-%D8%A7%D9%88%D9%84-ljtefyxtno01</link>
                <description>در این مجموعه پست‌ها، خلاصه‌ای از فصل‌های ویرایش دوم کتاب &quot;یادگیری ماشینی برای معاملات الگوریتمی&quot; استیفان جانسن را مینویسم. کتاب جالبیه. کلی کد و روش باحال برای پردازش اطلاعات مالی و اخبار و چیزای دیگه را بررسی کرده و سعی میکنه تاثیرشون روی قیمت سهام شرکتا را تحلیل کنه.😁راستی یه مدته دارم رو یه نرم‌افزار خفن برای بک تستینگ کار میکنم که به زودی آماده میشه. با اون نرم‌افزار میتونی بدون دانش برنامه نویسی و بلد بودن زبان و این چیزا، استراتژی معاملاتیت را راحت تعریف کنی و ببینی که با داده‌های چند سال گذشته چقدر سود میده. اگه یکم از بورس سردرمیاری و دوست داری از اولین افرادی باشی که نرم‌افزار را تست می‌کنند، دنبالم کن.معاملات الگوریتمی را خیلی ساده اگر تعریفش کنیم، یعنی یه کدی داشته باشیم که اطلاعات را از چند جا بگیره و بهمون بگه کی و چقدر بخریم یا بفروشیم. ممکنه کدمون خودش خرید و فروش را هم انجام بده. اطلاعاتی هم که میگم میتونه تراکنش‌های بورس باشه، یا اطلاعیه‌های و صورت‌های مالی شرکتا و یا حتی اخبار و توییت‌ها!تکامل معاملات الگوریتمیاوایل اینطوری بود که (و هنوز هم هست) یه مشت فرمول داشتیم که بهمون میگفتن کی بخریم کی بفروشیم. مثلا با یه فرمول ساده بررسی میکردیم فلان شرکت چند روزه قیمت سهامش اومده پایین نسبت به دو هفته قبل، پس سهامشو بخریم و اگه رفته بالا بفروشیم. فقط چون کلی شرکت توی بورس بودن و خیلی سریع قیمتا بالا و پایین میشد، یه کد ریز میزدیم که قیمت سهام شرکتا را بگیره و فرمولمون را روشون اجرا کنه. در واقع معاملات الگوریتمی صرفا هدفش این بود که فرمولمون را سریع اجرا کنه و تمام. معاملات پرفرکانس (High Frequency Trading یا مخفف اون HFT) هم به همین کار اشاره داره.توابع و مدل‌هایی برای اندازه‌گیری ریسک و ارزش سرمایه‌گذاری در شرکتا از قبل وجود دارند ولی ما مشکلمون اینه که حجم داده بالاست.شرکتای بزرگی مثل رنسانس تکنولوژیز و دی. ای. شاو، با این روش کلی پول پارو کردن. مزایای این مدل معامله کردن اینه که:حجم داده مهم نیست: سهام چند هزارتا شرکت را میشه 24 ساعته به صورت ثانیه به ثانیه کنترل کرد و اگه طبق الگوریتممون ارزش معامله داشت، معامله را خودکار انجام داد.آدم توش نیست: خسته شدمو، اشتباه حساب کردمو و فکر کردم اینجور میشه، اونجور شد نداریم. الگوریتم مشخصه، همه چیز هم مث هلو ثبت میشه، پس میدونیم چرا یه کاری انجام شده.تستش میشه کرد / تست میشه کردش: اگه داده ها را یه جا داشته باشیم، راحت توی چند ثاینه میشه دید که الگوریتممون چقدر بهمون سود میده و کجاها ضرر میداده. بعد هم نمودارای خوشگل مشگل کشید ازش.یکم که سخت‌افزار قوی شد و پای یادگیری ماشین اومد وسط، روش‌های شبکه عصبی و پردازش زبان طبیعی و این جور چیزا هم به معاملات الگوریتمی اضافه شد. یعنی قبلا خودمون باید میشستیم فرمول و رابطه دربیاریم و تست کنیم چی جواب میده و چی جواب نمیده، الان یه مشت کارت گرافیک میذاریم بالا، یه عالمه جمع و ضرب اون پشت انجام میشه تا یه مدل برای پیش‌بینی رفتار بازار برامون بسازه. به جز اون، میشه داده‌های متنی (مثل اخبار و توییت و چیزای دیگه) را هم تحلیل کرد و حدس زد که فرضا فلانی یه کامنتی گذاشته یا فلان لایحه اومده، سهام کدوم شرکت میره هوا.با یادگیری ماشین میشه خودکار، یکسری مدل برای پیش‌بینی ارزش سهام شرکتا ساخت و میتونیم داده‌های متنوعی را بررسی کنیم.فرآیند معاملات الگوریتمیخب، حالا فرضا تا اینجا را خونده باشی و به سرت زد که ما هم شاید بتوانیم....کلی به موضوع نگاه کنیم، کاری که قراره انجام بدیم چند تا مرحله داره:جمع‌آوری داده: باید از چند تا منبع یه مش داده بگیریم. مثلا اگه قراره بورس تهران را تحلیل کنیم، باید اطلاعات نمادهای بورس ایران، اطلاعیه‌های کدال (مثلا صورت‌های مالی شرکتا و سهامداراشون) و اینجور جاها را بررسی کنیم و ازشون داده بگیریم. اگه بورس آمریکا را میخوایم، از sec.gov و یاهو فایننس و اینجور جاها داده بگیریم. و ....تحقیق: برای تحلیل داده‌ها کلی مدل و فرمول/اندیکاتور هست. خیلی از این مدل‌ها و اندیکاتورها هم پارامترهای مختلف دارند که باید تنظیم کرد. اینکه چقدر به سیگنال هر اندیکاتور هم بخوایم اعتماد کنیم مهمه. توی این مرحله باید بشینیم دستی یا با یه کد اینا را دربیاریم. مثلا 100 تا اندیکاتور رایگان توی talib هست، این مدل تنسورفلو هم از فلان رفیقمون گرفتیم و 10 تا پارامتر داره، فلان شرکتا را هم دوست داریم سهامشون را معامله کنیم و این جور چیزا. تو این مرحله فقط میخوایم بدونیم چه گزینه‌هایی داریم.بک تستینگ: بعد از اینکه خوب گزینه‌هامون را شناختیم، حالا از داده‌هامون استفاده میکنیم تا ببینیم پارامترهای فاز تحقیق را چی بزنیم تا بیشتر سود کنیم. اینجا با یه کدی چیزی شروع میکنیم عددا مختلف را بذاریم توی فرمولامون و ببینیم فرضا توی دو ماه گذشته با این فرمول و پارامترها چقدر سود میکردیم.چالش‌های معاملات الگوریتمیاگه معالات الگوریتمی انقدر خوبه، چرا همه ازش استفاده نمی‌کنند؟ بدیهتا جمع‌آوری داده و ایجاد مدل و درک اینکه داره چه اتفاقی میوفته کار هر کسی نیست. طرف هم باید برنامه‌نویسی و تحلیل داده بلد باشه، هم با بدبختی یا کلی هزینه (به خصوص در مورد بورس ایران) داده جمع کنه و هم از بورس یه چیزی بارش باشه تا تازه بتونه به معاملات الگوریتمی فکر کنه. بدیهتا کمتر جاندارانی تا این مرحله پیش میرن.کیفیت داده و پردازش اون به صورتی که بشه روش کد اجرا کرد هم مهمه. داده‌های مربوط به قیمت یک سهام تازه کوچیکشونه. شما اگه بخوای داده اطلاعیه‌ها و کانالای خبری و کشتی‌های تجاری و تفاهم‌های سیاسی و اینا را هم وارد مدلت کنی به چوخ عظما میری.از طرف دیگه، همینطوری داده را بذاری جلوی مدل‌های یادگیری ماشین یه چیز هچل هفت چند گیگی تحویل میگری که کسی نمیدونه کجاش داره چیکار میکنه. اصطلاحا میگیم، مدل تفسیر‌پذیر نیست. یه فرمول ریز و داغون که معلومه چیکار میکنه را میشه بهترش کرد و بررسی کرد چقدر قابل اعتماده ولی یه شبکه عصبی چند گیگی که عشقی یه مشت داده به خوردش دادیم تا آموزش ببینه را هیچ جوره نمیشه تست کرد. حاضری سرمایه یه عمر خودتو و بقیه رو بسپاری به این؟با همه این حرفا، یادگیری ماشین خیلی پیشرفت کرده و توی پیش‌بینی بازار خیلی عملکرد خفنی داره. برای همین توی این کتاب (پستای بعدی) آروم زمینه را برای معامله با این روش و آموزش مدل‌ قابل تفسیر آماده میکنه.نتیجه‌گیریمعاملات الگوریتمی یک روش منطقی برای حضور در بازارهای معاملاتیه و باید تلاشمون را بکنیم که بجای تکیه بر احساس و غریزه و اینجور چیزا، ازش استفاده کنیم. یادگیری ماشین هم به شدت در این زمینه کمکمون میکنه. تو این کتاب (پست‌های پیش رو) قراره با معاملات الگوریتمی آشنا بشیم.</description>
                <category>نوید شیرمحمدی</category>
                <author>نوید شیرمحمدی</author>
                <pubDate>Sat, 27 Jul 2024 16:33:42 +0330</pubDate>
            </item>
                    <item>
                <title>کوبرنتیز: 02-راه‌اندازی</title>
                <link>https://virgool.io/@nashi/%DA%A9%D9%88%D8%A8%D8%B1%D9%86%D8%AA%DB%8C%D8%B2-02-%D8%B1%D8%A7%D9%87-%D8%A7%D9%86%D8%AF%D8%A7%D8%B2%DB%8C-pnfjdjq2bsym</link>
                <description>در این مجموعه پست‌ها قصد دارم درباره‌ی راه‌اندازی کوبرنتیز بنویسم. میدونم که خیلی بیش از دو روز از پست قبلی میگذره ولی امیدوارم آماده کردن این پست ارزششو داشته باشه. با خوندن این پست با روش‌های مختلف راه‌اندازی کوبرنتیز آشنا میشی...بدیهتا! یکی از موارد جالب درباره کوبرنتیز اینه که با وجود جدید بودنش، خیلی سریع و شدید توسعه پیدا کرده. یعنی اصلا خودشو هم نگاه نکنی، فقط برای نصبش، هر کی از راه رسیده یه راه حلی داده. یه چند مورد از روش‌های متداول راه‌اندازی کوبرنتیز اینا هستن:مینی کیوب (Minikube): برای یادگیری و دولوپرا خوبهمیکرو کوبرنتیز (Mikrok8s): شرکت پشت اوبونتو پشتشه (پشت پشت = جلو؟) کی تری اس (K3s): نمیدونم مخفف چیه ولی خیلی خوفه (میرسیم بهش)کوبیدم :) (Kubeadm): خود توسعه دهنده‌های کوبرنتیز این روشو معرفی کردن و سختهروش اول: Minikubeاین روش برای کسایی که میخوان تازه کوبرنتیز را یاد بگیرند و دولوپرها خوبه. با این روش میتونی روی سیستم خودت (حتی اگه ویندوزه) یه نود تکی از کوبرنتیز با تمام ابزارهای لازم راه بندازی که کار master و worker را با هم میکنه. روی ویندوز کافیه پاورشل را با دسترسی ادمین باز کنی و بنویسی choco install minikube تا خودکار نرم‌افزارهای لازم نصب شن (شامل داکر و WSL هم میشه). اگه روی ویندوز نیستی یا میخوای فایل نصب را بگیری و چند بار نصب کنی، کافیه یه سر به سایتش بزنی. انقدر فرم این صفحه واضحه که نیازی به توضیح نمی‌بینم.بعد از نصب هم کافیه اول داکر را راه بندازی (فقط روی داکر دسکتاپ کلیک کن) و با minkube start نودتو راه بندازی. برای متوقف کردنش هم از minikube stop استفاده کن. برای اینم که ببینی همه چیز اوکیه و چی نصب کردی بزن minikube kubectl --get nodes تا فهرست نودها (یدونه نود) بهت نمایش داده بشه.اگه پلاگینی چیزی هم لازم داشتی میتونی مثل بلوک زیر راه بندازیش (مثلا ingress را باید خودت اضافه کنی چون برای کارای محلی زدن اینو و به ingress نیازی احساس نوگشته بید):minikube addons list
minikube addons enable ingressدر کل روش خوب و سر راستیه ولی دو تا مشکل داره:فقط یه نود داری و اونم روی سیستم خودتههمه دستوراتی که انلاین برای کوبرنتیز میبینی را باید با minikube بزنیروش دوم: Mikrok8sاین روش هم روی مک و ویندوز جواب میده و روی لینوکس‌هایی که snap داشته باشن (مثل اوبونتو). به سایتش که سر بزنی میتونی برای پلتفرم‌های مختلف (پایین صفحه) روش نصب را ببینی. نصبش روی ویندوز خیلی جذابیتی نداشت، ولی روی لینوکس کافیه توی ترمینال دستورای زیرو بنویسی (بکوپیسی):sudo snap install microk8s --classic
sudo usermod -a -G microk8s $USER
newgrp microk8sبعد از نصب دستورای زیر را میتونی اجرا کنی (خود سایتش هم چند تا دستور بامزه گفته که نگاه کنی بد نیست):دیدن نودها: microk8s kubectl get nodesبررسی اوضاع احوال کوبرنتیز: microk8s statusاضافه کردن داشبور: microk8s enable dashboardاضافه کردن نود کارگر (یه دستور و تیکت میده که باید در نور کارگر بدبخت یکپیسی): microk8s add-nodeاین روش هم خوبه ... نه راستش این روش بر خلاف روش قبلی خیلی خوبه. یه چیزیه که میشه بهش گفت کلاستر و توی کار ازش استفاده کرد. ولی مشکلش اینه که از snap استفاده میکنه. مشکلای snap هم که اگه میدونی، میدونی.روش سوم: K3sاگه دو تا روش قبل خیلی برای به دلتون نچسبید، بهتون حق میدم. ولی این یکی چیز خوبیه. تو این روش یه فایل زیر (به قول بزرگان نیم-قاله-سه-چی) دانلود میکنی و بعد اجراش یه کلاستر مطابق با آخرین استانداردهای صنعتی و سنتی خواهید داشت مشتریان عزیز... . من چیزی نگم. همین تک پایینو بکوپیس تمومه (نود مستر):curl -sfL https://get.k3s.io | sh -برای اضافه کردن نود برده ذلیل هم اول برو /var/lib/rancher/k3s/server/node-token یه توکنه کپی کن. IP نود مستر را با ip a بگیر و دستور زیرو در سرور اجرا کن تا به صورت ابدی به بردگی ارباب بی‌رحمش دربیاد (سکوت):curl -sfL https://get.k3s.io | K3S_URL=https://&lt;controller IP&gt;:6443 K3S_TOKEN=&lt;token&gt; sh -روش چهارم: Kubeamdشاید براتون سوال باشه که چرا این همه روش برای نصب کوبرنتیز هست (فقط سه تاشو گفتیم ولی این نوک چیزه...). در جواب باید گریست...چون روش اصلی نصب کوبرنتیز خیلی سخته. یعنی لیترالی سخته. و الان میخوایم ببینیم چیه. اول باید یه سرور جور کنید و پورتای زیرو در مستر بگشایید: پورت‌های 64430-64439 برای API کوبرنتیزپورت‌های 2379-2380 برای etcd (دیتابیس کوبرنتیز برای اینکه ثبت کنه اوضاع چطوره)پورت 10250: API کوبلت (Kubelet)پورت 10251: برای scheduler کوبرنتیز (میگه چه موقع، چه کارایی انجام شه)پورت 10252: برای kube-controller-manager (نمیدونم چیه ولی مهمه)همچنین در تک تک نودهای کارگر پورتای زیرو باید باز کنی:پورت‌های 10250: برای APIپورت‌های 30000 تا 32767: وقتی پاد میاد بالا و یرویس تعریف میکنی، پورت‌ها از این بازه انتخاب میشن.بعدش (یا قبلش) باید مطمئن بشی که IP مستر و ورکر (ارباب و کارگر) عوض نمیشه که راحت از فایل /etc/netplam/* میشه انجامش داد (اون ستاره برای اینه که یه فایل توی این پوشه هست و معمولا اسمش از سیستم به سیستم فرق میکنه، مثلا روی VM من 00-installer-config.yaml بود).  خیلی نمیخوام درگیر این فایل بشم (خیلی ربطی نداره، gemini هم رایگانه)، ولی کلیتش اینه که یه IP استاتیک روی اینترفیس تعریف کردم و DNS هم گذشتم روی شکن (shecan.ir) تا بتونم بعدا ایمیج‌های داکر را دانلود کنم. (انصافا ویرگول باید یه فکری به حال این کد بلاک‌ها بکنه، نه رنگ دارن نه درست میشه توشون کپی پیست کرد، اگه اشتباه فاصله‌گذاری داره، یه کاریش کنید)network:
  ethernets:
    ens18:
      dhcp4: false
      addresses:
        - 10.10.1.15/24
      routes:
        - to: default
          via: 10.10.1.1
          on-link: true
      nameservers:
        addresses:
          - 185.51.200.2
          - 178.22.122.10
  version: 2بعد هم با netplan apply تنظیمات شبکه را اعمال کنید (ممکنه لازم بشه دسترسی به فایل را محدود کنید به 600).خان بعدی تعریف شبکه overlay هست که با دستور زیر در تعدادی ضربه انجامش میدیم:cat &lt;&lt;EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

# sysctl params required by setup, params persist across reboots
cat &lt;&lt;EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOFبعد هم با sudo sysctl --system تغییرات را اعمال (قانون) میکنیم در خان بعدی (نمیدونم از چندتا) باید swap را غیرفعال کنید (ظاهرا از یه نسخه‌ای به بعد کوبرنتیز دیگه به این کار نیازی نیست ولی منابع موثق در این رابطه یافت نشد)sudo swapoff -a
(crontab -l 2&gt;/dev/null; echo &amp;quot@reboot /sbin/swapoff -a&amp;quot) | crontab - || trueاگه هنوز زنده‌اید، در خان بعدی (من که کیف میکنم) باید یه ران تایم (run time) نصب کنیم که کانتینرها را اجرا کنه. با دستور زیر این جنایت علیه بشریت را مرتکب میشم (واقعا اگه برای دستورای زیر توضیح لازمه نباید از این روش کوبرنتیز را نصب کنی، یا شاید بهتره اول بری لینوکس کار کنی؟):sudo apt-get update -y
sudo apt-get install -y software-properties-common curl apt-transport-https ca-certificates

curl -fsSL https://pkgs.k8s.io/addons:/cri-o:/prerelease:/main/deb/Release.key |    gpg --dearmor -o /etc/apt/keyrings/cri-o-apt-keyring.gpg

echo &amp;quotdeb [signed-by=/etc/apt/keyrings/cri-o-apt-keyring.gpg] https://pkgs.k8s.io/addons:/cri-o:/prerelease:/main/deb/ /&amp;quot | tee /etc/apt/sources.list.d/cri-o.list

sudo apt-get update -y
sudo apt-get install -y cri-o
sudo systemctl daemon-reload
sudo systemctl enable crio --now
sudo systemctl start crio.service

VERSION=&amp;quotv1.28.0&amp;quot
wget https://github.com/kubernetes-sigs/cri-tools/releases/download/$VERSION/crictl-$VERSION-linux-amd64.tar.gz
sudo tar zxvf crictl-$VERSION-linux-amd64.tar.gz -C /usr/local/bin
rm -f crictl-$VERSION-linux-amd64.tar.gzبعد باید روی تمام نودها دستور زیرو بزنی تا اجزای مشترک کوبرنتیز بین مستر و ورکر نصب بشن. قبلش فقط اینو اضافه کنم که برای دیدن آخرین نسخه کوبرنتیز کافیه بزنی apt-cache madison kubeadm | tac:KUBERNETES_VERSION=1.29

sudo mkdir -p /etc/apt/keyrings

curl -fsSL https://pkgs.k8s.io/core:/stable:/v$KUBERNETES_VERSION/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

echo &amp;quotdeb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v$KUBERNETES_VERSION/deb/ /&amp;quot | sudo tee /etc/apt/sources.list.d/kubernetes.list

sudo apt-get update -y
sudo apt-get install -y kubelet kubeadm kubectlچون کوبرنتیز موجود حساسیه، نباید بذاریم ورژنش آپدیت بشه (منطقشون منم نمیفهمه ولی همینه که هست؟). برای این کار کافیه بزنی sudo apt-mark hold kubelet kubeadm kubectl تا موقع آپدیت ورژن این چد ملعون بالا نره (آپدیت نشن نکبتیا).بعد ... باید دستور زیرو بزنی تا به کوبلت حالی کنی IP سیستم چیهsudo apt-get install -y jq

local_ip=&amp;quot$(ip --json addr show eth0 | jq -r &#039;.[0].addr_info[] | select(.family == &amp;quotinet&amp;quot) | .local&#039;)&amp;quot

cat &gt; /etc/default/kubelet &lt;&lt; EOF
KUBELET_EXTRA_ARGS=--node-ip=$local_ip
EOFتا اینجا تمام دستورا روی مستر و ورکر یکسان بود، از اینجا به بعد دیگه اینطور نیست. اول باید به سه سوال (به جز بودن یا نبودن) جواب بدی. قرار این کلاستر از بیرون قابل دسترس باشه یا داخلیه؟اگه از بیرون قابل دسترسه: اول با  (curl ifconfig.me &amp;&amp; echo &quot;&quot;) ببین IPت چیه (متاسفانه راست‌چین اینجا کار دست آدم میده، ولی کپی کنید درست میشه). بعد متغیرها محیطی زیرو تنظمیم کنی (توی ترمینا کپی پیست کن). بدیهتا باید IP ها را خودت با توجه به شبکت تنظیم کنی. دومی برای پادهاست و میتونی دستش نزنی. IPADDR=&amp;quot10.10.1.15&amp;quot
NODENAME=$(hostname -s)
POD_CIDR=&amp;quot192.168.0.0/16&amp;quotبعد دستور زیرو میزنی تا مستر اجرا شهsudo kubeadm init --control-plane-endpoint=$IPADDR  --apiserver-cert-extra-sans=$IPADDR  --pod-network-cidr=$POD_CIDR --node-name $NODENAME --ignore-preflight-errors Swapاگه هم که کلاستر داخلیه همون یه سه تا متغیر محیطی را تنظیم کن (این بار با هر IPای که میخوای توی شبکت باشه) و دستور زیرو میزنیsudo kubeadm init --apiserver-advertise-address=$IPADDR  --apiserver-cert-extra-sans=$IPADDR  --pod-network-cidr=$POD_CIDR --node-name $NODENAME --ignore-preflight-errors Swapدستورای بالا (هر کدوم که اجرا کردی) بهت یه دستور نمایش میدن که باید در ورکر وارد کنی تا به کلاستر (حلقه رعیتی) ملحق بشه. یه چیزی تو مایه‌های دستور زیره خروجی:sudo kubeadm join 10.128.0.37:6443 --token j4eice.33vgvgyf5cxw4u8i --discovery-token-ca-cert-hash sha256:37f94469b58bcc8f26a4aa44441fb17196a585b37288f85e22475b00c36f1c61 دستورای زیرو هم ممکنه بعدش بخوای اجرا کنی برای دسترسی (خودش میگفت فکر کنم؟):mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/configبعد از نصب میتونی دستورای زیرو بزنی تا اطلاعات کلاستر را ببینی و اشک بریزی:kubectl get po -n kube-systemkubectl get --raw=&#x27;/readyz?verbosekubectl cluster-infoبرای دیدن نودها هم میتونی از kubectl get nodes اسنفاده کنی. اگه خواستی به کارگرهایی گه در کلاستر هستند هم اسم و القاب زشت بدی، دستور زیر هست:kubectl label node my_node_label  node-role.kubernetes.io/worker=workerبعد از کارای بالا میتونی Calico هم برای بسری ماژولهای شبکه بهتر نصب کنی که من از خیرش میگذرم فعلا. این چیت شیت هم میذارم که ببینی چه دستورایی میشه روی کلاستر اجرا کرد. تا قسمت بعد!</description>
                <category>نوید شیرمحمدی</category>
                <author>نوید شیرمحمدی</author>
                <pubDate>Sat, 20 Apr 2024 23:10:01 +0330</pubDate>
            </item>
                    <item>
                <title>کوبرنتیز: 01-معرفی</title>
                <link>https://virgool.io/codenevis/%DA%A9%D9%88%D8%A8%D8%B1%D9%86%D8%AA%DB%8C%D8%B2-01-%D9%85%D8%B9%D8%B1%D9%81%DB%8C-ofmyt1kkhqeo</link>
                <description>در این مجموعه پست‌ها قصد دارم درباره‌ی کوبرنتیز یکسری آموزش بذارم. البته باید این هم اضافه کنم که در این زمینه خودم هم تازه کار محسوب میشم بنابراین خیلی روی درست و جامع بودن این آموزش حساب باز نکنید. با این حال، سنگ مفت گنجیشک مفت، بزن بریم.یکی از تکنولوژی‌های خفنی که در چند سال گذشته تاثیر مثبت و خیلی زیادی روی بحث توسعه نرم‌افزار و چرخه کد زنی داشته، کانتینرها بودن. دیگه کمتر برنامه‌نویسی میاد و برای توسعه و تست یه کد با ماشین مجازی محیط توسعه و بقیه ابزارهاش را اجرا می‌کنه. بجاش به نوشتن چند تا فایل داکر و یکی دو تا داکر کامپوز، میتونه چند صد تا کانتینر را ایجاد و پیکربندی کنه و به راحتی از کانتینرهای موجود برای ابزارهای مختلف استفاده کنه.اما طبق اصل ناپایستگی مشکلات، مشکلات نه کم می‌شوند و نه از بین می‌روند، بلکه زیاد و کلفت‌تر شده و همواره تغییر شکل می‌دهند :)درسته که داکر خیلی چیز خفنیه ولی وقتی تعداد کانتینرها زیاد میشه، دیگه نمیشه جمعشون کرد. کافیه یه کانتینر (مثلا دیتابیس یا rabbitmq) از کار بیوفته تا کل سیستم بیاد پایین. اختصاص IP و مدیریت پیکربندی کانتینرها هم جای خود. در اینجاست که گوگل کوبرنتیز را معرفی می‌کنه.کوبرنتیز یک فریم‌ورک متن بازه (فعلا) که برای هماهنگ‌سازی و مقیاسیدن :) برنامه‌های مبتنی بر کانتینر معرفی شده و ضمن اشتغال آفرینی به ما در حل چالش‌های زیر کمک می‌کنه:مدیریت پیچیدگی: مدیریت دستی کانتینرها (یه دویست سی‌صد تا) کاریست بس سخت و دردناک. اصلا امکان نداره یه جایی را دست بذاری و بعدش مجبور نشی آبشاری کلی فایل دیگه را عوض کنی تا دوباره برنامت کار کنه.دسترسی: اگه چند تا سرور داشته باشی، کوبرنتیز میاد و کانتینرهاتو بین اونها تقسیم میکنه (مگه اینکه بهش بگی نکنه) تا اگه یکی از سرورها به فنا رفت، برنامت به جاییش نباشه.مقیاس‌پذیری: با کوبرنتیز مثل گلابی میتونی تعداد کانتینرهاتو زیاد و کم کنی تا اگه سرعت اینترنت به کاربرا اجازه داد زیادی به برنامت وصل بشن، سرعت سرویست نیاد پایین.بازیابی: وقتی یه کانتینر از کار میوفته، کوبرنتیز خودش دوباره راهش میندازه تا برنامت از کار نیوفته. خیلی هم عالی.معماری کوبرنتیزکوبرنتیز  ،مثل سایر محصولات گوگل، معماری نسبتا ضخیم و بی‌تربیتی داره. اما در کل با یه معماری ارباب-کارگر طرفیم که دو نوع گره داره:گره ارباب (master node): این گره (یا گره‌ها) مدیریت خوشه (کلاستر) را بر عهده دارند. ترافیک ورودی به خوشه توسط این گره بین سایر گره‌های تقسیم میشه. همینطور زمانبندی و اینکه چه کانتینری کجا باشه را هم این گره تعیین میکنه. ادمین میتونه به این گره وصل بشه و از API برای مدیریت خوشه استفاده کنه. همینطور دیتابیس etcd هم که وضعیت گره‌های خوشه را نگه میداره روی این گره است.گره کارگر (worker node): این نوع گره، از گره ارباب دستور میگیره که تعدادی کانتینر را اجرا کنه. روی این گره حداقل یه container runtime هست (مثل داکر، یا containerd یا cri-o) که کانتینر را اجرا میکنه. همینطور kubelet هم هست که به عنوان یه واسط بین سرور و container runtime عمل میکنه و تضمین میکنه که کانتینرها دارند درست اجرا میشن. برای شبکه هم یه kube-proxy روی این نوع گره هست که میتونه مسیریابی بسته‌های را با کیفیت مورد انتظار گوگل انجام بده.اجزای کلیدی کوبرنتیزبرای کار با کوبرنتیز یه تعدادی جزء (منفردالبه اجزا) هستند که هر کدوم یه کاری میکنند و در کنار هم میتونند برای توسعه محصولات بومی بدون معادل خارجی مورد استفاده قرار بگیرند. موارد زیر فعلا تعریفن، در پست‌های بعدی که دست به کیبورد بشیم (بله نصب کوبرنتیز هم شامل میشه) بهتر میشه درک کرد. بنابراین اگه یکم گنگ و بی‌مفهوم و غیر بدیهی و ضد و نقیض و In contrast بنظ میرسه خیلی سخت نگیرید.پاد (Pod): یک گروه از کانتینرها (معمولا هم یک کانتینر) که از دید برنامه‌نویس یا دواپس‌کار یک بلوک را تشکیل میدن. این بلوک‌ها را کنار هم میذاریم تا برنامه اصلی را بسازیم. پاد ممکنه در هر لحظه به فنا بره و IPش عوض بشه، ولی تضمین میشه که کوبرنتیز دوباره میسازدش.سرویس (Service): یکی از بدترین نام‌گذاری‌های طول تاریخ بشر. سرویس به ما اجازه میده که چند تا پاد را بهشون یه اسم (مثل آدرس وب‌سایت) اختصاص بدیم و وقتی یه بسته بهش میرسه، به یکی از این پادها میده (load balancing). با توجه به اینکه پاد در هر لحظه ممکنه به فنا بره، سرویس به کمک ما میاد تا بدون توجه به فجایع مربوط به پاد و اینکه در هر لحظه چند تا پاد داریم، باهاشون کار کنیم.اینگرس (Ingress): فارسیش میشه اجازه ورود. اینگرس کمک میکنه که اجازه دسترسی به سرویس از بیرون را بدیم و روش HTTPS و مسیریابی یا URL تعریف کنیم. کانفیگ مپ (ConfigMap): فارسیش میشه نقشه پیکربندی. کانفیگ مپ کمک میکنه که پیکربندی برنامه را از تعریف شبکه و کانتینر و ... جدا کنیم. قسمت خفن اینجاست که با کانفیگ مپ میشه به صورت پویا (در زمان اجرا) کانفیگ برنامه را عوض کنیم، بدون اینکه به بیلد کردن دوباره برنامه نیاز باشه! معمولا برای تعریف متغیرهای محیطی و URLها مورد استفاده قرار میگیره (و نه رمزها).راز (Secret): مثل کانفیگ مپه ولی برای نگداری از کلمات عبور و رمز و کلید API و اینجور چیزا بکار میاد. مطابق انتظار با فرمت base64 داده باید داخلش ثبت کنید (صرفا جهت اطلاع، base64 امنیتی برای شما فراهم نمیکنه و صرفا یه شیوه نمایشه که تضمین میکنه کاراکتر دردسرساز نداریم).حجم (Volume): تقریبا معادل همون دیسک میشه (برای دوستانی که تا حالا با داکر کار نکردند) و به ما کمک میکنه که دسترسی به داده‌های مشترک را برای پادها فراهم کنیم و همینطور یجایی بهشون بدیم که داده‌هاشون را ثبت کنند. اینطوری اگه پاد به فنا رفت، داده به فنا نمیره و پاد بعدی میتونه ازش استفاده کنه.پیاده‌سازی (Deployment) و مجموعه حالت‌دار (Stateful Set)موقع کار با کوبرنتیز یه راز سیاه هست که همیشه باید بهش دقت کنید، اونم اینکه پاد در هر لحظه ممکنه به فنا بره، حتی اگه دیتابیس باشه. و اگه یه چیز درمورد دیتابیس مهم باشه اینه که عمرا نباید جایی بره. کلا کوبرنتیز برای برنامه‌هایی خوبه که حالت (داده) در خودشون نگه نمیدارند یا حداقل داده خیلی مهمی ندارند. مثلا یه برنامه تحت وب را میشه تقسیم کرد به کش، دیتابیس و خود برنامه (که فرضا با جنگو نوشتیم). کش اگه به فنا رفت، سرویس کند میشه ولی بعد یکی دو ساعت دوباره همه‌چیز مثل روز اوله. کد جنگو هم اگه کرش کرد، دوباره که پادش بیاد بالا هیچ مشکلی نداریم. ولی دیتابیس اگه به فنا رفت خودمون هم به فنا رفتیم. اینجاست که دو تا مفهموم پیاده‌سازی و مجموعه حالت‌دار برامون دست تکون میدن:پیاده‌سازی: وقتی بکار میاد که برنامه حالت نداره و میخوایم راحت تعداد پادها را زیاد و کم کنیم.مجموعه حالت‌دار: وقتی که داده‌های مهم داریم و نمیشه خیلی به برنامه دست زد (مثل دیتابیس) میتونیم از مجموعه حالت‌دار استفاده کنیم. این نکته هم اضافه کنم که معمولا کوبرنتیز اصلا گزینه خوبی برای دیتابیس نیست (دردسرش بشتر از سودشه) و  با توجه به حساسیت کار، دیتابیس را همیشه بیرون از کوبرنتیز نگه میداریم. خوشبختانه خود دیتابیس‌ها راهکارهای مناسب برای مقیاس پذیری و دسترسی پذیری و بازیابی از خطا و موارد مهم دیگه را پشتیبانی می‌کنند و ما هم سری که درد نمیکنه را دستمال نمیبندیم.در پایان، کوبرنتیز سخته ولی با توجه به مسیر توسعه تکنولوژی و برنامه نویسی، یادگرفتنش خیلی ارزشمنده. در پست بعدی (که احتمالا دو روز دیگه مینویسم) میریم و کوبرنتیز را هم روی سیستم خودمون و هم روی یک سرور نصب میکنیم. فعلا!</description>
                <category>نوید شیرمحمدی</category>
                <author>نوید شیرمحمدی</author>
                <pubDate>Sun, 07 Apr 2024 09:52:53 +0330</pubDate>
            </item>
                    <item>
                <title>هکاتون 1402: چالش CrackMe</title>
                <link>https://virgool.io/@nashi/%D9%87%DA%A9%D8%A7%D8%AA%D9%88%D9%86-1402-%DA%86%D8%A7%D9%84%D8%B4-crackme-apadjmlrcezq</link>
                <description>معرفی هکاتونفروردین امسال (1402) کوئرا یک مسابقه مسابقه فتح پرچم (یا همون CTF) برگزار کرد با نام هکاتون. ثبت‌نام مسابقه تا 23ام اسفندماه 1401 ادامه داشت و شما میتونستید پس از پرداخت هزینه نسبتا سنگین (480)، برای مسابقه و 18 ساعت آموزش (نه چندان با کیفیت) اقدام کنید. در بخش معرفی رویداد این مطالب نوشته شده بود:رویداد هکاتون امنیت، چهارمین هکاتون برنامه‌نویسی کوئرا است که با موضوع امنیت و در چارچوب طرح شهید بابایی بنیاد ملی نخبگان برگزار می‌شود.این رویداد شامل یک بخش آموزشی و یک بخش رقابتی است. در ابتدا، موضوعات جذاب و کاربردی حوزه امنیت در ۳ روز و با همراهی اساتید برتر این حوزه برگزار می‌شود و شما مجموعا ۱۸ ساعت آموزش می‌بینید. بعد از آموزش به تیم‌های ۲ الی ۴ نفره تقسیم می‌شوید و در یک مسابقه چالشی به رقابت می‌پردازید. بعد از مسابقه راه‌حل تیم‌ها داوری می‌شود و نفرات برتر مشمول دریافت امتیاز نخبگی بنیاد و همینطور برنده جایزه نقدی مسابقه می‌شوند. علاوه بر این نفرات برتر برای استخدام به شرکت‌های مطرح معرفی خواهند شد. برای مشاهده مراحل و زمان‌بندی رویداد روی این لینک کلیک کنید.? به تمام شرکت‌کنندگان، گواهی شرکت در رویداد اهدا خواهد شد اما فقط نفرات برتر مسابقه و بعد از داوری راه‌حل‌ها، مشمول دریافت امتیاز نخبگی بنیاد می‌شوند.⚠️ شرکت در رویداد به صورت فردی است اما پیش از مسابقه، شرکت‌کنندگان به تیم‌های ۲ الی ۴ نفره تقسیم می‌شوند تا به صورت تیمی به رقابت بپردازند. اگر از ابتدا تیم شما مشخص است و دوست دارید با تیم خود در این رویداد شرکت کنید لطفا به صورت جدا جدا ثبت‌نام خود را تکمیل کنید و بعد از ثبت‌نام به ما اطلاع دهید که می‌خواهید در یک تیم باشید.برای برگزاری رویداد از پلتفرم CTFd استفاده شده بود و تیم کوئرا چند روز قبل از مسابقه، با هدف آشنایی بچه‌ها با پلتفرم یک کوییز آزمایشی (و بدون تاثیر در نتایج مسابقه) قرار داد. سوالات این کوییز از رویداد‌هایی مثل picoctf و uutctf انتخاب شده بودند و به عنوان دست گرمی کمک بزرگی محسوب میشد. در پرانتز این هم بگم که سوالات مسابقه با اختلاف....باااا اختلااااف، سخت‌تر و جذاب‌تر بودند.و اما چالش CrackMeامتیاز: 100متن سوال:Can you login?The falg is queraCTF{username_password}. Find the username and password.فایل: لینکدر این سوال یک فایل apk به ما داده شده که اگر روی شبیه‌ساز (مثل AVD یا Genymotion) نصبش کنیم میبینیم که یک برنامه ساده است که در صفحه اولش نوشته Login و یک دکمه Login داره. همینطور دو تا فیلد برای وارد کردن username و password داریم. اگر کلمه عبور و نام کاربری درست نباشند، یک toast به ما نمایش داده میشه که میگه Username or Password is incorrect. ما باید نام کاربری و کلمه عبور درست را از apk استخراج کنیم.برای بررسی فایل‌های apk معمولا از ابزار Jadx استفاده میشه. این ابزار فایل apk را به عنوان ورودی دریافت میکنه و سعی میکنه کد‌های کامپایل‌شده موجود در این فایل را به جاوا برگردونه (دیکامپایل کنه). دقت کنید که میگم سعی میکنه. در مواردی ممکنه Jadx نتونه کد را دیکامپایل کنه که در این صورت کد با فرمت smali در بدنه‌ی کد دیکامپایل شده دیده میشه و فایلی با نام com/&lt;apk name&gt;/BadLogic تولید میشه.نکته دیگه‌ای که فکر میکنم دونستنش لازمه اینه که با Jadx نمیشه فایل را apk را اصلاح کرد و فقط برای خوندن کد استفاده میشه. اگر قصد تغییر در فایل apk را دارید باید با apktool اون را دیکامپایل کنید (که در نتیجه‌اش تعدادی فایل smali دریافت می‌کنید) و بعد با یک ادیتور بخش‌هایی را که نیازه عوض کنید. بعد هم با apktool دوباره برنامه را کامپایل کنید و با ابزار Sign امضا کنید. اگر دوست دارید این موارد را یاد بگیرید این آموزش را پیشنهاد میکنم (میتونید از کانال تلگرامی t.me/zer0daylab دریافت کنید).راه حلبرای حل سوال کافیه که فایل apk را با Jadx دیکامپایل کنیم (فقط کافیه فایل را بندازید داخل UI یا دکمه Open را بزنید). بعد از دیکامپایل شدن برنامه، وارد مسیر com/example.logmein میشیم و فایل‌ Login را بررسی میکنیم. در فایل Login میشه منطق بررسی نام کاربری و کلمه عبور را دید:طبق چیزی که میبینیم، برای نمایش پیام Username and Password is correct، دو تا اتفاق میوفته:1- نام کاربری اول با base64 کدگذاری میشه و بعد با مقدار R3JleWhhdEluWW91ckFyZWE= مقایسه میشه. اگر با CyberChef بررسی کنیم میبینیم که این رشته معادل GreyhatInYourArea است.2- مقدار پسورد با الگوریتم md5 هش میشه و با مقدار d23b3bc1dc24919d2439219ad6072d33 مقایسه میشه. برای شکستن این هش از سایت dCode استفاده کردم و نتیجه شد monkeyfish.جواب: queraCTF{GreyhatInYourArea_monkeyfish}</description>
                <category>نوید شیرمحمدی</category>
                <author>نوید شیرمحمدی</author>
                <pubDate>Mon, 10 Apr 2023 16:25:40 +0330</pubDate>
            </item>
                    <item>
                <title>هکاتون 1402: چالش Login</title>
                <link>https://virgool.io/@nashi/%D9%87%DA%A9%D8%A7%D8%AA%D9%88%D9%86-1402-%DA%86%D8%A7%D9%84%D8%B4-login-yxyqapbhyuyn</link>
                <description>معرفی هکاتونفروردین امسال (1402) کوئرا یک مسابقه مسابقه فتح پرچم (یا همون CTF) برگزار کرد با نام هکاتون. ثبت‌نام مسابقه تا 23ام اسفندماه 1401 ادامه داشت و شما میتونستید پس از پرداخت هزینه نسبتا سنگین (480)، برای مسابقه و 18 ساعت آموزش (نه چندان با کیفیت) اقدام کنید. در بخش معرفی رویداد این مطالب نوشته شده بود:رویداد هکاتون امنیت، چهارمین هکاتون برنامه‌نویسی کوئرا است که با موضوع امنیت و در چارچوب طرح شهید بابایی بنیاد ملی نخبگان برگزار می‌شود.این رویداد شامل یک بخش آموزشی و یک بخش رقابتی است. در ابتدا، موضوعات جذاب و کاربردی حوزه امنیت در ۳ روز و با همراهی اساتید برتر این حوزه برگزار می‌شود و شما مجموعا ۱۸ ساعت آموزش می‌بینید. بعد از آموزش به تیم‌های ۲ الی ۴ نفره تقسیم می‌شوید و در یک مسابقه چالشی به رقابت می‌پردازید. بعد از مسابقه راه‌حل تیم‌ها داوری می‌شود و نفرات برتر مشمول دریافت امتیاز نخبگی بنیاد و همینطور برنده جایزه نقدی مسابقه می‌شوند. علاوه بر این نفرات برتر برای استخدام به شرکت‌های مطرح معرفی خواهند شد. برای مشاهده مراحل و زمان‌بندی رویداد روی این لینک کلیک کنید.? به تمام شرکت‌کنندگان، گواهی شرکت در رویداد اهدا خواهد شد اما فقط نفرات برتر مسابقه و بعد از داوری راه‌حل‌ها، مشمول دریافت امتیاز نخبگی بنیاد می‌شوند.⚠️ شرکت در رویداد به صورت فردی است اما پیش از مسابقه، شرکت‌کنندگان به تیم‌های ۲ الی ۴ نفره تقسیم می‌شوند تا به صورت تیمی به رقابت بپردازند. اگر از ابتدا تیم شما مشخص است و دوست دارید با تیم خود در این رویداد شرکت کنید لطفا به صورت جدا جدا ثبت‌نام خود را تکمیل کنید و بعد از ثبت‌نام به ما اطلاع دهید که می‌خواهید در یک تیم باشید.برای برگزاری رویداد از پلتفرم CTFd استفاده شده بود و تیم کوئرا چند روز قبل از مسابقه، با هدف آشنایی بچه‌ها با پلتفرم یک کوییز آزمایشی (و بدون تاثیر در نتایج مسابقه) قرار داد. سوالات این کوییز از رویداد‌هایی مثل picoctf و uutctf انتخاب شده بودند و به عنوان دست گرمی کمک بزرگی محسوب میشد. در پرانتز این هم بگم که سوالات مسابقه با اختلاف....باااا اختلااااف، سخت‌تر و جذاب‌تر بودند.و اما چالش Loginامتیاز: 100متن سوال: Can you login?فایل: لینکدر این سوال یک فایل apk به ما داده شده که اگر روی شبیه‌ساز (مثل AVD یا Genymotion) نصبش کنیم میبینیم که یک برنامه ساده است که در صفحه اولش نوشته Welcome و یک دکمه Login داریم. وقتی روی دکمه Login میزنیم به صفجه جدیدی میریم که دو تا فیلد برای وارد کردن username و password داره و یک دکمه Login برای تایید. ما باید نام کاربری و کلمه عبور درست را از apk استخراج کنیم.برای بررسی فایل‌های apk معمولا از ابزار Jadx استفاده میشه. این ابزار فایل apk را به عنوان ورودی دریافت میکنه و سعی میکنه کد‌های کامپایل‌شده موجود در این فایل را به جاوا برگردونه (دیکامپایل کنه). دقت کنید که میگم سعی میکنه. در مواردی ممکنه Jadx نتونه کد را دیکامپایل کنه که در این صورت کد با فرمت smali در بدنه‌ی کد دیکامپایل شده دیده میشه و فایلی با نام com/&lt;apk name&gt;/BadLogic تولید میشه.نکته دیگه‌ای که فکر میکنم دونستنش لازمه اینه که با Jadx نمیشه فایل را apk را اصلاح کرد و فقط برای خوندن کد استفاده میشه. اگر قصد تغییر در فایل apk را دارید باید با apktool اون را دیکامپایل کنید (که در نتیجه‌اش تعدادی فایل smali دریافت می‌کنید) و بعد با یک ادیتور بخش‌هایی را که نیازه عوض کنید. بعد هم با apktool دوباره برنامه را کامپایل کنید و با ابزار Sign امضا کنید. اگر دوست دارید این موارد را یاد بگیرید این آموزش را پیشنهاد میکنم (میتونید از کانال تلگرامی t.me/zer0daylab دریافت کنید).راه حلبرای حل سوال کافیه که فایل apk را با Jadx دیکامپایل کنیم (فقط کافیه فایل را بندازید داخل UI یا دکمه Open را بزنید). بعد از دیکامپایل شدن برنامه، وارد مسیر com/example.myapplication میشیم و فایل‌های MainActivity و MainActivity2 را بررسی میکنیم. در فایل MainActivty2 میشه منطق بررسی نام کاربری و کلمه عبور را دید:شرطی که نام کاربری و کلمه عبور را چک میکنه را در زیر می‌نوسیم. در این کد بررسی میشه که آیا نام کاربری با رشته‌ی حاصل از اتصال s2 و s3 برابر هست یا نه (user=s2+s3) و اینکه کلمه عبور با رشته‌ی حاصل از اتصال s5 و s4 برابر باشه (pass=s5+s4). if (Intrinsics.areEqual($user.getText().toString(), this$0.getString(R.string.s2) + this$0.getString(R.string.s3)) &amp;&amp; Intrinsics.areEqual($pass.getText().toString(), this$0.getString(R.string.s5) + this$0.getString(R.string.s4)) {    // do something; } کافیه در Jadx دنبال رشته‌های مورد نظر بگردیم. به این منظور روی علامت ذره‌بین نوار ابزار کلیک می‌کنیم (Text Search) و در پنچره‌ای که باز میشه تیک Resource (منبع) را میزنیم و عبارت زیر را جستجو می‌کنیم (فرمت ذخیره رشته در منابع برنامه اندروید).&lt;string name=&quot;s2دقت کنید که اگر تیک Resource را نزنید و دنبال s2 بگردید، جسجو در کد انجام میشه و با عبارت زیر روبرو میشید:public static final int s2 = 0x7f0f0095;جستجو را برای s3، s4 و s5 هم انجام می‌دیم که نتیجه میشه مثل زیر:&lt;string name=&quot;s2&quot;&gt;ereh&lt;/string&gt;&lt;string name=&quot;s3&quot;&gt;asghjk&lt;/string&gt;&lt;string name=&quot;s4&quot;&gt;asgsshjk&lt;/string&gt;&lt;string name=&quot;s5&quot;&gt;asghuuhjk&lt;/string&gt;با توجه به این رشته‌ها، میشه گفت که نام کاربری میشه erehasghjk و کلمه عبور هم میشه asghuuhjkasgsshjk. با وارد کردن این مقادیر در برنامه (که روی گوشی یا شبیه‌ساز نصب کردیم)، عبارت cXVlcmFDVEZ7ZWFzeV9wZWFzeV9BTkRSMDFEX0NoNExMRU5nZX0 روی صفحه نمایش داده میشه. اگر حوصله تایپ ندارید (که من اصلا ندارم) از صفحه موبایل اسکرین‌شات بگیرید و بدید CyberChef تا براتون کاراکترهاش را تشخیص بده. فقط دوتا نکته: 1- بهتره قسمت‌های اضافی عکس را ببرید 2- حتما یکبار خودتون خروجی را بخونید چون بعضی کاراکترها را اشتباه تشخیص میده. یا اینکه از OCR داخل Foxit PhantomPDF استفاده کنید که خیلی بهتره ولی فقط روی ویندوز اجرا میشه.در آخرین مرحله با CyberChef رشته مورد نظرتون را که با base64 رمزگذاری شده، رمزگشایی کنید.جواب: queraCTF{easy_peasy_ANDR01D_Ch4LLENge}</description>
                <category>نوید شیرمحمدی</category>
                <author>نوید شیرمحمدی</author>
                <pubDate>Mon, 10 Apr 2023 15:55:50 +0330</pubDate>
            </item>
                    <item>
                <title>هکاتون 1402: چالش DH Talk</title>
                <link>https://virgool.io/@nashi/%D9%87%DA%A9%D8%A7%D8%AA%D9%88%D9%86-1402-%DA%86%D8%A7%D9%84%D8%B4-dh-talk-qdyoujtrm1kb</link>
                <description>معرفی هکاتونفروردین امسال (1402) کوئرا یک مسابقه مسابقه فتح پرچم (یا همون CTF) برگزار کرد با نام هکاتون. ثبت‌نام مسابقه تا 23ام اسفندماه 1401 ادامه داشت و شما میتونستید پس از پرداخت هزینه نسبتا سنگین (480)، برای مسابقه و 18 ساعت آموزش (نه چندان با کیفیت) اقدام کنید. در بخش معرفی رویداد این مطالب نوشته شده بود:رویداد هکاتون امنیت، چهارمین هکاتون برنامه‌نویسی کوئرا است که با موضوع امنیت و در چارچوب طرح شهید بابایی بنیاد ملی نخبگان برگزار می‌شود.این رویداد شامل یک بخش آموزشی و یک بخش رقابتی است. در ابتدا، موضوعات جذاب و کاربردی حوزه امنیت در ۳ روز و با همراهی اساتید برتر این حوزه برگزار می‌شود و شما مجموعا ۱۸ ساعت آموزش می‌بینید. بعد از آموزش به تیم‌های ۲ الی ۴ نفره تقسیم می‌شوید و در یک مسابقه چالشی به رقابت می‌پردازید. بعد از مسابقه راه‌حل تیم‌ها داوری می‌شود و نفرات برتر مشمول دریافت امتیاز نخبگی بنیاد و همینطور برنده جایزه نقدی مسابقه می‌شوند. علاوه بر این نفرات برتر برای استخدام به شرکت‌های مطرح معرفی خواهند شد. برای مشاهده مراحل و زمان‌بندی رویداد روی این لینک کلیک کنید.? به تمام شرکت‌کنندگان، گواهی شرکت در رویداد اهدا خواهد شد اما فقط نفرات برتر مسابقه و بعد از داوری راه‌حل‌ها، مشمول دریافت امتیاز نخبگی بنیاد می‌شوند.⚠️ شرکت در رویداد به صورت فردی است اما پیش از مسابقه، شرکت‌کنندگان به تیم‌های ۲ الی ۴ نفره تقسیم می‌شوند تا به صورت تیمی به رقابت بپردازند. اگر از ابتدا تیم شما مشخص است و دوست دارید با تیم خود در این رویداد شرکت کنید لطفا به صورت جدا جدا ثبت‌نام خود را تکمیل کنید و بعد از ثبت‌نام به ما اطلاع دهید که می‌خواهید در یک تیم باشید.برای برگزاری رویداد از پلتفرم CTFd استفاده شده بود و تیم کوئرا چند روز قبل از مسابقه، با هدف آشنایی بچه‌ها با پلتفرم یک کوییز آزمایشی (و بدون تاثیر در نتایج مسابقه) قرار داد. سوالات این کوییز از رویداد‌هایی مثل picoctf و uutctf انتخاب شده بودند و به عنوان دست گرمی کمک بزرگی محسوب میشد. در پرانتز این هم بگم که سوالات مسابقه با اختلاف....باااا اختلااااف، سخت‌تر و جذاب‌تر بودند.و اما چالش DH Talkامتیاز: 100متن سوال:Two people are taked over the network using DH.Can you see what are they saying?توجه: غلط گرامری از متن خود سواله :)در این سوال یک فایل pcap از مکالمه دو نفر روی شبکه به ما داده شده که لینکش را میذارم. اگر محتوای فایل را بررسی کنیم میبینیم که دو نفر قصد دارند از الگوریتم دیفی-هلمن برای ارسال پیام استفاده کنند و در بین پیام‌هاشون یکی از دو طرف کلید خصوصی خودش را به اشتباه ارسال میکنه. قبل از گفتن راه حل درباره الگوریتم دیفی-هلمن کمی توضیح میدم.دیفی-هلمن (مخفف DH) یک الگوریتم تبادل کلید (key exchange) محسوب میشه که به دو نفر اجازه میده به صورت امن روی یک کانال عمومی (مثل شبکه اینترنت) به یک کلید مشترک برای تبادل پیام برسند. مراحی اصلی این الگوریتم به این صورتند: یه عدد اول بزرگ داریم به نام p که همه میدونند چی هستند (حتی کسی که می‌خواد رمز را بشکنه) و یک عدد کوچکتر بنام g که از p کوچیکتره . میتونه هر چیزی باشه. به g میگن مولد چون اگر p بار با خودش جمع بشه تمام اعداد بین 0 تا p-1 را در پیمانه p تولید میکنه (جبر پیمانه‌ای).افرادی که میخوان پیام رد و بدل کنند، هر کدوم یک عدد دلخواه بین 0 تا p-1 انتخاب میکنند. مثلا آلیس a و باب هم b را انتخاب میکنه. این اعداد میتونند هر عددی باشند.آلیس میاد و g^a (بخون g به توان a) را حساب می‌کنه و روی شبکه عمومی میفرسته برای باب. باب هم g^b را حساب میکنه و میفرسته برای آلیس. دقت کنید که g^a و g^b را همه میتونند ببیند. نکته اینجاست که محاسبه‌ی a و b از روی g^a و g^b یک مساله سخته (درس رمزنگاری ارشد کامپیوتر) بنابراین کسایی که g^a و g^b را میبینند نمی‌تونند a و b را پیدا کنند.آلیس که a را داشت و g^b را از باب گرفته، خیلی ساده g^b را به توان a میرسونه و میرسه به g^(ab) که کلید مشترکه. باب هم به صورت مشابه با داشتن b و g^a به همین کلید مشترک میرسه. روی این مورد هم تاکید میکنم که با داشتن g^a و g^b نمیشه به g^(ab) رسید (یه مساله سخت دیگه در رمزنگاری).  این کلید مشترک (g^ab) میتونه در الگوریتم‌هایی مثل AES برای رمزگذاری پیام استفاده بشه.این هم بگم که معمولا g^a را با A نمایش میدن و g^b را با B. همینطور به کلید مشترک (g^ab) میگن secret و با s نمایشش میدن.راه حلاگر فایل pcap را با استفاده از wireshark بررسی کنیم میشه پیام‌های رد و بدل شده روی شبکه را دید. با این حال برای این کار ترجیح مید اول از CyberChef استفاده کنم. اگر فایل pcap را به CyberChef بدیم و فیلتر string را اعمال کنیم، تمام اطلاعات مورد نیاز به صورت زیر بهمون نمایش داده میشه:متن خروجی:Are you ready for a key exchangeYep.P: 22953686867719691230002707821868552601124472329079G: 11My chosen number: 65321321Oh, no! You shoudn&#x27;t send your chosen number.No problem.My public key: 22765143677454692215350940273371681210671460017738Got the shared keyYes.Send your message.YVTJGc2RHVmtYMThyZU5jSGlNbTVEQmRhdlFjcFdUYk1EUmF2TVNabUJRVEFIUzJQRWp6dndTTHJ2MXVXUFJNSQpES2xzRHFyUGZOelVZZUxLd3l0d3lBPT0KHow can I read itBbSicat in.txt  base64 -d  openssl aes-256-cbc -d -a -pbkdf2 -k our_shared_keyBb61Thanks!با توجه به پیام‌های بالا و بررسی فرستنده پیام‌ها در wireshark میشه گفت: p = 22953686867719691230002707821868552601124472329079g = 11a = 65321321B = g^b = 22765143677454692215350940273371681210671460017738 اگر در wireshark فایل pcap را برسی کنیم متوجه دو مورد خیلی مهم میشیم:متن رمز شده YVTJGc2RHVm... نیست بلکه VTJGc2RHVm... است.برای رمز‌گشایی باید از دستور زیر استفاده کرد:cat in.txt | base64 -d | openssl aes-256-cbc -d -a -pbkdf2 -k &lt;کلید مشترک&gt;در نهایت با داده‌های بالا و استفاده از سایت dCode میشه کلید مشترک‌ را حساب کرد (بله، با پایتون هم میشه ولی انصافا این سایت خیلی خفنه):کلید مشترک 16477643432539305193820212134537114955092883848262 است. کافیه پیام رمز شده را در فایل in.txt ذخیره کنیم و با دستور زیر متن اصلی را بازیابی کنیم:cat in.txt | base64 -d | openssl aes-256-cbc -d -a -pbkdf2 -k 16477643432539305193820212134537114955092883848262 جواب: queraCTF{D1FfIe_HeLlMaN_WA$_N0T_T0O_HarD}</description>
                <category>نوید شیرمحمدی</category>
                <author>نوید شیرمحمدی</author>
                <pubDate>Mon, 10 Apr 2023 01:21:35 +0330</pubDate>
            </item>
                    <item>
                <title>هکاتون 1402: چالش Blinker</title>
                <link>https://virgool.io/@nashi/%D9%87%DA%A9%D8%A7%D8%AA%D9%88%D9%86-1402-%DA%86%D8%A7%D9%84%D8%B4-blinker-olh0nzvnkfog</link>
                <description>معرفی هکاتونفروردین امسال (1402) کوئرا یک مسابقه مسابقه فتح پرچم (یا همون CTF) برگزار کرد با نام هکاتون. ثبت‌نام مسابقه تا 23ام اسفندماه 1401 ادامه داشت و شما میتونستید پس از پرداخت هزینه نسبتا سنگین (480)، برای مسابقه و 18 ساعت آموزش (نه چندان با کیفیت) اقدام کنید. در بخش معرفی رویداد این مطالب نوشته شده بود:رویداد هکاتون امنیت، چهارمین هکاتون برنامه‌نویسی کوئرا است که با موضوع امنیت و در چارچوب طرح شهید بابایی بنیاد ملی نخبگان برگزار می‌شود.این رویداد شامل یک بخش آموزشی و یک بخش رقابتی است. در ابتدا، موضوعات جذاب و کاربردی حوزه امنیت در ۳ روز و با همراهی اساتید برتر این حوزه برگزار می‌شود و شما مجموعا ۱۸ ساعت آموزش می‌بینید. بعد از آموزش به تیم‌های ۲ الی ۴ نفره تقسیم می‌شوید و در یک مسابقه چالشی به رقابت می‌پردازید. بعد از مسابقه راه‌حل تیم‌ها داوری می‌شود و نفرات برتر مشمول دریافت امتیاز نخبگی بنیاد و همینطور برنده جایزه نقدی مسابقه می‌شوند. علاوه بر این نفرات برتر برای استخدام به شرکت‌های مطرح معرفی خواهند شد. برای مشاهده مراحل و زمان‌بندی رویداد روی این لینک کلیک کنید.? به تمام شرکت‌کنندگان، گواهی شرکت در رویداد اهدا خواهد شد اما فقط نفرات برتر مسابقه و بعد از داوری راه‌حل‌ها، مشمول دریافت امتیاز نخبگی بنیاد می‌شوند.⚠️ شرکت در رویداد به صورت فردی است اما پیش از مسابقه، شرکت‌کنندگان به تیم‌های ۲ الی ۴ نفره تقسیم می‌شوند تا به صورت تیمی به رقابت بپردازند. اگر از ابتدا تیم شما مشخص است و دوست دارید با تیم خود در این رویداد شرکت کنید لطفا به صورت جدا جدا ثبت‌نام خود را تکمیل کنید و بعد از ثبت‌نام به ما اطلاع دهید که می‌خواهید در یک تیم باشید.برای برگزاری رویداد از پلتفرم CTFd استفاده شده بود و تیم کوئرا چند روز قبل از مسابقه، با هدف آشنایی بچه‌ها با پلتفرم یک کوییز آزمایشی (و بدون تاثیر در نتایج مسابقه) قرار داد. سوالات این کوییز از رویداد‌هایی مثل picoctf و uutctf انتخاب شده بودند و به عنوان دست گرمی کمک بزرگی محسوب میشد. در پرانتز این هم بگم که سوالات مسابقه با اختلاف....باااا اختلااااف، سخت‌تر و جذاب‌تر بودند.و اما چالش Blinkerامتیاز: 200متن سوال: Extract the flag from the video.The flag is in queraCTF{somthing} format. something is a text containing lowercase letters and _.راهنمایی: ships used this to communicate.ویدئو: لینک https://github.com/blueBye/Hackaton2023/blob/main/blinker%20(1).mp4 توجه: متاسفانه ویدئو این سوال در میانه مسابقه جایگزین شد. ویدئو اول در این لینک قرار داره.  با دیدن این ویدئو و راهنمایی سوال خیلی سریع میشه متوجه شد که با کد مورس طرفیم. قبل از ارائه راه حل سوال کمی درباره کد مورس توضیح میدم. کد موردس یکی از روش‌های اولیه کدگذاری متن محسوب میشه و کاری که میکنه اینه که هر کاراکتر البفا انگلیسی (شامل a-z0-9 و کارکترهایی مثل / و ? و غیره) را در قالب یک الگو از نقطه و خط نمایش میده. با یه سرچ ساده morse code table میشه جدول کد مورس برای کاراکترهای مختلف را پیدا کرد. همینطور میشه از CyberChef برای تولید کد مورس استفاده کرد.اگر فرستنده قصد ارسال پیامی در قالب کد مورس را داشته باشه، باید کارکتر به کاراکتر، متنش را به الگوهای مورس ترجمه کنه و با تنظیم مکث بین ارسال نقطه و خط‌ها و مکث بین کاراکترها، متن را ارسال کنه. فرضا اگر قصد داشته باشیم متن Hello Wrold را ارسال کنیم، کد مورس معادل میشه مثل زیر. دقت کنید که حروف بزرگ و کوچیک اهمیتی ندارند. Hello: .... . .-.. .-.. --- World: .-- --- .-. .-.. -.. کسی که کد را ارسال میکنه (چه با تلگراف و چه با نور یا هر روش دیگه) میاد و به ازای هر نقطه یک مدت زمان کوتاه سیگنال میفرسته (مثلا لامپ را روشن میکنه) و به ازای هر خط یک مدت زمان  بلندتر سیگنال را میفرسته. همینطور بین ارسال نقطه و خط‌های یک کاراکتر از مکث کوتاه استفاده میکنه و بین ارسال کاراکترهای مختلف از فاصله بلندتری استفاده میکنه (ارسال eee و s را در CyberChef بررسی کنید).در این چالش، وجود لوگوی کوئرا در یک فریم معادل ارسال سیگنال در مورس در نظر گرفته شده و نبود لوگو به معنی عدم ارسال سیگناله. متاسفانه در ط.ل انجام مسابقه نونستم ابزار مناسبی برای تشخیص کد مورس در ویدئو پیدا کنم (یک کد سی در گیت‌هاب بود که کامپایل نمی‌شد، با CyberChef هم نمی‌تونستم فریم‌های ویدئو را دریافت کنم). برای همین دست به کد شدم :)) راه حلایده کلی ساده است: ویدئو را فریم به فریم جدا کن و اگر در فریمی لوگو کوئرا بود 1 چاپ کن و اگر نه 0. بعد هم صفر و یک‌ها را به کد کورس تبدیل کن. برای پردازش ویدئو از کتابخونه‌های OpenCV و Numpy در پایتون استفاده کردم. کد زیر، ویدئو را فریم به فریم جدا میکنه و اگر میانگین پیکسل‌ها بزرگتر از 50 بود یک چاپ میکنه و در غیر این صورت صفر. عدد 50 را بعد از چاپ مقدار np.average(frame) در کنسول انتخاب کردم چون دیدم فریم‌هایی که لوگو کوئرا را دارند، میانگین روشنایی پیکسل‌هاشون میشه حدود 57 و بقیه فریم‌ها صفر (سیاه =(0،0،0)).  https://gist.github.com/blueBye/cb7842adcbb351c24dcb84926fe63153 نتیجه در فایل result.txt ذخیره میشه. بخشی از این فایل به صورت زیره:1111111111111111111100000000001111111111111111111100000000000000000000000000000000000000001111111111111111111100000000001111111111111111111100000000001111111111111111111100000000000000000000000000000000000000001111111111000000000011111111111111111111000000000011111111110000000000000000000000000000000000000000111111111100000000001111111111000000000011111111110000000000000000000000000000000000000000111111111100000000000000000000000000000000000000001111111111111111111100000000001111111111000000000011111111111111111111000000000011111111110000000000000000000000000000000000000000111111111111111111110000000000111111111111111111110000000000111111111111111111110000000000000000000000000000000000000000حالا فقط کافیه در vscode با یک ctrl+h ساده اول دنباله‌های بلند صفر را به \n تبدیل کنیم، بعد دنباله‌های کوتاه صفر را به هیچ (نقش فاصله برای تشخیص خط و نقطه است که در ادامه مشخص میشن)، و بعد دنباله‌های بلند یک را به خط و دنباله‌های کوتاه 1 را به نقطه. دقت کنید که مهمه اول دنباله‌ها بلندتر به کاراکتر معادلشون تبدیل بشن و بعد دنباله‌ها کوتاه‌تر. در این سوال تبدیل‌ها میشن به این صورت:دنباله 11111111111111111111 به خطدنباله 0000000000000000000000000000000000000000 به کاراکتر خط جدید (\n)دنباله 0000000000 به هیچیدنباله 1111111111 به نقطهبخشی از نتیجه میشه مثل زیر:-----.-.....-.-.حالا با CybreChef دنباله را ترجمه میکنیم و به جواب میرسیم:جواب: queraCTF{morse_video_is_very_great}کمی بیشترهمونطور که گفتم، هنوز چند ساعت از شروع مسابقه نگذشته بود که ویدئو عوض شد. ویدئو اول با سرعت خیلی بالاتری، پیام بلندتری را مخابره می‌کرد. برای حل چالش اول از کد قسمت بالا برای چاپ صفر و یک استفاده کردم. مشکل اینجا بود که بر خلاف ویدئو دوم، در ویدئو اول طول دنباله‌های صفر و یک ثابت نبود. مثلا تول کد هفت‌تا یک پشت س هم میدیدی، شش‌تا و پنج‌تا و .. و حتی تک یک هم بود. به طور مشابه صفر‌ها هم همین وضعیت را داشتند. اینجا بود که تصمیم گرفتم این دنباله صفر و یک را به یک فایل صوتی تبدیل کنم و به این سایت بدم تا متن را برگردونه (بماند که متن خروجی هم کاملا بی معنی بود). حدس میزنم هدف کوئرا این بوده که در اینجا طول دنباله صحیح را حدس بزنیم (با کد و تست حالت‌ها) یا با تغییر وضعیت سیگنال کار کنیم (مثل رمزکذاری منچستر در بحث شبکه). در هر صورت قبل از اینکه بیشتر درگیر بشیم کلا ویدئو عوض شد و کد تولید فایل صوتی رو دستم موند. این کدی که میذارم را برای تولید فایل صوتی استفاده کردم (با حذف بخشی از دنباله تولید شده توسط کد قبل در متغیر data). چه دیدی، شاید یه روزی به کارتون اومد. https://gist.github.com/blueBye/a6cf3b64f74ce6a7146bf6a8c40452d6 </description>
                <category>نوید شیرمحمدی</category>
                <author>نوید شیرمحمدی</author>
                <pubDate>Sun, 09 Apr 2023 23:01:45 +0330</pubDate>
            </item>
                    <item>
                <title>هکاتون 1402: چالش Customer Care</title>
                <link>https://virgool.io/@nashi/%D9%87%DA%A9%D8%A7%D8%AA%D9%88%D9%86-1402-%DA%86%D8%A7%D9%84%D8%B4-customer-care-wtgfom8aztau</link>
                <description>معرفی هکاتونفروردین امسال (1402) کوئرا یک مسابقه مسابقه فتح پرچم (یا همون CTF) برگزار کرد با نام هکاتون. ثبت‌نام مسابقه تا 23ام اسفندماه 1401 ادامه داشت و شما میتونستید پس از پرداخت هزینه نسبتا سنگین (480)، برای مسابقه و 18 ساعت آموزش (نه چندان با کیفیت) اقدام کنید. در بخش معرفی رویداد این مطالب نوشته شده بود:رویداد هکاتون امنیت، چهارمین هکاتون برنامه‌نویسی کوئرا است که با موضوع امنیت و در چارچوب طرح شهید بابایی بنیاد ملی نخبگان برگزار می‌شود.این رویداد شامل یک بخش آموزشی و یک بخش رقابتی است. در ابتدا، موضوعات جذاب و کاربردی حوزه امنیت در ۳ روز و با همراهی اساتید برتر این حوزه برگزار می‌شود و شما مجموعا ۱۸ ساعت آموزش می‌بینید. بعد از آموزش به تیم‌های ۲ الی ۴ نفره تقسیم می‌شوید و در یک مسابقه چالشی به رقابت می‌پردازید. بعد از مسابقه راه‌حل تیم‌ها داوری می‌شود و نفرات برتر مشمول دریافت امتیاز نخبگی بنیاد و همینطور برنده جایزه نقدی مسابقه می‌شوند. علاوه بر این نفرات برتر برای استخدام به شرکت‌های مطرح معرفی خواهند شد. برای مشاهده مراحل و زمان‌بندی رویداد روی این لینک کلیک کنید.? به تمام شرکت‌کنندگان، گواهی شرکت در رویداد اهدا خواهد شد اما فقط نفرات برتر مسابقه و بعد از داوری راه‌حل‌ها، مشمول دریافت امتیاز نخبگی بنیاد می‌شوند.⚠️ شرکت در رویداد به صورت فردی است اما پیش از مسابقه، شرکت‌کنندگان به تیم‌های ۲ الی ۴ نفره تقسیم می‌شوند تا به صورت تیمی به رقابت بپردازند. اگر از ابتدا تیم شما مشخص است و دوست دارید با تیم خود در این رویداد شرکت کنید لطفا به صورت جدا جدا ثبت‌نام خود را تکمیل کنید و بعد از ثبت‌نام به ما اطلاع دهید که می‌خواهید در یک تیم باشید.برای برگزاری رویداد از پلتفرم CTFd استفاده شده بود و تیم کوئرا چند روز قبل از مسابقه، با هدف آشنایی بچه‌ها با پلتفرم یک کوییز آزمایشی (و بدون تاثیر در نتایج مسابقه) قرار داد. سوالات این کوییز از رویداد‌هایی مثل picoctf و uutctf انتخاب شده بودند و به عنوان دست گرمی کمک بزرگی محسوب میشد. در پرانتز این هم بگم که سوالات مسابقه با اختلاف....باااا اختلااااف، سخت‌تر و جذاب‌تر بودند.و اما چالش Customer Careامتیاز: 150متن سوال: Take care of the customers and find the flaghttp://185.94.76.76:47561راهنمایی: check the /rootمتاسفانه این سوال صرفا در طول اجرای مسابقه قابل انجام بود چراکه فایل داکر یا VM برای پیاده‌سازی‌ در آینده به بچه‌ها داده نشد و با پایان رویداد سرور هم قطع شد. اما چیزی که در آدرس IP میدیدم این بود که یک صفحه ساده HTML داریم با یک فرم. در این فرم می‌شد یک اسم وارد کرد و اگر اسم در پایگاه داده موجود بود (مثل Intech)، زیر تگ form در html، نوشته می‌شد: 1 results.  Intech   ,   false&quot;به محض دیدن فرم و صفحه‌ی شامل فرم اولین حدس میتونه آسیب‌پذیری تزریق SQL (مخفف: SQLI) باشه. با استفاده از BurpSuit و  وارد کردن مقدار زیر بجای search (در محتوای درخواستی که میرفت سمت سرور) این فرض اثبات شد.search = &#x60; OR true;#در این مرحله همچنان محتوای Hint سوال را نخونده بودم چون (به اشتباه) تصور میکردم از امتیازم کم میشه. بنابراین سعی کردم تا حد امکان درباره پایگاه‌داده اطلاعات بگیرم. با استفاده از کوئری زیر فهرست جداول پایگاه داده را استخراج کردم:search= &#x27; OR true union select table_name from  information_schema.tables;#بخشی از نتیجه پرس‌وجو شد فرست زیر. تنها جدولی که در فهرست جداول پیش‌فرض MySQL نبود جدول customers بود. برای اینکه ببینم کدوم جداول جزو جداول پیش‌فرض نیستند عبارت sql table را قبل از نام جدول قرار می‌دادم و با گوگل سرچ میکردم. در تمام موارد (به جز costomer) به داکیومنت سایت MariaDB و MySQL بر می‌خوردم. این هم بگم که اون سه تا اسم اول (Macrosoft و Initech و Initrode) محتوای جدول customer هستند که به‌خاطر OR true در کوئری استخراج شدند.85 results. Macrosoft	,Initech	,Initrode	,CHARACTER_SETS	,COLLATIONS	,COLLATION_CHARACTER_SET_APPLICABILITY	,...setup_consumers	,setup_instruments	,setup_timers	,threads	,customers	,falseسعی کردم فهرست ستون‌های هر جدول و نوع داده اونها را با کوئری زیر استخراج کنم. مثلا برای جدول customers داریم:search=&#x27; OR true union select concat(column_name,0x3a,data_type) from information_schema.columns where table_name=&#x27;customers&#x27;;#و خروجی میشه مثل زیر که نشون میده جدول customers فقط یک ستون داره به نام c و از نوع char: 4 results. Macrosoft	,Initech	,Initrode	,c:char	,falseاهمیت این موضوع از این جهته که اگر با union قصد استخراج داده را داشته باشیم باید data type ستون‌هایی که متصل میشن یکسان باشه (اینجا چون c از نوع char هست و نمی‌تونیم قسمت‌های قبلی کوئری روی سرور را اصلاح کنیم، پس باید ستون جدید هم از نوع char باشه). در مرحله بعد سعی کردم تمام محتوای برخی از ستون‌های جدوال مختلف را با query زیر دریافت کنم که نتیجه‌ای هم نداشت:search= &#x27; OR true union select concat(&#x27;&gt;&gt; &#x27;, username) from users;#راه حلبا توجه به راهنمایی سوال میشه متوجه شد که باید از SQLI برای خوندن فایل روی سرور استفاده کنیم. خوشبختانه (یا بدبختانه) در SQL میشه از load_file به این منظور استفاده کرد. کوئری زیر راه حل این سواله:search=&#x27; union select load_file(&#x27;/root/flag.txt&#x27;) from information_schema.tables;#و پاسخی که دریافت می‌کنیم:4 results.Macrosoft	,Initech	,Initrode	,queraCTF{C@r1ng_ab0utS3cur1ty_iSCr33py_WGKNW23}	,false پاسخ: queraCTF{C@r1ng_ab0utS3cur1ty_iSCr33py_WGKNW23}</description>
                <category>نوید شیرمحمدی</category>
                <author>نوید شیرمحمدی</author>
                <pubDate>Sun, 09 Apr 2023 01:23:54 +0330</pubDate>
            </item>
                    <item>
                <title>هکاتون 1402: چالش Peaky Blinders</title>
                <link>https://virgool.io/@nashi/%D9%87%DA%A9%D8%A7%D8%AA%D9%88%D9%86-1402-%DA%86%D8%A7%D9%84%D8%B4-peaky-blinders-nwqkqaur7sx0</link>
                <description>معرفی هکاتونفروردین امسال (1402) کوئرا یک مسابقه مسابقه فتح پرچم (یا همون CTF) برگزار کرد با نام هکاتون. ثبت‌نام مسابقه تا 23ام اسفندماه 1401 ادامه داشت و شما میتونستید پس از پرداخت هزینه نسبتا سنگین (480)، برای مسابقه و 18 ساعت آموزش (نه چندان با کیفیت) اقدام کنید. در بخش معرفی رویداد این مطالب نوشته شده بود:رویداد هکاتون امنیت، چهارمین هکاتون برنامه‌نویسی کوئرا است که با موضوع امنیت و در چارچوب طرح شهید بابایی بنیاد ملی نخبگان برگزار می‌شود.این رویداد شامل یک بخش آموزشی و یک بخش رقابتی است. در ابتدا، موضوعات جذاب و کاربردی حوزه امنیت در ۳ روز و با همراهی اساتید برتر این حوزه برگزار می‌شود و شما مجموعا ۱۸ ساعت آموزش می‌بینید. بعد از آموزش به تیم‌های ۲ الی ۴ نفره تقسیم می‌شوید و در یک مسابقه چالشی به رقابت می‌پردازید. بعد از مسابقه راه‌حل تیم‌ها داوری می‌شود و نفرات برتر مشمول دریافت امتیاز نخبگی بنیاد و همینطور برنده جایزه نقدی مسابقه می‌شوند. علاوه بر این نفرات برتر برای استخدام به شرکت‌های مطرح معرفی خواهند شد. برای مشاهده مراحل و زمان‌بندی رویداد روی این لینک کلیک کنید.? به تمام شرکت‌کنندگان، گواهی شرکت در رویداد اهدا خواهد شد اما فقط نفرات برتر مسابقه و بعد از داوری راه‌حل‌ها، مشمول دریافت امتیاز نخبگی بنیاد می‌شوند.⚠️ شرکت در رویداد به صورت فردی است اما پیش از مسابقه، شرکت‌کنندگان به تیم‌های ۲ الی ۴ نفره تقسیم می‌شوند تا به صورت تیمی به رقابت بپردازند. اگر از ابتدا تیم شما مشخص است و دوست دارید با تیم خود در این رویداد شرکت کنید لطفا به صورت جدا جدا ثبت‌نام خود را تکمیل کنید و بعد از ثبت‌نام به ما اطلاع دهید که می‌خواهید در یک تیم باشید.برای برگزاری رویداد از پلتفرم CTFd استفاده شده بود و تیم کوئرا چند روز قبل از مسابقه، با هدف آشنایی بچه‌ها با پلتفرم یک کوییز آزمایشی (و بدون تاثیر در نتایج مسابقه) قرار داد. سوالات این کوییز از رویداد‌هایی مثل picoctf و uutctf انتخاب شده بودند و به عنوان دست گرمی کمک بزرگی محسوب میشد. در پرانتز این هم بگم که سوالات مسابقه با اختلاف....باااا اختلااااف، سخت‌تر و جذاب‌تر بودند.و اما چالش Peaky Blindersامتیاز: 100متن سوال: Can you decode the flag?فایل: flag.txt queraCTF{2803 2817 2801 280A 2807 2807 2811_280A 280E _281B 2817 2811 2801 281E}توجه: در فایل اصلی، هر یک از کاراکترها در یک خط مجزا قرار داشتند. همچنین هر یک از اعداد 28xx در یک خط قرار داشت که برای خوانایی پست، خط حروف حذف و خط میان اعداد چها رقمی با فاصله جایگزین شدند.خب باید اعتراف کنم که این سوال به شدت ساده بود و من به شدت جاده خاکی زدم :)) . با این حال جاده جالبی بود...بذارین قبل از گفتن راه حل بگم چی شد. اولین حدس من با دیدن دنباله اعداد بالا (که غلط هم از آب دراومد) این بود که با یک رمز shift (مثل caesar cipher) مواجه هستم و اون بخش 2800 صرفا یه رد گم کنیه. برای بررسی این فرضیه یک اسکریپت پایتون نوشتم. این اسکریپت میومد و خیلی شیک و مجلسی کاراکترهای متناظر با اعداد بالا (که 2800 ازشون کم شده بود) را با یک عدد جمع میکرد و کاراکتر جدید را چاپ میکرد. https://gist.github.com/blueBye/28d5280e195da2b4c138ea6c4d8b9ab9 بخشی خروجی کد بالا یه چیزی شبیه اینه:0D.744&gt;7;HD&gt;.K1E/855?8&lt;IE?/L2F0966@9=JF@0M3G1:77A:&gt;KGA1N4H2;88B;?LHB2O5I3&lt;99C&lt;@MIC3P6J4=::D=ANJD4Q7K5&gt;;;E&gt;BOKE5R8L6?&lt;&lt;F?CPLF6S9M7@==G@DQMG7T:N8A&gt;&gt;HAERNH8U;O9B??IBFSOI9V&lt;P:C@@JCGTPJ:Wبعد از کمی سعی و خطا با کاراکترهای مختلف بالاخره قانع شدم که راه حل این نیست. فرض دومم این بود که با یک substitution cipher طرفم و اون Peaky Blinders یک نقشی در راه حل داره. در این مرحله توجهم را گذشتم روی اون دو تا عدد 2807 بخش اول (قبل از اولین _) و همینطور محتوای بخش دوم (یعنی 280A 280E). در این گام تاریخی رفتم و فهرست شخصیت‌های سریان پیکی بلایندرز را گرفتم و با ctrl+f دنبال اسم‌هایی کشتم که هفت حرفی هستند و کاراکتر پنجم و ششمشون یکیه. نتیجه شد Jurossi :).  بخش دوم را احتمال دادم on باشه چون در Jurossi  هم کاراکتر چهارم با کد 280A اومده (تا اینجای کار کلی فسفر سوزونده بودم). بخش سوم را میدونستم باید یک کلمه 5 حرفی باشه و با توجه به کد کراکترهای Jurossi  میدونستم باید به فرمت ؟uir? باشه. رفتم سر یک سایت حدس کلمه و با حرز قاطع :)) نتیجه گرفتم که فلگ میشه queraCTF{jurossi_on_quirk}. تا همین لحظه دارم از این سیر تفسیر و استدلال میخندم.راه حلبرای حل این چالش کافیه در جدول UTF-8 کد کاراکترهای فایل flag را سرچ کنید. بخش 28xx مربوط به کاراکترهای بریل (Braille) میشه.queraCTF{⠃⠗⠁⠊⠇⠇⠑_⠊⠎_⠛⠗⠑⠁⠞} با استفاده از CyberChef میشه به فلگ رسید:جواب: queraCTF{BRAILLE_IS_GREAT}</description>
                <category>نوید شیرمحمدی</category>
                <author>نوید شیرمحمدی</author>
                <pubDate>Sun, 09 Apr 2023 00:34:35 +0330</pubDate>
            </item>
                    <item>
                <title>هکاتون 1402: چالش Bit</title>
                <link>https://virgool.io/@nashi/%D9%87%DA%A9%D8%A7%D8%AA%D9%88%D9%86-1402-%DA%86%D8%A7%D9%84%D8%B4-bit-peje2pi35rpn</link>
                <description>معرفی هکاتونفروردین امسال (1402) کوئرا یک مسابقه مسابقه فتح پرچم (یا همون CTF) برگزار کرد با نام هکاتون. ثبت‌نام مسابقه تا 23ام اسفندماه 1401 ادامه داشت و شما میتونستید پس از پرداخت هزینه نسبتا سنگین (480)، برای مسابقه و  18 ساعت آموزش (نه چندان با کیفیت) اقدام کنید. در بخش معرفی رویداد این مطالب نوشته شده بود:رویداد هکاتون امنیت، چهارمین هکاتون برنامه‌نویسی کوئرا است که با موضوع امنیت و در چارچوب طرح شهید بابایی بنیاد ملی نخبگان برگزار می‌شود.این رویداد شامل یک بخش آموزشی و یک بخش رقابتی است. در ابتدا، موضوعات جذاب و کاربردی حوزه امنیت در ۳ روز و با همراهی اساتید برتر این حوزه برگزار می‌شود و شما مجموعا ۱۸ ساعت آموزش می‌بینید. بعد از آموزش به تیم‌های ۲ الی ۴ نفره تقسیم می‌شوید و در یک مسابقه چالشی به رقابت می‌پردازید. بعد از مسابقه راه‌حل تیم‌ها داوری می‌شود و نفرات برتر مشمول دریافت امتیاز نخبگی بنیاد و همینطور برنده جایزه نقدی مسابقه می‌شوند. علاوه بر این نفرات برتر برای استخدام به شرکت‌های مطرح معرفی خواهند شد. برای مشاهده مراحل و زمان‌بندی رویداد روی این لینک کلیک کنید.? به تمام شرکت‌کنندگان، گواهی شرکت در رویداد اهدا خواهد شد اما فقط نفرات برتر مسابقه و بعد از داوری راه‌حل‌ها، مشمول دریافت امتیاز نخبگی بنیاد می‌شوند.⚠️ شرکت در رویداد به صورت فردی است اما پیش از مسابقه، شرکت‌کنندگان به تیم‌های ۲ الی ۴ نفره تقسیم می‌شوند تا به صورت تیمی به رقابت بپردازند. اگر از ابتدا تیم شما مشخص است و دوست دارید با تیم خود در این رویداد شرکت کنید لطفا به صورت جدا جدا ثبت‌نام خود را تکمیل کنید و بعد از ثبت‌نام به ما اطلاع دهید که می‌خواهید در یک تیم باشید.برای برگزاری رویداد از پلتفرم CTFd استفاده شده بود و تیم کوئرا چند روز قبل از مسابقه، با هدف آشنایی بچه‌ها با پلتفرم یک کوییز آزمایشی (و بدون تاثیر در نتایج مسابقه) قرار داد. سوالات این کوییز از رویداد‌هایی مثل picoctf و uutctf انتخاب شده بودند و به عنوان دست گرمی کمک بزرگی محسوب میشد. در پرانتز این هم بگم که سوالات مسابقه با اختلاف....باااا اختلااااف، سخت‌تر و جذاب‌تر بودند.و اما چالش Bitامتیاز: 100متن سوال: The flag is somewhere in the image.با توجه به اسم سوال و اینکه یک تصویر با فرمت PNG داریم، اولین حدسم این بود که با پنهان‌نگاری از نوع LSB سروکار دارم. قبل از گفتن راه‌حل یک توضیح کوتاهی درباره پنهان نگاری و LSB باید بگم.فرض کنید قصد دارید یک داده را برای یک نفر دومی ارسال کنید و یک نفر سومی هم هست که کانال ارتباطی شما و نفر دوم را کنترل می‌کنه. هدف شما اینه که داده مورد نظرتون به نحوی منتقل بشه که نفر سوم متوجه ارسال پیام نشه. دقت کنید اصلا اینکه بفهمه داده شما چی بوده مهم نیست، مساله اینه که متوجه نشه شما داده‌ای ارسال کردید.پنهان نگاری یا steganography به عملیاتی گفته میشه که سعی میکنه یک داده را در یک پوشه (مثلا یک تصویر، متن یا فایل صوتی) پنهان کنه به شکلی که ناظر خارجی نتونه تشخیص بده داده‌ای در پوشه پنهان شده. یکی از روش‌های پنهان‌نگاری اولیه برای تصویر  LSB یا Least Significant Bit نام داره. ایده این روش اینه که در هر پیکسل از تصویر، بیت‌ها کم ارزش (سمت راست) تاثیر کمی در کیفیت تصویر دارند، پس میشه ازشون برای پنهان کردن داده استفاده کرد. مثلا در تصویر PNG که هر پیکسل چهار کانال Red, Blue, Green و Alpha را داره (یا بعضا سه کانال)، اگر مقدار کانال قرمز یکی از پیکسل‌ها 10001001 باشه یا 10001000، کیفیت تصویر از دید انسان فرقی نمیکنه.نکته مهمی که هست اینه که تصویر با فرمت JPG از این کم اهمیت بودن پیکسل‌ها کم ارزش برای فشرده سازی استفاده میکنه (در کنار تبدیل فوریه و ...) برای همین LSB در تصاویر با فرمت PNG میتونه استفاده بشه.خلاصه کلام: در LSB بیت‌ها کم ارزش هر یک از کانال‌های پیکسل‌خای تصویر میتونه برای پنهان‌سازی داده مورد استفاده قرار بگیره.راه حلدر گام اول بهتره بررسی کنیم که اصلا از LSB استفاده شده یا نه. خوشبختانه به سادگی با ابزار CyberChef میشه این موضوع را بررسی کرد. کافیه تصویر را وارد کنیم و از بلوک View Bit Plane استفاده کنیم (لینک). نتیجه میشه عکس زیر. از الگو سیاه و سفید سمت چپ تصویر خروجی (بخش Output) کاملا واضحه که این بخش از تصویر حاوی اطلاعات مخفیه.برای استخراج LSB میشه از ابزار CyberChef استفاده کرد. برای تحلیل تصویر کافیه از بلوک‌ها Extract LSB  و Strings استفاده کنیم. با این لینک می‌تونید پیکربندی من برای این چالش را بررسی کنید. پرچم در کانال Alpha قرار داره.پرچم: queraCTF{u$eFu1_bIt_P1aN3}کمی بیشتر1. تصویری که در این پست می‌بینید را نمیشه برای پنهان نگاری استفاده کرد چون روی وب تمام تصاویر با فرمت JPG فشرده میشن. تصویر را از این لینک دانلود کنید. اگر هم خواستید میتونید با سرچ image steganography یا LSB Steganography tools ابزارهای این کار را پیدا کنید.2. ابزار CyberChef را میتونید به صورت رایگان دانلود کنید و روی سیستم خودتون داشته باشید. این ابزار می‌تونه برای حل چالش‌ها کدگذاری (مثل Base64)، رمزنگاری (مثل AES) و کلی کار خفن دیگه مورد استفاده قرار بگیره.3. همونطور که گفتم LSB یکی از روش‌های پنهان‌نگاری اوله محسوب میشه. برای پیچیده‌تر کردن پنهان‌نگاری میشه با استفاده از کلید، تعدادی از پیکسل‌های خاص را در کل تصویر برای پنهان‌ کردن داده مورد استفاده قرار داد.</description>
                <category>نوید شیرمحمدی</category>
                <author>نوید شیرمحمدی</author>
                <pubDate>Sat, 08 Apr 2023 23:17:13 +0330</pubDate>
            </item>
            </channel>
</rss>